JDBC 数据库连接池(JDBCUtils工具类)


前言

注:记录自己学的知识点,用词极其不严谨,写的随意,无参考价值。


一、JDBC作用?

连接数据库,数据库有多个厂家,为方便开发者的调用,各个数据库厂家统一了一个接口类供调用。

二、获取数据的连接方式

写个最好用的, 通过Properties对象获取配置文件。

   public void connect03() throws IOException, ClassNotFoundException, SQLException {
        // 通过Properties对象获取配置文件的信息
       Properties properties = new Properties();
       properties.load(new FileInputStream("src\\mysql.properties")); //配置文件地址
       // 获取相关的值
       String user = properties.getProperty("user");
       String password = properties.getProperty("password");
       String driver = properties.getProperty("driver");
       String url = properties.getProperty("url");

       //注册驱动
       Class.forName("com.mysql.jdbc.Driver");

       //获取链接
       Connection connection = DriverManager.getConnection(url, user, password);

       System.out.println("method 4 = " + connection);
   }

三、Statement/PreStatement执行sql

执行sql语句 实现对数据库的增删改查之类的操作
二者均可执行sql 但前者有sql注入的风险
所谓sql注入 就是有‘牛逼’的人 通过执行一些长的特别的sql语句来损害你的数据库
PreStatement不但可以很好的解决sql注入风险而且大大减少了编译次数,效率更高(Pre 预编译)

四、ResultSet结果集

若执行的sql语句是
select : 保存查询的结果
update / insert/ delete 之类的 :保存受影响的行数(返回int)
例:
select:

	    String sql = "select * from friends"
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        ResultSet resultSet = preparedStatement.executeQuery();
        while (resultSet.next()) {
            int id = resultSet.getInt(1);
            String name = resultSet.getString(2);
            String phone = resultSet.getString(3);
            System.out.println(id + "\t" + name + "\t" + phone);
        }

update:

 	    // String sql = "create table friends (id INT primary key auto_increment, name varchar(32) not null default ' ', phone varchar(32) not null default ' ')";
        //String sql  = "insert into friends values (null, 'xx', '199180074079')";
        String sql = "insert into friends values (null, 'tom', '1557434575765')";
        // String sql = "update friends set name = 'king' where name = 'tom'";
        // String sql = "delete from friends where name = 'bue'";
         int rows = preparedStatement.executeUpdate();
         System.out.println(rows > 0 ? "success" : "error"); //row > 0 则说明数据库受sql语句影响 执行了相关的sql操作。

五、JDBC相关API

韩老师的图
在这里插入图片描述在这里插入图片描述

六、事务

