Java ';getDelegate()';和';展开();用于获取实体管理器的Hibernate会话
为了使用Hibernate加速SQL表中所有行的迭代(因为JPA不支持流式处理),我采用了。虽然这很好,但它告诉我们应该使用Java ';getDelegate()';和';展开();用于获取实体管理器的Hibernate会话,java,spring,hibernate,jpa,spring-transactions,Java,Spring,Hibernate,Jpa,Spring Transactions,为了使用Hibernate加速SQL表中所有行的迭代(因为JPA不支持流式处理),我采用了。虽然这很好,但它告诉我们应该使用 Session session = entityManager.unwrap(Session.class); 而不是答案中的方式: Session session = (Session) manager.getDelegate(); 然而,有了这个变化,我突然得到了以下例外: java.lang.IllegalStateException: No transactio
Session session = entityManager.unwrap(Session.class);
而不是答案中的方式:
Session session = (Session) manager.getDelegate();
然而,有了这个变化,我突然得到了以下例外:
java.lang.IllegalStateException: No transactional EntityManager available
实体管理器自动连接到Spring组件中的字段中,如下所示:
@Component
public class Updater {
@Autowired
private EntityManager entityManager;
@Transactional
public void update() {
// ...
Result loadedResult = loadAll()
// ...
}
private Result loadAll() {
Session session = (Session) manager.getDelegate();
//Session session = entityManager.unwrap(Session.class);
SessionFactory sessionFactory = session.getSessionFactory();
StatelessSession statelessSession = sessionFactory.openStatelessSession();
// ... @linked answer ...
}
}
顾名思义,loadAll
只读取数据并将其转换为一些结果
<代码>更新不会写入数据库
请注意,loadAll
仅通过update
调用。另外,用@Transactional
注释loadAll
也不能解决问题
我知道还有几个关于这个错误的问题,答案是@Transactional
。我的问题是getDelegate
和unwrap
之间的区别到底是什么:为什么一个失败而另一个没有?(为什么@Transactional
不能解决问题?)
我使用的是H2 1.4.190和Hibernate 4.3.11.Final(通过Spring Boot 1.3.2.RELEASE)
编辑完整的最小示例(省略包声明和导入)。所有类都在包com中。示例:
Entity.java
EntityRepository.java
Runner.java:
Updater.java:
堆栈跟踪:
java.lang.IllegalStateException:无法执行CommandLineRunner
在org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:809)~[spring-boot-1.3.2.RELEASE.jar:1.3.2.RELEASE]
在org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:790)~[spring-boot-1.3.2.RELEASE.jar:1.3.2.RELEASE]
在org.springframework.boot.SpringApplication.afterRefresh(SpringApplication.java:777)~[spring-boot-1.3.2.RELEASE.jar:1.3.2.RELEASE]
在org.springframework.boot.SpringApplication.run(SpringApplication.java:308)~[spring-boot-1.3.2.RELEASE.jar:1.3.2.RELEASE]
在com.example.Runner.main(Runner.java:16)[classes/:na]
在sun.reflect.NativeMethodAccessorImpl.invoke0(本机方法)~[na:1.8.0\u 60]
在sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)~[na:1.8.0\u 60]
在sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)~[na:1.8.0\u 60]
在java.lang.reflect.Method.invoke(Method.java:497)~[na:1.8.0\u 60]
在com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)[idea\u rt.jar:na]
原因:java.lang.IllegalStateException:没有可用的事务性EntityManager
在org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:268)~[spring-orm-4.2.4.RELEASE.jar:4.2.4.RELEASE]
在com.sun.proxy.$Proxy49.unwrap(未知源)~[na:na]
在com.example.Updater.loadAll(Updater.java:49)~[classes/:na]
在com.example.Updater.doUpdate(Updater.java:36)~[classes/:na]
在com.example.Updater.update(Updater.java:31)~[classes/:na]
在com.example.Updater$$FastClassBySpringCGLIB$$503dcdb8.invoke()~[classes/:na]
在org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)~[spring-core-4.2.4.RELEASE.jar:4.2.4.RELEASE]
在org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:651)~[spring-aop-4.2.4.RELEASE.jar:4.2.4.RELEASE]
在com.example.Updater$$EnhancerBySpringCGLIB$$f362c8.update()~[classes/:na]
在com.example.Runner.run(Runner.java:25)[classes/:na]
在org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:806)~[spring-boot-1.3.2.RELEASE.jar:1.3.2.RELEASE]
... 省略9个公共框架
好吧,我没有使用Spring,但是当我出于性能原因想要获得SessionFactory时,我只是在一个无状态的
EJB中声明它:
@Stateless
public class OpinionViewCache {
@PersistenceUnit(unitName="opee") SessionFactory sessionFactory;
private StatelessSession statelessSession;
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
为了获得会话,我使用了一个简单的调用:
statelessSession = sessionFactory.openStatelessSession();
当我完成时关闭它:
statelessSession.close();
否则,我用于从Java SE测试的代码非常简单:
EntityManagerFactory emf = Persistence.createEntityManagerFactory("opjpa");
EntityManager em = emf.createEntityManager();
EntityManagerImpl emImpl = (EntityManagerImpl)em;
HibernateEntityManagerFactory factory = emImpl.getFactory();
SessionFactory sessionFactory = factory.getSessionFactory();
注入EntityManager
时,不要使用@Autowired
使用@PersistenceContext
。虽然这会删除IntelliJ的“无法自动连线…”检查错误,但不会更改观察到的行为。发布完整堆栈跟踪。update()方法没有用@Transactional注释?您的方法不是@Transactional
,因此没有事务。这一点在StatcTrace中也很清楚,因为对于更新程序
@Component
public class Updater {
@Autowired
private EntityRepository repository;
@PersistenceContext //@Autowired
private EntityManager entityManager;
public void insert(int... values) {
for (int value : values) {
Entity entity = new Entity();
entity.value = value;
repository.save(entity);
}
repository.flush();
}
public void update() {
// Call "transactioned" method through an intermediary method.
// The code works if 'Runner' calls 'transactionedUpdate' directly.
transactionedUpdate();
}
@Transactional
public void transactionedUpdate() {
int sum = loadAll();
// Set all 'value's to 'sum'.
List<Entity> entities = repository.findAll();
for (Entity entity : entities) {
entity.value = sum;
repository.save(entity);
}
repository.flush();
}
public int loadAll() {
// Session session = (Session) entityManager.getDelegate();
Session session = entityManager.unwrap(Session.class);
SessionFactory sessionFactory = session.getSessionFactory();
StatelessSession statelessSession = sessionFactory.openStatelessSession();
Query query = statelessSession.createQuery("FROM com.example.Entity e");
query.setFetchSize(1000);
query.setReadOnly(true);
query.setLockMode("e", LockMode.NONE);
ScrollableResults results = query.scroll(ScrollMode.FORWARD_ONLY);
int sum = 0;
while (results.next()) {
Entity entity = (Entity) results.get(0);
sum += entity.value;
}
results.close();
statelessSession.close();
return sum;
}
public void printAll() {
List<Entity> entities = repository.findAll();
for (Entity entity : entities) {
System.out.println(entity.id + ": " + entity.value);
}
}
}
spring:
jpa:
open-in-view: false
hibernate:
ddl-auto: update
naming-strategy: org.springframework.boot.orm.jpa.hibernate.SpringNamingStrategy
database: H2
show_sql: false
properties:
hibernate.cache.use_second_level_cache: true
hibernate.cache.use_query_cache: false
datasource:
driver-class-name: org.h2.Driver
url: jdbc:h2:file:~/data-test/db;DB_CLOSE_DELAY=-1
name:
username: test
password:
java.lang.IllegalStateException: Failed to execute CommandLineRunner
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:809) ~[spring-boot-1.3.2.RELEASE.jar:1.3.2.RELEASE]
at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:790) ~[spring-boot-1.3.2.RELEASE.jar:1.3.2.RELEASE]
at org.springframework.boot.SpringApplication.afterRefresh(SpringApplication.java:777) ~[spring-boot-1.3.2.RELEASE.jar:1.3.2.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:308) ~[spring-boot-1.3.2.RELEASE.jar:1.3.2.RELEASE]
at com.example.Runner.main(Runner.java:16) [classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_60]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_60]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_60]
at java.lang.reflect.Method.invoke(Method.java:497) ~[na:1.8.0_60]
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144) [idea_rt.jar:na]
Caused by: java.lang.IllegalStateException: No transactional EntityManager available
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:268) ~[spring-orm-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at com.sun.proxy.$Proxy49.unwrap(Unknown Source) ~[na:na]
at com.example.Updater.loadAll(Updater.java:49) ~[classes/:na]
at com.example.Updater.doUpdate(Updater.java:36) ~[classes/:na]
at com.example.Updater.update(Updater.java:31) ~[classes/:na]
at com.example.Updater$$FastClassBySpringCGLIB$$503dcdb8.invoke(<generated>) ~[classes/:na]
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) ~[spring-core-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:651) ~[spring-aop-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at com.example.Updater$$EnhancerBySpringCGLIB$$f362c2c8.update(<generated>) ~[classes/:na]
at com.example.Runner.run(Runner.java:25) [classes/:na]
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:806) ~[spring-boot-1.3.2.RELEASE.jar:1.3.2.RELEASE]
... 9 common frames omitted
@Stateless
public class OpinionViewCache {
@PersistenceUnit(unitName="opee") SessionFactory sessionFactory;
private StatelessSession statelessSession;
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
statelessSession = sessionFactory.openStatelessSession();
statelessSession.close();
EntityManagerFactory emf = Persistence.createEntityManagerFactory("opjpa");
EntityManager em = emf.createEntityManager();
EntityManagerImpl emImpl = (EntityManagerImpl)em;
HibernateEntityManagerFactory factory = emImpl.getFactory();
SessionFactory sessionFactory = factory.getSessionFactory();