【发布时间】:2021-02-19 06:30:49
【问题描述】:
问题
有一个 Quartz 作业,我将其称为 Job-A,它以固定间隔运行。在每个时间间隔,作业都在执行一些数据库更新的线程中运行。但是,下一次立即运行看不到上一次运行所做的更新。流程是这样的:
-
Job-A运行。主题:thread-1。- 选择要处理的实体。
- 在当前会话中提交连接,以使自上次提交/回滚以来所做的所有更改永久化,并释放当前持有的所有数据库锁。
- 将实体(此处称为
Entity-A)标记为processed。目标是只处理此实体一次。 - 更新并提交事务。
- 刷新实体,使更改在后续操作中可见。
-
Job-A再次运行。主题:thread-2。- 选择要处理的实体。
-
预期:
Thread-2将Entity-A视为processed并跳过它。 -
实际:
Thread-2确实不看到Entity-A的processed状态并且再次选择它。 为什么?
-
预期:
- 其余步骤相同。
- 选择要处理的实体。
技术栈
- 休眠 3.6.6
- 会话上下文是
ThreadLocal
- 会话上下文是
- MySQL 5.7.3
- 石英 2.3.2
-
Job-A带有@DisallowConcurrentExecution注释,因此多个 Job-A 实例永远不会同时运行。 -
Job-A以秒为单位的固定间隔运行。
-
问题
- 我怀疑存在竞态条件,但竞态条件是否与此问题相关?如果是这样,我该如何缩小罪魁祸首?
- 其他可能的原因是什么?我该如何追踪?
【问题讨论】:
-
如何获取当前会话? IIRC,休眠可以重用来自 ThreadLocal 存储的相同会话。但如果你想看到新的数据,你必须开始一个新的会话,我想。
-
@GreyFairer,我通过
SessionFactory的getCurrentSession()方法获取当前会话。在获得一个新的会话实例(如果没有重用)后,我开始一个事务。是的,Hibernate 可以从 ThreadLocal 重用相同的会话,因为打开和关闭会话的开销很大。 -
打开/关闭会话并不昂贵,理想情况下应该为每个事务完成。
标签: java mysql multithreading hibernate quartz