我正在@Stateless
其余资源中的WildFly 9.0.2上实现非可重复读取隔离级别
Account
实体,打印余额,然后做其他工作(睡眠)。Account
实体,打印余额并通过calculateBalance()
方法计算余额,然后更新实体。它再次读取实体并打印出余额。根据我对不可重复读取级别的理解,线程B应该阻塞,直到线程A完全完成(退出事务/无状态休息资源)。
这是打印输出:
由此我可以看到线程B没有阻塞,即使线程A仍然忙,也可以运行。
以下是代码:
@GET
@Path("/{accountId}/{threadName}")
public Response calculcateBalance(@PathParam("accountId") Long accountId, @PathParam("threadName") String threadName) {
Account account = em.find(Account.class, accountId);
printBalance(account,threadName);
if ("ThreadA".equals(threadName)) {
sleepSeconds(10);
} else if ("ThreadB".equals(threadName)) {
account.calculateBalance();
em.merge(account);
}
account = em.find(Account.class, accountId);
printBalance(account,threadName);
return Response.ok().build();
}
如果我将隔离级别更改为Serializable所有块。
我对不可重复的理解读错了吗?是否应该在线程A完成之前阻塞线程B?
答案 0 :(得分:2)
这取决于底层数据库系统。如果您使用的是默认使用2PL的SQL Server,则线程A会在读取该行时获取共享锁,并且线程B将阻止写入该行(直到线程A释放共享锁)。
Oracle,PostgreSQL和MySQL使用MVCC,而Repeatable Read不使用锁定,因为读者不会阻止编写者和编写者不阻止读者。 在MVCC中,检测到异常,如果线程B修改该行,则线程A将检测到该更改并将中止其事务。