我正在使用像MariaDB一样的hibernate乐观锁定
@Version
@Column(columnDefinition="TIMESTAMP(3) DEFAULT '2016-01-01'")
private Timestamp timestamp;
最近,我有一个StaleStateException
,作为一个快速的黑客,我试图通过锁定应用程序来对抗它。这导致以下序列(第二列是一个线程号;每个线程都有自己的连接):
A 1 createSession
B 2 createSession
C 1 read some irrelevant entity
D 2 read some irrelevant entity
E 1 try to obtain lock
F 2 try to obtain lock
G 1 LOCK GRANTED
H 1 READ THE ENTITY, timestamp=2016-09-28 14:52:32.076
I 1 do some other stuff
J 1 WRITE THE ENTITY, new timestamp=2016-09-28 14:52:32.076
K 1 COMMIT
L 1 release lock
M 2 LOCK GRANTED
N 1 READ THE ENTITY, timestamp=2016-09-28 14:52:32.076
O 2 do some other stuff
P 2 WRITE THE ENTITY, StaleStateException
问题显然在第N行,其中第二个线程看到旧的时间戳。我没有在任何地方指定隔离级别,Mysql的默认值应该是REPEATABLE READ,但AFAIK没有级别,除了 甚至SNAPSHOT或SERIALIZABLE应该让第二个线程看到旧值,是吗?
我可以看到应用程序级别锁定是一个坏主意,我只是想在我切换到重试或数据库锁定之前了解正在发生的事情。
可能的原因是我使用JodaTime Instant进行版本控制, which is broken
答案 0 :(得分:0)
您尚未说明交易的开始和结束位置。
如果每个会话在步骤A& B,那么确实,Serializable意味着会话2只会看到它提交的旧时间戳单元并开始新的事务。
如果会话2使用Read Committed,它将在会话1提交后看到新值。
在此示例中,JPA正在按照您的要求执行操作,并使用“版本”字段来避免隐藏更新。如果您不在乎,并且想要进行更新,请不要使用版本......?