gpt4 book ai didi

java - JPA LockModeType.PESSIMISTIC_WRITE 无法按预期工作。没有 key 的应用程序,在锁定时读取数据库快照

转载 作者:行者123 更新时间:2023-11-30 07:23:44 26 4
gpt4 key购买 nike

我有两个应用程序运行相同的代码,在 hibernate 的帮助下查询相同的 Oracle 数据库。
有一个表保存要发送的电子邮件。
这两个应用程序都运行一个调度程序,该调度程序会查询此表上的列以查找“QUEUED”字符串(标记要发送的电子邮件),创建并发送电子邮件,最后将“QUEUED”更新为“SENT”,这样这些电子邮件就不会发送再次发送。
理论上,我希望一个应用程序读取一些行,锁定它们以防止读取和写入,更新它们并解锁以供其他应用程序使用。
因此,我使用以下查询:

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.PESSIMISTIC_WRITE 相当于“SELECT FOR UPDATE”。
相反,会发生以下行为:

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

最佳答案

我想我已经找到了解决方案(或解决方法)。当您使用PESSIMISTIC_WRITE时,第二个服务器不知道第一个服务器正在更改数据。有趣的是,当使用 LockModeType.PESSIMISTIC_READ 时,他可以知道这一点,但在 Oracle 中,LockModeType.PESSIMISTIC_READ 是使用 LockModeType.PESSIMISTIC_WRITE 实现的。因此,您的解决方法是将 version 字段和设置模式添加到 LockModeType.PESSIMITIC_FORCE_INCRMENT

关于java - JPA LockModeType.PESSIMISTIC_WRITE 无法按预期工作。没有 key 的应用程序,在锁定时读取数据库快照,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37119874/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com