本质:
不论是什么池,本质都是容器,用来存储对象
至于用什么容器存储就因人而异
至于存什么对象也因人而异

1.字符串常量池

2.数据库连接池

常见的数据库连接池有c3p0,druid等
这里演示c3p0
先在pom.xml中导入其依赖

  1. <dependencies>
  2. <dependency>
  3. <groupId>com.mchange</groupId>
  4. <artifactId>c3p0</artifactId>
  5. <version>0.9.5.2</version>
  6. </dependency>
  7. </dependencies>

另外还需要导入mysql的驱动包,这里导入5.x版本,对应setDriverClass中的参数

  1. <dependency>
  2. <groupId>mysql</groupId>
  3. <artifactId>mysql-connector-java</artifactId>
  4. <version>5.1.38</version>
  5. </dependency>

不要忘了:导入包之后要点击刷新一下
不要忘了:导入包之后要点击刷新一下
不要忘了:导入包之后要点击刷新一下

  1. public class C3P0test1 {
  2. public static void main(String[] args) throws PropertyVetoException, SQLException {
  3. //javax.sql包下的DataSource接口是所有第三方的数据源都要实现的接口,否则没法用java操作数据库
  4. ComboPooledDataSource dataSource = new ComboPooledDataSource();
  5. dataSource.setDriverClass("com.mysql.jdbc.Driver");
  6. dataSource.setUser("root");
  7. dataSource.setPassword("开机密码");
  8. dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/hanshangping");
  9. //下面两行设置数据库连接池中只有一个数据库连接对象,initial和max都得设置为1
  10. dataSource.setInitialPoolSize(1);
  11. dataSource.setMaxPoolSize(1);
  12. //java.sql包下的Connection接口
  13. //java.sql和javax.sql的区别
  14. //c3p0对java自带的DataSource和Connection都进行了实现
  15. Connection connection = dataSource.getConnection();
  16. System.out.println(connection);
  17. //com.mchange.v2.c3p0.impl.NewProxyConnection@52d455b8 [wrapping: com.mysql.jdbc.JDBC4Connection@4f4a7090]
  18. //c3p0的NewProxyConnection是一个代理类,也就是说该类中会存在mysql的数据库连接对象(代理类中一定要有被代理对象)
  19. Object inner = getInner(connection);
  20. System.out.println(inner.getClass().getName());
  21. //com.mysql.jdbc.JDBC4Connection,该类在导入的mysql-connector-java依赖中,数据库连接池出来之前我们一直使用的mysql连接类
  22. //数据库连接池就是对原生的mysql连接对象进行了代理,生成了代理连接对象
  23. }
  24. public static Object getInner(Object connection){
  25. Object result=null;
  26. Field field=null;
  27. try {
  28. field = connection.getClass().getDeclaredField("inner");
  29. //开启权限
  30. field.setAccessible(true);
  31. //获取传入的NewProxyConnection类中被代理的Connection对象
  32. result=field.get(connection);
  33. } catch (NoSuchFieldException | IllegalAccessException e) {
  34. e.printStackTrace();
  35. }
  36. return result;
  37. }
  38. }
  1. 数据库连接池就是对驱动类中的连接对象进行代理,这也是驱动类的意义所在
  2. 我的理解是我们可以直接利用驱动类中的连接对象进行数据库连接,不过就不能有池化功能了
  3. 不论是驱动类还是数据库连接池,它们都得遵守java内部关于sql的接口规定
  4. image.png
  1. public class C3P0test1 {
  2. public static void main(String[] args) throws PropertyVetoException, SQLException {
  3. //javax.sql包下的DataSource接口是所有第三方的数据源都要实现的接口,否则没法用java操作数据库
  4. ComboPooledDataSource dataSource = new ComboPooledDataSource();
  5. dataSource.setDriverClass("com.mysql.jdbc.Driver");
  6. dataSource.setUser("root");
  7. dataSource.setPassword("开机密码");
  8. dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/hanshangping");
  9. //下面两行设置数据库连接池中只有一个数据库连接对象,initial和max都得设置为1
  10. dataSource.setInitialPoolSize(1);
  11. dataSource.setMaxPoolSize(1);
  12. Connection connection = dataSource.getConnection();
  13. Object inner = getInner(connection);
  14. //因为设置了数据库连接池中就一个对象,所以如果前面的连接不关闭,后面要想获取连接就会阻塞,即程序卡住了
  15. //如果设置了多个对象,则不关闭的话不推荐(占用内存)但是不会出错
  16. connection.close();
  17. Connection connection1 = dataSource.getConnection();
  18. System.out.println(connection);
  19. System.out.println(connection1);
  20. System.out.println(connection==connection1);
  21. // Object inner = getInner(connection); //代理类的close方法中会将被代理对象inner置为null,进而产生空指针异常,所以要在close之前就获取
  22. Object inner1 = getInner(connection1);
  23. System.out.println(inner.getClass().getName());
  24. System.out.println(inner1.getClass().getName());
  25. System.out.println(inner==inner1);
  26. }
  27. public static Object getInner(Object connection){
  28. Object result=null;
  29. Field field=null;
  30. try {
  31. field = connection.getClass().getDeclaredField("inner");
  32. //开启权限
  33. field.setAccessible(true);
  34. //获取传入的NewProxyConnection类中被代理的Connection对象
  35. result=field.get(connection);
  36. } catch (NoSuchFieldException | IllegalAccessException e) {
  37. e.printStackTrace();
  38. }
  39. return result;
  40. }
  41. }
  42. com.mchange.v2.c3p0.impl.NewProxyConnection@769c9116 [wrapping: null]
  43. com.mchange.v2.c3p0.impl.NewProxyConnection@6aceb1a5 [wrapping: com.mysql.jdbc.JDBC4Connection@2d6d8735]
  44. false
  45. com.mysql.jdbc.JDBC4Connection
  46. com.mysql.jdbc.JDBC4Connection
  47. true
  1. 由于设置了数据库连接池中只有一个连接对象(原生的mysql连接对象com.mysql.jdbc.JDBC4Connection,而不是代理对象com.mchange.v2.c3p0.impl.NewProxyConnection),所以当我们先开一个连接再关闭再开一个连接,两次连接对应的原生连接对象必然是同一个,而代理对象则就不是(每次都new)
  2. 如果不进行close就会阻塞,因为就一个连接资源,上一个没释放,下一个就只能阻塞
  3. 代理类NewProxyConnection中的close方法会将其中的被代理对象Connection inner置为null
  4. 当我把数据库连接池的参数设置为2,并且把close方法去掉,其他不变的打印结果为:

    1. com.mchange.v2.c3p0.impl.NewProxyConnection@18ef96 [wrapping: com.mysql.jdbc.JDBC4Connection@6956de9]
    2. com.mchange.v2.c3p0.impl.NewProxyConnection@769c9116 [wrapping: com.mysql.jdbc.JDBC4Connection@6aceb1a5]
    3. false
    4. com.mysql.jdbc.JDBC4Connection
    5. com.mysql.jdbc.JDBC4Connection
    6. false
  5. 可以看出两次的原生连接对象都是不同的,符合逻辑

