У меня есть приложение Hibernate, которое может производить одновременные вставки и обновления (через Session.saveOrUpdate
) для записей с тем же первичным ключом, которому назначено . Эти транзакции выполняются в течение некоторого времени, в среднем около 15 секунд (поскольку данные собираются из удаленных источников и сохраняются по мере поступления). Мой уровень изоляции БД установлен на Read Committed, и я использую MySQL и InnoDB.
Проблема в том, что этот сценарий создает чрезмерное время ожидания блокировки, по истечении которого происходит либо тупик, либо длительные транзакции. Это приводит меня к нескольким вопросам:
- Движок базы данных снимает блокировки только при совершении транзакции?
- Если это так, я должен стремиться сократить свои транзакции?
- Если это так, то будет ли хорошей практикой использование отдельных транзакций чтения и записи, когда транзакция записи может быть короткой и иметь место только после сбора всех моих данных (большая часть моей длины транзакции включает сбор удаленных данных ).
Edit:
Вот простой тест, который приблизительно соответствует тому, что, по моему мнению, происходит. Поскольку я имею дело с долго выполняющимися транзакциями, фиксация происходит через много времени после первого сброса. Поэтому, чтобы проиллюстрировать мою ситуацию, я оставил коммит вне теста:
@Entity
static class Person {
@Id
Long id = Long.valueOf(1);
@Version
private int version;
}
@Test
public void updateTest() {
for (int i = 0; i < 5; i++) {
new Thread() {
public void run() {
Session s = sf.openSession();
Transaction t = s.beginTransaction();
Person p = new Person();
s.saveOrUpdate(p);
s.flush(); // Waits...
}
}.run();
}
}
И запросы, которые это выжидательно производит, ожидают на второй вставке:
select id, version from person where id=?
insert into person (version, id) values (?, ?)
select id, version from person where id=?
insert into person (version, id) values (?, ?)