首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用Java、Hibernate和EntityManager的@ transaction中的事务提交问题

使用Java、Hibernate和EntityManager的@ transaction中的事务提交问题
EN

Stack Overflow用户
提问于 2020-05-09 18:10:16
回答 2查看 6K关注 0票数 1

我正在尝试学习Spring,Hibernate和H2数据库一起使用maven来构建代码。目前,我遇到了一些问题,如何正确地使用@ transaction注释来自动启动事务并在entityManager.persist成功完成或回滚时提交事务。

我的测试项目很简单。POJO类是Person,包含名字、姓氏和电子邮件地址。有一个服务类PersonSerice是一个接口,它提供CRUD函数来添加、更改、读取和删除person数据。有一个PersonServiceImpl调用DAO类的方法。在这里,PersonDAOImpl::createPerson方法的示例代码使用

代码语言:javascript
运行
复制
public void createPerson(Person person) {
    entityManager.getTransaction().begin();
    entityManager.persist(person);
    entityManager.getTransaction().commit();
}

一切都如期而至。有一个Hibernate SQL输出。

"Hibernate:调用hibernate_sequence Hibernate的下一个值:插入person (电子邮件、nachname、vorname、id)值(?、?)“

我想要摆脱手动调用entityManager.getTransaction().commit();,所以我尝试在调用DAO方法的ServiceImpl方法上编写@Transactional

代码语言:javascript
运行
复制
    public void createPerson(Person person) {
    entityManager.getTransaction().begin();
    entityManager.persist(person);
    entityManager.getTransaction().commit();
}

现在它不能正常工作了。我只是得到了。“Hibernate:调用hibernate_sequence的下一个值”在数据库中写入了一些东西,但是如果没有手动提交,我就无法列出所有条目或删除它们。因此,我目前不知道出了什么问题,也不知道如何获得@Transactional,自动提交。在这里,Eclipse调试器中显示的部分entityManager内容:

ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler ( entityManager $Proxy26 (id=33) h id=116)

代码语言:javascript
运行
复制
  containerManaged   false
代码语言:javascript
运行
复制
  exceptionTranslator    null      jta    false      synchronizedWithTransaction    false
代码语言:javascript
运行
复制
  target SessionImpl  (id=122)
代码语言:javascript
运行
复制
     actionQueue ActionQueue  (id=306)
代码语言:javascript
运行
复制
     ...         autoJoinTransactions    true
代码语言:javascript
运行
复制
     ...

我想我的主要问题可能在xml资源文件中,所以我想在这里展示它们。下面是我的Beans.xlm (./src/main/resources/Beans.xml)

代码语言:javascript
运行
复制
<?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>

一句可能是个问题。"<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager" />",因为我的pom中没有aspectj依赖项。但是,添加它们并没有改变任何事情,我也不知道要按预期的方式让@Transactional正常工作需要什么。

其他文件。

这是我的(./src/main/resources/META-INF/persistence.xml) persistence.xml

代码语言:javascript
运行
复制
<?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

代码语言:javascript
运行
复制
<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>

在这里database.properties

代码语言:javascript
运行
复制
db.driverClassName=org.h2.Driver
db.url=jdbc:h2:mem:test;DB_CLOSE_DELAY=-1
db.username=sa
db.password=

在这里Person.java

代码语言:javascript
运行
复制
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 + "]";
    }
}

PersonService.java

代码语言:javascript
运行
复制
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

代码语言:javascript
运行
复制
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();
    }
}

PersonDAO.java

代码语言:javascript
运行
复制
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

代码语言:javascript
运行
复制
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();
    }

}

请原谅我发布了源代码,但我希望它能帮助其他人理解我在做什么,以及如何解决问题,使事务能够正常工作,而无需将它们手动写入代码中。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-05-09 18:35:44

使用@PersistenceUnit时,需要创建/销毁EntityManager并手动管理事务。如果您想使用spring @Transactional,您需要删除由@PersistenceUnit注释的entityManagerFactory,而是在您的entityManager变量上使用@PersistenceContext,如下所示。

代码语言:javascript
运行
复制
@PersistenceContext
private EntityManager entityManager;

原因是,当您使用@PersistenceContext时,您定义了一个容器托管bean(这里是spring管理的),这样您就不需要显式地提交/回滚您的事务,而在@PersistenceUnit中,您指定要处理事务。

更新:

与最近提到的“当前线程没有实际事务可用的EntityManager”相关:

  • ,您可以从配置中删除mode=" aspectj“,如果您不需要使用aspectj,并且可以依赖spring默认的AOP。在从immediately.
  • Or中删除mode=" aspectj“之后,您的代码应该工作,调整配置以正确实现Beans.xml。至少您需要将aspectj依赖项添加到您的项目pom中,并将“context:load”定义添加到Beans.xml中。请查看spring事务管理文档以了解aspectj的使用情况.

希望这能有所帮助。

票数 4
EN

Stack Overflow用户

发布于 2020-05-09 20:57:49

我试着回答阿里·盖伦克斯的建议,但我的评论是简短的,我明白了,我在entityManager之后遇到了另一个问题。感谢Ali,我被告知我的PersonDAOImpl类中的@PersistenceUnit对于我的EntityManagerFactory及其setter函数会造成问题,并且应该使用@PersistenceContext。这里是我的PersonDaoImpl新代码的一部分

代码语言:javascript
运行
复制
@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);
    }
...

现在既没有调用setter setEntityManagerFactory也没有调用setter setEntityManager。此问题发生在createPerson方法调用entityManager.persist(person)期间。entityManager调用引发以下异常:

代码语言:javascript
运行
复制
" javax.persistence.TransactionRequiredException: No EntityManager with actual transaction available for current thread - cannot reliably process 'persist' call "

在此异常之前,entityManager显示Eclipse调试器中的折叠内容。

代码语言:javascript
运行
复制
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)

完整的控制台输出是:

代码语言:javascript
运行
复制
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对当前线程可用,需要什么?

Update:,多亏了Ali的更新建议,我让它工作了:)在我的测试项目中,我选择了最简单的解决方案,没有aspectj。这里改变了我的Beans.xml的部分:.

代码语言:javascript
运行
复制
       <!--  <tx:annotation-driven mode="aspectj" transaction-manager="transactionManager" />  -->
       <tx:annotation-driven transaction-manager="transactionManager" /> 
...
       <aop:config proxy-target-class="true"/>

现在,无需手动事务调用,一切都可以正常工作。(非常感谢:)

上面的代码正在运行,我可以在Eclipse (mvn:-Dexec.mainClass="maven.springhibernateh2.basic.CRUDTest"). -Dexec.mainClass=“maven.springhibernateh2.basic.CRUDTest”).)中运行它。不幸的是,我无法构建一个可执行的jar来运行它。请看:problem creating an executable jar with maven using spring 5 and hibernate 5 => BeanDefinitionParsingException,我想pom.xml有个问题。如果有任何建议,我将非常高兴。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61701466

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档