环境描述:
由于特殊原因服务器的网络是电信ADSL拨号上网的,用"自动切换IP精灵"进行自动断网重连,每次重新连上网络需要2s时间,设置2小时切换一次网络。
MYSQL数据库在远程一台服务器上,另有一台测试数据库(MYSQL,也是ADSL拨号)。
发现程序部署上去后,总会莫名的锁表,而连接测试数据库则没有问题。加入详细日志后发现是因为开启事务后,在程序更新多张表期间,“自动切换IP精灵”切换网络导致网络中断,事务未提交导致锁表! 那为什么测试数据库没有问题?
后来发现线上MYSQL版本是5.7.14,测试数据库版本是5.0.27,查找数据库版本更新资料发现:自5.5以后,其中有一条新增功能是
改善事务处理中的元数据锁定。例如,事物中一个语句需要锁一个表,会在事物结束时释放这个表,而不是像以前在语句结束时释放表(参考文章http://blog.csdn.net/chajinglong/article/details/52939350)。,也就是说 自5.5版本之后information_schema库增加了INNODB_TRX、INNODB_LOCKS、INNODB_LOCK_WAITS等几张与事务相关的表,事务的元数据锁定将更好的由事务表控制。这也是为什么测试数据库没有锁表的原因。
我原来的理解是断网后数据库会自动释放锁定的表,哪怕事务没有提交,因为连接中断数据库也会释放。
其实不是,为此专门做个测试:
cmd开启两个数据库的连接:
连接一:
mysql>set autocommit = 0;
mysql>begin;
mysql>update user set name='aa' where id = 1;
不提交事务,再打开 另一个窗口
连接二:
mysql>set autocommit = 0;
mysql>begin;
mysql>update user set name='aa' where id = 1;
则连接二处于挂起状态
如果此时关闭连接一窗口,则连接二会立刻返回执行结果!也就是关闭窗口,连接中断 数据库会自动释放事务 立刻回滚。
但是当我用连接池连接数据库并模拟 断网的情况时,通过SELECT * FROM information_schema.INNODB_TRX;会看到有事务未提交,并且没有因为断网数据库自动回滚(一时想不明白为何会如此)。
解决未提交事务方法是:
开启事务后,先执行一次select 查询,然后执行SELECT TRX_MYSQL_THREAD_ID FROM INFORMATION_SCHEMA.INNODB_TRX WHERE TRX_MYSQL_THREAD_ID = CONNECTION_ID(); 获得当前connection连接的trx_mysql_thread_id,最后 kill trx_mysql_thread_id的值,即可删除未提交事务。
各位如果有更好的解决方法,可告知下。