eclipselink 更新语句中缺少字段
Missing field in update statement in eclipselink
我正在使用 payare 5.201,它使用 eclipselink 2.7。
我正在使用 EJB(无状态 bean)来处理我的事务。
有一个 class A 和方法 X,它从数据库中检索实体 E 并在 class B 上调用方法 Y 并将 E 作为参数传递。
方法 X 是 @ASynchronous,这意味着它将 运行 在单独的线程中。
所以线程 T1 中的方法 A.X 运行s 和 T2 中的 B.Y。
当 A.X 调用 B.Y 时 A.X 不必等待,因为 B.Y returns 是异步的。
就在 A.Z 调用 B.Y 之前,它将 E 中的值 F 设置为 true。这表明 B.Y 是 运行ning。
A.X 正在通过 E,这看起来很奇怪。这样做是为了确保 B.Y 获得正确的对象。
如果我愿意,例如传递 E 的 id 并在 B.Y 中查询它然后我可以获得竞争条件,因为当 E 在 T1 中提交时无法保证所以 B.Y 可以获得 E.F 的旧值。
当B.Y收到E时,它是同一个对象,但它没有注册到B中的(其他)实体管理器。当B.Y准备好时,E被合并到实体管理器中有效更新对 E.
所做的任何更改
当 B.Y 准备就绪时,E.F 设置为 false 以指示其完成。
当 B.Y 退出时,EJB 接管并将 E 中的值更新到数据库中。
我现在看到的问题是 E.F 没有更新。在 sql 日志中,我看到记录已更新,但字段 F 不在更新语句中。这意味着 eclipselink 看不到该字段的任何更改。有趣的是,这种情况并不总是发生。
在调查了 Eclipse 之后,我读到了有关更改跟踪的信息,它可以在启用编织时使用。这可以例如通过在实体上使用@ChangeTracking(ChangeTrackingType.ATTRIBUTE) 来激活。
我正在使用 Payara,默认情况下启用编织,我没有任何@ChangeTracking 注释,这意味着 eclipselink 将根据某些规则在 运行 时间选择这些注释。
当我设置
@ChangeTracking(ChangeTrackingType.ATTRIBUTE)
在 E 实体上,问题消失,E.F 已更新。
实体E与eager fetchtype有一定关系。当我将这些关系的 fetchtype 设置为 LAZY 时,它也再次起作用。
我的结论是,问题的发生是因为eclipse 给实体E 分配了一个ChangeTrackingType 而不是ATTRIBUTE。我假设这是因为我有急切的获取类型。
问题:
- 为什么这个问题只是偶尔出现?
- 我希望 ChangeTrackingType 被确定一次`?
- 我如何运行计时'ask' ChangeTrackingType 用于table 的系统。
- 所以我可以验证不同的 ChangeTrackingType 值
- 是否有调试设置可以让 eclipselink 根据 table 记录 ChangeTrackingType 值?
感谢@Chris,我能够确认我的实体 class 的 ObjectChangePolicy 确实已延迟。
此值意味着 (ChangeTracking) 仅当值与从数据库加载时的值不同时才会对字段进行 sql 更新。
还有属性设置。
这将在调用 setter 并且原始值不同时更新字段。
所以这实际上是正在发生并导致问题的原因:
延期流程:
当 B.Y 在 A.X 能够提交之前加载 E 记录时,B.Y 中的字段 F 仍然为假。如果 A.X 提交,则 F 在数据库中为真。
当 B.Y 完成后,它会将 F 设置为 false。但是当 E 被加载时,该值也是假的,这意味着不会进行任何更新。
现在介绍解决方案:
首先,B.Y 有可能(尽管不太可能)比 A.X 完成得更快。要覆盖此 B.Y 必须告诉 A.X 不要将 F 设置为 true。这可以通过将作为参数传递的 E 上的 F 设置为 false 轻松实现。
对于第二部分,我知道有两个解决方案:
1)
在 B.Y 结束时使用 EntityManager.flush()
强制更新,然后立即使用 EntityManager.refresh()
刷新数据,然后再次将 F 设置为 false。刷新数据确保 F 现在为真,并在 F 设置为假后更新它。
2)
使用 ATTRIBUTE 并先将值设置为 true,然后再设置为 false。
这听起来很愚蠢,但这是一种强制系统更新字段的简单方法。
显然我的偏好是选项 2,因为第一个选项需要重新加载对象并再次更新它,因此它会导致 2 个额外的 sql 语句。
我正在使用 payare 5.201,它使用 eclipselink 2.7。
我正在使用 EJB(无状态 bean)来处理我的事务。
有一个 class A 和方法 X,它从数据库中检索实体 E 并在 class B 上调用方法 Y 并将 E 作为参数传递。
方法 X 是 @ASynchronous,这意味着它将 运行 在单独的线程中。
所以线程 T1 中的方法 A.X 运行s 和 T2 中的 B.Y。
当 A.X 调用 B.Y 时 A.X 不必等待,因为 B.Y returns 是异步的。
就在 A.Z 调用 B.Y 之前,它将 E 中的值 F 设置为 true。这表明 B.Y 是 运行ning。
A.X 正在通过 E,这看起来很奇怪。这样做是为了确保 B.Y 获得正确的对象。
如果我愿意,例如传递 E 的 id 并在 B.Y 中查询它然后我可以获得竞争条件,因为当 E 在 T1 中提交时无法保证所以 B.Y 可以获得 E.F 的旧值。
当B.Y收到E时,它是同一个对象,但它没有注册到B中的(其他)实体管理器。当B.Y准备好时,E被合并到实体管理器中有效更新对 E.
所做的任何更改当 B.Y 准备就绪时,E.F 设置为 false 以指示其完成。
当 B.Y 退出时,EJB 接管并将 E 中的值更新到数据库中。
我现在看到的问题是 E.F 没有更新。在 sql 日志中,我看到记录已更新,但字段 F 不在更新语句中。这意味着 eclipselink 看不到该字段的任何更改。有趣的是,这种情况并不总是发生。
在调查了 Eclipse 之后,我读到了有关更改跟踪的信息,它可以在启用编织时使用。这可以例如通过在实体上使用@ChangeTracking(ChangeTrackingType.ATTRIBUTE) 来激活。
我正在使用 Payara,默认情况下启用编织,我没有任何@ChangeTracking 注释,这意味着 eclipselink 将根据某些规则在 运行 时间选择这些注释。
当我设置
@ChangeTracking(ChangeTrackingType.ATTRIBUTE)
在 E 实体上,问题消失,E.F 已更新。
实体E与eager fetchtype有一定关系。当我将这些关系的 fetchtype 设置为 LAZY 时,它也再次起作用。
我的结论是,问题的发生是因为eclipse 给实体E 分配了一个ChangeTrackingType 而不是ATTRIBUTE。我假设这是因为我有急切的获取类型。
问题:
- 为什么这个问题只是偶尔出现?
- 我希望 ChangeTrackingType 被确定一次`?
- 我如何运行计时'ask' ChangeTrackingType 用于table 的系统。
- 所以我可以验证不同的 ChangeTrackingType 值
- 是否有调试设置可以让 eclipselink 根据 table 记录 ChangeTrackingType 值?
感谢@Chris,我能够确认我的实体 class 的 ObjectChangePolicy 确实已延迟。
此值意味着 (ChangeTracking) 仅当值与从数据库加载时的值不同时才会对字段进行 sql 更新。
还有属性设置。
这将在调用 setter 并且原始值不同时更新字段。
所以这实际上是正在发生并导致问题的原因:
延期流程:
当 B.Y 在 A.X 能够提交之前加载 E 记录时,B.Y 中的字段 F 仍然为假。如果 A.X 提交,则 F 在数据库中为真。
当 B.Y 完成后,它会将 F 设置为 false。但是当 E 被加载时,该值也是假的,这意味着不会进行任何更新。
现在介绍解决方案:
首先,B.Y 有可能(尽管不太可能)比 A.X 完成得更快。要覆盖此 B.Y 必须告诉 A.X 不要将 F 设置为 true。这可以通过将作为参数传递的 E 上的 F 设置为 false 轻松实现。
对于第二部分,我知道有两个解决方案:
1)
在 B.Y 结束时使用 EntityManager.flush()
强制更新,然后立即使用 EntityManager.refresh()
刷新数据,然后再次将 F 设置为 false。刷新数据确保 F 现在为真,并在 F 设置为假后更新它。
2)
使用 ATTRIBUTE 并先将值设置为 true,然后再设置为 false。 这听起来很愚蠢,但这是一种强制系统更新字段的简单方法。
显然我的偏好是选项 2,因为第一个选项需要重新加载对象并再次更新它,因此它会导致 2 个额外的 sql 语句。