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 隔离级别锁定表?的主要内容,如果未能解决你的问题,请参考以下文章

给出一个jdbc的transaction例子?

javax.transaction.Transactional 与 org.springframework.transaction.annotation.Transactional

JDBC - Transaction

spring+jdbc+template+transaction实现

jdbc-transaction

JDBC中Transaction的实现