zoukankan      html  css  js  c++  java
  • Java学习之数据库连接池&DBCP&C3P0

    一、数据库连接池

    出现缘由:数据库的连接对象创建工作,比较消耗性能。

    工作原理:在内存中开辟一块空间(集合),并放置多个连接对象。需要连接的话,直接从内存空间中获取。不需要创建连接对象。使用完毕,归还连接对象。确保连接对象能循环利用。

    二、自定义数据库连接池

    通过数据库连接池工作原理,自定义数据库连接池需要以下几步:

    ①、内存中开辟空间

    ②、创建数据库连接对象,并放置到内存中

    ③、定义获取数据库连接对象的方法

    ④、定义释放(归还)数据库连接对象的方法

    代码实现:

    /**
    * @Title: MyDataSource
    * @Description: sun公司提供数据库连接池规范是以DataSource命名的
    * @author: marw
    * @date 2020/03/26 16:16:58
    */
    public class MyDataSource implements DataSource {
    
        //①、开辟空间
        List<Connection> list=new ArrayList<Connection>();
        
        /**
         * ②、创建数据库连接对象,并放置到内存中
         */
        public MyDataSource() {
        for (int i = 0; i < 10; i++) {
            Connection connection = JDBCUtil.getConnection();
            list.add(connection);
        }
        }
        
        /**
         * ③、 sun公司 提供数据库连接池规范中包含了获取数据库连接对象的方法
         * 只需要重写此方法
         */
        @Override
        public Connection getConnection() throws SQLException {
        //内存扩容
        if (list.size() == 0) {
            for (int i = 0; i < 3; i++) {
            Connection connection = JDBCUtil.getConnection();
            list.add(connection);
            }
        }
        // 移除集合中第一个元素(数据库连接对象),并获取移除的元素
        return list.remove(0);
        }
        
        /**
         * ④、释放(归还)数据库连接对象
         */
        public void Liberate(Connection connection) {
        list.add(connection);
        }
    
    ... ...
    
    }

    使用自定义数据库连接池

    public class TestPool {
        @Test
        public void testPool() {
        Connection connection=null;
        PreparedStatement ps =null;
        MyDataSource dataSource=null;
        try {
            MyDataSource dataSource=new MyDataSource();
            connection=dataSource.getConnection();
            
            String sql="insert into account values(?,?)";
            ps =connection.prepareStatement(sql);
            ps.setString(1, "qian");
            ps.setInt(2, 1000);
            ps.executeUpdate();
            
        } catch (SQLException e) {
            
            e.printStackTrace();
        }
        finally {
         dataSource.Liberate(connection);//释放连接对象 JDBCUtil.release(connection, ps); } } }

    使用自定义数据库连接池,有以下几个问题

    ①、每次使用都需要自己创建新的连接池对象,那样的话每一次访问都会创建10连接池对象,这个需要使用单例解决

    ②、无法面向接口编程,Liberate方法,不想自定义方法可以重写Connection接口的close方法,让它实现归还连接对象。

     想要扩展Connection接口的close方法

      Ⅰ、直接修改方法

      Ⅱ、继承,必须知道Connection接口的实现类

      Ⅲ、装饰模式

    使用装饰模式代码:

    public class ConnectionWrap implements Connection {
        Connection connection=null;
        List<Connection> list=null;
        
        public ConnectionWrap(Connection connection,List<Connection> list) {
        super();
        this.connection=connection;
        this.list=list;
        }
    
        @Override
        public void close() throws SQLException {
        list.add(connection);
        }
    
        @Override
        public PreparedStatement prepareStatement(String sql) throws SQLException {
    
        return connection.prepareStatement(sql);
        }
    
    ... ...
    
    }

    使用装饰模式对象

    public class MyDataSource implements DataSource {
    
        //①、开辟空间
        List<Connection> list=new ArrayList<Connection>();
        
        /* 单例 start */
        private static MyDataSource dataSource=new MyDataSource();
        /**
         * ②、创建数据库连接对象,并放置到内存中
         */
        private MyDataSource() {
        for (int i = 0; i < 10; i++) {
            Connection connection = JDBCUtil.getConnection();
            list.add(connection);
        }
        }
        
        public static MyDataSource getInstance() {
        return dataSource;
        }
        /* 单例 end */
        
        /**
         * ③、 sun公司 提供数据库连接池规范中包含了获取数据库连接对象的方法
         * 只需要重写此方法
         */
        @Override
        public Connection getConnection() throws SQLException {
        //内存扩容
        if (list.size() == 0) {
            for (int i = 0; i < 3; i++) {
            Connection connection = JDBCUtil.getConnection();
            list.add(connection);
            }
        }
        // 移除集合中第一个元素(数据库连接对象),并获取移除的元素
        Connection conn=list.remove(0);
        
        // 装饰模式 返回Connection对象,进行装饰,使其对象的close方法,有归还功能
        Connection connection = new ConnectionWrap(conn, list);
        return connection;
        }
        
    ... ...
    
    }

    测试代码

    public class TestPool {
        @Test
        public void testPool() {
        Connection connection=null;
        PreparedStatement ps =null;
        
        try {
            DataSource dataSource=MyDataSource.getInstance();
            connection=dataSource.getConnection();
            
            String sql="insert into account values(?,?)";
            ps =connection.prepareStatement(sql);
            ps.setString(1, "qian");
            ps.setInt(2, 1000);
            ps.executeUpdate();
            
        } catch (SQLException e) {
            
            e.printStackTrace();
        }
        finally {
            JDBCUtil.release(connection, ps);
        }
        }
    }

    三、开源连接池

     Ⅰ、DBCP使用

    ①、下载jar文件(下载两个jar文件:commons-dbcp和commons-pool)

      commons-dbcp下载:http://commons.apache.org/proper/commons-dbcp/download_dbcp.cgi

      commons-pool下载:http://commons.apache.org/proper/commons-pool/download_pool.cgi

      commons-logging下载:http://commons.apache.org/proper/commons-logging/download_logging.cgi

    ②、导入jar文件

      根据解压后的文件找到对应jar文件,复制到工程的lib文件中,Java工程需(右击jar文件=>Build Path => Add to Build Path)

      

       错误信息:java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory,导入commons-logging-1.2.jar辅助类包即可

     ③、不使用配置文件

     1 @Test
     2 public void testDBCP01() {
     3     Connection conn = null;
     4     PreparedStatement ps = null;
     5     try {
     6 
     7         // 1. 构建数据源对象
     8         BasicDataSource dataSource = new BasicDataSource();
     9         // 连的是什么类型的数据库, 访问的是哪个数据库 , 用户名, 密码。。
    10         // jdbc:mysql://localhost/bank 主协议:子协议 ://本地/数据库
    11         dataSource.setDriverClassName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
    12         dataSource.setUrl("jdbc:sqlserver://localhost:1433;databaseName=Bank;");
    13         dataSource.setUsername("sa");
    14         dataSource.setPassword("XXXX");
    15 
    16         // 2. 得到连接对象
    17         conn = dataSource.getConnection();
    18         String sql = "insert into account values(? , ?)";
    19         ps = conn.prepareStatement(sql);
    20         ps.setString(1, "admin");
    21         ps.setInt(2, 1000);
    22 
    23         ps.executeUpdate();
    24 
    25     } catch (SQLException e) {
    26         e.printStackTrace();
    27     } finally {
    28         JDBCUtil.release(conn, ps);
    29     }
    30 }

    ④、使用配置文件

    ##dbcpconfig.properties文件内容

     1 #连接设置
     2 driverClassName=com.microsoft.sqlserver.jdbc.SQLServerDriver
     3 url=jdbc:sqlserver://localhost:1433;databaseName=Bank;
     4 username=sa
     5 password=XXXX
     6 
     7 #<!-- 初始化连接 -->
     8 initialSize=10
     9 
    10 #最大连接数量
    11 maxActive=50
    12 
    13 #<!-- 最大空闲连接 -->
    14 maxIdle=20
    15 
    16 #<!-- 最小空闲连接 -->
    17 minIdle=5
    18 
    19 #<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 -->
    20 maxWait=60000
    21 
    22 
    23 #JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:[属性名=property;] 
    24 #注意:"user" 与 "password" 两个属性会被明确地传递,因此这里不需要包含他们。
    25 connectionProperties=useUnicode=true;characterEncoding=gbk
    26 
    27 #指定由连接池所创建的连接的自动提交(auto-commit)状态。
    28 defaultAutoCommit=true
    29 
    30 #driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。
    31 #可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
    32 defaultTransactionIsolation=READ_UNCOMMITTED

    ##将dbcpconfig.properties文件放到src目录下

      

     1 @Test
     2 public void testDBCP() {
     3     Connection conn = null;
     4     PreparedStatement ps = null;
     5     try {
     6 
     7         BasicDataSourceFactory factory = new BasicDataSourceFactory();
     8         Properties properties = new Properties();
     9         InputStream is =this.getClass().getClassLoader().getResourceAsStream("dbcpconfig.properties");
    10         properties.load(is);
    11         DataSource dataSource = factory.createDataSource(properties);
    12 
    13         // 2. 得到连接对象
    14         conn = dataSource.getConnection();
    15         String sql = "insert into account values( ? , ?)";
    16         ps = conn.prepareStatement(sql);
    17         ps.setString(1, "liangcw");
    18         ps.setInt(2, 100);
    19 
    20         ps.executeUpdate();
    21 
    22     } catch (Exception e) {
    23         e.printStackTrace();
    24     } finally {
    25         JDBCUtil.release(conn, ps);
    26     }
    27 }

    Ⅱ、C3P0使用

    ①、下载jar

      C3P0下载:https://sourceforge.net/projects/c3p0/

    ②、导入jar文件

      

      错误信息:java.lang.NoClassDefFoundError: com/mchange/v2/ser/Indirector,把上图中的mchange-commons-java-0.2.19.jar文件导入项目中

    ③、不使用配置文件  

     1 @Test
     2 public void testC3P0() {
     3     Connection conn = null;
     4     PreparedStatement ps = null;
     5     try {
     6         //1. 创建datasource
     7         ComboPooledDataSource dataSource = new ComboPooledDataSource();
     8         //2. 设置连接数据的信息
     9         dataSource.setDriverClass("com.microsoft.sqlserver.jdbc.SQLServerDriver");
    10         dataSource.setJdbcUrl("jdbc:sqlserver://localhost:1433;databaseName=Bank;");
    11         dataSource.setUser("sa");
    12         dataSource.setPassword("AAA@111");
    13         
    14         //2. 得到连接对象
    15         conn = dataSource.getConnection();
    16         String sql = "insert into account values( ? , ?)";
    17         ps = conn.prepareStatement(sql);
    18         ps.setString(1, "admin1");
    19         ps.setInt(2, 103200);
    20         
    21         ps.executeUpdate();
    22         
    23     } catch (Exception e) {
    24         e.printStackTrace();
    25     }finally {
    26         JDBCUtil.release(conn, ps);
    27     }
    28 }

    ④、使用配置文件

    ##创建c3p0-config.xml文件,文件内容如下

     1 <c3p0-config>
     2   <!-- ComboPooledDataSource dataSource = new ComboPooledDataSource(); 
     3        对应default-config
     4            默认数据库连接
     5   -->
     6   <default-config>
     7     <property name="driverClass">com.microsoft.sqlserver.jdbc.SQLServerDriver</property>
     8     <property name="jdbcUrl">jdbc:sqlserver://localhost:1433;databaseName=Bank;</property>
     9     <property name="user">sa</property>
    10     <property name="password">AAA@111</property>
    11     
    12     <property name="initialPoolSize">10</property>
    13     <property name="maxIdleTime">30</property>
    14     <property name="maxPoolSize">100</property>
    15     <property name="minPoolSize">10</property>
    16     <property name="maxStatements">200</property>
    17   </default-config>
    18   <!-- ComboPooledDataSource dataSource = new ComboPooledDataSource("intergalactoApp:); 
    19        对应named-config
    20            指定数据库连接
    21   -->
    22   <named-config name="intergalactoApp"> 
    23     <property name="driverClass">com.microsoft.sqlserver.jdbc.SQLServerDriver</property>
    24     <property name="jdbcUrl">jdbc:sqlserver://localhost:1433;databaseName=Bank;</property>
    25     <property name="user">sa</property>
    26     <property name="password">AAA@111</property>
    27     
    28     <property name="initialPoolSize">10</property>
    29     <property name="maxIdleTime">30</property>
    30     <property name="maxPoolSize">100</property>
    31     <property name="minPoolSize">10</property>
    32     <property name="maxStatements">200</property>
    33   </named-config>
    34 </c3p0-config>

    ##将c3p0-config.xml文件放到src目录下

      

     1 @Test
     2 public void testC3P0() {
     3     Connection conn = null;
     4     PreparedStatement ps = null;
     5     try {
     6         //1. 创建datasource
     7         ComboPooledDataSource dataSource = new ComboPooledDataSource();
     8                 
     9         //2. 得到连接对象
    10         conn = dataSource.getConnection();
    11         String sql = "insert into account values( ? , ?)";
    12         ps = conn.prepareStatement(sql);
    13         ps.setString(1, "admin2");
    14         ps.setInt(2, 103200);
    15         
    16         ps.executeUpdate();
    17         
    18     } catch (Exception e) {
    19         e.printStackTrace();
    20     }finally {
    21         JDBCUtil.release(conn, ps);
    22     }
    23 }

    推荐使用C3P0数据库连接池。

    自定义JDBCUtil使用C3P0改造

     1 public class JDBCUtil {
     2     static ComboPooledDataSource dataSource=null;
     3     static {
     4     dataSource=new ComboPooledDataSource();
     5     }
     6 
     7     public static Connection getConnection() {
     8     Connection connection = null;
     9     try {
    10         connection = dataSource.getConnection();
    11     } catch (SQLException e) {
    12 
    13         e.printStackTrace();
    14     }
    15     return connection;
    16     }
    17 
    18     public static void release(Connection conn, Statement st, ResultSet rs) {
    19     closeResultSet(rs);
    20     closeStatement(st);
    21     closeConnection(conn);
    22     }
    23     
    24     public static void release(Connection conn, Statement st) {
    25 
    26     closeStatement(st);
    27     closeConnection(conn);
    28     }
    29     private static void closeResultSet(ResultSet rs) {
    30     if (rs != null) {
    31         try {
    32         rs.close();
    33         } catch (SQLException e) {
    34 
    35         e.printStackTrace();
    36         }
    37         rs = null;
    38     }
    39     }
    40 
    41     private static void closeStatement(Statement st) {
    42     if (st != null) {
    43         try {
    44         st.close();
    45         } catch (SQLException e) {
    46 
    47         e.printStackTrace();
    48         }
    49         st = null;
    50     }
    51     }
    52 
    53     private static void closeConnection(Connection conn) {
    54     if (conn != null) {
    55         try {
    56         conn.close();
    57         } catch (SQLException e) {
    58 
    59         e.printStackTrace();
    60         }
    61         conn = null;
    62     }
    63     }
    64 }
    View Code
  • 相关阅读:
    Python_数据类型与变量
    啦啦啦
    Java开发环境搭建
    TCP/IP 学习 --- 4(linux网络基础api)
    TCP/IP 学习 --- 3 (流量控制和拥塞控制)
    TCP/IP 学习 --- 2
    TCP/IP 学习记录 -- 1
    多线程
    如何解析xml文件
    Redis
  • 原文地址:https://www.cnblogs.com/WarBlog/p/12575896.html
Copyright © 2011-2022 走看看