简体   繁体   English

EntityManager 持久化和合并在@Transactional 方法中不起作用

[英]EntityManager persist and merge not working in @Transactional method

I have strange behaviour of @Transactional annotation and EntityManager persist and merge methods.我有@Transactional 注释和 EntityManager 持久化和合并方法的奇怪行为。 I've annotated method as @Transactional and in it I call EntityManager.persists(entity)...and nothing happens.我已将方法注释为@Transactional,并在其中调用 EntityManager.persists(entity)...但没有任何反应。 Entity is not saved to DB, no exception fired, totally nothing.实体不保存到数据库,没有异常被触发,完全没有。 I've read tons of examples, SO questions, and my code seems ok but not working.我已经阅读了大量示例、SO 问题,我的代码似乎还可以但无法正常工作。

Hibernate config:休眠配置:

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));
            }
        };
    }
}

Entity:实体:

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;
    }

}

Dao:道:

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);
    }

}

And executing this code do totally nothing:执行此代码完全没有任何作用:

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

I tried to check transaction status inside persist method:我试图在persist方法中检查事务状态:

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

So I can conclude that transaction has not started, or started, but entitymanager did not see it automatically (see below).所以我可以断定事务没有开始,或者已经开始,但是 entitymanager 没有自动看到它(见下文)。 In one of the questions I saw that before calling persist(entity) entity manager was joined to the transaction and made the same thing:在我看到的一个问题中,在调用 persist(entity) 实体管理器之前加入了事务并做了同样的事情:

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

Aaaaand...it works. Aaaaand...它的工作原理。 And transaction status become ACTIVE.并且交易状态变为ACTIVE。

So my questions are: - why it did not work without joinTransaction() ?所以我的问题是: - 为什么没有joinTransaction()它不起作用? I've never seen it in examples... - (possibly after solving 1st question this one will not make sense) persisting and merging actually are in abstract dao class, but I have many entities, many entities dao and many custom methods in them.我从来没有在例子中见过它...... - (可能在解决第一个问题之后这个问题没有意义)持久化和合并实际上是在抽象的 dao 类中,但是我有很多实体,很多实体 dao 和许多自定义方法. And calling joinTransaction() in each of them is not good idea.并且在他们每个人中调用joinTransaction()并不是一个好主意。 How make it in pretty way?如何以漂亮的方式制作它?

EDIT:编辑:

Checked one more thing - added propagation property:检查了一件事 - 添加了传播属性:

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

And it throws an exception:它抛出一个异常:

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

EDIT2:编辑2:

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

Finally found the problem: I was migrating from SessionFactory to EntityManager and leave in config file old settings for SessionFactory.终于找到了问题:我正在从 SessionFactory 迁移到 EntityManager 并保留 SessionFactory 的配置文件旧设置。 And the issue was that transaction managers has the same method names for SF and EM:问题是事务管理器对 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;
}

This is mistake though bean names are different.尽管 bean 名称不同,但这是错误的。 Changing SF transaction manager method to sessionTransactionManager(...) resolve the issue.将 SF 事务管理器方法更改为sessionTransactionManager(...)解决了该问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM