java – 当我有Spring管理的Hibernate事务时如何启用Hibernate Interceptor?

前端之家收集整理的这篇文章主要介绍了java – 当我有Spring管理的Hibernate事务时如何启用Hibernate Interceptor?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

如果我与@Cascade(CascadeType.SAVE_UPDATE)有@OneToMany关系如下

public class One {

    private Integer id;

    private List

很多课

public class Many {

    private Integer id;

    /**
      * required no-arg constructor
      */ 
    public Many() {}

    public Many(Integer uniqueId) {
        this.id = uniqueId
    }

    /**
      * Without @GeneratedValue annotation
      * Hibernate will use assigned Strategy
      */ 
    @Id
    public Integer getId() {
        return this.id;
    }

}

如果我有以下场景

One one = new One();

/**
  * generateUniqueId method will Take care of assigning unique id for each Many instance
  */
one.getManyList().add(new Many(generateUniqueId()));
one.getManyList().add(new Many(generateUniqueId()));
one.getManyList().add(new Many(generateUniqueId()));
one.getManyList().add(new Many(generateUniqueId()));

我打电话给

sessionFactory.getCurrentSession().save(one);

继续之前

根据Transitive persistence Hibernate参考文档,您可以看到

If a parent is passed to save(),update() or saveOrUpdate(),all children are passed to saveOrUpdate()

好.现在让我们看看Java Persistence With Hibernate一书中有关saveOrUpdate方法内容

Hibernate queries the MANY table for the given id,and if it is found,Hibernate updates the row. If it is not found,insertion of a new row is required and done.

哪个可以翻译

INSERT INTO ONE (ID) VALUES (?)

/**
  * I have four Many instances added To One instance
  * So four select-before-saving
  *
  * I DO NOT NEED select-before-saving 
  * Because i know i have a Fresh Transient instance
  */
SELECT * FROM MANY WHERE MANY.ID = ?
SELECT * FROM MANY WHERE MANY.ID = ?
SELECT * FROM MANY WHERE MANY.ID = ?
SELECT * FROM MANY WHERE MANY.ID = ?

INSERT INTO MANY (ID,ONE_ID) VALUES (?,?)
INSERT INTO MANY (ID,?)

任何解决方法避免选择之前保存???是的,你也可以

>添加@Version列(未应用)
>实现Hibernate拦截器提供的isTransient方法(我有选项)

因此,当使用这种级联时,为了避免选择保存前的默认行为,我通过将Hibernate Interceptor分配给一个Hibernate Session来改进我的代码,Hibernate Session的Transaction由Spring管理.

这是我的存储库

之前(没有任何Hibernate拦截器):它工作正常!

@Repository
public class SomeEntityRepository extends AbstractRepository

之后(使用Hibernate Inteceptor):出现问题(没有执行SQL查询 – 无论是INSERT还是SELECT-BEFORE-SAVING)

@Repository
public class SomeEntityRepository extends AbstractRepository

我的问题是:为什么Spring在使用Hibernate拦截器时不会持久保存我的实体及其关系,我该怎么办才能解决这个问题呢?

最佳答案
Spring维护当前会话和当前事务之间的关联(参见SessionFactoryUtils.java.)由于已经存在与当前DAO方法调用相关联的会话,因此您必须使用此会话,或者参与处理黑暗的细节将新会话与先前的事务上下文相关联.这可能是可能的,但风险很大,绝对不推荐.在休眠状态下,如果你已经打开了一个会话,那么就应该使用它.

话虽如此,您可能会为您创建一个新会话并将其与当前事务上下文相关联.使用SessionFactoryUtils.getNewSession(SessionFactory,Interceptor).如果你使用它而不是hibernate的sessionFactory,那么这应该保持与事务的关联.

最初,您可以直接在DAO中编写代码.当它经过试验和测试并希望能够正常工作时,您可以采取措施将弹簧代码移出DAO,例如使用AOP向add()方法添加建议,以创建和清理新会话.

另一种选择是使用全局拦截器.即使它是全局的,你也可以赋予它本地可控的行为. TransientInterceptor包含threadLocal< Boolean>.这是当前线程的标志,用于指示拦截器是否应为isTransient返回true.您在add()方法的开头将其设置为true,并在结束时将其清除.例如.

   class TransientInterceptor extends EntityInterceptor {
      ThreadLocal

然后在你的DAO中:

@Override
public void add(SomeEntity instance) {
   try {
       TransientInterceptor.set(true);
       sessionFactory.getCurrentSession().save(instance);
   }
   finally {
      TransientInterceptor.set(false);   
   }
}

然后,您可以将TransientInterceptor设置为SessionFactory上的全局拦截器(例如,LocalSessionfactorybean).为了减少这种侵入,您可以创建一个AOP周围的建议,以便在适当的情况下将此行为应用于所有DAO添加方法.

原文链接:https://www.f2er.com/spring/432424.html

猜你在找的Spring相关文章