我試圖爲在不同的JBoss節點中運行的cron作業實現某種信號量。我試圖使用數據庫(Oracle 11g)作爲鎖定機制,使用一個表來同步不同節點中的cron作業。 表是非常簡單的:爲什麼我的悲觀鎖定JPA與Oracle不起作用
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);
因此,當一個作業開始它在表上搜索其cronjobtype的進入,並檢查它是否已經在運行。如果不是,則將條目設置運行標誌更新爲true。第一個選擇是使用Hibernate和Pessimistic Lock使用JPA CriteriaApi進行的。
query.setLockMode(javax.persistence.LockModeType.PESSIMISTIC_WRITE);
所有這些操作都是在一個事務中完成的。
當一個進程中運行,它使querys如下:
[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)帶兩個連接更新和bloking工作在這個工具內罰款。但是,如果我選擇SQL工具上的更新並啓動cron作業,則它們不會混亂並且沒有問題地運行。
我認爲問題來自JPA,Hibernate或Oracle驅動程序,但我不確定。任何想法在哪裏是問題?我應該使用anotehr策略嗎? 在此先感謝。
你會在JBOSS內部實現「主動」嗎?在你將連接返回到連接池的時候,JBOSS會對它發出ROLLBACK,並且所有的鎖都會丟失。您的cron-jobs也必須使用SELECT FOR UPDATE,純粹的閱讀在Oracle中永遠不會被阻止。 – ibre5041
我不確定你的主動等待是什麼意思,我不使用任何JBOSS特殊功能。我希望等待的功能是在數據庫選擇操作上完成的。 –
我認爲這不是關於悲觀鎖定,而是關於一般交易。只要事務處於打開狀態並且連接保留在線程中,即使是純粹的單個UPDATE也可以工作。在JPA中,當代碼離開事務邊界回滾並且所有鎖都丟失時。 – ibre5041