使用Spring Data JPA检索数据上下文更改

时间:2014-03-09 10:58:29

标签: spring hibernate jpa spring-data unit-of-work

在我的应用程序中,我需要检索每个事务的新,更新和删除实体的列表。像这样:

// useful functionality
@Transactional
public void createNewBlogPost(int userId, String title, String text) {
  Post post = new Post();
  post.title = title; // "hello"
  post.text = text; // "there"
  postRepository.save(post);
  // more work with JPA repositories here
}
...
// gets called right after createNewBlogPost()
public void onTransaction(UnitOfWork uow) {
  List<?> newEntities = uow.getNewEntities();
  assertEquals(1, newEntities.size()); // 1 new entity

  Object firstNewEntity = newEntities.get(0);
  assertTrue(firstNewEntity instanceof Post); // this new entity
                                              // is a Post

  Post newPost = (Post)firstNewEntity;
  assertEquals("hello", newPost.title);
  assertEquals("there", newPost.text);
}

我设法找到的最相关的东西是Spring提供的审核功能,其中包含@CreatedBy@CreatedDate@LastModifiedBy@LastModifiedDate等注释。虽然它在技术上非常接近,但它并不是我想要实现的目标。

Spring Data JPA是否提供了一种机制来检索每个单个事务的数据更改?

2 个答案:

答案 0 :(得分:1)

由于您的用例是Hibernate和JPA特定的,因此您应该查看Hibernate EnversSpring Data Envers。他们可能会给你一些想法,但要小心:项目本身,我不确定他们是否活跃。

答案 1 :(得分:0)

我花了一些时间进行研究,并设法找到一个相对简单的Hibernate特定解决方案。基本上有两个问题需要解决:

  1. 拦截数据更改事件。
  2. 按要求进行。
  3. 要解决第1页问题,可以使用EventListenerRegistry。这是一个例子:

    @Component
    public class HibernateListenersConfigurer {
        @Autowired
        private EntityManagerFactory entityManagerFactory;
    
        @Autowired
        private HibernateListeners hibernateListeners;
    
        @PostConstruct
        public void init() {
            HibernateEntityManagerFactory hibernateEntityManagerFactory =
                    (HibernateEntityManagerFactory)entityManagerFactory;
            SessionFactoryImpl sessionFactoryImpl =
                    (SessionFactoryImpl)hibernateEntityManagerFactory.getSessionFactory();
            EventListenerRegistry eventListenerRegistry = sessionFactoryImpl.
                    getServiceRegistry().
                    getService(EventListenerRegistry.class);
    
            eventListenerRegistry.appendListeners(EventType.PRE_INSERT, hibernateListeners);
            eventListenerRegistry.appendListeners(EventType.PRE_UPDATE, hibernateListeners);
            eventListenerRegistry.appendListeners(EventType.PRE_DELETE, hibernateListeners);
        }
    }
    

    hibernateListeners对象获取所有这些事件,并且可以执行审计它们所需的任何操作。这是一个例子:

    @Component
    public class HibernateListeners implements 
            PreInsertEventListener, 
            PreUpdateEventListener, 
            PreDeleteEventListener {
    
        @Autowired
        private ChangeTracker changeTracker;
    
        @Override
        public boolean onPreInsert(PreInsertEvent event) {
            // event has a bunch of relevant details
            changeTracker.trackChange(event);    
            return false;
        }
        ...other listeners here...
    

    然后,为了解决p.2,上面看到的changeTracker是一个请求范围的bean:

    @Component
    @Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
    public class ChangeTracker {
        // a sort of "Unit of Work"
        private List<Change> changes = new ArrayList<Change>();
    
        public void trackChange(PreInsertEvent event) {
            changes.add(makeChangeFromEvent(event));
        }
    
        public void handleChanges() {
            // Do whatever needed :-)
        }
    }
    

    然后,在请求处理完成后,几乎没有可用的选项可以最终调用handleChanges():手动调用它,使用HandlerInterceptor,使用过滤器,使用AOP。 HandlerInterceptor和过滤器不是很好,因为在我的情况下,它们在响应已经发送到客户端后被调用,这导致“业务数据”和“更改数据”之间的不一致。我最终切换到AOP,似乎工作正常。

    这是一个游乐场:https://github.com/loki2302/spring-change-tracking-experiment