说说你遇到哪些数据库事务引起的奇葩Bug?
Posted 程序员Club
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了说说你遇到哪些数据库事务引起的奇葩Bug?相关的知识,希望对你有一定的参考价值。
这两周真的好忙,有一个比较大的需求,从上周到这周一直在写代码,有时候为了出结果,不愿意站起来,导致坐一天腿疼,今天后台需求都实现了,和前台联调也差不多明天就结束了,不出意外明天就可以自测,然后扔给测试人员测试。
我今天写的一篇文章呢,缘由是下午Java后台小组开了一个会,CTO讲了一下昨晚发生的数据库死锁,对于平常开发中不常用事务的我,很好奇实际开发中哪里用到事务,今天也听得很开心,趁着这股劲,我大概整理总结一番。
目前总结的问题:
1、事务开始后,try前还有操作;
2、事务提交后,exception前还有db操作;
3、事务中存在外部调用dubbo;
4、事务中存在外部redis调用;
5、事务中存在外部调用activemq;
6、两个事务嵌套 ;
自己细细品味,着实一番风味,确实平时开发中不会想那么多,反正我一个try-catch把所有都包起来,只要涉及到数据库的地方我都加上事务,这样就不会报错了,殊不知,就是因为你的“聪明”,反而做了无用功,甚至出现bug.
基于上面的各种问题,CTO总结的最优事务代码:
boolean isRollback = true;
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
TransactionStatus status = transactionManager_vvmusic.getTransaction(def);
try {
if (error) {
return ;
}
// success
transactionManager_vvmusic.commit(status);
isRoback=false;
} catch(Exception e) {
// log ...
} finally {
if (isRollback) {
try {
transactionManager_vvmusic.rollback(status);
} catch(Exception e) {
//log...
}
}
}
一边总结,一边百度,一边和别人讨论,这块事务回滚加在catch里面也是可以的,但是catch()括号里一般是建议捕获当前代码会出现的异常(这个对于我这种菜鸟来说有点难度,我得预期它会抛出什么异常,哈哈),如果你没有预测到所有可能出现的异常,假设只捕获了A异常,现在就会出现一个问题,一不小心就是抛出了一个你没想到的B异常,直接报错,事实上我想要事务回滚,如果没有finally,你就得手动执行sql了,但是加上finally,就非常棒了! 加finally也是为了代码规范。
今天CTO在这块讲解的有一丢丢问题,但是当时我还是一脸懵,晚上自己细细回想,将正确的理解写在这里。
DB给出的查询事务对应的线程及事务:
select t1.trx_id,
t1.trx_state,
t1.trx_query,
t2.id,
t2.state,
t2.command
from information_schema.innodb_trx t1,
information_schema.processlist t2
where t1.trx_mysql_thread_id = t2.id
-- 查询正在执行的事务:
SELECT * FROM information_schema.INNODB_TRX;
-- 查看正在锁的事务
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS;
-- 查看等待锁的事务
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS;
平时真的很少接触事务这块,看到这几行代码,一脸懵,哈哈,刚开始以为information_schema.innodb_trx就是平常用到的表名,t1是它的别名,事实上我还是太年轻。
这里提到了INNODB_TRX表、INNODB_LOCKS表、INNODB_LOCK_WAITS表这三个事务锁相关的表,通过查看这三个表可以获取事务加锁以及事务锁等待的情况,从而更简单的监控当前事务可能存在的锁问题,例如分析死锁。
INNODB_TRX:主要包含了正在InnoDB引擎中执行的事务的信息,包括waiting for a lock和running的事务。
INNODB_LOCKS:主要包含了InnoDB事务锁的具体情况,包括事务正在申请的锁和事务上加的锁。
INNODB_LOCK_WAITS:主要包含了blocked的事务的锁等待的状态。
trx_id InnoDB存储引擎内部唯一的事务ID
trx_state 当前事务的状态: RUNNING, LOCK WAIT, ROLLING BACK or COMMITTING.
trx_started 事务的开始时间
trx_requested_lock_id 事务等待的锁的ID(如果事务状态不是LOCK WAIT,这个字段是NULL),详细的锁的信息可以连查INNODB_LOCKS表
trx_wait_started 事务等待开始的时间 (如果事务状态不是LOCK WAIT,这个字段是NULL)
trx_weight 事务的权重,反映了一个事务修改和锁住的行数。当发生死锁回滚的时候,优先选择该值最小的进行回滚
trx_mysql_thread_id Mysql中的线程ID,show processlist显示的结果
trx_query 事务运行的sql语句
trx_operation_state 事务当操作的类型 如updating or deleting,starting index read等
trx_tables_in_use 查询用到的表的数量
trx_tables_locked 查询加行锁的表的数量
trx_lock_structs The number of locks reserved by the transaction
trx_lock_memory_bytes 锁在内存占用的空间大小
trx_rows_locked 事务锁住的行数(不是准确数字)
trx_rows_modified 事务插入或者修改的行数
trx_concurrency_tickets A value indicating how much work the current transaction can do before being swapped out, as specified by the innodb_concurrency_ticketsoption.
trx_isolation_level 隔离级别
trx_unique_checks 唯一键检测 是否开启
trx_foreign_key_checks 外键检测 是否开启
如果有认真看上面sql语句的,发现里面除了事务,涉及到线程,在mysql5.5之后增加了processlist表,里面存储了当前连接信息,跟show processlist存储的一样,通过processlist可以统计分析一些信息,而不依赖shell命令(如 grep)。
我自己在数据库里执行了一下show processlist ,出现了如下结果:
对照下面的字段意思,是不是很酷!
ID:线程ID,这个信息对统计来说没有太大作用
USER:连接使用的账号,这个是一个统计维度,用于统计来自每个账号的连接数
HOST:连接客户端的IP/hostname+网络端口号,这也是一个统计维度,用于确定发起连接的客户端
DB:连接使用的default database,DB通常对应具体服务,可以用于判断服务的连接分布,这算一个统计维度
COMMAND:连接的动作,实际上是说连接处于哪个阶段,常见的有Sleep、Query、Connect、Statistics等,这也是一个统计维度,主要用于判断连接是否处于空闲状态
TIME:连接处于当前状态的时间,单位是s,这个在后面进行分析,暂不算在连接状态的统计维度中
STATE:连接的状态,表示当前MySQl连接正在做什么操作,这算一个统计维度,可能的值也比较多,详细可以查阅官方文档
INFO:连接正在执行的SQL,这个在下一节分析,暂不算在连接状态的统计维度中
我在我自己的数据库里面执行了一下sql语句:
select t1.trx_id,
t1.trx_state,
t1.trx_query,
t2.id,
t2.state,
t2.command
from information_schema.innodb_trx t1,
information_schema.processlist t2
where t1.trx_mysql_thread_id = t2.id
返回结果:
虽然我没有事务发生,但是对照上面字段的意思,查出来的信息非常厉害,对你查找bug很有帮助。
今天就讲解到这里,只是聊一聊自己对数据库事务的拙见。还有不懂的记得找度娘,下期见!
今日话题:你遇到过哪些事务引起的奇葩Bug,来这里畅所欲言!
喜欢就给个“好看”
以上是关于说说你遇到哪些数据库事务引起的奇葩Bug?的主要内容,如果未能解决你的问题,请参考以下文章