我有两个运行相同代码的应用程序,在hibernate的帮助下查询同一个Oracle数据库
有一个表可以保存要发送的电子邮件
这两个应用程序都运行一个调度程序,用于查询此表中的列以查找" QUEUED" string(标记要发送的电子邮件),创建和发送电子邮件,最后更新," 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
答案 0 :(得分:1)
我认为我找到了解决方案(或解决方法)。当您使用PESSIMISTIC_WRITE
时,第二个服务器不知道第一个服务器正在更改数据。在使用LockModeType.PESSIMISTIC_READ
时,他可以了解这一点,但在LockModeType.PESSIMISTIC_READ
中使用LockModeType.PESSIMISTIC_WRITE
实现了version
。因此,针对您的解决方法是将LockModeType.PESSIMISTIC_FORCE_INCREMENT
字段和设置模式添加到library(ggplot2)
dat = data.frame(x=c(0,100), ymin=0, y=c(100,0), ymax=100)
ggplot(dat) +
geom_ribbon(aes(x, ymin=y, ymax=ymax), fill="blue") +
geom_ribbon(aes(x, ymin=ymin, ymax=y), fill="red") +
geom_abline(aes(intercept=100, slope=-1)) +
#geom_line(aes(x,y), lwd=1) + # If you just want a line with the same extent as the data
theme_bw()