背景:用户需求需要批量走流程,但单线程走流程速度比较慢,10条的话需要花费10倍的时间,故改成多线程模式;改成多线程模式之后遇到多种bug;
1、处理完成之后,刷新页面,流程数据还没保存完成导致刷新页面错误
解决方法:主线程延迟500ms 返回。
2、jpa方式下,并且主线程等待子线程完成之后返回。会导致子线程里面修改的值被主线程覆盖掉。
伪代码例子:
public class A{
@Autowired
private B b;
public test(id){
b.test(id);
new Thread(new Runnable(){
@OverWrite
public void run(){
Entity entity = entityDao.findById(id);
entity.setName("A");
entityDao.save(entity);
}
}).start();
Thread.currentThread().sleep(500);
}
}
public class B{
@Transactional(propagation = Propagation.REQUIRES_NEW)
public test(id){
Entity entity = entityDao.findById(id);
entity.setName("B");
entityDao.save(entity);
}
}
public class Entity{
private String id;
private String name;
}
得到结果是B,所以猜测@Transactional事务是在线程结束时候提交。待验证。
3、并发处理流程会导致数据库锁超时问题。由于公司采用注解方式封装业务流程,封装比较重,故流程容易死锁。
问题的具体排查:
1、首先通过下面的sql排查问题
SHOW OPEN TABLES WHERE In_use > 0;
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS;
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS;
SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX;
SELECT * from `performance_schema`.events_statements_current;
SELECT * from `performance_schema`.threads;
SELECT * from information_schema.`PROCESSLIST`;
SELECT b.trx_mysql_thread_id as 'blocked_thread_id' ,b.trx_query AS 'blocked_sql_text' ,c.trx_mysql_thread_id AS 'blocker_thread_id',c.trx_query AS 'blocker_sql_text'
,f.SQL_TEXT,d.ID,c.trx_started,f.THREAD_ID
from information_schema.INNODB_LOCK_WAITS a
JOIN information_schema.INNODB_TRX b ON a.requesting_trx_id = b.trx_id
JOIN information_schema.INNODB_TRX c ON a.blocking_trx_id = c.trx_id
JOIN information_schema.`PROCESSLIST` d ON d.ID = c.trx_mysql_thread_id
JOIN `performance_schema`.threads e ON e.PROCESSLIST_ID = d.ID
JOIN `performance_schema`.events_statements_current f ON f.THREAD_ID = e.THREAD_ID;
最后发现,同一个线程,获取@Aspect切面的参数存在并发问题:
classA:thread:Thread-221; instanceId:10775658
classB:thread:Thread-221; instanceId:10775667
classC:thread:Thread-221; instanceId:10775658
接下来具体排查为什么不一致问题。
再由于 采用分布式锁,会等所有线程成功再一起提交。
故线程1锁住了 表的10775667。线程2也要操作10775667,需要等待线程1提交。而线程1需要等待线程2提交。造成死锁。
后面通过日志打印排查。发现入参是共享的参数,导致属性覆盖。