Wildfly 和 MySQL 的不可重复读取隔离级别
Non-repeatable read isolation level with Wildfly and MySQL
我正在 @Stateless
剩余资源
中的 WildFly 9.0.2 上实现不可重复读取隔离级别
- 线程 A 正在读取一个
Account
实体,打印余额,然后做一些其他工作(睡眠)。
- 线程 B 进入并读取相同的
Account
实体,打印余额并通过 calculateBalance()
方法计算余额,然后更新实体。它再次读取实体并打印出余额。
- 线程 A 然后读取实体并打印出余额。
根据我对不可重复读取级别的理解,线程 B 应该阻塞直到线程 A 完全完成(退出 transaction/Stateless 剩余资源)。
这是打印输出:
- 线程 A:printBalance=500
- 线程 B:printBalance=500
- 线程 B:printBalance=600
- 线程 A:printBalance=500
从那里我可以看到线程 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 everything blocks。
我对不可重复读的理解有误吗?在线程 A 完成之前,线程 B 是否应该被阻塞?
这取决于底层数据库系统。如果您使用默认使用 2PL 的 SQL 服务器,则线程 A 将在读取该行时获取共享锁,而线程 B 将阻止写入该行(直到线程 A 释放共享锁)。
Oracle、PostgreSQL 和 MySQL 使用 MVCC,并且可重复读取不使用锁定,因为读取器不会阻止写入器,写入器也不会阻止读取器。
在 MVCC 中,会检测到异常,如果线程 B 修改了该行,则线程 A 会检测到该更改并中止其事务。
因此,在 MVCC 中,anomalies are detected rather than prevented。
我正在 @Stateless
剩余资源
- 线程 A 正在读取一个
Account
实体,打印余额,然后做一些其他工作(睡眠)。 - 线程 B 进入并读取相同的
Account
实体,打印余额并通过calculateBalance()
方法计算余额,然后更新实体。它再次读取实体并打印出余额。 - 线程 A 然后读取实体并打印出余额。
根据我对不可重复读取级别的理解,线程 B 应该阻塞直到线程 A 完全完成(退出 transaction/Stateless 剩余资源)。
这是打印输出:
- 线程 A:printBalance=500
- 线程 B:printBalance=500
- 线程 B:printBalance=600
- 线程 A:printBalance=500
从那里我可以看到线程 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 everything blocks。
我对不可重复读的理解有误吗?在线程 A 完成之前,线程 B 是否应该被阻塞?
这取决于底层数据库系统。如果您使用默认使用 2PL 的 SQL 服务器,则线程 A 将在读取该行时获取共享锁,而线程 B 将阻止写入该行(直到线程 A 释放共享锁)。
Oracle、PostgreSQL 和 MySQL 使用 MVCC,并且可重复读取不使用锁定,因为读取器不会阻止写入器,写入器也不会阻止读取器。 在 MVCC 中,会检测到异常,如果线程 B 修改了该行,则线程 A 会检测到该更改并中止其事务。
因此,在 MVCC 中,anomalies are detected rather than prevented。