abo*_*sun 8 java aop spring hibernate jpa
我发现,在相对简单的例子真是奇怪的行为,可能是我无法理解,因为春天@Transactional自然不深的知识,但是这是很有趣的.
我有简单的User dao,它扩展了spring JpaDaoSupport类并包含标准的save方法:
@Transactional
public User save(User user) {
getJpaTemplate().persist(user);
return user;
}
Run Code Online (Sandbox Code Playgroud)
如果工作正常,直到我已经添加新的方法,以同一类:用户getSuperUser(),这个方法应该isAdmin返回用户== true,并且如果在数据库没有超级用户,此方法应该创建一个.那是它的样子:
public User createSuperUser() {
User admin = null;
try {
admin = (User) getJpaTemplate().execute(new JpaCallback() {
public Object doInJpa(EntityManager em) throws PersistenceException {
return em.createQuery("select u from UserImpl u where u.admin = true").getSingleResult();
}
});
} catch (EmptyResultDataAccessException ex) {
User admin = new User('login', 'password');
admin.setAdmin(true);
save(admin); // THIS IS THE POINT WHERE STRANGE THING COMING OUT
}
return admin;
}
Run Code Online (Sandbox Code Playgroud)
正如你所看到的代码是奇怪向前时发现,没有交易被创建,并承诺在保存(管理)方法的调用,并没有新的用户实际上并没有,尽管@Transactional注解创建我感到很困惑.
在结果,我们有情况:当save()方法从UserDAO的类之外调用 - 计@Transactional注解的用户成功创建和,但如果保存()从同一个DAO类的其他方法的调用内 - @Transactional注解忽略.
这里我是如何更改save()方法来强制它始终创建事务.
public User save(User user) {
getJpaTemplate().execute(new JpaCallback() {
public Object doInJpa(EntityManager em) throws PersistenceException {
em.getTransaction().begin();
em.persist(user);
em.getTransaction().commit();
return null;
}
});
return user;
}
Run Code Online (Sandbox Code Playgroud)
如您所见,我手动调用begin和commit.有任何想法吗?
@Transactional
仅考虑来自对象外部的调用.对于内线电话,它不是.要解决这个问题,只需添加@Transactional
到您的入口点即可.@Transactional
用于DAO - 而是在Service类上使用它.我认为带有注释的声明性事务是在代理的基础上实现的.
如果通过动态代理访问DAO,它会检查是否有注释并用事务包装它.
如果你从班级内部打电话给你的班级,就无法拦截这个电话.
要避免此问题,您也可以使用注释标记createSuperuser方法.