首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么我在JPA中使用Oracle的悲观锁不起作用?

为什么我在JPA中使用Oracle的悲观锁不起作用?
EN

Stack Overflow用户
提问于 2015-04-30 09:15:06
回答 3查看 9.2K关注 0票数 12

我试图为运行在不同JBoss节点上的cron作业实现某种类型的信号量。我试图使用数据库(Oracle 11g)作为一种锁定机制,使用一个表来同步不同节点中的cron作业。这张桌子很简单:

代码语言:javascript
复制
CREATE TABLE SYNCHRONIZED_CRON_JOB_TASK
(
   ID            NUMBER(10)           NOT NULL,
   CRONJOBTYPE   VARCHAR2(255 Byte),
   CREATIONDATE  TIMESTAMP(6)         NOT NULL,
   RUNNING       NUMBER(1)
);

ALTER TABLE SYNCHRONIZED_CRON_JOB_TASK
   ADD CONSTRAINT PK_SYNCHRONIZED_CRON_JOB_TASK
   PRIMARY KEY (ID); 

因此,当作业启动时,它会在表中搜索其checks类型的条目,并检查它是否已在运行。如果没有,则将entry设置运行标志更新为true。第一个选择是使用JPA CriteriaApi进行的,使用Hibernate和悲观锁。

代码语言:javascript
复制
query.setLockMode(javax.persistence.LockModeType.PESSIMISTIC_WRITE);

所有这些交易都是在一笔交易中完成的。

当一个进程运行时,它所做的查询如下:

代码语言:javascript
复制
[Server:server-two] 10:38:00,049 INFO  [stdout] (scheduler-2) 2015-04-30 10:38:00,048 WARN  (Loader.java:264) - HHH000444: Encountered request for locking however dialect reports that database prefers locking be done in a separate select (follow-on locking); results will be locked after initial query executes
[Server:server-two] 10:38:00,049 INFO  [stdout] (scheduler-2) Hibernate: select * from ( select distinct synchroniz0_.id as id1_127_, synchroniz0_.creationDate as creation2_127_, synchroniz0_.running as running3_127_, synchroniz0_.CRONJOBTYPE as CRONJOBT4_127_ from SYNCHRONIZED_CRON_JOB_TASK synchroniz0_ where synchroniz0_.CRONJOBTYPE=? ) where rownum <= ?
[Server:server-two] 10:38:00,053 INFO  [stdout] (scheduler-2) Hibernate: select id from SYNCHRONIZED_CRON_JOB_TASK where id =? for update
[Server:server-two] 10:38:00,056 INFO  [stdout] (scheduler-2) Hibernate: update SYNCHRONIZED_CRON_JOB_TASK set creationDate=?, running=?, CRONJOBTYPE=? where id=?

此警告没有问题,您可以看到第一个select,然后看到更新的select,因此Oracle应该阻止该行上的其他select操作。但关键是,查询不会被阻塞,因此两个作业可以进入并使select和update没有问题。锁不能工作,如果同时运行两个cron作业,我们可以看到:

