Java JDBC 操作

Posted 月光莫里亚

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java JDBC 操作相关的知识,希望对你有一定的参考价值。

1.简介

JDBC(Java DataBase Connectivity) 是一种可用于执行SQL语句的Java API,是一套面向对象的应用程序接口,

统一了数据库的访问方式,数据库厂商提供了实现接口的类,称为‘驱动程序’。因此JDBC并不能直接访问数据库,

需要依赖数据库厂商提供的JDBC驱动程序。

--SQL语言:

数据定义语言(Data Definition Language,DDL)如:create,alter,drop等

数据操纵语言(Data Manipulation Language,DML)如update,delete等

数据查询语言(Data Query language,DQL),查询

数据控制语言(Data Control Language,DCL),如grant,revoke等

事务控制语言(Transaction Control Language,TCL),如commit,rollback等

2.准备工作,以mysql为例

a.安装了Mysql 数据库

b.下载mysql驱动包并在项目中导入jar包:mysql-connector-java-5.1.42-bin.jar 

3.JDBC的操作

步骤:

1.注册驱动

2.连接数据库

3.创建语句对象,用于执行SQL

4.执行SQL

5.处理执行结果

6.关闭连接

一、JDBC基本操作

1)在数据库先建立一张表Student

CREATE TABLE student(
    id INT AUTO_INCREMENT,
    NAME VARCHAR(20),
    age INT ,
    PRIMARY KEY(id)
);

2)jdbc实现

