【问题标题】:Bypass JPA/Hibernate cache and hit database绕过 JPA/Hibernate 缓存并命中数据库
【发布时间】:2014-11-12 04:46:42
【问题描述】:

我一直在努力使用 JPA(使用 Hibernate)绕过缓存并访问数据库。

我们正在构建一个框架来接收必须保存的实体,但在某些情况下,我需要检查数据库上的当前数据以确定要执行哪种更新(这是业务需求)。

因此,我有一个由用户更新的传入附加实体,但我需要验证其当前数据库信息以确定要执行的业务规则(有时在 JPA 合并()操作之前和有时之后)。

我认为它可以工作的唯一方法是使用实​​体管理器工厂和这个新的实体管理器创建一个全新的 javax.persistence.EntityManager,执行操作,但我遇到了并发错误。

看(这是在 DAO 的 save() 方法中):

EntityManager newEM = currentEntityManager.getEntityManagerFactory().createEntityManager();
newEM.find(e.getClass(), new Short("1"));

但是当我尝试执行 find() 操作时,我认为 JPA 会尝试获取当前由 currentEntityManager 管理的实例,而不是尝试访问数据库。

javax.persistence.PersistenceException: org.hibernate.exception.LockAcquisitionException: could not load an entity: [com.company.framework.persistence.model.TestEntity]
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1763)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1694)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.find(AbstractEntityManagerImpl.java:1141)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.find(AbstractEntityManagerImpl.java:1068)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:334)
at com.sun.proxy.$Proxy32.find(Unknown Source)

你们能帮帮我吗?这是一个 2 周的问题。我真的没有想法。 非常感谢。

【问题讨论】:

  • 您是否尝试过不使用代码currentEntityManager.getEntityManagerFactory() 创建一个新的entityManager?您是否使用 FORCE WRITE 作为锁定类型?还是悲观锁?
  • @uaiHebert 我正在使用 JPA 默认值,而对于并发控制,我正在使用 @Version 字段。 currentEntityManager 是使用 @PersistenceContext 注入的 DAO 实体管理器。您建议我以哪种其他方式创建将访问数据库而不是缓存的实体管理器?

标签: java database hibernate caching jpa


【解决方案1】:

最简单的解决方案是将 DataSource 注入到 DAO 中,就在实体管理器旁边并创建一个 JDBCTemplate:

 @Autowired
 private final DataSource dataSource;

 private final JdbcTemplate jdbcTemplate;

@Override
public void afterPropertiesSet() {
    jdbcTemplate = new JDBCTemplate(dataSource);
}

然后使用 jdbcTemplate 运行您的查询,因为这些查询将使用与 EntityManager 不同的 JDBC 连接。

如果连接绑定到当前线程你需要在一个Callable中执行你的语句提交给一个ExecutorService。确保对可调用结果调用 Future.get 方法,以便发起线程等待可调用对象完成。

在 Java EE 中,您还可以使用 @NotSupported 事务传播来标记您的 Bean 方法。这将暂停当前事务并在单独的事务中执行您的查询。

【讨论】:

  • 感谢您的提示...我认为这会起作用,但我真的不想创建新的数据源,因为我已经有一个注入的实体管理器...我真的不敢相信Hibernate/JPA 没有给我绕过缓存的选项。这是一个普遍的要求。必须有另一种方式大声笑:)
  • 您不必创建另一个数据源。您只能创建一个并将实体管理器工厂配置为也使用它。检查我更新的答案。
  • 我没有找到这个注解...我可以在哪个包中找到它?我的 DAO 中是否会有一个用 @NotSupported 注释的简单方法?
  • 查看 Adam Bien 关于扩展持久性上下文的示例:adam-bien.com/roller/abien/entry/…
  • 在您的情况下,您需要调用另一个标有此注释的会话 Bean。
猜你喜欢
  • 1970-01-01
  • 2012-03-18
  • 2011-03-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-29
  • 1970-01-01
相关资源
最近更新 更多