JPA @EntityListener无法按预期工作 [英] JPA @EntityListener does not work as expected

查看:206
本文介绍了JPA @EntityListener无法按预期工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在整合Spring4和Hibernate5,但存在一个我无法解决的问题。
我在BaseEntity类上使用@EntityListener注释,这是其他业务模型的超类。
我也在BaseEntity上使用@MappedSuperclass。
但它不起作用!



使用Spring基础注释并成功运行应用程序。
我也插入了一个记录到数据库。
所以我认为我的项目配置是最新的。



任何机构让我知道为什么?
非常感谢。

这是BaseEntity类。

pre $ @MappedSuperclass
@EntityListeners(EntityListener.class)
public class BaseEntity实现Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long ID;

@Column(nullable = false,updatable = false)
private日期createDate;

@Column(nullable = false)
私人日期modifyDate;

public Long getId(){
return id;
}

public void setId(Long id){
this.id = id;
}

public Date getCreateDate(){
return createDate;
}

public void setCreateDate(Date createDate){
this.createDate = createDate;
}

public Date getModifyDate(){
return modifyDate;
}

public void setModifyDate(Date modifyDate){
this.modifyDate = modifyDate;


这是EntityListener类。

  public class EntityListener {

@PrePersist
public void prePersist(BaseEntity entity){
entity。 setCreateDate(new Date());
entity.setModifyDate(new Date());
}

@PreUpdate
public void preUpdate(BaseEntity entity){
entity.setModifyDate(new Date());
}

}

以下是我的项目配置库

  @Configuration 
@EnableWebMvc
// @ ImportResource({classpath:xxxxx ({b.PropertySource(classpath:application.properties)
})
@ComponentScan({com.yeager.admin.persistence ,com.yeager.admin.web,com.yeager.admin.service,com.yeager.admin.common})
@EnableAspectJAutoProxy
// @ EnableRetry
public class AppConfig {

@Bean(name =multipartResolver)
public CommonsMultipartResolver getResolver()throws IOException {
CommonsMultipartResolver解析器= new CommonsMultipartResolver();
返回解析器;


$Be
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer(){
return new PropertySourcesPlaceholderConfigurer();


@Bean
public static SpringContext springContext(){
return new SpringContext();
}

}

关于DAL的主要配置是这样的,

  @Configuration 
@EnableTransactionManagement
@PropertySource({classpath:persistence-mysql.properties })
public class PersistenceConfig {

@Autowired
private Environment env;

public PersistenceConfig(){
super();


$ Be $ b $ public LocalSessionFactoryBean sessionFactory(){

final LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setPackagesToScan(com.yeager.admin.persistence.entity);
sessionFactory.setHibernateProperties(hibernateProperties());


return sessionFactory;


@Bean
public DataSource dataSource(){
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
尝试{
comboPooledDataSource.setDriverClass(env.getProperty(jdbc.driver));
} catch(PropertyVetoException e){
e.printStackTrace();
}
comboPooledDataSource.setJdbcUrl(env.getProperty(jdbc.url));
comboPooledDataSource.setUser(env.getProperty(jdbc.username));
comboPooledDataSource.setPassword(env.getProperty(jdbc.password));
comboPooledDataSource.setInitialPoolSize(Integer.valueOf(env.getProperty(datasource.pool.initialPoolSize)));

返回comboPooledDataSource;

$ b @Bean
public PlatformTransactionManager transactionManager(){
final HibernateTransactionManager transactionManager = new HibernateTransactionManager();
transactionManager.setSessionFactory(sessionFactory()。getObject());
返回transactionManager;


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


私有最终属性hibernateProperties(){

最终属性hibernateProperties = new Properties();

hibernateProperties.setProperty(hibernate.dialect,env.getProperty(hibernate.dialect));
hibernateProperties.setProperty(hibernate.show_sql,env.getProperty(hibernate.show_sql));
hibernateProperties.setProperty(hibernate.generate_statistics,env.getProperty(hibernate.generate_statistics));
hibernateProperties.setProperty(hibernate.jdbc.fetch_size,env.getProperty(hibernate.jdbc.fetch_size));
hibernateProperties.setProperty(hibernate.jdbc.batch_size,env.getProperty(hibernate.jdbc.batch_size));
hibernateProperties.setProperty(hibernate.max_fetch_depth,env.getProperty(hibernate.max_fetch_depth));
hibernateProperties.setProperty(hibernate.cache.use_second_level_cache,env.getProperty(hibernate.cache.use_second_level_cache));
hibernateProperties.setProperty(hibernate.cache.use_query_cache,env.getProperty(hibernate.cache.use_query_cache));
// hibernateProperties.setProperty(hibernate.cache.provider_class,env.getProperty(hibernate.cache.provider_class));
hibernateProperties.setProperty(hibernate.hbm2ddl.auto,update);

返回hibernateProperties;




$ b

我使用LocalSessionFactoryBean类的Hibernate而不是JPA的EntityManager类。我不知道这是因为什么原因?

--------------- 6.19 --------- -----



我错了。我不应该使用基于Spring LocalSessionFactoryBean类的@EntityListener注释。
对于hibernate5,有一种特殊的配置方式。
http:// docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html#annotations-jpa-entitylisteners
现在,我修改了我的代码,如下所示:

  @Component 
public class EntityEventListener {

@Autowired
private SessionFactory sessionFactory;

@PostConstruct
public void registerListeners(){
EventListenerRegistry eventListenerRegistry =((SessionFactoryImplementor)sessionFactory).getServiceRegistry()。getService(EventListenerRegistry.class);
eventListenerRegistry.prependListeners(EventType.PRE_INSERT,PreInsertEntityListener.class);
}

}

PreInsertEntityListener

  public class PreInsertEntityListener实现PreInsertEventListener {
@Override
公共布尔onPreInsert(PreInsertEvent事件){
// if( event.getEntity()instanceof AdminUser){
//((AdminUser)event.getEntity())。setCreateDate(new Date());
//((AdminUser)event.getEntity())。setModifyDate(new Date());
//}
BaseEntity baseEntity =(BaseEntity)event.getEntity();
baseEntity.setCreateDate(new Date());
baseEntity.setModifyDate(new Date());
返回false;
}
}

但是,我还有其他问题。
我读了hibernate doc并搜索了很多关于这个的信息。

请帮助我,谢谢!

我的代码在插入实体数据时不起作用。解决方案

虽然您没有发布具体/派生实体或业务代码来保存它,但您发布的代码似乎是正确的。

给它一个小测试,我添加了一个生成的UID给超类,并创建了一个具体的实体:

  import javax.persistence.Entity ; 

@Entity
public class DerivedEntity extends BaseEntity {

private static final long serialVersionUID = -6441043639437893962L;




$ b $ p
$ b

自从你提到Spring之后,这里是Spring Data JPA存储库来保存它:

  import org.springframework.data.repository.CrudRepository; 
import org.springframework.stereotype.Repository;

@Repository
public interface DerivedEntityRepository extends CrudRepository< DerivedEntity,Long> {

}

这个小测试应该显示(<$ c
$ b

  import static org.assertj.core.api。 Assertions.assertThat; 

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.annotation.Transactional;

@RunWith(SpringRunner.class)
@Transactional
@SpringBootTest
public class DerivedEntityRepositoryTests {

@Autowired
private DerivedEntityRepository derivedEntityRepository;

@Test
public void insertDerivedEntity(){
DerivedEntity entity = new DerivedEntity();
entity = derivedEntityRepository.save(entity);
assertThat(entity.getCreateDate())。isNotNull();
}

}

只要提及它,如果您不希望将来增强自定义侦听器,现有的Spring Data JPA AuditingEntityListener 完全符合您目前所做的(甚至更多)。在这种情况下,您可以使用 @EnableJpaAuditing 来增强 @Configuration 类并修改您的 BaseEntity

  @MappedSuperclass 
@EntityListeners(AuditingEntityListener.class)
public class BaseEntity实现Serializable {

// ...

@CreatedDate
@Column(nullable = false,updatable = false)
private日期createDate;

@LastModifiedDate
@Column(nullable = false)
私人日期modifyDate;

// ...
}

您的自定义 EntityListener 可有可无。



只要看看 Spring JPA审核了解更多信息。如果你想增强Hibernate审计,请尝试 Hibernate Envers


I am integrating Spring4 and Hibernate5, but there is a problem that I can't resolve. I use @EntityListener annotation on the BaseEntity class that is a super class for other business model. Also I use @MappedSuperclass on the BaseEntity. But it don't work!

Use Spring base annotation and run application successfully. Also I inserted a record to db. So I think my configuration of project is current.

Any body let me know why? Thanks very much.

This is BaseEntity class.

@MappedSuperclass
@EntityListeners(EntityListener.class)
public class BaseEntity implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Column(nullable = false, updatable = false)
    private Date createDate;

    @Column(nullable = false)
    private Date modifyDate;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Date getCreateDate() {
        return createDate;
    }

    public void setCreateDate(Date createDate) {
        this.createDate = createDate;
    }

    public Date getModifyDate() {
        return modifyDate;
    }

    public void setModifyDate(Date modifyDate) {
        this.modifyDate = modifyDate;
    }
}

This is EntityListener class.

public class EntityListener {

  @PrePersist
  public void prePersist(BaseEntity entity) {
    entity.setCreateDate(new Date());
    entity.setModifyDate(new Date());
  }

  @PreUpdate
  public void preUpdate(BaseEntity entity) {
    entity.setModifyDate(new Date());
  }

}

The following is my project configuration base on Spring annotation.

@Configuration
@EnableWebMvc
//@ImportResource({ "classpath:xxxxx.xml" })
@PropertySources({
    @PropertySource("classpath:application.properties")
})
@ComponentScan({"com.yeager.admin.persistence","com.yeager.admin.web","com.yeager.admin.service","com.yeager.admin.common"})
@EnableAspectJAutoProxy
//@EnableRetry
public class AppConfig {

    @Bean(name = "multipartResolver")
    public CommonsMultipartResolver getResolver() throws IOException {
        CommonsMultipartResolver resolver = new CommonsMultipartResolver();
        return resolver;
    }

    @Bean
    public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
        return new PropertySourcesPlaceholderConfigurer();
    }

    @Bean
    public static SpringContext springContext() {
        return new SpringContext();
    }

}

The main configuration about DAL like this,

@Configuration
@EnableTransactionManagement
@PropertySource({"classpath:persistence-mysql.properties"})
public class PersistenceConfig {

    @Autowired
    private Environment env;

    public PersistenceConfig() {
        super();
    }

    @Bean
    public LocalSessionFactoryBean sessionFactory() {

        final LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
        sessionFactory.setDataSource(dataSource());
        sessionFactory.setPackagesToScan("com.yeager.admin.persistence.entity");
        sessionFactory.setHibernateProperties(hibernateProperties());


        return sessionFactory;
    }

    @Bean
    public DataSource dataSource() {
        ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
        try {
            comboPooledDataSource.setDriverClass(env.getProperty("jdbc.driver"));
        } catch (PropertyVetoException e) {
            e.printStackTrace();
        }
        comboPooledDataSource.setJdbcUrl(env.getProperty("jdbc.url"));
        comboPooledDataSource.setUser(env.getProperty("jdbc.username"));
        comboPooledDataSource.setPassword(env.getProperty("jdbc.password"));
        comboPooledDataSource.setInitialPoolSize(Integer.valueOf(env.getProperty("datasource.pool.initialPoolSize")));

        return comboPooledDataSource;
    }

    @Bean
    public PlatformTransactionManager transactionManager() {
        final HibernateTransactionManager transactionManager = new HibernateTransactionManager();
        transactionManager.setSessionFactory(sessionFactory().getObject());
        return transactionManager;
    }

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

    private final Properties hibernateProperties() {

        final Properties hibernateProperties = new Properties();

        hibernateProperties.setProperty("hibernate.dialect", env.getProperty("hibernate.dialect"));
        hibernateProperties.setProperty("hibernate.show_sql", env.getProperty("hibernate.show_sql"));
        hibernateProperties.setProperty("hibernate.generate_statistics",env.getProperty("hibernate.generate_statistics"));
        hibernateProperties.setProperty("hibernate.jdbc.fetch_size", env.getProperty("hibernate.jdbc.fetch_size"));
        hibernateProperties.setProperty("hibernate.jdbc.batch_size", env.getProperty("hibernate.jdbc.batch_size"));
        hibernateProperties.setProperty("hibernate.max_fetch_depth", env.getProperty("hibernate.max_fetch_depth"));
        hibernateProperties.setProperty("hibernate.cache.use_second_level_cache",env.getProperty("hibernate.cache.use_second_level_cache"));
        hibernateProperties.setProperty("hibernate.cache.use_query_cache",env.getProperty("hibernate.cache.use_query_cache"));
//      hibernateProperties.setProperty("hibernate.cache.provider_class",env.getProperty("hibernate.cache.provider_class"));
        hibernateProperties.setProperty("hibernate.hbm2ddl.auto", "update");

        return hibernateProperties;
    }

}

I use LocalSessionFactoryBean class of Hibernate rather than EntityManager class of JPA. I wonder if this cause ?

--------------- 6.19 --------------

I am wrong. I don't should use @EntityListener annotation base on Spring LocalSessionFactoryBean class. For hibernate5, there is a special configuration way. http://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html#annotations-jpa-entitylisteners Now, I modify my code as following,

@Component
public class EntityEventListener {

    @Autowired
    private SessionFactory sessionFactory;

    @PostConstruct
    public void registerListeners(){
        EventListenerRegistry eventListenerRegistry = ((SessionFactoryImplementor) sessionFactory).getServiceRegistry().getService(EventListenerRegistry.class);
        eventListenerRegistry.prependListeners(EventType.PRE_INSERT, PreInsertEntityListener.class);
    }

}

PreInsertEntityListener

public class PreInsertEntityListener implements PreInsertEventListener {
    @Override
    public boolean onPreInsert(PreInsertEvent event) {
//        if (event.getEntity() instanceof AdminUser){
//            ((AdminUser) event.getEntity()).setCreateDate(new Date());
//            ((AdminUser) event.getEntity()).setModifyDate(new Date());
//        }
        BaseEntity baseEntity = (BaseEntity) event.getEntity();
        baseEntity.setCreateDate(new Date());
        baseEntity.setModifyDate(new Date());
        return false;
    }
}

But, I have a other problem. I read hibernate doc and search many information about this. My code don't work already when I insert entity data.

Please help me, thanks!

解决方案

Although you did neither post the concrete / derived entity nor the business code to persist it, the code you posted seems correct.

For giving it a small test I added a generated UID to the super class and created a concrete entity:

import javax.persistence.Entity;

@Entity
public class DerivedEntity extends BaseEntity {

    private static final long serialVersionUID = -6441043639437893962L;

}

And since you mentioned Spring, here is a Spring Data JPA repository to save it:

import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface DerivedEntityRepository extends CrudRepository<DerivedEntity, Long> {

}

This small test should show that the (@PrePersist) listener works:

import static org.assertj.core.api.Assertions.assertThat;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.annotation.Transactional;

@RunWith(SpringRunner.class)
@Transactional
@SpringBootTest
public class DerivedEntityRepositoryTests {

    @Autowired
    private DerivedEntityRepository derivedEntityRepository;

    @Test
    public void insertDerivedEntity() {
        DerivedEntity entity = new DerivedEntity();
        entity = derivedEntityRepository.save(entity);
        assertThat(entity.getCreateDate()).isNotNull();
    }

}

And just to mention it, if you don't want to enhance your custom listener in future, the existing Spring Data JPA AuditingEntityListener does exactly what you are doing at the moment (and even more). In this case you could just enhance a @Configuration class with @EnableJpaAuditing and modify your BaseEntity as following:

@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public class BaseEntity implements Serializable {

    // ...

    @CreatedDate
    @Column(nullable = false, updatable = false)
    private Date createDate;

    @LastModifiedDate
    @Column(nullable = false)
    private Date modifyDate;

    // ...
}

That would make your custom EntityListener dispensable.

Just take a look Spring JPA Auditing for more information. If you want to enhance auditing with Hibernate, try Hibernate Envers.

这篇关于JPA @EntityListener无法按预期工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