代码语言:javascript
复制
[Server:server-one] 10:38:00,008 INFO  [stdout] (scheduler-3) 2015-04-30 10:38:00,008 WARN  (Loader.java:264) - HHH000444: Encountered request for locking however dialect reports that database prefers locking be done in a separate select (follow-on locking); results will be locked after initial query executes
[Server:server-two] 10:38:00,008 INFO  [stdout] (scheduler-2) 2015-04-30 10:38:00,008 WARN  (Loader.java:264) - HHH000444: Encountered request for locking however dialect reports that database prefers locking be done in a separate select (follow-on locking); results will be locked after initial query executes
[Server:server-two] 10:38:00,009 INFO  [stdout] (scheduler-2) Hibernate: select * from ( select distinct synchroniz0_.id as id1_127_, synchroniz0_.creationDate as creation2_127_, synchroniz0_.running as running3_127_, synchroniz0_.CRONJOBTYPE as CRONJOBT4_127_ from SYNCHRONIZED_CRON_JOB_TASK synchroniz0_ where synchroniz0_.CRONJOBTYPE=? ) where rownum <= ?
[Server:server-one] 10:38:00,009 INFO  [stdout] (scheduler-3) Hibernate: select * from ( select distinct synchroniz0_.id as id1_127_, synchroniz0_.creationDate as creation2_127_, synchroniz0_.running as running3_127_, synchroniz0_.CRONJOBTYPE as CRONJOBT4_127_ from SYNCHRONIZED_CRON_JOB_TASK synchroniz0_ where synchroniz0_.CRONJOBTYPE=? ) where rownum <= ?
[Server:server-two] 10:38:00,013 INFO  [stdout] (scheduler-2) Hibernate: select id from SYNCHRONIZED_CRON_JOB_TASK where id =? for update
[Server:server-one] 10:38:00,014 INFO  [stdout] (scheduler-3) Hibernate: select id from SYNCHRONIZED_CRON_JOB_TASK where id =? for update
[Server:server-two] 10:38:00,016 INFO  [stdout] (scheduler-2) 2015-04-30 10:38:00,015 DEBUG (SynchronizedCronJobService.java:65) - Task read SynchronizedCronJobTask [id=185, type=AlertMailTaskExecutor, creationDate=2015-04-25 07:11:33.0, running=false]
[Server:server-two] 10:38:00,018 INFO  [stdout] (scheduler-2) Hibernate: update SYNCHRONIZED_CRON_JOB_TASK set creationDate=?, running=?, CRONJOBTYPE=? where id=?
[Server:server-one] 10:38:00,022 INFO  [stdout] (scheduler-3) 2015-04-30 10:38:00,022 DEBUG (SynchronizedCronJobService.java:65) - Task read SynchronizedCronJobTask [id=185, type=AlertMailTaskExecutor, creationDate=2015-04-25 07:11:33.0, running=false]
[Server:server-one] 10:38:00,024 INFO  [stdout] (scheduler-3) Hibernate: update SYNCHRONIZED_CRON_JOB_TASK set creationDate=?, running=?, CRONJOBTYPE=? where id=?

我尝试在一个具有两个连接的SQL (SQLWorkbenchJ)上选择这个更新,并且这个工具中的bloking运行得很好。但是,如果我选择在SQL工具上进行更新并启动cron作业,它们就不会正常运行。

我认为问题来自JPA、Hibernate或Oracle驱动程序,但我不确定。知道问题在哪里吗?我应该使用安泰尔策略吗?提前谢谢。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-04-30 14:13:48

最后,我设法使它发挥作用,但也有一些不同之处。其想法是使用LockModeType.PESSIMISTIC_FORCE_INCREMENT而不是PESSIMISTIC_WRITE。使用此锁定模式,Cron作业的行为如下:

  1. 当第一个作业进行select for update时,一切按预期进行,但对象上的版本会发生变化。
  2. 如果另一个作业在第一个作业仍在其事务上时尝试进行相同的选择,JPA将启动一个OptimisticLockException,因此如果捕捉到该异常,则可以确保它是为读取锁抛出的。

这一解决方案有各种对应方:

  1. SynchronizedCronJobTask必须有一个版本字段,并且使用@Version进行版本控制。
  2. 您需要处理OptimisticLockException,并且应该在事务服务方法之外捕获它,以便在发生de时进行回滚。
  3. IMHO是一种非典雅的解决方案,比简单的Cron等待前一个乔布斯完成的锁差得多。
票数 4
EN

Stack Overflow用户

发布于 2018-07-31 16:31:50

我可以证实Ricardos的观察。我有几个锁模式测试与H2-数据库,所有的工作与预期。悲观锁模式与Oracle数据库的组合都不能正常工作。我没有尝试乐观的锁定,但令人惊讶的是,有一个锁模式,不工作的顶级狗在所有。

票数 1
EN

Stack Overflow用户

发布于 2015-04-30 10:11:42

将锁定模式设置为PESSIMISTIC_READ,因为您需要第二台服务器在更改数据之前了解第一台服务器的更改。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29963687

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档