Beschleunigung der Iteration aller Zeilen in einer SQL-Tabelle mithilfe von Hibernate (JPA unterstützt kein Streaming) Ich folgte dem Ansatz this answer. Während dies gut funktioniert, sagt this answer uns, dass wir die Session
Objekt abrufen solltenWas ist der Unterschied zwischen 'getDelegate()' und 'unwrap()' zum Abrufen der Hibernate-Sitzung eines Entity Managers
Session session = entityManager.unwrap(Session.class);
statt der Art und Weise unter Verwendung von in der Antwort Geographie:
Session session = (Session) manager.getDelegate();
Hower, mit dieser Änderung bekomme ich plötzlich die folgende Ausnahme:
java.lang.IllegalStateException: No transactional EntityManager available
Das Unternehmen Manager in ein Feld in einer Federkomponente wie diese autowired ist:
@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 ...
}
}
Wie der Name schon sagt, liest loadAll
nur Daten und wandelt sie in eine Result
. update
schreibt in die Datenbank.
Beachten Sie, dass loadAll
nur über update
aufgerufen wird. Auch das Kommentieren loadAll
mit @Transactional
behebt das Problem nicht.
Ich weiß, dass es mehrere andere Fragen bezüglich dieses Fehlers gibt, @Transactional
die Antwort zu sein. Meine Frage ist, was der Unterschied zwischen getDelegate
und unwrap
wirklich ist: Warum scheitert das eine und das andere nicht? (Und warum nicht @Transactional
das Problem beheben?)
Ich benutze H2 1.4.190 und Hibernate 4.3.11.Final (durch Spring Boot 1.3.2.RELEASE).
EDIT Vollständiges minimales Beispiel (mit Paketdeklarationen und Importe weggelassen). Alle Klassen sind im Paket com.example
:
Entity.java
@javax.persistence.Entity
public class Entity {
@Id
@GeneratedValue
public int id;
public int value;
}
EntityRepository.java
public interface EntityRepository extends JpaRepository<Entity, Integer> {
}
Config.java:
@Configuration
@ComponentScan
@EnableJpaRepositories
@EntityScan
@EnableTransactionManagement
public class Config {
}
Runner.java:
@SpringBootApplication
public class Runner implements CommandLineRunner {
public static void main(String[] args) {
SpringApplication application = new SpringApplication(Runner.class);
application.setWebEnvironment(false);
application.run(args);
}
@Autowired
private Updater updater;
@Override
public void run(String... args) throws Exception {
updater.insert(1, 4, 2);
updater.update();
updater.printAll();
}
}
Updater.java:
@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);
}
}
}
Anwendung.yml:
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:
Stapel Spur:
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
nicht '@ Autowired' Verwendung Verwenden Sie '@ PersistenceContext', wenn ein' EntityManager' injiziert wird. –
Während dies den IntelliJ-Fehler "Konnte nicht automatisch ..." beseitigt, ändert sich das beobachtete Verhalten nicht. –
Veröffentlichen Sie den vollständigen Stack-Trace. –