package com.huan.jdbc;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class JDBCDemo01 {
    public static void main(String[] args) {
        //声明连接
        Connection connection = null;
        try {
            //加载驱动
            Class.forName("com.mysql.jdbc.Driver");
            //数据库连接信息
            //地址  jdbc:mysql://地址/数据库
            String url = "jdbc:mysql://localhost:3306/huan";
            String user = "root";
            String password = "root";
            //获得连接
            connection = DriverManager.getConnection(url, user, password);
            //语句对象
            Statement st = connection.createStatement();
            String sql = "insert into student (name,age) values (\'zhangsan\',30)";
            //执行sql  DDL-execute()方法  DML-executeUpdate()方法 DQL-executeQuery()方法
            int n = st.executeUpdate(sql);
            String querySql = "select id,name,age from student";
            ResultSet rs = st.executeQuery(querySql);
            //处理结果
            while(rs.next()){
                int id = rs.getInt("id");
                String name = rs.getString("name");
                int age = rs.getInt("age");
                System.out.println("id:"+id+" name:"+name+" age:"+age);
            }
            //释放资源
            rs.close();
            st.close();
            
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }finally {
            //关闭连接
            if(connection != null){
                try {
                    connection.close();
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
        
    }
}

上面先执行了一条插入语句,由于主键id是自增的,因此直插入了名字zhangsan和年龄30,然后查询了表的数据

输出如下:

id:1 name:zhangsan age:30

二、JDBC连接的封装

由于连接数据库的过程都是一样,为了提高代码的重用,可以将数据库的连接封装起来:

首先将数据库的连接信息放到配置文件中,比如在项目根目录下新建文件db.properties,如下:

#db.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/huan
jdbc.user=root
jdbc.password=root

JDBCUtil类

package com.huan.jdbc;

import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;


public class JDBCUtil {
    
    private static String driverClass;
    private static String url;
    private static String user;
    private static String password;
    //静态块加载数据库配置属性
    static{
        Properties config = new Properties();
        try {
            config.load(new FileInputStream("db.properties"));
        } catch (Exception e) {
            e.printStackTrace();
        }
        driverClass = config.getProperty("jdbc.driver");
        url = config.getProperty("jdbc.url");
        user = config.getProperty("jdbc.user");
        password =config.getProperty("jdbc.password");
    }
    
    
    //获取数据库连接
    public static Connection getConnection() throws SQLException {
        
        try {
            Class.forName(driverClass);
            Connection connection = DriverManager.getConnection(url, user, password);
            return connection;
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            throw new SQLException("没有找到驱动",e);
        }

    }
    
    //关闭资源
    public static void close(Connection connection,Statement st,ResultSet rs){
        
        if(connection != null){
            try {
                connection.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        
        if(st != null){
            try {
                st.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        
        if(rs != null){
            try {
                rs.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        
    }
    
}

测试JDBCUtil

package com.huan.jdbc;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class JDBCUtilTest {
    public static void main(String[] args) {
        Connection connection = null;
        Statement st = null;
        ResultSet rs =null;
        try {
            connection = JDBCUtil.getConnection();
            String sql = "select id ,name ,age from student" ;
            st = connection.createStatement();
            rs = st.executeQuery(sql);
            while(rs.next()){
                int id = rs.getInt("id");
                String name = rs.getString("name");
                int age = rs.getInt("age");
                System.out.println("id:"+id+" name:"+name+" age:"+age);
            }
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }finally {
            JDBCUtil.close(connection, st, rs);
        }
        
        
        
    }
}

输出:

id:1 name:zhangsan age:30

三 SQL预处理及事务

SQL预处理:在之前的处理中都是将sql语句发送到数据库,有数据库的sql解释器把sql语句生成底层的内部命令,然后执行命令,完成操作,当前不断的

                  向数据库发送sql语句,会增加数据库sq解释器的负担,影响执行速度。

                  而Connection的prepareStatement(Stirng sql)方法能够对sql语句进行预处理,生成数据底层的命令,并封装在PrepareStatement对

                  象中,通过对应的方法执行底层数据库的命令,从而减轻数据库的负担,提高访问速度。

                  并且之前的sql都是拼接的,当带参数拼接时容易造成SQL的注入(参数中含有sql成分,改变原有的sql语句逻辑),而PrepareStatement在

                 编译之后,其中的sql执行计划已经确定,当替换参数时不会改变执行计划,因此可以避免sql注入。

事务控制:   当我们在编写逻辑的时候,存在多条的插入或者更新语句,前面的sql成功执行之后出现错误,这时导致业务逻辑中断,而执行成功的数据已经

                 存入数据库,从而导致数据不完整。为避免这种事情的发生就需要手动进行事务控制。

                1.关闭自动提交--connection.setAutoCommit(false);

                2.业务执行完成后提交-connection.commit();

                3.在遇到异常时回滚-connection.rollback();

package com.huan.jdbc;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;

public class PrepareStatementDemo {
    public static void main(String[] args) {
        Connection connection = null;
        //SQL预处理对象
        PreparedStatement ps = null;
        ResultSet rs =null;
        
        try {
            connection = JDBCUtil.getConnection();
            connection.setAutoCommit(false);
            //?代表参数
            String sql = "insert into student (name,age) values(?,?)";
            //编译预执行计划 在数据库上创建执行计划  
            //(第二个参数可以不要-Statement.RETURN_GENERATED_KEYS 代表返回主键,没有的话下面的要去掉ps.getGeneratedKeys()会)
            ps = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
            //?的位置 和 替换的值
            ps.setString(1, "lisi");
            ps.setInt(2, 20);
            //n 更新结果的数量
            int n = ps.executeUpdate();
            System.out.println("成功插入"+n+"条数据");
            //获取插入成功数据的主键
            ResultSet keySet = ps.getGeneratedKeys();
            int key = -1;
            while(keySet.next()){
                key = keySet.getInt(1);
            }
            System.out.println("插入数据的主键:"+key);
            //查询
            String querySql = "select id , name ,age from student";
            ps = connection.prepareStatement(querySql);
            rs = ps.executeQuery();
            //获取结果集的元数据相关信息
            ResultSetMetaData metaData = rs.getMetaData();
            //列数
            int count = metaData.getColumnCount();
            for(int i = 1; i <= count; i++){
                System.out.print(metaData.getColumnName(i)+" ");
            }
            System.out.println();
            //查询结果打印
            while(rs.next()){
                int id = rs.getInt("id");
                String name = rs.getString("name");
                int age = rs.getInt("age");
                System.out.println(id+" "+name+" "+age);
            }
            //提交
            connection.commit();
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            if(connection != null){
                try {
                    //出现异常回滚
                    connection.rollback();
                } catch (SQLException e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                }
            }
        }finally {
            JDBCUtil.close(connection, ps, rs);
        }

    }
}

输出结果:

成功插入1条数据
插入数据的主键:2
id name age 
1 zhangsan 30
2 lisi 20

成功插入了 lisi 这条记录,且返回主键为2.最后打印了列名和查询得到的数据

这里用了事务的回滚,如果保存完之后再查询的中间出现异常,数据是不会存到数据库的,可以动手试下。

四、JDBC的批量操作

PrepareStatement和Statement都提供了可以批量操作SQL的方法

1.将sql添加至缓存区

Statement: addBatch(sql)方法,可以将sql直接添加Statement缓存区;

PrepareStatement:需要先执行setxxx(n,参数)方法将参数赋值,然后调用addBatch(sql)方法

2.执行executeBatch()将参数批量发送到数据库,并且执行

3.可以使用clearBatch()清空缓存区的参数或者sql

package com.huan.jdbc;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Arrays;

import org.junit.Test;

public class JDBCBatchDemo {

    
    @Test
    public void testJdbcPrepareBatch(){
        
        Connection connection = null;
        PreparedStatement ps = null;
        
        try {
            connection = JDBCUtil.getConnection();
            String sql  = "insert into student (name,age) values (?,?)";
            ps = connection.prepareStatement(sql);
            ps.setString(1, "ps1");
            ps.setInt(2, 11);
            ps.addBatch();
            ps.setString(1, "ps2");
            ps.setInt(2, 12);
            ps.addBatch();
            int [] n = ps.executeBatch();
            System.out.println(Arrays.toString(n));    
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
        
        
        
    }
    
    
    @Test
    public void testJdbcStatementBatch(){
        Connection connection = null;
        Statement st = null;
        try {
            connection = JDBCUtil.getConnection();
            String sql1 = "insert into student(name,age) values(\'statement1\',20)";
            String sql2 = "insert into student(name,age) values(\'statement2\',30)";
            String sql3 = "insert into student(name,age) values(\'statement3\',40)";
            
            st = connection.createStatement();
            //批量添加
            st.addBatch(sql1);
            st.addBatch(sql2);
            st.addBatch(sql3);
            //执行
            int [] n = st.executeBatch();
                    
            System.out.println(Arrays.toString(n));
            
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }finally{
            JDBCUtil.close(connection, st, null);
        }
    }
    
    
}

testJdbcStatementBatch()测试方法完成后查看数据库,数据成功添加:

image

testJdbcPrepareBatch()测试方法执行之后查看数据库,数据成功添加:

image

五、连接池(数据源)的使用

连接池能够重用数据库的连接,控制数据库的连接总数,当关闭从连接池中获取的连接时,只是将此连接归还给连接池,没有真正的与数据库断开连接。

重用的连接池有:DBCP和c3p0

1)c3p0的使用

官网下载jar包,将c3p0-0.9.5.2.jar和mchange-commons-java-0.2.11.jar加入项目中。

package com.huan.jdbc;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import com.mchange.v2.c3p0.ComboPooledDataSource;


public class C3p0DataSourceDemo {
    
    public static void main(String[] args) {
        Connection connection = null;
        
        try {
            ComboPooledDataSource cpds = new ComboPooledDataSource();
            //配置连接池参数
            cpds.setDriverClass("com.mysql.jdbc.Driver");
            cpds.setJdbcUrl("jdbc:mysql://localhost:3306/huan");
            cpds.setUser("root");
            cpds.setPassword("root");
            //连接池的管理策略 ...
            //最小连接数量
            cpds.setMinPoolSize(5);
            //最大连接数量
            cpds.setMaxPoolSize(20);
            //超时时间ms
            cpds.setCheckoutTimeout(10000);
            //获取连接
            connection = cpds.getConnection();
            String sql = "select id,name,age from student";
            PreparedStatement ps = connection.prepareStatement(sql);
            ResultSet rs = ps.executeQuery();
            while(rs.next()){
                int id = rs.getInt("id");
                String name = rs.getString("name");
                int age = rs.getInt("age");
                System.out.println("id:"+id+" name:"+name+" age:"+age);
            }
            
            rs.close();
            ps.close();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }finally {
            try {
                connection.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

    }
    
}

输出结果:

id:1 name:zhangsan age:30
id:2 name:lisi age:20
id:3 name:statement1 age:20
id:4 name:statement2 age:30
id:5 name:statement3 age:40
id:6 name:ps1 age:11
id:7 name:ps2 age:12

2)DBCP的使用

官网下载jar包,将commons-logging-1.2.jar,commons-dbcp2-2.1.1.jar和commons-pool2-2.4.2.jar下载后导入项目

package com.huan.jdbc;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import org.apache.commons.dbcp2.BasicDataSource;

public class DBCPDemo {
    public static void main(String[] args) {
        Connection connection = null;

        try {
            BasicDataSource bds = new BasicDataSource();
            // 连接参数
            bds.setDriverClassName("com.mysql.jdbc.Driver");
            bds.setUrl("jdbc:mysql://localhost:3306/huan");
            bds.setUsername("root");
            bds.setPassword("root");
            // 管理策略参数
            bds.setInitialSize(5);
            bds.setMinIdle(5);
            bds.setMaxTotal(20);
            bds.setMaxWaitMillis(10000);

            connection = bds.getConnection();
            String sql = "select id,name,age from student";
            PreparedStatement ps = connection.prepareStatement(sql);
            ResultSet rs = ps.executeQuery();
            while (rs.next()) {
                int id = rs.getInt("id");
                String name = rs.getString("name");
                int age = rs.getInt("age");
                System.out.println("id:" + id + " name:" + name + " age:" + age);
            }

            rs.close();
            ps.close();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            try {
                if (connection != null) {
                    connection.close();
                }

            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

    }

}

输出结果:

id:1 name:zhangsan age:30
id:2 name:lisi age:20
id:3 name:statement1 age:20
id:4 name:statement2 age:30
id:5 name:statement3 age:40
id:6 name:ps1 age:11
id:7 name:ps2 age:12

关于JDBC的一些总结就写这么多了~~

以上是关于Java JDBC 操作的主要内容,如果未能解决你的问题,请参考以下文章

关于mysql驱动版本报错解决,Cause: com.mysql.jdbc.exceptions.jdbc4Unknown system variable ‘query_cache_size(代码片段

java jdbc操作数据库通用代码

如何在片段中填充列表视图?

Java——JDBC Template

用Java手动封装JDBC连接池

jdbc