如果我与@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拦截器时不会持久保存我的实体及其关系,我该怎么办才能解决这个问题呢?
话虽如此,您可能会为您创建一个新会话并将其与当前事务上下文相关联.使用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添加方法.