Oracle을 사용한 비관적인 JPA 잠금이 작동하지 않는 이유
저는 다른 JBoss 노드에서 실행되는 cron 작업에 대해 일종의 세마포어를 구현하려고 합니다.데이터베이스(Oracle 11g)를 잠금 메커니즘으로 사용하여 테이블 하나를 사용하여 다른 노드의 cron 작업을 동기화하려고 합니다.표는 매우 간단합니다.
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);
따라서 작업이 시작되면 테이블에서 해당 cronjob 유형의 항목을 검색하고 이미 실행 중인지 확인합니다.그렇지 않으면 항목 설정 실행 플래그가 true로 업데이트됩니다.이 첫 번째 선택은 최대 절전 모드 및 비관적 잠금을 사용하여 JPA 기준 API로 이루어집니다.
query.setLockMode(javax.persistence.LockModeType.PESSIMISTIC_WRITE);
이러한 모든 작업은 한 번의 트랜잭션 내에서 이루어집니다.
한 프로세스가 실행될 때 프로세스가 수행하는 쿼리는 다음과 같습니다.
[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=?
이 경고에는 문제가 없습니다. 먼저 선택한 후 업데이트할 선택 항목을 볼 수 있으므로 Oracle은 이 행에서 다른 선택 작업을 차단해야 합니다.그러나 중요한 것은 두 개의 작업이 입력되어 문제 없이 선택 및 업데이트를 수행할 수 있도록 쿼리가 차단되지 않는다는 점입니다.잠금이 작동하지 않습니다. 두 개의 cron 작업을 동시에 실행하면 확인할 수 있습니다.
[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)에서 업데이트를 위해 이 선택을 시도했는데 이 도구에서 차단이 잘 작동합니다.그러나 SQL 도구에서 업데이트를 위해 이 옵션을 선택하고 cron 작업을 시작하면 차단되지 않고 문제 없이 실행됩니다.
JPA, Hibernate 또는 Oracle 드라이버에서 문제가 발생한 것 같습니다.어디에 문제가 있는지 아십니까?다른 전략을 사용해야 합니까?잘 부탁드립니다.
마침내 저는 그것을 작동시킬 수 있었지만 약간의 수정이 있었습니다.이 개념은 LockModeType을 사용하는 것입니다.SYPECTIC_WRITE 대신 SYPECTIC_FORCE_INCREMENT.이 잠금 모드를 사용하면 Cron 작업은 다음과 같이 동작합니다.
- 첫 번째 작업에서 업데이트를 선택하면 모든 작업이 예상대로 진행되지만 개체의 버전은 변경됩니다.
- 첫 번째 작업이 트랜잭션 중인 상태에서 다른 작업이 동일한 항목을 선택하려고 하면 JPA가 OptimisticLockException을 실행하므로 해당 예외가 발견되면 읽기 잠금을 위해 던져졌는지 확인할 수 있습니다.
이 솔루션에는 다음과 같은 다양한 솔루션이 있습니다.
- SynchronizedCronJobTask에는 버전 필드가 있어야 하며 @Version으로 버전을 제어해야 합니다.
- OptimisticLockException을 처리해야 하며 잠금이 발생할 때 롤백을 수행하려면 트랜잭션 서비스 메서드 외부에서 이를 탐지해야 합니다.
- IMHO는 Cron Jobs가 이전 Jobs가 완료되기를 기다리는 단순한 잠금보다 훨씬 더 나쁜 고급 솔루션입니다.
리카르도스의 관찰을 확인할 수 있습니다.저는 H2-Database로 여러 개의 잠금 모드를 테스트했고 모두 예상대로 작동했습니다.비관적인 잠금 모드 중 어느 것도 Oracle 데이터베이스와 함께 올바르게 작동하지 않았습니다.낙관적인 잠금은 시도하지 않았는데, 탑독과 전혀 연동되지 않는 잠금 모드가 있다는 것이 놀랍습니다.
데이터를 변경하기 전에 두 번째 서버가 첫 번째 서버의 변경사항을 알고 있어야 하므로 잠금 모드를 SEPMISTIC_READ로 설정합니다.
언급URL : https://stackoverflow.com/questions/29963687/why-my-pessimistic-locking-in-jpa-with-oracle-is-not-working
'sourcecode' 카테고리의 다른 글
리소스 및 컨트롤러 링크 작성기를 찾을 수 없으며 더 이상 사용되지 않습니다. (0) | 2023.07.23 |
---|---|
SpEL @ConditionalOnProperty 문자열 속성이 비어 있거나 null입니다. (0) | 2023.07.23 |
MySQL에서 이미지를 저장하는 데 사용할 데이터 유형은 무엇입니까? (0) | 2023.07.23 |
MySQL에서 GROUP_CONCAT에서 1024자 이상을 되돌릴 수 있습니까? (0) | 2023.07.23 |
C: 구조물에 대한 포인터 배열에 대한 포인터(할당/할당 취소 문제) (0) | 2023.07.23 |