数据库连接池

概念:其实就是一个容器 (集合),存放数据库连接的容器。

当系统初始化好后,容器被创建,容器中会申请一些连接对象,当用户来访问数据库时,从容器中获取连接对象,用户访问完之后,会将连接对象归还给容器。image.png

好处

  1. 节约资源
  2. 用户访问高效

实现

标准接口:DataSource javax.sql 包下的
方法:

  • 获取连接:getConnection()
  • 归还连接:Connection.close()。如果连接对象Connection是从连接池中获取的,那么调用Connection.close()方法,则不会再关闭连接了。而是归还连接

一般我们不去实现它,有数据库厂商来实现

  1. C3P0:数据库连接池技术
  2. Druid:数据库连接池实现技术,由阿里巴巴提供的

C3P0:数据库连接池技术

但有点老

步骤

  1. 导入jar包 (两个) c3p0-0.9.5.2.jar、mchange-commons-java-0.2.12.jar,不要忘记导入数据库驱动jar包
  2. 定义配置文件:
    名称: c3p0.properties 或者 c3p0-config.xml
    路径:直接将文件放在src目录下即可。
  3. 创建核心对象 数据库连接池对象 ComboPooledDataSource
  4. 获取连接: getConnection
  1. <c3p0-config>
  2. <!-- 使用默认的配置读取连接池对象 -->
  3. <default-config>
  4. <!-- 连接参数 -->
  5. <property name="driverClass">com.mysql.cj.jdbc.Driver</property>
  6. <property name="jdbcUrl">jdbc:mysql://localhost:3306/test</property>
  7. <property name="user">root</property>
  8. <property name="password">12345678</property>
  9. <!-- 连接池参数 -->
  10. <!--初始化申请的连接数-->
  11. <property name="initialPoolSize">5</property>
  12. <!--最大连接数-->
  13. <property name="maxPoolSize">10</property>
  14. <!--超时处理-->
  15. <property name="checkoutTimeout">3000</property>
  16. </default-config>
  17. <named-config name="otherc3p0">
  18. <!-- 连接参数 -->
  19. <property name="driverClass">com.mysql.jdbc.Driver</property>
  20. <property name="jdbcUrl">jdbc:mysql://localhost:3306/day25</property>
  21. <property name="user">root</property>
  22. <property name="password">root</property>
  23. <!-- 连接池参数 -->
  24. <property name="initialPoolSize">5</property>
  25. <property name="maxPoolSize">8</property>
  26. <property name="checkoutTimeout">1000</property>
  27. </named-config>
  28. </c3p0-config>
  1. <c3p0-config>
  2. <!-- 用户自定义配置 -->
  3. <named-config name="c3p0Config">
  4. <property name="driverClass">com.mysql.cj.jdbc.Driver</property>
  5. <property name="jdbcUrl">jdbc:mysql://localhost:3306/db_1?characterEncoding=utf-8&amp;useSSL=true</property>
  6. <property name="user">root</property>
  7. <property name="password">12345678</property>
  8. <!-- 最大连接数 -->
  9. <property name="maxPoolSize">10</property>
  10. <!-- 最小连接数 -->
  11. <property name="minPoolSize">5</property>
  12. <!-- 初始化连接数,连接池创建初始化连接数 -->
  13. <property name="initialPoolSize">3</property>
  14. <!-- 多长时间检测一下链接的可用性,以秒做单位-->
  15. <property name="idleConnectionTestPeriod">3600</property>
  16. <!-- 如果连接处不够用,一次性创建多少链接 -->
  17. <property name="acquireIncrement">5</property>
  18. <!-- 链接的最大空闲时间,以分钟做为单位 -->
  19. <property name="maxIdleTime">50</property>
  20. </named-config>
  21. </c3p0-config>

代码

  1. //1.创建数据库连接池对象
  2. DataSource ds = new ComboPooledDataSource();
  3. //方式二(少用)
  4. DataSource ds = new ComboPooledDataSource( configName: "otherc3pe");
  5. //2. 获取连接对象
  6. Connection conn = ds.getConnection();

Druid:数据库连接池实现技术,由阿里巴巴提供的

步骤

  1. 导入 jar 包 druid-1.0.9.jar
  2. 定义配置文件:

    • 是 properties 形式的
    • 可以叫任意名称,可以放在任意目录下
      1. driverClassName=com.mysql.jdbc.Driver
      2. url=jdbc:mysql://127.0.0.1:3306/tmp
      3. username=root
      4. password=root
      5. initialSize=5
      6. maxActive=10
      7. maxWait=3000
  3. 加载配置文件。Properties

  4. 获取数据库连接池对象:通过工厂来来获取 DruidDataSourceFactory
  5. 获取连接:getConnection

