JDBC Transaction 如何在 TRANSACTION_READ_COMMITTED 隔离级别锁定表?
Posted
技术标签:
【中文标题】JDBC Transaction 如何在 TRANSACTION_READ_COMMITTED 隔离级别锁定表?【英文标题】:How does JDBC Transaction lock a table in TRANSACTION_READ_COMMITTED isolation level? 【发布时间】:2012-07-19 11:18:32 【问题描述】:我已阅读本教程:http://docs.oracle.com/javase/tutorial/jdbc/basics/transactions.html,但我认为我仍然缺少一些东西。
举个例子:
线程 T1 有自己的连接 线程 T2 有自己的连接因此,这些线程在两个不同的连接上执行事务(setAutoCommit(false))。此事务在单个数据库表上执行以下查询:
选择一行以读取累进数字 (PN) 插入一行,将渐进数设置为:PN++(我已经 阅读 +1)此表中的累进数字必须是唯一的(它是主键)。
JDBC Transactions(带有 TRANSACTION_READ_COMMITTED 隔离级别)是否避免了 T1 和 T2 读取相同的 PN 值并尝试在表中插入相同的 PN++ 的问题?在执行插入并调用 commit() 之前,表是否被锁定?
【问题讨论】:
【参考方案1】:不,为了确保您始终拥有唯一编号,您需要: 1) [更好] 根据 DB 将 DB 字段更改为身份/序列/自动编号 2) 使用 UUID 作为标识符 3) [worst] 在读/增量/写序列期间锁定行
TRANSACTION_READ_COMMITTED 只会确保您只能读取已提交到数据库的数据。 IE。如果您在
之间还有另外 200 个数据库操作UPDATE sequence
和
commit
在您提交之前,其他线程将无法读取您更新的数据,因此实际上它会做与您想要的完全相反的事情。
【讨论】:
问题是,在我的情况下,主键也是由其他两个字段(年和月)形成的,而不仅仅是由必须是唯一的累进数字,然后,在一个月内一年,然后从零开始再过一个月 那么恐怕在 READ、increment、UPDATE 期间锁定行可能是你唯一的方法。【参考方案2】:您还可以在应用程序级别进行同步。如果一个应用程序中只有一种方法在执行增量,这将起作用。
private **synchronized** void increment()
Calendar calendar = Calendar.getInstance();
int year = calendar.get(Calendar.YEAR);
int current = dao.getMaxNumber(year);
dao.insertNumber(year, current+1);
【讨论】:
如果您的代码在单个节点上运行以上是关于JDBC Transaction 如何在 TRANSACTION_READ_COMMITTED 隔离级别锁定表?的主要内容,如果未能解决你的问题,请参考以下文章
javax.transaction.Transactional 与 org.springframework.transaction.annotation.Transactional