【发布时间】:2017-02-06 12:24:34
【问题描述】:
我正在使用类似 MariaDB 的休眠乐观锁定
@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 都应该让第二个线程看到旧值,不是吗?
我可以看到应用程序级锁定是一个坏主意,我只是想了解发生了什么,然后再切换到重试或 DB 锁定。
一个可能的原因是我使用 JodaTime Instant 进行版本控制, which is broken.
【问题讨论】:
-
如果你不“阅读一些不相关的实体”会发生什么?
-
@JohnDonn 我不知道,也无法轻易找到它,因为它是从无法轻易删除的真实代码中提取的。制作 SSCCE 肯定会有所帮助,但它相当复杂。 +++ 我猜,新的时间戳会被读取,因为
createSession是懒惰的。但这只是猜测。
标签: java mysql multithreading hibernate