Art*_*ald 6 java performance spring hibernate interceptor
如果我与@Cascade(CascadeType.SAVE_UPDATE)有@OneToMany关系如下
public class One {
private Integer id;
private List<Many> manyList = new ArrayList<Many>();
@Id
@GeneratedValue
public Integer getId() {
return this.id;
}
@OneToMany
@JoinColumn(name="ONE_ID", updateable=false, nullable=false)
@Cascade(CascadeType.SAVE_UPDATE)
public List<Many> getManyList() {
return this.manyList;
}
}
Run Code Online (Sandbox Code Playgroud)
很多课
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;
}
}
Run Code Online (Sandbox Code Playgroud)
如果我有以下场景
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()));
Run Code Online (Sandbox Code Playgroud)
我打电话给
sessionFactory.getCurrentSession().save(one);
Run Code Online (Sandbox Code Playgroud)
继续之前
根据Transitive持久性 Hibernate参考文档,您可以看到
如果父节点传递给save(),update()或saveOrUpdate(),则所有子节点都传递给saveOrUpdate()
好.现在让我们看看Java Persistence With Hibernate一书中有关saveOrUpdate方法的内容
Hibernate 在MANY表中查询给定的id,如果找到,则Hibernate 更新该行.如果未找到,则需要插入新行.
哪个可以翻译
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, ONE_ID) VALUES (?, ?)
INSERT INTO MANY (ID, ONE_ID) VALUES (?, ?)
INSERT INTO MANY (ID, ONE_ID) VALUES (?, ?)
Run Code Online (Sandbox Code Playgroud)
任何解决方法避免选择之前保存??? 是的,你也可以
因此,当使用这种级联时,为了避免选择保存前的默认行为,我通过将Hibernate Interceptor分配给一个Hibernate Session来改进我的代码,Hibernate Session 的Transaction由Spring管理.
这是我的存储库
之前(没有任何Hibernate拦截器):它工作正常!
@Repository
public class SomeEntityRepository extends AbstractRepository<SomeEntity, Integer> {
@Autowired
private SessionFactory sessionFactory;
@Override
public void add(SomeEntity instance) {
sessionFactory.getCurrentSession().save(instance);
}
}
Run Code Online (Sandbox Code Playgroud)
之后(使用Hibernate Inteceptor):出现问题(没有执行SQL查询 - 无论是INSERT还是SELECT-BEFORE-SAVING)
@Repository
public class SomeEntityRepository extends AbstractRepository<SomeEntity, Integer> {
@Autowired
private SessionFactory sessionFactory;
@Override
public void add(SomeEntity instance) {
sessionFactory.openSession(new EmptyInterceptor() {
/**
* To avoid select-before-saving
*/
@Override
public Boolean isTransient(Object o) {
return true;
}
}).save(instance);
}
}
Run Code Online (Sandbox Code Playgroud)
我的问题是:为什么Spring在使用Hibernate拦截器时不会持久保存我的实体及其关系,我该怎么办才能解决这个问题呢?
Spring 维护当前会话和当前事务之间的关联(请参阅SessionFactoryUtils.java。)由于已经有一个与当前 DAO 方法调用关联的会话,因此您必须使用此 Session,或者冒险涉足模糊的领域。将新会话与先前事务上下文关联的详细信息。这可能是可能的,但风险相当大,绝对不推荐。在休眠中,如果您已经打开了一个会话,那么应该使用它。
话虽如此,您也许可以让 spring 为您创建一个新会话并将其与当前事务上下文关联起来。使用SessionFactoryUtils.getNewSession(SessionFactory, Interceptor)。如果您使用它而不是 hibernate 的 sessionFactory,那么这应该保持与事务的关联。
最初,您可以直接在 DAO 中对其进行编码。当它经过尝试和测试并希望发现可以工作时,您可以采取措施将 spring 代码移出 DAO,例如使用 AOP 将建议添加到创建和清理新会话的 add() 方法。
另一种选择是使用全局拦截器。即使它是全局的,您也可以赋予它本地可控的行为。TransientInterceptor 包含一个threadLocal<Boolean>. 这是当前线程的标志,指示拦截器是否应返回 true isTransient。您可以在 add() 方法开始时将其设置为 true ,并在最后将其清除。例如
class TransientInterceptor extends EntityInterceptor {
ThreadLocal<Boolean> transientFlag = new ThreadLocal<Boolean)();
public boolean isTransient() {
return transientFlag.get()==Boolean.TRUE;
}
static public setTransient(boolean b) {
transientFlag.set(b);
}
}
Run Code Online (Sandbox Code Playgroud)
然后在你的 DAO 中:
@Override
public void add(SomeEntity instance) {
try {
TransientInterceptor.set(true);
sessionFactory.getCurrentSession().save(instance);
}
finally {
TransientInterceptor.set(false);
}
}
Run Code Online (Sandbox Code Playgroud)
然后,您可以将 TransientInterceptor 设置为 SessionFactory 上的全局拦截器(例如LocalSessionFactoryBean。)为了减少侵入性,您可以围绕建议创建一个 AOP,以在适当的情况下将此行为应用于所有 DAO 添加方法。
| 归档时间: |
|
| 查看次数: |
5506 次 |
| 最近记录: |