【问题标题】:PreInsert and PreUpdate Event Listener in hibernate休眠中的 PreInsert 和 PreUpdate 事件侦听器
【发布时间】:2013-12-04 06:28:38
【问题描述】:

我使用PreInsertEventListenerPreUpdateEventListener 事件监听器在表中插入创建日期和更新日期。
我面临的问题是,当我在数据库中保存实体时,创建日期无法插入到与更新记录时插入更新日期相同的表中,它也不会插入更新日期。

我的代码示例如下所示:

监听类:

public class PreInsertListener implements PreInsertEventListener,  
                                          PreUpdateEventListener 
{
    @Override
    public boolean onPreInsert(PreInsertEvent arg0) {
        City.class.cast(arg0.getEntity()).setCreated_date(new Date());
        return false;
    }

    @Override
    public boolean onPreUpdate(PreUpdateEvent arg0) {
        System.out.println("Update event......");
        City.class.cast(arg0.getEntity()).setUpdated_date(new Date());
        return false;
    }
}

休眠连接类:

public class HibernateUtil 
{

    private static final SessionFactory sessionFactory;

    static {
        try {
            AnnotationConfiguration config = new AnnotationConfiguration();
            config.setListener("pre-insert", new PreInsertListener());
            config.setListener("pre-update", new PreInsertListener());
            sessionFactory = config.configure().buildSessionFactory();;

        } catch (Throwable ex) {
            System.err.println("Initial SessionFactory creation failed." + ex);
            throw new ExceptionInInitializerError(ex);
        }
    }

    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }
}

DAO 中的实体保存和更新方法:

public Long saveCity(String cityName)
{
    Session session = HibernateUtil.getSessionFactory().openSession();
    Transaction transaction = null;
    Long cityId = null;
    try {
        transaction = session.beginTransaction();
        City city = new City();
        city.setName(cityName);
        cityId = (Long) session.save(city);
        //session.flush();
        transaction.commit();
    } catch (HibernateException e) {
        transaction.rollback();
        e.printStackTrace();
    } finally {
        session.close();
    }
    return cityId;
}

public void updateCity(Long cityId, String cityName)
{
    Session session = HibernateUtil.getSessionFactory().openSession();
    Transaction transaction = null;
    try {
        transaction = session.beginTransaction();
        City city = (City) session.get(City.class, cityId);
        city.setName(cityName);
        session.update(city);
        //session.flush();
        transaction.commit();
    } catch (HibernateException e) {
        transaction.rollback();
        e.printStackTrace();
    } finally {
        session.close();
    }
}

我的测试班:

public class Main 
{
    public static void main(String[] args) {

        CityDAO cityDAO = new CityDAO();

        long cityId1 = cityDAO.saveCity("New York");

        cityDAO.updateCity(cityId1, "Paris");
    }
 }

如果我使用session.flush(),它将插入创建日期和更新日期,但每次调用刷新方法时都会执行更新的查询。目前我注释了代码以调用session.flush() 方法,如代码所示。

这个问题的解决方案是什么?

【问题讨论】:

  • @AndreiI 它也不起作用。我在提交语句后在我的 dao 函数中放置了session.evict(),对吗?
  • @AndreiI 仍然没有在插入和更新记录的列中获取日期值。
  • @Andreil 我已经为此添加了我的答案及其对我的工作。谢谢

标签: java hibernate orm event-listener


【解决方案1】:

这样做

public class PreInsertListener implements PreInsertEventListener,  
                                          PreUpdateEventListener 
{
    @Override
    public boolean onPreInsert(PreInsertEvent arg0) {
        if(arg0.getEntity() instanceof City){
            City city = (City)arg0.getEntity();
            city.setCreated_date(new Date());               
        }
        return false;
    }

    @Override
    public boolean onPreUpdate(PreUpdateEvent arg0) {
         if(arg0.getEntity() instanceof City){
            City city = (City)arg0.getEntity();
            city.setCreated_date(new Date());                
        }
        return false;
    }
}

【讨论】:

  • 它不起作用。现在整个记录没有插入数据库。
  • 我已经添加了我的答案。通过这种方式,它对我有用。谢谢。
【解决方案2】:

我最近在集成 Spring4 和 Hibernate5 时遇到了同样的问题。 这是我的 BaseEntity 类。

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

然后,你应该注册实体事件监听器。

@SuppressWarnings("unchecked")
@Component
public class EntityEventListenerRegistry {

    @Autowired
    private SessionFactory sessionFactory;

    /**
     * EventListenerRegistry:http://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html#annotations-jpa-entitylisteners
     */
    @PostConstruct
    public void registerListeners(){
        EventListenerRegistry eventListenerRegistry = ((SessionFactoryImplementor) sessionFactory).getServiceRegistry().getService(EventListenerRegistry.class);
        eventListenerRegistry.prependListeners(EventType.PRE_INSERT, EntityListener.class);
        eventListenerRegistry.prependListeners(EventType.PRE_UPDATE, EntityListener.class);
    }

}

效果很好,希望对你有帮助。

【讨论】:

  • 虽然此代码可能会回答问题,但提供有关它如何和/或为什么解决问题的额外上下文将提高​​答案的长期价值。
  • @thewaywewere 此链接可能会有所帮助。 stackoverflow.com/questions/44602299/…
【解决方案3】:

我创建了 Interceptor,使用 Hibernate EmptyInterceptor 对其进行了扩展。
覆盖方法onSave(),保存对象时调用,对象尚未保存到数据库中,onFlushDirty()更新对象时调用,对象尚未更新到数据库中。
在这个函数中,我通过名称检查了我的方法,我必须在创建或更新时设置日期。
这是 onFlushDirty() 方法的示例代码。

public boolean onFlushDirty(Object entity,Serializable id,Object[] currentState, 
                  Object[] previousState,String[] propertyNames, Type[] types) 
{

    if ( entity instanceof City ) {

        for ( int i=0; i < propertyNames.length; i++ ) {
            if ( "lastUpdatedOn".equals( propertyNames[i] ) ) {
                currentState[i] = new Date();
                return true;
            }
        }
    }
    return false;
}  

这里lastUpdatedOn 是我设置更新记录日期的方法名称。

onSave() 方法:

public boolean onSave(Object entity, Serializable id, Object[] state,   
                     String[] propertyNames, Type[] types)   
{
    if ( entity instanceof City) {

        for ( int i=0; i<propertyNames.length; i++ ) {
            if ( "createdOn".equals( propertyNames[i] ) ) {
                state[i] = new Date();
                return true;
            }
        }
    }
    return false;
}

这里createdOn 是设置记录创建日期的方法。

用这个拦截器类扩展你的 POJO 类。

【讨论】:

  • 我有一个问题,如果联系人有地址并且地址被修改但不是联系人。将获得地址 onFlushDirty 方法,因此我可以修改其日期,但我也想修改父(联系人)lastUpdatedOn。有什么建议吗?
  • @SantoshGiri 此解决方案适用于特定对象。对于相关对象,您需要单独调用父对象上的更新
  • @YagneshAgola 让我感到困惑,如果 Contact 已设置
    并且我在现有(加载的联系人)中添加新地址并且当我更新联系人时,这是否意味着地址和联系人都是脏的还是只有地址?
猜你喜欢
  • 2015-04-05
  • 2013-08-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-06
  • 2012-01-26
相关资源
最近更新 更多