我一直在努力与JPA(使用Hibernate)绕过缓存并点击数据库。
我们正在构建一个接收必须保存的实体的框架,但在某些情况下,我需要检查数据库上的当前数据以确定要执行哪种更新(这是业务需求)。
因此,我有一个由用户更新的传入附加实体,但我需要验证其当前数据库信息以确定要执行的业务规则(有时在JPA merge()操作之前和之后)。
我认为它可以工作的唯一方法是使用实体管理器工厂创建一个全新的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周的问题。我真的没有想法。
非常感谢你。
答案 0 :(得分:2)
最简单的解决方案是将DataSource注入您的DAO,就在您的实体管理器旁边并创建一个JDBCTemplate:
@Autowired
private final DataSource dataSource;
private final JdbcTemplate jdbcTemplate;
@Override
public void afterPropertiesSet() {
jdbcTemplate = new JDBCTemplate(dataSource);
}
然后使用jdbcTemplate运行查询,因为它们将使用与EntityManager不同的JDBC连接。
如果连接绑定到当前线程,则需要在提交给ExecutorService的Callable中执行语句。确保在可调用结果上调用Future.get方法,以便原始线程等待callable完成。
在Java EE中,您还可以使用@NotSupported事务传播标记Bean方法。这将暂停当前事务并在单独的事务中执行查询。