当前位置: 首页 > 知识库问答 >
问题:

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

隆向晨
2023-03-14

我对@Transactional annotation和EntityManager persist和merge方法有奇怪的行为。我将method注释为@transactional,并在其中调用EntityManager.persists(entity)...但什么也没有发生。实体没有保存到数据库,没有激发异常,完全没有。我已经读了大量的例子,所以问题,我的代码看起来很好,但不工作。

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);
((Session)this.getEntityManager().getDelegate()).getTransaction().getStatus() = NOT_ACTIVE
@Transactional(transactionManager = "tm")
public void persist(T entity) {
    getEntityManager().joinTransaction();
    getEntityManager().persist(entity);
}
@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'

编辑2:

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

共有1个答案

裘兴思
2023-03-14

最后发现了问题:我从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(...)解决问题。

 类似资料:
  • 问题内容: 我对Spring 3.2.3 @Transactional注解有疑问。我的服务类如下所示: 如果我调用persist()方法,所有方法都可以正常工作。但是,如果我在类级别将@Transactional注释掉- 事务将不会启动。谁能告诉我为什么Spring只能在methol级忽略@Transactional? 问题答案: 您不能从processDisclosureData()调用pers

  • 问题内容: 我在带有MySQL 5.0 DB的WebSphere Application Server 8上使用OpenJPA 2.2.0。 我有一个要合并到数据库中的对象列表。 就像是: 当我运行此循环时,我需要大约300-600毫秒来合并一个对象。当我删除“ em.merge(ob);”行时 那么我需要“ 0”毫秒来遍历1个列表对象。 所以我的问题是:我该怎么做才能缩短合并一个对象的时间? 谢

  • 我正在@Async和@Transactional方法中的@Service类中执行一些持久化操作。 在这种方法中,我们持久化一些对象,然后在同一事务中持久化与这些已持久化对象相关的新对象。 JPA抛出一个异常,因为他认为这个相关对象没有被持久化: 这是我的服务类结构: 我想是与事务和异步方法有关,因为相同的代码在没有Async注释时工作。 我还尝试在Transactional注释中使用传播,但不起作

  • 摘自Java Persistence with Hibernate(Manning,2007)第419页: 我应该在会话上使用持久化()吗?Hibernate会话接口还具有一个持久化()方法。它与JPA的持久化()操作具有相同的语义学。但是,这两种操作在刷新方面有一个重要的区别。在同步期间,Hibernate会话不会将持久化()操作级联到关联的实体和集合,即使您使用此选项映射了关联。它只级联到调用

  • 问题内容: 到目前为止,我的偏好是始终使用EntityManager 来处理插入和更新。但是我还注意到,合并会在更新/插入之前执行其他选择查询,以确保数据库中不存在记录。 现在,我正在一个需要对数据库进行大量(批量)插入的项目。从性能的角度来看,在我绝对知道我一直在创建要持久化的对象的新实例的情况下,使用持久化而不是合并有意义吗? 问题答案: 它不是用一个好主意时,就足够了- 做了很多更多的工作。

  • 我正在阅读JPA 2.1规范,有这个片段: 通过调用新实体实例上的persist方法或级联persist操作,新实体实例将同时成为托管实例和持久实例。应用于实体X的持久化操作的语义如下:。。。 是否可以在不显式调用persist()方法的情况下调用persist操作,或者persist操作始终必须是通过调用persist()的触发器? 假设我有两个实体A和B,其中A与B有一个域(cascade=P