数据库连接池简介和 C3P0的JDBC配置

前面一节我们介绍了如何利用jdbc连接数据库,已经实现了数据库的连接,但是在实际的项目开发中,可以发现基本上都使用了数据库连接池技术,为什么要使用数据库连接池呢?根源在于对数据库连接的低效管理
答: 普通的JDBC数据库连接,用户请求一次查询的时候就会向数据库发起一次连接,执行完后就断开连接,这样的方式会消耗大量的资源和时间,数据库的连接资源并没有得到很好的重复利用。若是同时有几百人甚至几千人在线,频繁地进行数据库连接操作,这将会占用很多的系统资源,严重的甚至会造成服务器的奔溃。这样频繁的创建销毁数据库连接十分耗费时间和资源,而且开发者也不能很好的控制数据库的连接数,有可能因为分配的连接过多而导致内存耗尽。

数据库连接池的实现原理解析,以及设计连接池时需要考虑的因素

  1. 并发问题
    首先必须考虑多线程的环境, 可以使用synchronized关键字,lock等即可确保线程是同步的,public synchronized Connection getConnection()
  2. 多数据库服务器和多用户
    设计一个符合单例模式的连接池管理类,在连接池管理类的唯一实例被创建时读取一个资源文件,其中资源文件中存放着多个数据库的url地址等信息。根据资源文件提供的信息,创建多个连接池类的实例,每一个实例都是一个特定数据库的连接池。连接池管理类实例为每个连接池实例取一个名字,通过不同的名字来管理不同的连接池。
    对于同一个数据库有多个用户使用不同的名称和密码访问的情况,也可以通过资源文件处理,即在资源文件中设置多个具有相同url地址,但具有不同用户名和密码的数据库连接信息。
  3. 事务处理
    Connection类本身提供了对事务的支持,可以通过设置connection的autocommit属性为false 然后显式的调用commit或rollback方法来实现。
      try{
          connect.setAutoCommit(false);
          ........ 进行的数据库操作语句
          connect.commit();
      }catch{
          connect.rollback();
      }finally{
         connect.close();
      }

但是当2个线程共用一个连接Connection对象,而且各自都有自己的事务要处理时候,对于连接池是一个很头疼的问题,因为即使Connection类提供了相应的事务支持,可是我们仍然不能确定那个数据库操作是对应那个事务的,这是由于我们有2个线程都在进行事务操作而引起的。但要高效的进行Connection复用,就必须提供相应的事务支持机制。可采用每一个事务独占一个连接来实现,虽然这种方法有点浪费连接池资源,但是可以大大降低事务管理的复杂性。
4. 连接池的分配与释放
合理的分配与释放,可以提高连接的复用度,从而降低建立新连接的开销,同时还可以加快用户的访问速度。
对于连接的管理可使用空闲池。即把已经创建但尚未分配出去的连接按创建时间存放到一个空闲池中。每当用户请求一个连接时,系统首先检查空闲池内有没有空闲连接。如果有就把建立时间最长(通过容器的顺序存放实现)的那个连接分配给他(实际是先做连接是否有效的判断,如果可用就分配给用户,如不可用就把这个连接从空闲池删掉,重新检测空闲池是否还有连接);如果没有则检查当前所开连接池是否达到连接池所允许的最大连接数(maxconn)如果没有达到,就新建一个连接,如果已经达到,就等待一定的时间(timeout)。如果在等待的时间内有连接被释放出来就可以把这个连接分配给等待的用户,如果等待时间超过预定时间timeout 则返回空值(null)。系统对已经分配出去正在使用的连接只做计数,当使用完后再返还给空闲池,但是会发生无法对正在使用的连接进行管理的状况,所以建议使用一个链表存储。对于空闲连接的状态,可开辟专门的线程定时检测,这样会花费一定的系统开销,但可以保证较快的响应速度。也可采取不开辟专门线程,只是在分配前检测的方法

再分配、释放策略对于有效复用连接非常重要,引用记数模式在复用资源方面用的非常广泛,每一个数据库连接,保留一个引用记数,用来记录该连接的使用者的个数,我们对Connection类进行进一步包装来实现引用记数,确定当前被引用多少,具体是哪个用户引用了该连接将在连接池中登记,一旦一个连接被分配出去,那么就会对该连接的申请者进行登记,并且增加引用记数,当被释放回来时候就删除他已经登记的信息,同时减少一次引用记数

5、连接池的配置与维护
连接池中到底应该放置多少连接,才能使系统的性能最佳?系统可采取设置最小连接数(minconn)和最大连接数(maxconn)来控制连接池中的连接。最小连接数是系统启动时连接池所创建的连接数。如果创建过多,则系统启动就慢,但创建后系统的响应速度会很快;如果创建过少,则系统启动的很快,响应起来却慢。这样,可以在开发时,设置较小的最小连接数,开发起来会快,而在系统实际使用时设置较大的,因为这样对访问客户来说速度会快些。最大连接数是连接池中允许连接的最大数目,具体设置多少,要看系统的访问量,可通过反复测试,找到最佳点。
如何确保连接池中的最小连接数呢?有动态和静态两种策略。动态即每隔一定时间就对连接池进行检测,如果发现连接数量小于最小连接数,则补充相应数量的新连接以保证连接池的正常运转。静态是发现空闲连接不够时再去检查。

自己实现一个简易的数据库连接池,只考虑了连接池的一些方面

// 连接池类
我在设计的时候需要考虑的几点
1. 首先是数据库连接的存储,要能很容易的管理和获取数据库连接,将数据库连接分为两部分,一部分是空闲池,一部分是正在使用的数据库连接使用LinkedList 实现栈来存储空闲的数据库连接,(优势在于每一次获取到的连接都是新的连接,这样的连接基本上都是可用的,基本上不会发生连接不可用导致重新再去获取连接的操作), 使用LinkedList 实现队列来存储正在使用中数据库连接(优势在于,队列的头部就是目前使用时间最长的连接,方便进行检查,回收这个使用时间超过限制的数据库连接)
2. 如何回收分配出去的连接,即当外部的连接调用了close方法之后,如何让它返回到数据库连接池中,而不是销毁?
方法: 使用动态代理, 当请求一个Connection 时,返回用户一个代理的Connection 对象,这样就可以对close方法进行拦截,调用了close方法,会自动执行代理类中的invoke方法, 在invoke方法里面就可以实现对实际连接的一些操作了, 具体实现请查看 getConnection() 方法。
3. 其实获取连接的时候应当首先检查空闲池是否有空闲连接再检查空闲连接是否可用当数据库连接池没有连接的时候,要进行一次性创建新的连接,同时要进行检查看是否能进行连接的创建,是否达到了最大值等, 所以数据库的一些配置属性需要在静态代码块中通过Properties类读取出来。

public class MyDatabasePool {
   

    private LinkedList<Connection> idlelist; // 使用LinkedList实现栈存储数据库连接,存放的空闲连接
    private LinkedList<Connection> usinglist; // 使用LinkedList实现队列存储数据库连接,存放的正在使用的连接
    private static Properties props; // 读取配置文件信息
    private static int initialPoolSize; // 初始连接池大小
    private static int maxPoolSize; // 连接池最大连接数
    private static int acquireIncrement; // 无连接时,一次性创建连接数
    
  • 0
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值