我目前正在维护一些由以前的开发人员编写的处理车辆跟踪的项目。 我发现有时系统卡住了大约一分钟而不是继续工作,我们一直试图找到原因很长一段时间。
我可以在error.log中看到“超过锁定等待超时;尝试重新启动事务”,并且在发生这种情况的那一刻我总是看到两个在MySQL中运行的查询:
Insert into idling_events (gps_position_id, vehicle_id) values (23083665777 ,'46881')
和
insert into idling_events (gps_position_id, vehicle_id, created_at, updated_at) values (23083665761, null, null, null)
两个查询一直运行相同的秒数(因此它们同时启动)。一个由我正在维护的项目执行,另一个由执行类似工作的遗留项目执行(但我认为它没有任何区别,因为即使查询被命中,也可能发生同样的事情同一项目的不同主题)。
我试图谷歌,似乎当两个插入同一个表同时发生时,mysql可能会被锁死。我不明白为什么会这样?为什么mysql没有把两个查询放在队列中并按随机顺序逐个执行呢?
我们使用的隔离级别是REPEATABLE READ。我看到一些建议将它改为Stackoverflow上的READ COMMITTED,但我不确定它是否会解决我们的问题,也可能会破坏复制,正如我所理解的那样。
表的结构如下:
id bigint(14) unsigned, not null, primary key, auto_increment
gps_position_id bigint(14) unsigned, not null, key: mul
vehicle_id int(11), can be null, key: mul
created_at datetime, can be null
updated_at datetime, can be null
表正在使用innodb。 我们在这张表中也有gps_position_index和vehicle_index。我想知道问题是否与我们在桌子上有索引的事实有关?
我们用于保存空闲事件的方法是GenericHibernateDaoImpl中的save():
@Override
public T save(T item) {
factory.getCurrentSession().saveOrUpdate(item);
return item;
}
类GenericHibernateDaoImpl有@Transactional指令,因此,据我所知,事务在调用save()方法之前打开,并在save()完成时提交并保存。
并且遗留项目不使用Hibernate,它只使用java.sql.Statement:
setStatement.execute(FleetManagerSqlHelper.insertIdlingEvent(deviceBinding.getVehicleId(), Long.toString(gpsPositionId)));
处理这种情况的最佳方法是什么?我可以减少innodb_lock_wait_timeout(目前它是50)并且每次发生时都会捕获TimeoutException,重试它直到它完成工作(我甚至看到有人在网上推荐它),但这是正确的方法吗?这种情况也可能发生在其他表中,我猜,这是否意味着我需要重试项目内的所有查询?
我很感激任何建议,因为我没有那么多的MySQL经验,我对此行为感到非常困惑。
非常感谢!
答案 0 :(得分:0)
我们已将事务隔离级别更改为READ-COMMITTED,它似乎已解决了问题