b3log中数据库连接的处理

来源:互联网 发布:金蝶软件集团 编辑:程序博客网 时间:2024/05/29 13:38




b3log 中数据库连接的处理 


b3log 是以c3p0作为数据库连接池,那么它是怎么处理那些连接的呢?
它是定义了一个 transaction 接口,然后用 jdbcTransaction 实现此接口,此接口的作用就是维护一个 connection
而这个connetion 就是从数据库连接池中取得的,对于每次操作数据库,我们不用每次都从连接池中得到一个连接,
而是将它封装成事先。而所有的操作执行完成时,最后提交一次事务就可以了,也就是 transaction 中的commit 与
rollback。
在一个事务中,比较有增加、删除两个操作。而每个操作都要有数据库的连接,它们共用的是 一个连接,而它们的方法又
不同,然后又是多线程操作,怎么解决这个问题呢?b3log 是将一个transaction 放到了 ThreadLocal中,它就是一个
大的容器,每个线程取连接的时候,都从各自的线程中取连接,而这些方法当前也是从线程中取连接的,这样就做到了
多个操作的连接的共享


在按着上面的写了一个程序时,发现在会出现 transaction 会操作已经关闭的connection ,也就是在一个事务中,已经有
操作将连接关掉了,而其他操作还不知道,
自己排查了一下,原来是前面出线数据库连接忘了关,造成连接分配过多而死锁,后来把执行过的操作都直接关掉了数据库
问题就出在了这,对于查询而言,设计是他也是从ThreadLocal中的取连接的,如果Threadlocal中没有就直接从连接池中取
为什么要这样呢?因为查义并不需要事务执行,所以直接从连接池中取,但如果在一个事务中有查询,又不能再取连接,
所以就先从ThreadLocal中取,如果没有的话,再从连接池中取,对于查询,前面的解决死锁的方案是直接关闭,但
这个时候没有考虑到此连接是从连接池中来还是从ThreadLocal中,如果从连接池中应该直接关闭,而对于ThreadLocal中的
则要等到事务执行完成后才可以,那么这要怎么区分呢?


因为如果当前的connection 是从ThreadLocal中的来的,那么当前线程中一定有一个Transction 实体,我们可以查看
当前线程中的transaction 实体是否存在,如果存在的话,说明此连接是从transaction 中来的,否则就是连接池中来的,

private Connection getConnection() {
JdbcTransaction transaction = TX.get();
if (transaction == null) { // if not then return connections'
return Connections.getConnection();
}
return transaction.connection();
}
因为当前的tansaction 为空才从当前连接池中分配的,而当一个事务提交后,我们要对连接进行释放,也要把当前当前线程中
的Transaction 进行清除,但可能会出现这种情况,我们在执行了一个事务后,将该事务中的连接进行关闭,但当前线程还引用
着这个事务对象,我们下次请求时还是返回这个事务,但这个事务中中的连接已经被关闭,这样也会出现错误,因此我们在事务中
定义一个 isAlive 的布尔变量,当我们在取连接的时候,取到当前线程中的事务时,看看里面的isAlive 是否为真,如果不是的话
还要返回连接池中的,在beginTransaction时,得到线程中的transaction,不光检查transaction对象是否为空,还要检查是否isalive
如果不是的话,创建新的transactoin 放在当前线程中,而在执行事务关闭的时候,不光要关闭connection.close ,还要将isAlive 
flase,这样下次再取的时候,就直接会创建新的了