代码

  1. package cn.itcast.datasource.druid;
  2. import com.alibaba.druid.pool.DruidDataSourceFactory;
  3. import javax.sql.DataSource;
  4. import java.io.IOException;
  5. import java.io.InputStream;
  6. import java.sql.Connection;
  7. import java.util.Properties;
  8. public class DruidDemo1 {
  9. public static void main(String[] args) throws Exception {
  10. //1.导入jar包
  11. //2.定义配置文件
  12. //3.加载配置文件
  13. Properties pro = new Properties();
  14. InputStream is = DruidDemo1.class.getClassLoader().getResourceAsStream("druid.properties");
  15. pro.load(is);
  16. //4.获取连接池对象
  17. DataSource ds = DruidDataSourceFactory.createDataSource(pro);
  18. //5.获取连接
  19. Connection conn = ds.getConnection();
  20. System.out.println(conn);
  21. }
  22. }

练习

定义一个工具类来实现连接池

  1. 定义一个类 JDBCUtils
  2. 提供静态代码块加载配置文件,初始化连接池对象
  3. 提供方法
    1. 获取连接方法:通过数据库连接池获取连接
    2. 释放资源
    3. 获取连接池的方法

代码

  1. package cn.itcast.utils;
  2. import com.alibaba.druid.pool.DruidDataSourceFactory;
  3. import javax.sql.DataSource;
  4. import java.io.IOException;
  5. import java.sql.Connection;
  6. import java.sql.ResultSet;
  7. import java.sql.SQLException;
  8. import java.sql.Statement;
  9. import java.util.Properties;
  10. /**
  11. * Druid连接池的工具类
  12. */
  13. public class JDBCUtils {
  14. //1.定义成员变量 DataSource
  15. private static DataSource ds;
  16. static {
  17. try {
  18. //1.加载配置文件
  19. Properties pro = new Properties();
  20. pro.load(JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties"));
  21. //2.获取DataSource
  22. ds = DruidDataSourceFactory.createDataSource(pro);
  23. } catch (IOException e) {
  24. e.printStackTrace();
  25. } catch (Exception e) {
  26. e.printStackTrace();
  27. }
  28. }
  29. /**
  30. * 获取连接
  31. */
  32. public static Connection getConnection() throws SQLException {
  33. return ds.getConnection();
  34. }
  35. /**
  36. * 释放资源
  37. */
  38. public static void close(Statement stmt, Connection conn) {
  39. /* if(stmt != null){
  40. try {
  41. stmt.close();
  42. } catch (SQLException e) {
  43. e.printStackTrace();
  44. }
  45. }
  46. if(conn != null){
  47. try {
  48. conn.close();//归还连接
  49. } catch (SQLException e) {
  50. e.printStackTrace();
  51. }
  52. }*/
  53. close(null, stmt, conn);
  54. }
  55. public static void close(ResultSet rs, Statement stmt, Connection conn) {
  56. if (rs != null) {
  57. try {
  58. rs.close();
  59. } catch (SQLException e) {
  60. e.printStackTrace();
  61. }
  62. }
  63. if (stmt != null) {
  64. try {
  65. stmt.close();
  66. } catch (SQLException e) {
  67. e.printStackTrace();
  68. }
  69. }
  70. if (conn != null) {
  71. try {
  72. conn.close();//归还连接
  73. } catch (SQLException e) {
  74. e.printStackTrace();
  75. }
  76. }
  77. }
  78. /**
  79. * 获取连接池方法
  80. */
  81. public static DataSource getDataSource() {
  82. return ds;
  83. }
  84. }

使用工具类测试

  1. package cn.itcast.datasource.druid;
  2. import cn.itcast.utils.JDBCUtils;
  3. import java.sql.Connection;
  4. import java.sql.PreparedStatement;
  5. import java.sql.ResultSet;
  6. import java.sql.SQLException;
  7. /**
  8. * 使用新的工具类
  9. */
  10. public class DruidDemo2 {
  11. public static void main(String[] args) {
  12. /*
  13. * 完成添加操作:给account表添加一条记录
  14. */
  15. Connection conn = null;
  16. PreparedStatement pstmt = null;
  17. try {
  18. //1.获取连接
  19. conn = JDBCUtils.getConnection();
  20. //2.定义sql
  21. String sql = "insert into sign_info values(null,?,?)";
  22. //3.获取pstmt对象
  23. pstmt = conn.prepareStatement(sql);
  24. //4.给?赋值
  25. pstmt.setString(1,"王五");
  26. pstmt.setString(2,"123");
  27. //5.执行sql
  28. int count = pstmt.executeUpdate();
  29. System.out.println(count);
  30. } catch (SQLException e) {
  31. e.printStackTrace();
  32. }finally {
  33. //6. 释放资源
  34. JDBCUtils.close(pstmt,conn);
  35. }
  36. }
  37. }

spring JDBC :JDBC template

Spring 框架对 JDBC 的简单封装。提供了一个 JDBCTemplate 对象简化 JDBC 的开发

步骤

  1. 导入 jar 包
  2. 创建 JdbcTemplate 对象。依赖于数据源 DataSource
    1. JdbcTemplate template = new JdbcTemplate(ds);
  3. 调用 JdbcTemplate 的方法来完成 CRUD 的操作
    1. update():执行DML语句。增、删、改语句
    2. queryForMap():查询结果将结果集封装为map集合,将列名作为key,将值作为value 将这条记录封装为一个map集合
      1. 注意:这个方法查询的结果集长度只能是1
    3. queryForList():查询结果将结果集封装为list集合
      1. 注意:将每一条记录封装为一个Map集合,再将Map集合装载到List集合中
    4. query():查询结果,将结果封装为JavaBean对象
      1. query的参数:RowMapper
      2. 一般我们使用BeanPropertyRowMapper实现类。可以完成数据到JavaBean的自动封装
      3. new BeanPropertyRowMapper<类型>(类型.class)
    5. queryForObject:查询结果,将结果封装为对象
      1. 一般用于聚合函数的查询

案例

  1. package SpringJDBC;
  2. import JDBC06.druid.JDBCUtils;
  3. import org.springframework.jdbc.core.JdbcTemplate;
  4. public class JdbcTemplateDemo1 {
  5. public static void main(String[] args) {
  6. JdbcTemplate jdbcTemplate = new JdbcTemplate(JDBCUtils.getDataSource());
  7. String sql = "update user set username = ? where id =?";
  8. int count = jdbcTemplate.update(sql, "hello", "3");
  9. System.out.println(count);
  10. }
  11. }

练习

  1. 修改 1 号数据的 salary 为 10000
  2. 添加一条记录
  3. 删除刚才添加的记录
  4. 查询 id 为 1 的记录,将其封装为 Map 集合
  5. 查询所有记录,将其封装为 List
  6. 查询所有记录,将其封装为 Emp 对象的 List 集合
  7. 查询总记录数

代码

  1. import cn.itcast.domain.Emp;
  2. import cn.itcast.utils.JDBCUtils;
  3. import org.junit.Test;
  4. import org.springframework.jdbc.core.BeanPropertyRowMapper;
  5. import org.springframework.jdbc.core.JdbcTemplate;
  6. import org.springframework.jdbc.core.RowMapper;
  7. import java.sql.Date;
  8. import java.sql.ResultSet;
  9. import java.sql.SQLException;
  10. import java.util.List;
  11. import java.util.Map;
  12. public class JdbcTemplateDemo2 {
  13. private JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
  14. @Test
  15. public void test1(){
  16. String sql = "update emp set salary = 10000 where id = 1001";
  17. int count = template.update(sql);
  18. System.out.println(count);
  19. }
  20. @Test
  21. public void test2(){
  22. String sql = "insert into emp(id,ename,dept_id) values(?,?,?)";
  23. int count = template.update(sql, 1015, "郭靖", 10);
  24. System.out.println(count);
  25. }
  26. @Test
  27. public void test3(){
  28. String sql = "delete from emp where id = ?";
  29. int count = template.update(sql, 1015);
  30. System.out.println(count);
  31. }
  32. @Test
  33. public void test4(){
  34. String sql = "select * from emp where id = ? or id = ?";
  35. Map<String, Object> map = template.queryForMap(sql, 1001,1002);
  36. System.out.println(map);
  37. }
  38. @Test
  39. public void test5(){
  40. String sql = "select * from emp";
  41. List<Map<String, Object>> list = template.queryForList(sql);
  42. for (Map<String, Object> stringObjectMap : list) {
  43. System.out.println(stringObjectMap);
  44. }
  45. }
  46. @Test
  47. public void test6(){
  48. String sql = "select * from emp";
  49. List<Emp> list = template.query(sql, new RowMapper<Emp>() {
  50. @Override
  51. public Emp mapRow(ResultSet rs, int i) throws SQLException {
  52. Emp emp = new Emp();
  53. int id = rs.getInt("id");
  54. String ename = rs.getString("ename");
  55. int job_id = rs.getInt("job_id");
  56. int mgr = rs.getInt("mgr");
  57. Date joindate = rs.getDate("joindate");
  58. double salary = rs.getDouble("salary");
  59. double bonus = rs.getDouble("bonus");
  60. int dept_id = rs.getInt("dept_id");
  61. emp.setId(id);
  62. emp.setEname(ename);
  63. emp.setJob_id(job_id);
  64. emp.setMgr(mgr);
  65. emp.setJoindate(joindate);
  66. emp.setSalary(salary);
  67. emp.setBonus(bonus);
  68. emp.setDept_id(dept_id);
  69. return emp;
  70. }
  71. });
  72. for (Emp emp : list) {
  73. System.out.println(emp);
  74. }
  75. }
  76. @Test
  77. public void test6_2(){
  78. String sql = "select * from emp";
  79. List<Emp> list = template.query(sql, new BeanPropertyRowMapper<Emp>(Emp.class));
  80. for (Emp emp : list) {
  81. System.out.println(emp);
  82. }
  83. }
  84. @Test
  85. public void test7(){
  86. String sql = "select count(id) from emp";
  87. Long total = template.queryForObject(sql, Long.class);
  88. System.out.println(total);
  89. }
  90. }