我们如果在java系统中访问一个数据库,必须在系统的依赖中加入MySQL驱动。MySQL驱动用来和MySQL建立连接。
我们系统中可能会有多个线程并发地通过MySQL驱动访问MySQL。如果每个线程都需要建立数据库连接,执行结束后销毁连接,那么效率会非常低。因此需要数据库连接池,在连接池中维持多个数据库连接。这样多个线程可以使用不同的连接去执行SQL语句,执行完成后只需将连接返回连接池即可。
问题
问题一
应用服务器忽然不能提供服务了,通过查询日志得知是应用中的工作线程无法从druid连接池中获取数据库连接,猜测可能是druid中的连接全部被其它工作线程占用了,那么我该如何排查是哪些工作线程长时间的占用了连接呢?从而可以确定哪里的代码写的有问题。
一般这种都是长事务占用连接或者锁等待导致的,可以通过mysql的系统表去查看占用连接的事务,根据事务去知道线程id,根据线程id找到threads表中sql或者通过show processlist查看占用连接的机器
查询 正在执行的事务
SELECT * FROM information_schema.INNODB_TRX
如下图所示:首先设置事务手动提交,然后在客户端1中执行一个update,在客户端2中也执行一个update(和客户端1中更新相同行的数据),此时客户端2中的 update 会被阻塞住:
此时查看数据库中正在执行的事务,可以看到有2个记录,其中一个trx_state是 RUNNING(这个是客户端1),另一个是 LOCK_WAIT(这个是客户端2),从结果中还可以看到这个事务的id(trx_mysql_thread_id),可以使用mysql命令:kill thread_id 来杀掉线程:
