0
点赞
收藏
分享

微信扫一扫

Druid数据库连接池技术

秦瑟读书 2022-04-06 阅读 100

简介

mysql是一个TCP/IP协议的网络程序,如果我们每次都从数据库获取新的连接,那么:

  • 每获取一次新的连接的成本很高,需要“三次握手”,断开需要“四次挥手”等过程
  • 每一个客户端都有单独的线程来维护它的通信

这样每次高成本获取的连接只用一次,太奢侈了;另外,如果有很多的客户端同时去连接mysql服务器,会造成mysql的并发量就有风险,如果太多就会挂了。特别是遇到一些程序员,获取完连接,没有关闭的情况。

数据库连接池的技术的原理:先创建一个连接池pool,然后在池中初始化少量的连接对象,当程序获取连接对象时,用池中已有的对象,会快很多。等用户并发量上来后,会增加连接数,直到最高连接数为止。之前conn.close()真正的与服务器断开连接,现在从连接池中拿的连接对象,关闭时是还给连接池。可以设置连接池的最大连接数量,如果池中的所有连接都在使用的话,那么可以让“客户端”等待,虽然有等待的现象,但是总比每次使用都创建之后销毁了性能高。

针对这个问题,我们可以采用“数据库连接池”来解决。连接池技术有很多,Druid是其中比较优秀的,它是阿里推出的,它不仅仅为数据源,还能sql拦截等功能。

本博客示例中用到的Dept类,请参考:<a rel="nofollow" href="https://blog.csdn.net/lianghecai52171314/article/details/101469279">Dept源代码</a>

示例

  • 第一步:创建一个Maven Web项目,添加依赖

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.13</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.1.17</version>
    </dependency>
  • 第二步:在resources下创建mysql.properties文件

    driverClassName=com.mysql.cj.jdbc.Driver
    url=jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=UTF8&autoReconnect=true&failOverReadOnly=false
    username=root
    password=root
    
    initialSize=10
    maxActive=20
    maxWait=6000
  • 第三步:写基于Druid的数据库访问工具类
    因为Connection是不线程安全的,为了保证同一个线程(客户端)共享同一个Connection对象,可以使用LocalThread来限制Connection。

    import com.alibaba.druid.pool.DruidDataSourceFactory;
    
    import javax.sql.DataSource;
    import java.io.InputStream;
    import java.sql.Connection;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;
    import java.util.Properties;
    
    public class DBUtil {
        private static final ThreadLocal<Connection> threadLocal = new ThreadLocal<>();
        private static DataSource dataSource = null;
    
        static {    //配置文件加载,只执行一次
            try (InputStream is = DBUtil.class.getResourceAsStream("/mysql.properties");) {
                Properties properties = new Properties();
                properties.load(is);
                dataSource = DruidDataSourceFactory.createDataSource(properties);
            } catch (Exception e1) {
                throw new RuntimeException("读取配置文件异常", e1);
            }
        }
        public static Connection getConnection() {    //获取连接
            Connection conn = null;
            try {
                conn = threadLocal.get();//从当前线程获得conn
                if (conn == null || conn.isClosed()) { //重点,需要注意conn.isClosed()条件的判断
                    conn = dataSource.getConnection();
                    threadLocal.set(conn);
                }
            } catch (Exception e) {
                throw new RuntimeException("连接数据库异常", e);
            }
            return conn;
        }
        public  static QueryRunner getQueryRunner(){
            return  new QueryRunner(dataSource);
        }
        public static void release(ResultSet rs, Statement stmt, Connection conn) {
            try { // 建议采用这种形式来释放资源,因为finally里面的一定会被释放
                if (rs != null) {
                    rs.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
                try {
                    if (stmt != null) {
                        stmt.close();
                    }
                } catch (SQLException e) {
                    e.printStackTrace();
                } finally {
                    if (conn != null) {
                        try {
                            conn.close();
                        } catch (SQLException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    
    }
  • 第四步:测试连接

    public static void main(String[] args) throws SQLException {
        for(int i=0;i<5;i++){ //开启5个线程
            new Thread(()->{//在每个线程中获取Connection对象,并输出
                Connection conn = getConnection();
                System.out.println(conn);
            }).start();
        }
    }

    运行程序,结果如下:
    在这里插入图片描述

    修改mysql.properties,设置的值如下:

    initialSize=3
    maxActive=4

    再次运行测试代码,结果如下:
    在这里插入图片描述

  • 第五步: CRUD测试
    public class DemoTest {
        @Test
        public void insert() throws SQLException {
            String sql ="insert into tb_dept values (?,?,?)";
            Connection conn = DBUtil.getConnection();
            PreparedStatement ps = conn.prepareStatement(sql);
            ps.setInt(1,11);
            ps.setString(2,"aa");
            ps.setString(3,"aaaaa");
            ps.executeUpdate();
            DBUtil.release(null,ps,conn);
        }
        @Test
        public void update() throws SQLException {
            String sql ="update tb_dept set dname=?,loc =? where deptno =?";
            Connection conn = DBUtil.getConnection();
            PreparedStatement ps = conn.prepareStatement(sql);
            ps.setString(1,"b");
            ps.setString(2,"bbbbb");
            ps.setInt(3,11);
            ps.executeUpdate();
            DBUtil.release(null,ps,conn);
        }
        @Test
        public void delete() throws SQLException {
            String sql ="delete from tb_dept  where deptno =?";
            Connection conn = DBUtil.getConnection();
            PreparedStatement ps = conn.prepareStatement(sql);
            ps.setInt(1,11);
            ps.executeUpdate();
            DBUtil.release(null,ps,conn);
        }
        @Test
        public void select() throws SQLException {
            String sql ="select * from tb_dept where deptno =?";
            Connection conn = DBUtil.getConnection();
            PreparedStatement ps = conn.prepareStatement(sql);
            ps.setInt(1,10);
            ResultSet res = ps.executeQuery();
            while (res.next()){
                Dept  dept = new Dept(res.getInt("deptno"),res.getString("dname"),res.getString("loc"));
                System.out.println(dept);
            }
            DBUtil.release(res,ps,conn);
        }
    }
举报

相关推荐

0 条评论