Lock wait timeout

来源:互联网 发布:国外域名提供商 编辑:程序博客网 时间:2024/05/06 13:55

昨天开发过程中,调试一段代码的时候程序抛出了Lock wait timeout excaption。

Caused by: java.sql.SQLException: Lock wait timeout exceeded; try restarting transaction    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1055)    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:956)    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3558)    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3490)    at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1959)    at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2109)    at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2643)    at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2077)    at com.mysql.jdbc.PreparedStatement.execute(PreparedStatement.java:1356)

这个太奇怪了,因为没有并发存在(只有一个人在访问数据库),而且所有的操作都是在一个Service里面,事务的传播机制是PROPAGATION_REQUIRED (autocommit为默认值),按道理来说这些操作是在一个事务里面的,不应该会出现这种状况啊。

首先查看数据库:information_schema.trxinformation_schema.innodb_locks,information_schema.innodb_lock_waits



问题大概能看出来了,innodb_locks这两个锁加在同一个表的同一个index上面,一个是X锁,一个是S锁,而这两个锁有分别属于不同的trx,所以会出现锁等待的问题。可是让我比较纳闷的是,为什么数据库这边会有三个trx??不应该是一个吗?当场我就斯巴达了。在程序里大家都是由一个事物来管理呀,这一点百思不得其解,后来查看程序这边debug的log,发现程序这边也是有三个事务,额……

第二天早上在地铁上跟Adrian(一个项目组,而且合租房子)说起这个事情,聊着聊着发现我昨天一直忽略了重要的一点:这个系统数据库这边是分库分表的!

在这里简单介绍一下数据库这边,数据库设计这边是分库分表的,有两个库:DBA和DBB,两个库在同一台机器上;在每个库内,有一些表是分表的,像tablea0, tablea1这样(分表跟这次lock的问题关系不大)。所有需要分表的记录都直接或者间接关联到某个user下面,分库分表的策略都是根据userID来做的,根据userID计算出shardValue然后选择datasource和table。如果不需要分库分表,那么就访问默认的datasource,这里是DB_A。

出问题的代码,简单表述如下:

public class TestServiceImpl {    public void methodA() {        this.methodB();        foreach DB{            this.methodC();        }    }    //由于有分表,所以shardValue不同,操作的表不同。这里shardValue取决于有多少个表。    private void methodB() {        executeSQL:        update table_b_single         inner join (            select id from (                select id from DB_A.table_a_0                 union all                select id from DB_A.table_a_1                union all                select id from DB_B.table_a_0                union all                select id from DB_B.table_a_1            ) as tempTable        ) tempA        on table_b.id = tempA.id        set table_b.name='newName';    }     private void methodC() {        executeSQL:        insert into table_a_{shardValue} values (...);    }}

问题产生原因大致是这样的: 先说methodC,methodC中的SQL是在单个数据库中完成的,但是呢需要在每个库中都执行methodC中的SQL,由于事务不可能跨数据库,所以每次执行的时候在数据库层面使用不同的事务(起码每次在不同的库里执行,用到的DataSource都不一样)。methodC执行的时候会在tablea{shardValue}表的聚簇索引(主键索引)上面加X锁(写锁)。

然后是methodB,tablebsingle不需要分表,里面的记录和任何userID都没有关系,这样一来每次对tablebsignle进行操作,使用的datasource都是默认的datasource(DB_A),但是inner join里面的查询操作需要从两个数据库四张表获取数据,相应的会在这四张表上面都加锁(主键索引加S锁)。

很显然,对于methodA,数据库层面不可能只用一个事务,毕竟methodC和methodB的操作都会涉及到不同数据库,这样就解释了informationschema.innodbtrx里面会查出来多个事务。然后其实在程序层面也是用到了不同的事务,主要是这样的,这里分库分表用到了summercool这样一个框架,这个框架可以管理不同数据库的事务,也就是说,连接不同数据库程序用到的事务不一样,但是summercool会管理好这些不同的事务,使其对于开发人员来说可以视其操作在一个事务里,即使这操作需要用到不同数据库。这个地方可能有点绕啊,这么来说吧,对于开发人员来说summercool会确保methodA里面的操作具有原子性,即使methodC失败,methodB也会回滚。虽然methodB和methodC会用到不同的事务,但是呢对于开发人员来说这部分是透明的,无须自己管理。有点类似总分的感觉,如下图(三个不同颜色的矩形框表示三个事务),如果还是不懂恕楼主无能,解释不清。summercool的事务管理这部分我并没有去查阅详细代码,adrian看过这部分代码,表示大致是这个样子的。 

然后默认的autocommit为true,在methodB执行之后,事务并没有提交,那么methodB中的操作在两个数据库四张表上加的S锁并没有释放,而这个时候执行methodC,我们前面提到了,这两个操作并不会使用同样的事务,而这个时候methodC中的操作需要在tablea{shardValue}上面加X锁,那自然无法获取(都被methodB的操作加了S锁),一直被阻塞。

尝试交换methodB和methodC的执行顺序,同样会发生lock time out,但是这种情况下会变成S锁被X锁阻塞。

基本上应该就是这个样子,也算难得的一次经验。

PS:分库分表这种策略在做报表统计的时候,会有很多不方便的地方,因为需要统计的数据在不同表不同datasource里面。

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 微信登录申诉收不到短信怎么办 登录微信手机收不到验证码怎么办 美图t8冲一会电就发烧怎么办 美图t8系统不小心升级了 怎么办 美图手机看相册视频就会变黑怎么办 苹果4s屏幕唤醒速度慢怎么办 美图m4换电池后不显示卡怎么办 美图手机久没充电再充没反应怎么办 美图6s开不开机怎么办 苹果4s照片不能拍照黑屏怎么办 美图手机开机键坏了怎么办 金立金刚二手机烧卡怎么办 金立金刚手机开不开机怎么办 小米4手机拆机信号不好怎么办 荣耀自带游览器无法正常打开怎么办 苹果4s电池越来越不耐用怎么办 苹果4s电池不耐用了怎么办 苹果手机4s电池不耐用怎么办 红米4s电池不耐用怎么办 32位app私密相册打不开怎么办 红米手机取卡针断手机里了怎么办 我差评了客服打电话骂我怎么办 顺丰快递在预计时间没有回来怎么办 同款商品比京东便宜怎么办 京东自营不支持7天退货怎么办 天猫买了一个月的电动车坏了怎么办 发票号码和机打号码不一致怎么办 交电费的本子弄丢了怎么办 快递正在派件中发现地址错了怎么办 快递当天送达当天签收还算延怎么办 深圳国税公众号预约取号公司怎么办 社保买了停了2年怎么办 qq号被冻结申请不回来了怎么办 qq号被冻结 手机密保忘了怎么办 微信账号封了2天怎么办 买qq号被申诉找回了怎么办 收到了京东白条的催款通知单怎么办 成都买房社保不够两年怎么办18年 电话号码给人设置成骚扰电话怎么办 找不到领导电话不接短信不回怎么办 微信账号被别人手机号冻结了怎么办