保证数据的完整性和一致性
JDBC程序中当一个Connection对象创建时,默认情况下是自动提交的,也就是说遇到一条sql语句就执行提交,这样会造成什么问题呢?
在这里插入图片描述
A有1000存款,B有2000。第一条sql预取 = “A向B转账500”, 第二条sql语句= “B收到500转账"。 执行完第一条sql语句即自动提交 A剩500存款,而若执行第二条sql语句之前,程序发生了错误,则无法保证B收到转账,也就是无法保证两条sql语句同时执行。
我们可以用事务很好的解决这个问题

    public void useTransaction() {
        //得到连接
        Connection connection = null;

        PreparedStatement preparedStatement = null;
        //组织sql语句
        String sql01 = "update account set balance = balance - 100 where id = 1";
        String sql02 = "update account set balance = balance + 100 where id = 2";
        // 执行sql语句
        try {
            connection = JDBCUtils.getConnection();
            // 执行sql01
            connection.setAutoCommit(false); //设置为不自动提交  相当于开启事务
            preparedStatement = connection.prepareStatement(sql01);
            int rows01 = preparedStatement.executeUpdate();

            //执行sql02
            int i = 1 / 0; //抛出异常 导致sql02无法正常执行
            preparedStatement = connection.prepareStatement(sql02);
            int rows02 = preparedStatement.executeUpdate();

            //提交事务
            connection.commit();

            System.out.println(rows01 > 0 ? "success" : "error");
            System.out.println(rows02 > 0 ? "success" : "error");

        } catch (SQLException e) {
            System.out.println("执行sql语句过程中发生异常  撤销事务的执行");
            try {
                connection.rollback(); //回滚事务
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
            e.printStackTrace();
        } finally {
            JDBCUtils.close(null, preparedStatement, connection);
        }
    }

七、批处理

假如要执行一万条sql语句,一条一条处理也太蠢太慢了,于是就有了批处理Batch
怎么用呢?
1、addBatch() 将sql语句加入到批处理包中
2、executeBatch() 执行批处理包中的sql语句 (大量!)
3、clearBatch() 清除批处理包中的sql语句

   public void batch() throws SQLException {
        Connection connection = JDBCUtils.getConnection();
        String sql = "insert into admin2 values (null, ?, ?)";
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        for (int i = 0; i < 5000; i++) {
            preparedStatement.setString(1, "xx" + i);
            preparedStatement.setString(2, "" + i);

            //将sql语句加入道批处理包中
            preparedStatement.addBatch();

            // 每1000条数据批量处理
            if ((i + 1) % 1000 == 0) {
                preparedStatement.executeBatch();
                // 添加完后 清空batch
                preparedStatement.clearBatch();
            }
        }
    }

八、数据库连接池

跟上面意思差不多 当数据库要获取很多很多个连接的时候(getConnection())每次都断开在重新连接十分麻烦,且效率不高。
韩老师的图
在这里插入图片描述
常用的数据库连接池 : C3P0、Druid
在这里插入图片描述

数据库连接池不但能够提前连接好X个接口放到连接池中等待连接,而且每次连接中断后,仅仅是将连接放回连接池,无需断开,提高了效率。

1、C3P0配置文件

<c3p0-config>
<!--连接池名称 任意命名-->
  <named-config name="bue">
<!-- 驱动类 -->
  <property name="driverClass">com.mysql.jdbc.Driver</property>
  <!-- url--> <!-- xx_db06为自己使用的数据库-->
  	<property name="jdbcUrl">jdbc:mysql://127.0.0.1:3306/xx_db06</property>
  <!-- 用户名 -->
  		<property name="user">root</property>
  		<!-- 密码 -->
  	<property name="password">123456</property>
  	<!-- 每次增长的连接数-->
    <property name="acquireIncrement">5</property>
    <!-- 初始的连接数 -->
    <property name="initialPoolSize">10</property>
    <!-- 最小连接数 -->
    <property name="minPoolSize">5</property>
   <!-- 最大连接数 -->
    <property name="maxPoolSize">10</property>

	<!-- 可连接的最多的命令对象数 -->
    <property name="maxStatements">5</property> 
    
    <!-- 每个连接对象可连接的最多的命令对象数 -->
    <property name="maxStatementsPerConnection">2</property>
  </named-config>
</c3p0-config>

C3P0的使用

public void testC3P0_01() throws IOException, PropertyVetoException, SQLException {

        ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();

        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\mysql.properties"));

        String url = properties.getProperty("url");
        String user = properties.getProperty("user");
        String password = properties.getProperty("password");
        String driver = properties.getProperty("driver");

        // 给数据源comboPooledDataSource设置相关的参数
        comboPooledDataSource.setJdbcUrl(url);
        comboPooledDataSource.setUser(user);
        comboPooledDataSource.setPassword(password);
        comboPooledDataSource.setDriverClass(driver);

        // 设置输出化连接数
        comboPooledDataSource.setInitialPoolSize(10);
        // 设置最大连接数
        comboPooledDataSource.setMaxPoolSize(50);

        Connection connection = comboPooledDataSource.getConnection();// DataSource的接口实现
        System.out.println("connect successfully!");

        // 关闭连接
        connection.close();
    }

    @Test
    //使用配置文件模板完成
    public void testC3P0_02() throws SQLException {
        ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource("bue");
        Connection connection = comboPooledDataSource.getConnection();
        System.out.println("connect successfully!");

        connection.close();
    }

2、Druid配置文件

#key=value
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/xx_db06?rewriteBatchedStatements=true
#url=jdbc:mysql://localhost:3306/girls
username=root
password=123456
#initial connection Size
initialSize=10
#min idle connecton size
minIdle=5
#max active connection size
maxActive=20
#max wait time (5000 mil seconds)
maxWait=5000

德鲁伊的使用

 public void testDruid() throws Exception {
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\druid.properties"));

        // 创建一个指定参数的连接池
        DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);

        Connection connection = dataSource.getConnection();
        System.out.println("connect successfully!");
        connection.close();
    }

