Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/329.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java JPA LockModeType.悲观_WRITE无法按预期工作。应用程序不带密钥,在锁定时读取数据库快照_Java_Oracle_Hibernate_Jpa_Locking - Fatal编程技术网

Java JPA LockModeType.悲观_WRITE无法按预期工作。应用程序不带密钥,在锁定时读取数据库快照

Java JPA LockModeType.悲观_WRITE无法按预期工作。应用程序不带密钥,在锁定时读取数据库快照,java,oracle,hibernate,jpa,locking,Java,Oracle,Hibernate,Jpa,Locking,我有两个应用程序运行相同的代码,在hibernate的帮助下查询相同的Oracle数据库。 有一个表格用来存放要发送的电子邮件。 这两个应用程序都运行一个调度程序,在该表的一列中查询排队字符串,该字符串标记要发送的电子邮件、创建和发送电子邮件,并在最后更新、排队发送电子邮件,以便这些电子邮件不再发送。 理论上,我希望一个应用程序读取一些行,锁定它们的读写,更新它们,并解锁另一个应用程序使用。 因此,我使用以下查询: String jpql = "SELECT m FROM Email m WHE

我有两个应用程序运行相同的代码,在hibernate的帮助下查询相同的Oracle数据库。 有一个表格用来存放要发送的电子邮件。 这两个应用程序都运行一个调度程序,在该表的一列中查询排队字符串,该字符串标记要发送的电子邮件、创建和发送电子邮件,并在最后更新、排队发送电子邮件,以便这些电子邮件不再发送。 理论上,我希望一个应用程序读取一些行,锁定它们的读写,更新它们,并解锁另一个应用程序使用。 因此,我使用以下查询:

String jpql = "SELECT m FROM Email m WHERE m.status = :status";
return em.createQuery(jpql, Email.class)
        .setParameter("status", "QUEUED")
        .setLockMode(LockModeType.PESSIMISTIC_WRITE)
        .getResultList();  
这两个应用程序都使用,根据文档,LockModeType.悲观_WRITE相当于选择更新。 相反,会发生以下行为:

13:06:02,160 | MailQueueMonitor_1| Found 0 email(s) to be sent. // No rows returned from app1  

13:06:03,813 | MailQueueMonitor_2| Found 0 email(s) to be sent. // No rows returned from app2  

13:06:12,180 | MailQueueMonitor_1| Found 1 email(s) to be sent. // 1 mail returned from app1  

13:06:12,190 | MailQueueMonitor_1| Mailer will sleep for 30s    // App1 will sleep for 30s   

// At this point, app2 tries to execute query but freezes as app1 has the keys to the rows  

13:06:42,191 | MailQueueMonitor_1| Mailer woke up and will try to send mails    // App1 wakes up  

13:06:46,796 | MailQueueMonitor_1| Mailer sent mail     // App1 sent mail  

13:06:46,798 | MailQueueMonitor_1| Mailer changed mail status to SENT // App1 update status from QUEUED to SENT  

// At this point, app1 releases the locks and app2 unfreezes and executes query looking for QUEUED rows which should not exist at this point since they where updated to SENT.  

13:06:46,809 | MailQueueMonitor_2| Found 1 email(s) to be sent. // App2 queries and finds 1 row! It is like it queried a snapshot of the database before app2 updated all rows.  

13:06:46,836 | MailQueueMonitor_2| Mailer will sleep for 30s    // App2 will sleep for 30s  

13:07:16,836 | MailQueueMonitor_2| Mailer woke up and will try to send mails    // App2 wakes up  

13:07:21,457 | MailQueueMonitor_2| Mailer sent mails    // App2 sent mail. This is re-senting above email occuring to duplicate emails.  

13:07:21,458 | MailQueueMonitor_2| Mailer changed mail status SENT  // App2 update status from QUEUED to SENT, again!
问题是,为什么app2不读取更新的行,即使在锁释放后执行查询。 为什么app2尝试查询锁定行时不引发异常? 我应该如何锁定正在读取或更新的行,在锁定释放后,下一个查询数据库的应用程序将看到更新的数据

一些注意事项: 1.如果我在两个连续的行上运行两次查询,当锁被释放时,先前锁定的应用程序将执行第一个查询,其中一个被锁定的将返回未更新的数据,但第二个将按先前具有锁的应用程序返回更新的数据。 2.如果我通过两个ORACLE SQL DEVELOPER实例手动运行上述过程,则行为与预期一致,这意味着:

SQL_DEV_1: SELECT * FROM T_MAIL WHERE STATUS = 'QUEUED' FOR UPDATE; // Returns 1 row, locks the row
SQL_DEV_2: SELECT * FROM T_MAIL WHERE STATUS = 'QUEUED' FOR UPDATE; // Doesn't return anything but keeps waiting for locks to be released
SQL_DEV_1: UPDATE T_MAIL SET STATUS = 'SENT'; // Returns 1 row, locks the row
SQL_DEV_1: COMMIT; // Commit update, locks are released
SQL_DEV_2: // waiting query is executed, returns no rows since one and only row was update to SENT

我想我已经找到了解决办法。当您使用悲观写入时,第二台服务器不知道第一台服务器正在更改数据。换句话说,当使用LockModeType.悲观_读取时,他可以知道这一点,但在Oracle中,LockModeType.悲观_读取是使用LockModeType.悲观_写入实现的。因此,您的解决方案决定是将版本字段和设置模式添加到LockModeType。悲观的强制增量

在DB中设置了什么事务隔离级别?