JDBC悲观锁与乐观锁基础教程
通过本教程学习JDBC基础知识以及乐观锁与悲观锁机制,在上篇数据库事务与死锁中,我们通过并发模拟两个用户插入相同键值的记录发生死锁的场景,数据库的锁使用分为悲观锁与乐观锁。
悲观锁
当我们使用悲观锁更新或删除一行数据表记录时,数据库会锁住整个一行,排他性地用于读操作和谐操作,这能够确保这一行记录不会同时被其它用户锁住。
下面是悲观锁实现代码:
import org.h2.jdbc.JdbcSQLException; import java.sql.Connection; import static org.junit.Assert.fail;
/** @Before @Test(expected = JdbcSQLException.class) try (Connection connectionFromJackBauer = getConnection()) { // 然后 habib表示试图更新这行记录,但是不成功,泡Exception
// simply what we did in OpenConnectionExerciseJava6/7.java private void createTables(Connection conn) { } |
Jack插入记录后,再修改它,他使用了"select..for update" SQL语句来排他性锁住了整个记录,直到他提交了语句也就是释放了这段事务的锁,其他用户才能读取这行曾经被锁住过的记录。在锁住期间,任何其他用户读取都无法成功,抛出Exception错误,这就是悲观锁。
乐观锁
乐观锁这样定义,假设有很少概率出现同时两个用户更新同样的记录,在这种情况下如果万一发生,提供一种健壮的检测方式。你可加入一个额外的列如版本号 "version"到数据表结构中,每次update-sql 语句执行时,附加条件"and where version = X" 限制. 此外,每次你更新一行记录,你需要逐个增加版本号,以表明这行记录已经更新了。
这里有一小技巧:JDBC驱动包会在你使用update语句时返回你真正进行update了多少行,但是如果有其他人在我之前更新了同样的记录呢?看看代码:
import org.junit.Before; import java.sql.Connection;
/**
@Before
@Test(expected = OptimisticLockingException.class) // 上面刚刚插入了错误的release_date. 让我们快速在更新一下 // 同时, habib marwin试图设置release_date为今天+10,但是他试图使用版本为0 // self made. check out the one from hibernate or spring private void createTables(Connection conn) { |
运行结果如下:
Jack更新成功了一条记录,而 Habib Marwan使用错误的版本后进行了更新,因此无法成功。
下一页讨论 JDBC隔离级别基础教程
Hibernate专题