3、JDBCUtilsByDruid工具类

public class JDBCUtilsByDruid {
    private static DataSource ds;

    static {
        Properties properties = new Properties();
        try {
            properties.load(new FileInputStream("src\\druid.properties"));
            ds = DruidDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 获取连接
    public static Connection getConnection() throws SQLException {
        return ds.getConnection();
    }

    //关闭连接
    public static void close(ResultSet resultSet, Statement statement, Connection connection) {
        try {
            if (resultSet != null) {
                resultSet.close();
            }
            if (statement != null) {
                statement.close();
            }
            if (connection != null) {
                connection.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

4、Apache—DBUtils

有什么用
保存执行sql语句如select 查询到的结果
ResultSet不行吗?
不行,关闭connection后 resultSet结果集无法使用,resultSet不利于数据管理。
代码如下

	    public void testQueryMany() throws SQLException {
        // 获取连接
        Connection connection = JDBCUtilsByDruid.getConnection();
        // 创建QueryRunner
        QueryRunner queryRunner = new QueryRunner();
        //执行相关方法 返回ArrayList<?>集合
        String sql = "select * from actor where id > ?";
        List<Actor> list = queryRunner.query(connection, sql, new BeanListHandler<>(Actor.class), 1);
        for (Actor actor : list) {
            System.out.println(actor.id + "\t" + actor.name + "\t" + actor.sex);
        }
        JDBCUtilsByDruid.close(null, null, connection);
    }

此外还可返回单个对象、单个字段、操作DML
代码如下

//返回单个对象
    public void testQuerySingle() throws SQLException {
        // 得到连接
        Connection connection = JDBCUtilsByDruid.getConnection();

        //创建QueryRunner
        QueryRunner queryRunner = new QueryRunner();

        String sql = "select * from actor where id = ?";

        Actor actor = queryRunner.query(connection, sql, new BeanHandler<>(Actor.class), 1);
        System.out.println(actor);

        JDBCUtilsByDruid.close(null, null, connection);
    }

    @Test
    //返回单个字段的值
    public void testScalar() throws SQLException {
        Connection connection = JDBCUtilsByDruid.getConnection();
        String sql = "select name from actor where id = ?";
        QueryRunner queryRunner = new QueryRunner();
        Object query = queryRunner.query(connection, sql, new ScalarHandler(), 1);
        System.out.println(query);

        //关闭资源
        JDBCUtilsByDruid.close(null, null, connection);
    }

    @Test
    // 增删改查
    public void testDML() throws SQLException {
        Connection connection = JDBCUtilsByDruid.getConnection();
       // String sql = "insert into actor values (null, '斯特拉93', '车')";
       // String sql = "update actor set name = ? where id = ?";
        String sql = "delete from actor where id = ?";

        QueryRunner queryRunner = new QueryRunner();
        int update = queryRunner.update(connection, sql, 5);
        System.out.println(update > 0 ? "success" : "error");
    }

总结

操作不难,但知识点多,需要多梳理,实践。

  • 6
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值