【问题标题】:EntityManager persist and merge not working in @Transactional methodEntityManager 持久化和合并在 @Transactional 方法中不起作用
【发布时间】:2020-06-05 21:35:05
【问题描述】:

我有 @Transactional 注释和 EntityManager 持久化和合并方法的奇怪行为。我已将方法注释为 @Transactional 并在其中调用 EntityManager.persists(entity) ......并且没有任何反应。实体没有保存到数据库,没有触发异常,完全没有。我已经阅读了大量的示例和 SO 问题,我的代码似乎还可以,但无法正常工作。

休眠配置:

import org.hibernate.jpa.HibernatePersistenceProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
import org.springframework.jndi.JndiTemplate;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.naming.NamingException;
import javax.sql.DataSource;
import java.sql.Connection;
import java.util.Properties;

@Configuration
@EnableTransactionManagement
@ComponentScan(basePackages = {"com.mycompany"})
@DependsOn({"PropertiesConfig"})
public class HibernateConfig {

    public HibernateConfig() {}

    @Bean
    public DataSource dataSource() throws NamingException {
        return (DataSource) new JndiTemplate().lookup(PropertyService.getInstance().getProperty("jndi.jdbc.AGSQL"));
    }

    @Bean(name = "entityManager")
    @DependsOn("dataSource")
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() throws NamingException {
        System.out.println("*** Init EntityManagerFactory ***");
        LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
        em.setPersistenceProviderClass(HibernatePersistenceProvider.class);
        em.setDataSource(dataSource());
        em.setPackagesToScan(new String[] { "com.mycompany" });
        em.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
        em.setJpaProperties(hibernateProperties());
        return em;
    }

    @Bean(name = "tm")
    public PlatformTransactionManager transactionManager() throws NamingException {
        System.out.println("*** Init TransactionManager ***");
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
        return transactionManager;
    }

    @Bean
    public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
        return new PersistenceExceptionTranslationPostProcessor();
    }

    private Properties hibernateProperties() {
        return new Properties() {
            {
                setProperty("hibernate.dialect", PropertyService.getInstance().getProperty("hibernate.dialect"));
                setProperty("show_sql", PropertyService.getInstance().getProperty("show_sql"));
                setProperty("hibernate.connection.isolation", String.valueOf(Connection.TRANSACTION_READ_UNCOMMITTED));
            }
        };
    }
}

实体:

import org.hibernate.annotations.UpdateTimestamp;    
import javax.persistence.*;
import java.time.LocalDateTime;

@Entity
@Table(name = "Vehicle", schema = "dbo")
public class VehicleEntity {
    private Long deviceId;
    private LocalDateTime dtEdit;
    private String name;

    @Id
    @Column(name = "device_id")
    public Long getDeviceId() {
        return deviceId;
    }

    public void setDeviceId(Long deviceId) {
        this.deviceId = deviceId;
    }

    @Basic
    @Column(name = "dt_edit")
    @UpdateTimestamp
    public LocalDateTime getDtEdit() {
        return dtEdit;
    }

    public void setDtEdit(LocalDateTime dtEdit) {
        this.dtEdit = dtEdit;
    }

    @Basic
    @Column(name = "name")
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

道:

import com.mycompany.VehicleEntity;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

@Repository
public class VehicleDao {

    @PersistenceContext(unitName = "entityManager")
    private EntityManager entityManager;

    protected EntityManager getEntityManager() {
        return entityManager;
    }

    @Transactional(transactionManager = "tm")
    public void persist(VehicleEntity entity) {
        getEntityManager().persist(entity);
    }

    @Transactional("tm")
    public void merge(VehicleEntity entity) {
        getEntityManager().merge(entity);
    }

}

并且执行这段代码完全没有任何作用:

VehicleEntity ve = new VehicleEntity();
ve.setDeviceId(111L);
ve.setName("111");
vehicleDao.persist(ve);

我尝试在 persist 方法中检查交易状态:

((Session)this.getEntityManager().getDelegate()).getTransaction().getStatus() = NOT_ACTIVE

所以我可以得出结论,事务尚未开始,或开始,但 entitymanager 没有自动看到它(见下文)。在其中一个问题中,我看到在调用persist(entity) 之前,实体管理器已加入事务并做了同样的事情:

@Transactional(transactionManager = "tm")
public void persist(T entity) {
    getEntityManager().joinTransaction();
    getEntityManager().persist(entity);
}

Aaaaand...它有效。并且事务状态变为 ACTIVE。

所以我的问题是: - 为什么没有 joinTransaction() 就不能工作?我从来没有在例子中见过它...... - (可能在解决第一个问题后,这个问题没有意义)持久化和合并实际上是在抽象 dao 类中,但我有很多实体,很多实体 dao 和许多自定义方法。并且在他们每个人中调用 joinTransaction() 并不是一个好主意。怎么做的漂亮?

编辑:

检查了另一件事 - 添加了传播属性:

@Transactional(transactionManager = "tm", propagation = Propagation.MANDATORY)
public void persist(T entity) {
    getEntityManager().persist(entity);
}

它会抛出异常:

org.springframework.transaction.IllegalTransactionStateException: No existing transaction found for transaction marked with propagation 'mandatory'

EDIT2:

Spring version 5.1.7.RELEASE 
Hibernate version 5.4.10.Final
javax.persistence:javax.persistence-api:2.2 (dependency from hibernate-core)

【问题讨论】:

  • 你的Spring、Hibernate等版本是什么?
  • @Kayaman 添加了问题
  • 基于this 我想说这是因为您使用的是JTA,但您使用的是应用程序管理的实体管理器。你在哪个应用服务器上运行它?
  • Wildfly 18.0.1.
  • 您还需要将实体管理器配置为容器管理,这样事务处理将是自动的。

标签: java spring hibernate jpa entitymanager


【解决方案1】:

终于找到了问题:我正在从 SessionFactory 迁移到 EntityManager 并在配置文件中保留 SessionFactory 的旧设置。问题是事务管理器对 SF 和 EM 具有相同的方法名称:

@Bean(name = "transactionManager")
public PlatformTransactionManager transactionManager(SessionFactory sessionFactory) {
    JpaTransactionManager transactionManager = new JpaTransactionManager();
    transactionManager.setEntityManagerFactory(sessionFactory);
    return transactionManager;
}

@Bean(name = "tm")
public PlatformTransactionManager transactionManager(@Qualifier("customEntityManager") EntityManagerFactory emf) {
    System.out.println("*** Init TransactionManager ***");
    JpaTransactionManager transactionManager = new JpaTransactionManager();
    transactionManager.setEntityManagerFactory(emf);
    return transactionManager;
}

虽然 bean 名称不同,但这是错误的。 将 SF 事务管理器方法更改为 sessionTransactionManager(...) 可以解决问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-12-07
    • 1970-01-01
    • 2015-02-20
    • 1970-01-01
    • 2017-10-10
    • 2014-11-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多