• 手写数据库连接池


    数据库连接是个耗时操作.对数据库连接的高效管理影响应用程序的性能指标.

    数据库连接池正是针对这个问题提出来的.

    数据库连接池负责分配,管理和释放数据库连接.它允许应用程序重复使用一个现有的数据路连接,而不需要每次重新建立一个新的连接,利用数据库连接池将明显提升对数据库操作的性能.

    数据库连接池技术方案:

    1.C3P0

    2.DBCP

    3.Proxool

    4.Tomcat jdbc Oppl

    5.BoneCP

    6.Druid

    7.HikariCP

    数据库连接池属于一种池化技术:

    常见的有:http访问(httpclient),redis访问(redisPool),线程(线程池)等

    新建个空项目

    可能是版本原因idea创建空项目总要重启一下

    设置下maven和encoding

    新建模块

    DataSource是JDK里的规范,用来专门放连接的.是一个连接工厂

    自定义一个接口

    里面需要实现的两个方法是:  其他的父接口的其他方式可以暂时不管

    这样基础结构就有了

    1. package com.pool;
    2. import java.sql.Connection;
    3. import java.sql.DriverManager;
    4. import java.sql.SQLException;
    5. /**
    6. * @author hrui
    7. * @date 2023/9/10 3:06
    8. */
    9. public class MyAbstractDataSource implements MyDataSourceInterface{
    10. private String url;
    11. private String driver;
    12. private String username;
    13. private String password;
    14. //最大的连接数量
    15. private int poolMaxActiveConnection=10;
    16. //最大空闲连接数
    17. private int poolMaxIdIeConnection=5;
    18. //当连接都在使用时候,最大检出时间(等待时间),毫秒
    19. private int poolTimeToWait=20000;
    20. public int getPoolMaxActiveConnection() {
    21. return poolMaxActiveConnection;
    22. }
    23. public void setPoolMaxActiveConnection(int poolMaxActiveConnection) {
    24. this.poolMaxActiveConnection = poolMaxActiveConnection;
    25. }
    26. public int getPoolMaxIdIeConnection() {
    27. return poolMaxIdIeConnection;
    28. }
    29. public void setPoolMaxIdIeConnection(int poolMaxIdIeConnection) {
    30. this.poolMaxIdIeConnection = poolMaxIdIeConnection;
    31. }
    32. public int getPoolTimeToWait() {
    33. return poolTimeToWait;
    34. }
    35. public void setPoolTimeToWait(int poolTimeToWait) {
    36. this.poolTimeToWait = poolTimeToWait;
    37. }
    38. public String getUrl() {
    39. return url;
    40. }
    41. public void setUrl(String url) {
    42. this.url = url;
    43. }
    44. public String getDriver() {
    45. return driver;
    46. }
    47. public void setDriver(String driver) {
    48. this.driver = driver;
    49. }
    50. public String getUsername() {
    51. return username;
    52. }
    53. public void setUsername(String username) {
    54. this.username = username;
    55. }
    56. public String getPassword() {
    57. return password;
    58. }
    59. public void setPassword(String password) {
    60. this.password = password;
    61. }
    62. @Override
    63. public Connection getConnection() throws SQLException {
    64. return getConnection(username,password);
    65. }
    66. @Override
    67. public Connection getConnection(String username, String password) throws SQLException {
    68. return doGetConnection(username,password);
    69. }
    70. private Connection doGetConnection(String username, String password) throws SQLException {
    71. Connection connection = DriverManager.getConnection(url, username, password);
    72. return connection;
    73. }
    74. }

    上面三个方法,都是获得连接

    下面用动态代理方式实现对数据库连接的代理

    1. package com.pool;
    2. import java.lang.reflect.InvocationHandler;
    3. import java.lang.reflect.Method;
    4. import java.lang.reflect.Proxy;
    5. import java.sql.Connection;
    6. /**
    7. * 采用动态代理实现对数据库连接的代理
    8. * @author hrui
    9. * @date 2023/9/10 3:45
    10. */
    11. public class ConnectionProxy implements InvocationHandler {
    12. //真正连接
    13. private Connection realConnection;
    14. //代理连接
    15. private Connection proxyConnection;
    16. //数据源对象
    17. private MyDataSource myDataSource;
    18. public ConnectionProxy(Connection realConnection, MyDataSource myDataSource) {
    19. //初始化真实连接和数据源
    20. this.realConnection = realConnection;
    21. this.myDataSource = myDataSource;
    22. //初始化代理连接...需要一个代理对象 JDK动态代理
    23. this.proxyConnection= (Connection)Proxy.newProxyInstance(Connection.class.getClassLoader(),
    24. new Class[]{Connection.class},
    25. this);
    26. }
    27. public Connection getRealConnection() {
    28. return realConnection;
    29. }
    30. public void setRealConnection(Connection realConnection) {
    31. this.realConnection = realConnection;
    32. }
    33. public Connection getProxyConnection() {
    34. return proxyConnection;
    35. }
    36. public void setProxyConnection(Connection proxyConnection) {
    37. this.proxyConnection = proxyConnection;
    38. }
    39. public MyDataSource getMyDataSource() {
    40. return myDataSource;
    41. }
    42. public void setMyDataSource(MyDataSource myDataSource) {
    43. this.myDataSource = myDataSource;
    44. }
    45. /**
    46. * 当调用Connection对象里面的任何方法时,该方法会进行拦截
    47. * 主要目的为了拦截Connection的close方法,当关闭时进行拦截,将Connection对象放入连接池中
    48. * 其他方法无需拦截
    49. * @param proxy
    50. * @param method
    51. * @param args
    52. * @return
    53. * @throws Throwable
    54. */
    55. @Override
    56. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    57. //获取当前调用了Connection对象的什么方法
    58. String methodName=method.getName();
    59. if(methodName.equals("close")){
    60. //TODO 把连接放入连接池
    61. return null;
    62. }else{
    63. //其他方法
    64. return method.invoke(realConnection, args);
    65. }
    66. }
    67. }
    68. }

    下面写个类继承MyAbstractDataSource  在里面放入连接池

    1. package com.pool;
    2. import java.sql.Connection;
    3. import java.sql.SQLException;
    4. import java.util.ArrayList;
    5. import java.util.List;
    6. /**
    7. * 数据源连接池
    8. * @author hrui
    9. * @date 2023/9/10 4:15
    10. */
    11. public class MyDataSource extends MyAbstractDataSource{
    12. //空闲连接
    13. private final List<ConnectionProxy> idleConnections=new ArrayList<>();
    14. //激活的连接池
    15. private final List<ConnectionProxy> activeConnections=new ArrayList<>();
    16. //下面三个可以抽取放到父类抽象类中,由用户配置
    17. //最大的连接数量
    18. //private int poolMaxActiveConnection=10;
    19. //最大空闲连接数
    20. //private int poolMaxIdIeConnection=5;
    21. //当连接都在使用时候,最大检出时间(等待时间),毫秒
    22. //private int poolTimeToWait=20000;
    23. //用于同步监视器对象
    24. private final Object monitor=new Object();
    25. //用于同步监视器对象(关闭)
    26. //private final Object watch=new Object();
    27. /**
    28. * 重写:用于获取代理连接
    29. * @return
    30. * @throws SQLException
    31. */
    32. @Override
    33. public Connection getConnection() throws SQLException {
    34. ConnectionProxy connectionProxy=getConnectionProxy(super.getUsername(),super.getPassword());
    35. //返回代理连接
    36. return super.getConnection();
    37. }
    38. /**
    39. * 获取代理连接
    40. * @param username
    41. * @param password
    42. * @return
    43. */
    44. private ConnectionProxy getConnectionProxy(String username,String password) throws SQLException {
    45. //TODO
    46. //是否需要等待
    47. boolean wait=false;
    48. ConnectionProxy connectionProxy=null;
    49. //刚开始没有连接
    50. while(connectionProxy==null){
    51. synchronized (monitor){
    52. //看连接池有没有空闲连接,如果不为空,直接获取连接
    53. if(!idleConnections.isEmpty()){
    54. connectionProxy=idleConnections.remove(0);
    55. //如果是空的
    56. }else{
    57. //没有空闲连接,那么需要获取新的连接(创建连接)
    58. //这里先判断最大连接数是不是小于配置数量 10
    59. if(activeConnections.size()<supper.getPoolMaxActiveConnection()){
    60. //创建新连接 需要传入真实连接
    61. connectionProxy=new ConnectionProxy(super.getConnection(),this);
    62. }
    63. //否则需要等待20秒 上面定义了poolTimeToWait=20000
    64. }
    65. }
    66. if(!wait){
    67. wait=true;
    68. }
    69. if(connectionProxy==null){
    70. try {
    71. monitor.wait(supper.getPoolTimeToWait());
    72. } catch (InterruptedException e) {
    73. e.printStackTrace();
    74. //万一等待被线程打断,退出一下
    75. break;
    76. }
    77. }
    78. }
    79. if(connectionProxy!=null){
    80. //连接对象不是空,说明已经拿到连接了,放入容器
    81. activeConnections.add(connectionProxy);
    82. }
    83. return connectionProxy;
    84. }
    85. //用于关连接
    86. //不是把连接关系,而是还给连接池
    87. public void closeConnection(ConnectionProxy connectionProxy){
    88. synchronized (monitor){
    89. //最大连接(激活连接)里删除
    90. activeConnections.remove(connectionProxy);
    91. //如果空闲连接<定义的数量则放入空闲连接
    92. if(idleConnections.size()<supper.getPoolMaxIdIeConnection()){
    93. idleConnections.add(connectionProxy);
    94. }
    95. //通知一下,唤醒上面哪个等待获取连接的线程
    96. monitor.notify();
    97. }
    98. }
    99. }

    那么代理对象中把连接还给连接池的方法也有了

    就是当所有连接用完了,等待20秒的逻辑没写

    下面测试自己写的连接池

    新建模块  引入依赖

    不想玩了

  • 相关阅读:
    MYSQL数据库-基本操作
    C++ 内存泄漏检测与实现
    easyui jquery 可能用到方法mark
    代码随想录 单调栈part2
    Web3与传统互联网:挑战、融合与共生
    k8s学习--kube-proxy的三种工作模式详细解释
    软件测试下的AI之路(2)
    Enzo CYTO-ID自噬检测试剂盒特点&作用机制
    Pandas:sort_index、sort_values方法的使用
    Java实现word转PDF
  • 原文地址:https://blog.csdn.net/tiantiantbtb/article/details/132786829