Spring JPA@EntityListener未按预期工作
我正在集成Spring4和Hibernate5,但有一个问题我无法解决。 我在BaseEntity类上使用@EntityListener注释,该类是其他业务模型的超类。 我还在BaseEntity上使用@MappedSuperclass。 但它不起作用 使用SpringBase注释并成功运行应用程序。 我还向db插入了一条记录。 所以我认为我的项目配置是最新的 有人告诉我为什么吗? 非常感谢 这是BaseEntity类Spring JPA@EntityListener未按预期工作,spring,hibernate,jpa,entitylisteners,Spring,Hibernate,Jpa,Entitylisteners,我正在集成Spring4和Hibernate5,但有一个问题我无法解决。 我在BaseEntity类上使用@EntityListener注释,该类是其他业务模型的超类。 我还在BaseEntity上使用@MappedSuperclass。 但它不起作用 使用SpringBase注释并成功运行应用程序。 我还向db插入了一条记录。 所以我认为我的项目配置是最新的 有人告诉我为什么吗? 非常感谢 这是BaseEntity类 @MappedSuperclass @EntityListeners(Ent
@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;
}
}
@MappedSuperclass
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;
}
}
这是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());
}
}
public class EntityListener implements PreInsertEventListener, PreUpdateEventListener {
private static final String CREATE_DATE_PROPERTY = "createDate";
private static final String MODIFY_DATE_PROPERTY = "modifyDate";
@Override
public boolean onPreInsert(PreInsertEvent event) {
if (event.getEntity() instanceof BaseEntity){
//property name of entity
String[] propertyNames = event.getPersister().getEntityMetamodel().getPropertyNames();
//property value of entity
Object[] state = event.getState();
for (int i = 0; i < propertyNames.length ; i ++) {
if (CREATE_DATE_PROPERTY.equals(propertyNames[i]) || MODIFY_DATE_PROPERTY.equals(propertyNames[i])){
state[i] = new Date();
}
}
}
return false;
}
@Override
public boolean onPreUpdate(PreUpdateEvent event) {
if (event.getEntity() instanceof BaseEntity){
//property name of entity
String[] propertyNames = event.getPersister().getEntityMetamodel().getPropertyNames();
//property value of entity
Object[] state = event.getState();
for (int i = 0; i < propertyNames.length ; i ++) {
if (MODIFY_DATE_PROPERTY.equals(propertyNames[i])){
state[i] = new Date();
}
}
}
return false;
}
}
下面是我基于Spring注释的项目配置
@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();
}
}
DAL的主要配置如下:
@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;
}
}
我使用Hibernate的LocalSessionFactoryBean类,而不是JPA的EntityManager类。我想知道这是否是原因?
---------------6.19--------------
我错了。我不应该在SpringLocalSessionFactoryBean类上使用@EntityListener注释基。
对于hibernate5,有一种特殊的配置方式。
现在,我修改我的代码如下:
@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);
}
}
预插入侦听器
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;
}
}
但是,我还有一个问题。
我阅读了hibernate文档并搜索了很多关于这个的信息。插入实体数据时,我的代码已不起作用
请帮帮我,谢谢 尽管您既没有发布具体/派生实体,也没有发布业务代码来持久化它,但您发布的代码似乎是正确的 为了给它一个小测试,我向超类添加了一个生成的UID,并创建了一个具体的实体:
import javax.persistence.Entity;
@Entity
public class DerivedEntity extends BaseEntity {
private static final long serialVersionUID = -6441043639437893962L;
}
既然您提到了Spring,这里有一个Spring数据JPA存储库来保存它:
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface DerivedEntityRepository extends CrudRepository<DerivedEntity, Long> {
}
更重要的是,如果您不想在将来增强您的自定义侦听器,那么现有的Spring数据JPA正是您目前正在做的(甚至更多)。在这种情况下,您可以使用@EnableJpaAuditing
增强@Configuration
类,并修改BaseEntity
,如下所示:
@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;
// ...
}
这将使您的自定义EntityListener
变得可有可无
只需查看更多信息。如果您想使用Hibernate增强审计功能,请尝试。非常感谢大家。我已经解决了这个问题。 我将分享我的解决方案,希望如果你做同样的事情,它对你有帮助 首先,我的出发点是错误的。因为我以前使用过JPA,所以在集成Spring4和Hibernate5时默认使用@EntityListener注释。 然后,我阅读了Hibernate文档和许多相关文章,发现有一种实现实体侦听器的新方法 最后,我的解决方案如下 这是我的BaseEntity类
@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;
}
}
@MappedSuperclass
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;
}
}
首先,您需要定义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());
}
}
public class EntityListener implements PreInsertEventListener, PreUpdateEventListener {
private static final String CREATE_DATE_PROPERTY = "createDate";
private static final String MODIFY_DATE_PROPERTY = "modifyDate";
@Override
public boolean onPreInsert(PreInsertEvent event) {
if (event.getEntity() instanceof BaseEntity){
//property name of entity
String[] propertyNames = event.getPersister().getEntityMetamodel().getPropertyNames();
//property value of entity
Object[] state = event.getState();
for (int i = 0; i < propertyNames.length ; i ++) {
if (CREATE_DATE_PROPERTY.equals(propertyNames[i]) || MODIFY_DATE_PROPERTY.equals(propertyNames[i])){
state[i] = new Date();
}
}
}
return false;
}
@Override
public boolean onPreUpdate(PreUpdateEvent event) {
if (event.getEntity() instanceof BaseEntity){
//property name of entity
String[] propertyNames = event.getPersister().getEntityMetamodel().getPropertyNames();
//property value of entity
Object[] state = event.getState();
for (int i = 0; i < propertyNames.length ; i ++) {
if (MODIFY_DATE_PROPERTY.equals(propertyNames[i])){
state[i] = new Date();
}
}
}
return false;
}
}
我遇到了同样的问题,在我的例子中,用@EntityListeners定义的侦听器引用了另一个包中的类(不在同一个类加载器中),并且没有被扫描。将类添加到我的持久性上下文后,它开始按预期工作
因此,请始终确保将与持久性相关的任何类添加到持久性上下文中。您能将相关代码粘贴到此处吗?你说的“不起作用”是什么意思?您的侦听器回调是否未被调用?确定。我将粘贴BaseEntity类和EntityListener类。但如果我想使用JPA@EntityListeners注释基Hibernate,我应该怎么做?也许我不想集成Spring数据JPA。嗨,Kevin,我一分钟前读过Spring JPA审计和Hibernate Envers。我认为,在实体创建、删除和更新时,让监听器成为监听器不是我的观点。我确信我应该使用@EntityListeners注释来实现。你能帮我吗?非常感谢。我添加了有关Spring配置的更多信息。这对你很有帮助。看来你自己解决了问题。这也许是最好的办法。但我很高兴我能帮上一点忙。:)所以你最后说注释不起作用,是吗?它是否依赖于JPA或spring(启动)版本?