我正在尝试使用H2数据库使用maven来构建代码来学习Spring, Hibernate。目前我有一些问题,如何正确使用@Transactional注释来自动启动事务并在例如entityManager.persist成功或回滚时提交事务。
我的测试项目非常简单。POJO类是Person,包含名字、姓氏和电子邮件地址。有一个服务类PersonSerice,它是一个接口,提供CRUD函数来添加、更改、读取和删除个人数据。有一个PersonServiceImpl调用DAO类的方法。下面是PersonDAOImpl::createPerson方法的示例代码
public void createPerson(Person person) {
entityManager.getTransaction().begin();
entityManager.persist(person);
entityManager.getTransaction().commit();
}
一切按预期运行有一个HibernateSQL输出
“Hibernate:调用hibernate_sequenceHibernate的下一个值:插入到人(电子邮件,nachname,vorname,id)值(?, ?, ?, ?)”
我想摆脱手动调用entityManager.getTransaction()。commit();所以我尝试在调用DAO方法的ServiceImpl方法上编写@Transactional
public void createPerson(Person person) {
entityManager.getTransaction().begin();
entityManager.persist(person);
entityManager.getTransaction().commit();
}
现在它不能正常工作。我只是得到。“ Hibernate:调用hibernate_sequence的下一个值 ” 数据库中写入了一些内容,但我无法列出所有条目或在没有手动提交的情况下删除它们。所以我目前不知道出了什么问题,也不知道我该如何@Transactional自动执行提交。以下是 Eclipse 调试器中显示的实体管理器内容的一部分:
entityManager$proxy 26(id = 33)h ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler(id = 116)< br > container managed false < br > exception translator null JTA false synchronizedWithTransaction false < br > target session impl(id = 122)< br > action queue action queue(id = 306)< br >...autoJoinTransactions true
...
我想我的主要问题可能在xml资源文件中,所以我想在这里展示它们。这是我的Beans.xlm(./src/main/Resources/Beans.xml)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.2.xsd">
<context:component-scan base-package="maven.springhibernateh2.basic"></context:component-scan>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName"
value="${db.driverClassName}"></property>
<property name="url" value="${db.url}"></property>
<property name="username" value="${db.username}"></property>
<property name="password" value="${db.password}"></property>
</bean>
<bean
class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
<property name="locations">
<list>
<value>database.properties</value>
</list>
</property>
<property name="ignoreUnresolvablePlaceholders" value="true"/>
</bean>
<!-- Definition des JpaTransactionManagers -->
<bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<!-- Acitvation of @Transactional Annotation -->
<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager" />
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">
<property name="persistenceUnitName" value="roland.egger.maven.springhibernate" />
<property name="dataSource" ref="dataSource" />
</bean>
<context:spring-configured />
<context:annotation-config />
</beans>
一行可能是个问题。"
现在是其他文件。
这是我的persistence.xml(./src/main/Resources/META-INF/persistence.xml)
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="roland.egger.maven.springhibernate" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<class>maven.springhibernateh2.basic.Person</class>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" />
<property name="hibernate.hbm2ddl.auto" value="create" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.format_sql" value="true" />
</properties>
</persistence-unit>
</persistence>
这是我的pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>roland.egger</groupId>
<artifactId>maven.springhibernateh2.basic</artifactId>
<version>0.0.1-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
<properties>
<slf4j.version>1.7.30</slf4j.version>
<spring.version>5.2.5.RELEASE</spring.version>
<hibernate.version>5.4.15.Final</hibernate.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-orm -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-tx -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.h2database/h2 -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.200</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-core -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-entitymanager -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${hibernate.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.hibernate.javax.persistence/hibernate-jpa-2.1-api -->
<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.1-api</artifactId>
<version>1.0.2.Final</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
</dependency>
<!-- Fuer den RollingFileAppender -->
<dependency>
<groupId>log4j</groupId>
<artifactId>apache-log4j-extras</artifactId>
<version>1.1</version>
</dependency>
</dependencies>
</project>
此处数据库.属性
db.driverClassName=org.h2.Driver
db.url=jdbc:h2:mem:test;DB_CLOSE_DELAY=-1
db.username=sa
db.password=
这里的人.java
package maven.springhibernateh2.basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name="person")
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name="id")
private int personId;
@Column(name = "vorname")
private String Vorname;
@Column(name = "nachname")
private String Nachname;
@Column(name = "email")
private String Emailadresse;
public int getPersonId() {
return personId;
}
public void setPersonId(int personId) {
this.personId = personId;
}
public String getVorname() {
return Vorname;
}
public void setVorname(String vorname) {
Vorname = vorname;
}
public String getNachname() {
return Nachname;
}
public void setNachname(String nachname) {
Nachname = nachname;
}
public String getEmailadresse() {
return Emailadresse;
}
public void setEmailadresse(String emailadresse) {
Emailadresse = emailadresse;
}
public String toString() {
return "Person [PersonId=" + personId + ", Vorname=" + Vorname + ", Nachname=" + Nachname + ", Emailadresse=" + Emailadresse + "]";
}
}
人员服务.java
package maven.springhibernateh2.basic;
import java.util.List;
public interface PersonService {
public abstract void addPerson(Person person);
public abstract Person fetchPersonById(int personId);
public abstract void deletePersonByID(int personId);
public abstract void updatePersonEmailByID(String newEmail, int personId);
public abstract List<Person> getAllPersonInfo();
}
PersonServiceImpl.java
package maven.springhibernateh2.basic;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
@Component("personService")
public class PersonServiceImpl implements PersonService {
@Autowired
private PersonDAO personDAO;
public void setPersonDAO(PersonDAO personDAO) {
this.personDAO = personDAO;
}
@Transactional
public void addPerson(Person person) {
personDAO.createPerson(person);
}
@Transactional
public Person fetchPersonById(int personId) {
return personDAO.getPersonById(personId);
}
@Transactional
public void deletePersonByID(int personId) {
personDAO.deletePersonByID(personId);
}
@Transactional
public void updatePersonEmailByID(String newEmail, int personId) {
personDAO.updatePersonEmailByID(newEmail, personId);
}
@Transactional
public List<Person> getAllPersonInfo() {
return personDAO.getAllPersonData();
}
}
人道.java
package maven.springhibernateh2.basic;
import java.util.List;
public interface PersonDAO {
public abstract void createPerson(Person person);
public abstract Person getPersonById(int personId);
public abstract void deletePersonByID(int personId);
public abstract void updatePersonEmailByID(String newEmail, int personId);
public abstract List<Person> getAllPersonData();
}
PersonDAOImpl.java
package maven.springhibernateh2.basic;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceUnit;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import org.springframework.stereotype.Repository;
@Repository
public class PersonDAOImpl implements PersonDAO {
@PersistenceUnit(name = "roland.egger.maven.springhibernate")
private EntityManagerFactory entityManagerFactory;
private EntityManager entityManager;
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
public EntityManagerFactory getEntityManagerFactory() {
return entityManagerFactory;
}
@PersistenceUnit
public void setEntityManagerFactory(EntityManagerFactory entityManagerFactory) {
this.entityManagerFactory = entityManagerFactory;
this.entityManager = this.entityManagerFactory.createEntityManager();
}
public EntityManager getEntityManager() {
return entityManager;
}
public void createPerson(Person person) {
entityManager.persist(person);
}
public Person getPersonById(int personId) {
Person person = entityManager.find(Person.class, personId);
return person;
}
public void deletePersonByID(int personId) {
Person person = getPersonById(personId);
if (person != null) {
//entityManager.getTransaction().begin();
entityManager.remove(person);
//entityManager.getTransaction().commit();
}
}
public void updatePersonEmailByID(String newEmail, int personId) {
Person person = getPersonById(personId);
if (person != null)
{
entityManager.getTransaction().begin();
person.setEmailadresse(newEmail);
entityManager.getTransaction().commit();
}
}
public List<Person> getAllPersonData() {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Person> cq = cb.createQuery(Person.class);
Root<Person> rootEntry = cq.from(Person.class);
CriteriaQuery<Person> all = cq.select(rootEntry);
TypedQuery<Person> allQuery = entityManager.createQuery(all);
return allQuery.getResultList();
}
}
请原谅我发布了源代码,但我希望它能帮助其他人理解我在做什么,以及如何解决问题,使事务工作,而无需手动将其写入代码。
我试图回答Ali Gelenkers的建议,但评论很短,我看到,我之后遇到了另一个问题。感谢 Ali Gelenker,我被告知,在我的 PersonDAOImpl 类中,@PersistenceUnit我的 EntityManagerFactory 及其 setter 函数会导致问题,应该使用@PersistenceContext。这是我的PersonDaoIml新代码的一部分
@Repository
public class PersonDAOImpl implements PersonDAO {
private EntityManagerFactory entityManagerFactory;
@PersistenceContext
private EntityManager entityManager;
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
public EntityManagerFactory getEntityManagerFactory() {
return entityManagerFactory;
}
public void setEntityManagerFactory(EntityManagerFactory entityManagerFactory) {
this.entityManagerFactory = entityManagerFactory;
this.entityManager = this.entityManagerFactory.createEntityManager();
}
public EntityManager getEntityManager() {
return entityManager;
}
public void createPerson(Person person) {
entityManager.persist(person);
}
...
现在既没有调用setEntityManagerFactory也没有调用setter setEntityManager。问题发生在createPerson方法在调用entityManager.persist(人)期间。entityManager调用抛出以下异常:
" javax.persistence.TransactionRequiredException: No EntityManager with actual transaction available for current thread - cannot reliably process 'persist' call "
在此异常之前,entityManager在Eclipse的调试器中显示以下内容:
entityManager $Proxy26 (id=40)
h SharedEntityManagerCreator$SharedEntityManagerInvocationHandler (id=47)
logger LogAdapter$Slf4jLocationAwareLog (id=51)
properties null
proxyClassLoader Launcher$AppClassLoader (id=55)
synchronizedWithTransaction true
targetFactory $Proxy23 (id=62)
完整的控制台输出为:
INFO | 2020-05-09 22:44:44,953 | | | main | maven.springhibernateh2.basic.CRUDTest - Programmanfang...
INFO | 2020-05-09 22:44:45,486 | | | main | org.hibernate.jpa.internal.util.LogHelper - HHH000204: Processing PersistenceUnitInfo [name: roland.egger.maven.springhibernate]
INFO | 2020-05-09 22:44:45,532 | | | main | org.hibernate.Version - HHH000412: Hibernate ORM core version 5.4.15.Final
INFO | 2020-05-09 22:44:45,657 | | | main | org.hibernate.annotations.common.Version - HCANN000001: Hibernate Commons Annotations {5.1.0.Final}
INFO | 2020-05-09 22:44:46,193 | | | main | org.hibernate.dialect.Dialect - HHH000400: Using dialect: org.hibernate.dialect.H2Dialect
Hibernate:
drop table if exists person CASCADE
Hibernate:
drop sequence if exists hibernate_sequence
Hibernate: create sequence hibernate_sequence start with 1 increment by 1
Hibernate:
create table person (
id integer not null,
email varchar(255),
nachname varchar(255),
vorname varchar(255),
primary key (id)
)
INFO | 2020-05-09 22:44:46,877 | | | main | org.hibernate.engine.transaction.jta.platform.internal.JtaPlatformInitiator - HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
INFO | 2020-05-09 22:44:46,884 | | | main | org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean - Initialized JPA EntityManagerFactory for persistence unit 'roland.egger.maven.springhibernate'
ERROR | 2020-05-09 22:44:46,987 | | | main | maven.springhibernateh2.basic.CRUDTest - javax.persistence.TransactionRequiredException: No EntityManager with actual transaction available for current thread - cannot reliably process 'persist' call
INFO | 2020-05-09 22:44:46,987 | | | main | maven.springhibernateh2.basic.CRUDTest - Programmende...
INFO | 2020-05-09 22:44:46,988 | | | main | org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean - Closing JPA EntityManagerFactory for persistence unit 'roland.egger.maven.springhibernate'
使entityManager对当前线程可用需要什么?
更新:感谢Ali Gelenkers的最新建议,我让它工作了:)对于我的测试项目,我选择了没有aspectj的最简单的解决方案。下面是我的Beans.xml的更改部分:...
<!-- <tx:annotation-driven mode="aspectj" transaction-manager="transactionManager" /> -->
<tx:annotation-driven transaction-manager="transactionManager" />
...
<aop:config proxy-target-class="true"/>
现在,没有人工事务调用,一切都很好。非常感谢:)
更新2:上面的代码正在运行,我可以在Eclipse中使用mvn exec(mvn exec:java-Dexec.mainClass=“maven.springhibernateh2.basic.CRUDTest”)运行它。不幸的是,我无法构建一个可执行jar来运行它。请参见:使用spring 5和hibernate 5与maven创建可执行jar时出现的问题=
使用@PersistenceUnit时,需要创建/销毁EntityManager并手动管理事务。如果您想使用spring @Transactional,您需要删除由@PersistenceUnit注释的entityManagerFactory,并在entityManager变量上使用@PersistenceContext,如下所示。
@PersistenceContext
private EntityManager entityManager;
原因是,当您使用@PersistenceContext时,您定义了一个容器管理的bean(这里是spring管理的),这样您就不需要显式地提交/回滚您的事务,另一方面,使用@PersistenceUnit,您可以指定您想要处理的事务。
更新:
与提到“当前线程没有实际事务可用的实体管理器”的最新错误相关:
希望这有帮助。
我正在使用Guice注入EntityManager。当我提交注入实体管理器的操作时,BD端没有发生任何事情:没有事务通过!!!你能帮我弄清楚发生了什么吗? 这是我的代码: 网状物xml Inject torListener类: 持久性模块类: GuiceModule类: RestModule类: 公共类RestModule扩展了JerseyServletModule{ 最后是网络服务(jeresy
我正在查看一些现有的代码,并想知道在下面的场景中使用Spring的@Transactional注释会发生什么?考虑以下示例: 下面的updateDataBaseItem()方法是常见的,可以从其他非事务性方法和上面的方法调用:
问题内容: 我正在使用Spring / Spring-data-JPA,发现自己需要在单元测试中手动强制提交。我的用例是我正在做一个多线程测试,其中我必须使用在生成线程之前保留的数据。 不幸的是,鉴于测试正在事务中运行,即使不能使它也不能被衍生线程访问。 我尝试使用实体管理器来执行操作,但是在执行此操作时收到错误消息: 有什么方法可以提交事务并继续进行吗?我一直找不到任何允许我调用的方法。 问题答
我不熟悉Hibernate,并且继承了使用它的代码库。未定义自动提交,因此默认情况下为false。不过,基于我提出的其他问题,答案表明,最佳做法是对代码进行标定,以便在开始事务时始终应该提交()或回滚()(多亏了Apostolos)。该代码库使用以下代码中的格式来表示Select语句。我打算将任何新代码正确地划分为commit()或rollback(),但我只是好奇使用下面的模型会产生什么后果。应
我正在使用Hibernate Envers来持久化对象历史。在某些情况下,我们希望捕获对象图状态的快照—我们可以通过了解相应的Envers修订版来实现这一点,然后将其存储在审计记录中。 然而,我们有一个问题。父对象在我们创建和存储其子审核记录的同一事务中更新,并使用Envers revision完成。我们可以获得最新版本: 或创建新修订: 并且使用其中一个,但是父级的提交总是在这之后发生。这就是E
问题内容: 事务成功或回滚后,我需要调用某些方法。我正在使用 该应用程序使用一些外部Web服务,这些内部Web服务在回滚内部事务时需要“清除”。有没有办法在不使用声明式事务管理的情况下完成此操作。 问题答案: 在Hibernate中,您可以扩展和覆盖 方法并将其注册在 或中。 在Spring中,您可以使用扩展,覆盖和注册 。 编辑 使用Spring Aop向所有带注释的方法添加同步的示例