2016-11-21 24 views
0

我目前正在维护几个项目,处理由以前的开发人员编写的车辆跟踪。 我发现有时系统会卡住一分钟左右,而不是继续工作,我们一直在试图找出相当长时间的原因。MySQL并发插入,为什么会发生,以及处理它的最佳方法是什么?

我可以看到“锁等待超时超标;尝试重新启动交易”在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:

@Override 
public T save(T item) { 
    factory.getCurrentSession().saveOrUpdate(item); 
    return item; 
} 

类GenericHibernateDaoImpl有@Transactional指令,所以,据我了解,本次交易是开放式调用save()方法和前在save()完成时提交并保存。

和遗留项目不使用休眠,它只是使用java.sql.Statement中:

setStatement.execute(FleetManagerSqlHelper.insertIdlingEvent(deviceBinding.getVehicleId(), Long.toString(gpsPositionId))); 

什么是处理这种情况的最好方法?我可以减少innodb_lock_wait_timeout(目前为50),并在每次发生时都会捕获TimeoutException,然后重试它直到它完成任务(我甚至看到有人在网上推荐它),但这是否正确?这种情况也可能发生在其他表中,我想,这是否意味着我需要用重试来包围项目中的所有查询?

我很感激任何建议,因为我没有太多的MySQL经验,我很困惑这种行为。

非常感谢!

回答

0

我们已将事务隔离级别更改为READ-COMMITTED,它似乎已解决问题

相关问题