上海建设银行官网网站首页,wordpress图片不加载,企业建网站方案,江油建设局网站介绍 Java Persistence API带有完善的并发控制机制#xff0c;支持隐式和显式锁定。 隐式锁定机制很简单#xff0c;它依赖于#xff1a; 乐观锁定#xff1a;实体状态更改可以触发版本增加 行级锁定#xff1a;基于当前运行的事务隔离级别 #xff0c;INSERT / UPDATE… 介绍 Java Persistence API带有完善的并发控制机制支持隐式和显式锁定。 隐式锁定机制很简单它依赖于 乐观锁定实体状态更改可以触发版本增加 行级锁定基于当前运行的事务隔离级别 INSERT / UPDATE / DELETE语句可能会获取排他行锁 虽然隐式锁定适用于许多情况但显式锁定机制可以利用更细粒度的并发控制。 在以前的文章中我介绍了显式的乐观锁定模式 乐观的 OPTIMISTIC_FORCE_INCREMENT PESSIMISTIC_FORCE_INCREMENT 在这篇文章中我将解开显式的悲观锁模式 PESSIMISTIC_READ PESSIMISTIC_WRITE 读写器锁 数据库系统是高度并发的环境因此许多并发理论习惯用法也适用于数据库访问。 必须将并发更改序列化以保留数据完整性因此即使通常通过Multiversion并发控制机制对其进行补充大多数数据库系统仍使用两阶段锁定策略。 因为互斥锁定会阻碍可伸缩性平等地处理读写所以大多数数据库系统都使用读写器锁定同步方案因此 共享读取锁会阻止作者从而允许多个读者继续 排他写入锁同时阻止读取器和写入器从而使所有写入操作都按顺序应用 因为锁定语法不是SQL标准的一部分所以每个RDBMS都选择了不同的语法 数据库名称 共享锁语句 排他锁声明 甲骨文 更新 更新 的MySQL 锁定共享模式 更新 Microsoft SQL服务器 带HOLDLOCKROWLOCK 带上锁上锁 PostgreSQL的 分享 更新 DB2 只供RS阅读 用于RS更新 Java持久性抽象层隐藏了特定于数据库的锁定语义提供了仅需要两个锁定模式的通用API。 使用PESSIMISTIC_READ锁定模式类型获取共享/读取锁定而使用PESSIMISTIC_WRITE请求排他/写入锁定。 PostgreSQL行级锁定模式 对于下一个测试用例我们将使用PostgreSQL因为它既支持独占锁定 也支持共享显式锁定 。 以下所有测试将使用相同的并发实用程序模拟两个用户Alice和Bob。 每个测试方案将验证特定的读/写锁定组合。 private void testPessimisticLocking(ProductLockRequestCallable primaryLockRequestCallable, ProductLockRequestCallable secondaryLockRequestCallable) {doInTransaction(session - {try {Product product (Product) session.get(Product.class, 1L);primaryLockRequestCallable.lock(session, product);executeAsync(() - {doInTransaction(_session - {Product _product (Product) _session.get(Product.class, 1L);secondaryLockRequestCallable.lock(_session, _product);});},endLatch::countDown);sleep(WAIT_MILLIS);} catch (StaleObjectStateException e) {LOGGER.info(Optimistic locking failure: , e);}});awaitOnLatch(endLatch);
}情况1PESSIMISTIC_READ不阻止PESSIMISTIC_READ锁定请求 第一个测试将检查两个并发的PESSIMISTIC_READ锁定请求如何交互 Test
public void testPessimisticReadDoesNotBlockPessimisticRead() throws InterruptedException {LOGGER.info(Test PESSIMISTIC_READ doesnt block PESSIMISTIC_READ);testPessimisticLocking((session, product) - {session.buildLockRequest(new LockOptions(LockMode.PESSIMISTIC_READ)).lock(product);LOGGER.info(PESSIMISTIC_READ acquired);},(session, product) - {session.buildLockRequest(new LockOptions(LockMode.PESSIMISTIC_READ)).lock(product);LOGGER.info(PESSIMISTIC_READ acquired);});
} 运行此测试我们得到以下输出 [Alice]: c.v.h.m.l.c.LockModePessimisticReadWriteIntegrationTest - Test PESSIMISTIC_READ doesnt block PESSIMISTIC_READ#Alice selects the Product entity
[Alice]: Time:1 Query:{[
SELECT lockmodepe0_.id AS id1_0_0_,lockmodepe0_.description AS descript2_0_0_,lockmodepe0_.price AS price3_0_0_,lockmodepe0_.version AS version4_0_0_
FROM product lockmodepe0_
WHERE lockmodepe0_.id ?
][1]} #Alice acquires a SHARED lock on the Product entity
[Alice]: Time:1 Query:{[
SELECT id
FROM product
WHERE id ?
AND version ? FOR share
][1,0]}
[Alice]: c.v.h.m.l.c.LockModePessimisticReadWriteIntegrationTest - PESSIMISTIC_READ acquired#Alice waits for 500ms
[Alice]: c.v.h.m.l.c.LockModePessimisticReadWriteIntegrationTest - Wait 500 ms!#Bob selects the Product entity
[Bob]: Time:1 Query:{[SELECT lockmodepe0_.id AS id1_0_0_,lockmodepe0_.description AS descript2_0_0_,lockmodepe0_.price AS price3_0_0_,lockmodepe0_.version AS version4_0_0_
FROM product lockmodepe0_
WHERE lockmodepe0_.id ?
][1]}#Bob acquires a SHARED lock on the Product entity
[Bob]: Time:1 Query:{[
SELECT id
FROM product
WHERE id ?
AND version ? FOR share
][1,0]}
[Bob]: c.v.h.m.l.c.LockModePessimisticReadWriteIntegrationTest - PESSIMISTIC_READ acquired#Bobs transactions is committed
[Bob]: o.h.e.t.i.j.JdbcTransaction - committed JDBC Connection#Alices transactions is committed
[Alice]: o.h.e.t.i.j.JdbcTransaction - committed JDBC Connection 在这种情况下没有任何争用。 爱丽丝和鲍勃都可以获取共享锁而不会遇到任何冲突。 情况2PESSIMISTIC_READ阻止UPDATE隐式锁定请求 第二种情况将演示共享锁如何防止并发修改。 爱丽丝将获得一个共享锁而鲍勃将尝试修改该锁定的实体 Test
public void testPessimisticReadBlocksUpdate() throws InterruptedException {LOGGER.info(Test PESSIMISTIC_READ blocks UPDATE);testPessimisticLocking((session, product) - {session.buildLockRequest(new LockOptions(LockMode.PESSIMISTIC_READ)).lock(product);LOGGER.info(PESSIMISTIC_READ acquired);},(session, product) - {product.setDescription(USB Flash Memory Stick);session.flush();LOGGER.info(Implicit lock acquired);});
} 测试生成以下输出 [Alice]: c.v.h.m.l.c.LockModePessimisticReadWriteIntegrationTest - Test PESSIMISTIC_READ blocks UPDATE#Alice selects the Product entity
[Alice]: Time:0 Query:{[
SELECT lockmodepe0_.id AS id1_0_0_,lockmodepe0_.description AS descript2_0_0_,lockmodepe0_.price AS price3_0_0_,lockmodepe0_.version AS version4_0_0_
FROM product lockmodepe0_
WHERE lockmodepe0_.id ?
][1]} #Alice acquires a SHARED lock on the Product entity
[Alice]: Time:0 Query:{[
SELECT id
FROM product
WHERE id ?
AND version ? FOR share
][1,0]}
[Alice]: c.v.h.m.l.c.LockModePessimisticReadWriteIntegrationTest - PESSIMISTIC_READ acquired#Alice waits for 500ms
[Alice]: c.v.h.m.l.c.LockModePessimisticReadWriteIntegrationTest - Wait 500 ms!#Bob selects the Product entity
[Bob]: Time:1 Query:{[
SELECT lockmodepe0_.id AS id1_0_0_,lockmodepe0_.description AS descript2_0_0_,lockmodepe0_.price AS price3_0_0_,lockmodepe0_.version AS version4_0_0_
FROM product lockmodepe0_
WHERE lockmodepe0_.id ?
][1]} #Alices transactions is committed
[Alice]: o.h.e.t.i.j.JdbcTransaction - committed JDBC Connection#Bob can acquire the Product entity lock, only after Alices transaction is committed
[Bob]: Time:427 Query:{[
UPDATE product
SET description ?,price ?,version ?
WHERE id ?AND version ?
][USB Flash Memory Stick,12.99,1,1,0]}
[Bob]: c.v.h.m.l.c.LockModePessimisticReadWriteIntegrationTest - Implicit lock acquired#Bobs transactions is committed
[Bob]: o.h.e.t.i.j.JdbcTransaction - committed JDBC Connection 尽管Bob可以选择Product实体但UPDATE会一直延迟到提交Alice事务为止这就是UPDATE花费427ms运行的原因。 情况3PESSIMISTIC_READ阻止PESSIMISTIC_WRITE锁定请求 辅助PESSIMISTIC_WRITE锁定请求也表现出相同的行为 Test
public void testPessimisticReadBlocksPessimisticWrite() throws InterruptedException {LOGGER.info(Test PESSIMISTIC_READ blocks PESSIMISTIC_WRITE);testPessimisticLocking((session, product) - {session.buildLockRequest(new LockOptions(LockMode.PESSIMISTIC_READ)).lock(product);LOGGER.info(PESSIMISTIC_READ acquired);},(session, product) - {session.buildLockRequest(new LockOptions(LockMode.PESSIMISTIC_WRITE)).lock(product);LOGGER.info(PESSIMISTIC_WRITE acquired);});
} 提供以下输出 [Alice]: c.v.h.m.l.c.LockModePessimisticReadWriteIntegrationTest - Test PESSIMISTIC_READ blocks PESSIMISTIC_WRITE#Alice selects the Product entity
[Alice]: Time:0 Query:{[
SELECT lockmodepe0_.id AS id1_0_0_,lockmodepe0_.description AS descript2_0_0_,lockmodepe0_.price AS price3_0_0_,lockmodepe0_.version AS version4_0_0_
FROM product lockmodepe0_
WHERE lockmodepe0_.id ?
][1]}#Alice acquires a SHARED lock on the Product entity
[Alice]: Time:1 Query:{[
SELECT id
FROM product
WHERE id ?
AND version ? FOR share
][1,0]}
[Alice]: c.v.h.m.l.c.LockModePessimisticReadWriteIntegrationTest - PESSIMISTIC_READ acquired#Alice waits for 500ms
[Alice]: c.v.h.m.l.c.LockModePessimisticReadWriteIntegrationTest - Wait 500 ms!#Bob selects the Product entity
[Bob]: Time:1 Query:{[
SELECT lockmodepe0_.id AS id1_0_0_,lockmodepe0_.description AS descript2_0_0_,lockmodepe0_.price AS price3_0_0_,lockmodepe0_.version AS version4_0_0_
FROM product lockmodepe0_
WHERE lockmodepe0_.id ?
][1]} #Alices transactions is committed
[Alice]: o.h.e.t.i.j.JdbcTransaction - committed JDBC Connection#Bob can acquire the Product entity lock, only after Alices transaction is committed
[Bob]: Time:428 Query:{[
SELECT id
FROM product
WHERE id ?AND version ?
FOR UPDATE
][1,0]}
[Bob]: c.v.h.m.l.c.LockModePessimisticReadWriteIntegrationTest - PESSIMISTIC_WRITE acquired#Bobs transactions is committed
[Bob]: o.h.e.t.i.j.JdbcTransaction - committed JDBC Connection Bob的排他锁请求等待Alice的共享锁被释放。 情况4PESSIMISTIC_READ阻止PESSIMISTIC_WRITE锁定请求NO WAIT快速失败 Hibernate提供了一个PESSIMISTIC_NO_WAIT超时指令该指令转换为特定于数据库的NO_WAIT锁获取策略。 PostgreSQL NO WAIT指令描述如下 为防止该操作等待其他事务提交请使用NOWAIT选项。 使用NOWAIT如果无法立即锁定选定的行该语句将报告错误而不是等待。 注意NOWAIT仅适用于行级锁-所需的ROW SHARE表级锁仍以常规方式获取请参见第13章。 如果需要不等待就获取表级锁则可以先将LOCK与NOWAIT选项一起使用。 Test
public void testPessimisticReadWithPessimisticWriteNoWait() throws InterruptedException {LOGGER.info(Test PESSIMISTIC_READ blocks PESSIMISTIC_WRITE, NO WAIT fails fast);testPessimisticLocking((session, product) - {session.buildLockRequest(new LockOptions(LockMode.PESSIMISTIC_READ)).lock(product);LOGGER.info(PESSIMISTIC_READ acquired);},(session, product) - {session.buildLockRequest(new LockOptions(LockMode.PESSIMISTIC_WRITE)).setTimeOut(Session.LockRequest.PESSIMISTIC_NO_WAIT).lock(product);LOGGER.info(PESSIMISTIC_WRITE acquired);});
} 该测试生成以下输出 [Alice]: c.v.h.m.l.c.LockModePessimisticReadWriteIntegrationTest - Test PESSIMISTIC_READ blocks PESSIMISTIC_WRITE, NO WAIT fails fast#Alice selects the Product entity
[Alice]: Time:1 Query:{[
SELECT lockmodepe0_.id AS id1_0_0_,lockmodepe0_.description AS descript2_0_0_,lockmodepe0_.price AS price3_0_0_,lockmodepe0_.version AS version4_0_0_
FROM product lockmodepe0_
WHERE lockmodepe0_.id ?
][1]}#Alice acquires a SHARED lock on the Product entity
[Alice]: Time:1 Query:{[
SELECT id
FROM product
WHERE id ?
AND version ? FOR share
][1,0]}
[Alice]: c.v.h.m.l.c.LockModePessimisticReadWriteIntegrationTest - PESSIMISTIC_READ acquired#Alice waits for 500ms
[Alice]: c.v.h.m.l.c.LockModePessimisticReadWriteIntegrationTest - Wait 500 ms!#Bob selects the Product entity
[Bob]: Time:1 Query:{[
SELECT lockmodepe0_.id AS id1_0_0_,lockmodepe0_.description AS descript2_0_0_,lockmodepe0_.price AS price3_0_0_,lockmodepe0_.version AS version4_0_0_
FROM product lockmodepe0_
WHERE lockmodepe0_.id ?
][1]}#Bob tries to acquire an EXCLUSIVE lock on the Product entity and fails because of the NO WAIT policy
[Bob]: Time:0 Query:{[
SELECT id
FROM product
WHERE id ?AND version ?
FOR UPDATE nowait
][1,0]}
[Bob]: o.h.e.j.s.SqlExceptionHelper - SQL Error: 0, SQLState: 55P03
[Bob]: o.h.e.j.s.SqlExceptionHelper - ERROR: could not obtain lock on row in relation product#Bobs transactions is rolled back
[Bob]: o.h.e.t.i.j.JdbcTransaction - rolled JDBC Connection#Alices transactions is committed
[Alice]: o.h.e.t.i.j.JdbcTransaction - committed JDBC Connection 由于Alice已经在与产品实体相关联的数据库行上持有共享锁因此Bob的排他锁请求立即失败。 情况5PESSIMISTIC_WRITE阻止PESSIMISTIC_READ锁定请求 下一个测试证明排他锁将始终阻止共享锁获取尝试 Test
public void testPessimisticWriteBlocksPessimisticRead() throws InterruptedException {LOGGER.info(Test PESSIMISTIC_WRITE blocks PESSIMISTIC_READ);testPessimisticLocking((session, product) - {session.buildLockRequest(new LockOptions(LockMode.PESSIMISTIC_WRITE)).lock(product);LOGGER.info(PESSIMISTIC_WRITE acquired);},(session, product) - {session.buildLockRequest(new LockOptions(LockMode.PESSIMISTIC_READ)).lock(product);LOGGER.info(PESSIMISTIC_WRITE acquired);});
} 生成以下输出 [Alice]: c.v.h.m.l.c.LockModePessimisticReadWriteIntegrationTest - Test PESSIMISTIC_WRITE blocks PESSIMISTIC_READ#Alice selects the Product entity
[Alice]: Time:1 Query:{[
SELECT lockmodepe0_.id AS id1_0_0_,lockmodepe0_.description AS descript2_0_0_,lockmodepe0_.price AS price3_0_0_,lockmodepe0_.version AS version4_0_0_
FROM product lockmodepe0_
WHERE lockmodepe0_.id ?
][1]} #Alice acquires an EXCLUSIVE lock on the Product entity
[Alice]: Time:0 Query:{[
SELECT id
FROM product
WHERE id ?AND version ?
FOR UPDATE
][1,0]}
[Alice]: c.v.h.m.l.c.LockModePessimisticReadWriteIntegrationTest - PESSIMISTIC_WRITE acquired#Alice waits for 500ms
[Alice]: c.v.h.m.l.c.LockModePessimisticReadWriteIntegrationTest - Wait 500 ms!#Bob selects the Product entity
[Bob]: Time:1 Query:{[
SELECT lockmodepe0_.id AS id1_0_0_,lockmodepe0_.description AS descript2_0_0_,lockmodepe0_.price AS price3_0_0_,lockmodepe0_.version AS version4_0_0_
FROM product lockmodepe0_
WHERE lockmodepe0_.id ?
][1]}#Alices transactions is committed
[Alice]: o.h.e.t.i.j.JdbcTransaction - committed JDBC Connection#Bob can acquire the Product entity SHARED lock, only after Alices transaction is committed
[Bob]: Time:428 Query:{[
SELECT id
FROM product
WHERE id ?
AND version ? FOR share
][1,0]}
[Bob]: c.v.h.m.l.c.LockModePessimisticReadWriteIntegrationTest - PESSIMISTIC_WRITE acquired#Bobs transactions is committed
[Bob]: o.h.e.t.i.j.JdbcTransaction - committed JDBC Connection Bob的共享锁请求等待Alice的事务结束以便释放所有获得的锁。 情况6PESSIMISTIC_WRITE阻止PESSIMISTIC_WRITE锁定请求 排他锁也阻止排他锁 Test
public void testPessimisticWriteBlocksPessimisticWrite() throws InterruptedException {LOGGER.info(Test PESSIMISTIC_WRITE blocks PESSIMISTIC_WRITE);testPessimisticLocking((session, product) - {session.buildLockRequest(new LockOptions(LockMode.PESSIMISTIC_WRITE)).lock(product);LOGGER.info(PESSIMISTIC_WRITE acquired);},(session, product) - {session.buildLockRequest(new LockOptions(LockMode.PESSIMISTIC_WRITE)).lock(product);LOGGER.info(PESSIMISTIC_WRITE acquired);});
} 测试生成以下输出 [Alice]: c.v.h.m.l.c.LockModePessimisticReadWriteIntegrationTest - Test PESSIMISTIC_WRITE blocks PESSIMISTIC_WRITE#Alice selects the Product entity
[Alice]: Time:1 Query:{[
SELECT lockmodepe0_.id AS id1_0_0_,lockmodepe0_.description AS descript2_0_0_,lockmodepe0_.price AS price3_0_0_,lockmodepe0_.version AS version4_0_0_
FROM product lockmodepe0_
WHERE lockmodepe0_.id ?
][1]} #Alice acquires an EXCLUSIVE lock on the Product entity
[Alice]: Time:0 Query:{[
SELECT id
FROM product
WHERE id ?AND version ?
FOR UPDATE
][1,0]}
[Alice]: c.v.h.m.l.c.LockModePessimisticReadWriteIntegrationTest - PESSIMISTIC_WRITE acquired#Alice waits for 500ms
[Alice]: c.v.h.m.l.c.LockModePessimisticReadWriteIntegrationTest - Wait 500 ms!#Bob selects the Product entity
[Bob]: Time:1 Query:{[
SELECT lockmodepe0_.id AS id1_0_0_,lockmodepe0_.description AS descript2_0_0_,lockmodepe0_.price AS price3_0_0_,lockmodepe0_.version AS version4_0_0_
FROM product lockmodepe0_
WHERE lockmodepe0_.id ?
][1]}#Alices transactions is committed
[Alice]: o.h.e.t.i.j.JdbcTransaction - committed JDBC Connection#Bob can acquire the Product entity SHARED lock, only after Alices transaction is committed
[Bob]: Time:428 Query:{[
SELECT id
FROM product
WHERE id ?
AND version ? FOR update
][1,0]}
[Bob]: c.v.h.m.l.c.LockModePessimisticReadWriteIntegrationTest - PESSIMISTIC_WRITE acquired#Bobs transactions is committed
[Bob]: o.h.e.t.i.j.JdbcTransaction - committed JDBC Connection Bob的排他锁请求必须等待Alice释放其锁。 结论 关系数据库系统使用锁来保留ACID保证 因此了解共享和独占行级锁如何互操作非常重要。 显式悲观锁是一种非常强大的数据库并发控制机制您甚至可以使用它来修复乐观锁竞争条件 。 代码可在GitHub上获得 。 翻译自: https://www.javacodegeeks.com/2015/02/hibernate-locking-patterns-how-does-pessimistic_read-and-pessimistic_write-work.html