2.1不适用数据库连接池的情况

  1. package com.zhanglei.jdbc;
  2. import org.junit.Test;
  3. import java.sql.Connection;
  4. import java.sql.DriverManager;
  5. import java.sql.SQLException;
  6. import java.sql.Statement;
  7. /**
  8. * ClassName:JdbcTest01
  9. * Package:com.zhanglei.jdbc
  10. * Description:
  11. *
  12. * @Date:2021/8/2 10:47
  13. * @Author:zhanglei@3417529439@qq.com
  14. */
  15. public class JdbcTest01 {
  16. @Test
  17. public void test() throws ClassNotFoundException, SQLException {
  18. //1.forName有返回值不一定需要接收啊,加载了这个类后会注册到DriverManager里面去的,后面getConnection自己会去匹配的,用不着你去操心
  19. Class.forName("com.mysql.jdbc.Driver");
  20. Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/my1", "root", "56785");
  21. String sql="create table zhanglei_jdbc01 (id int, name varchar(32), price double ,introdution text)";
  22. Statement statement = connection.createStatement();
  23. statement.execute(sql);
  24. statement.close();
  25. connection.close();
  26. System.out.println("~~成功~~");
  27. }
  28. }

上面的com.mysql.jdbc.Driver也是需要导入mysql-connector-java这个依赖
然后用的是java自带的DriverManager进行数据库连接
而不是使用数据库连接池的datasource

3.线程池