我对Spring @Transactional
注释产生了误解并持续存在。我正在使用Spring 3.1,JPA和Hibernate。我认为persist意味着,将实体添加到持久化上下文(但是在commit或flush之前不执行任何查询),并且@Transactional
注释意味着,用事务包装方法。
但是,在这个简短的例子中,当执行指针到达时,它会因异常而失败,因为name不能为null(db约束)。
import javax.persistence.EntityManager;
@PersistenceContext
private EntityManager entityManager;
@Transactional
public void test() {
Brand brand = new Brand();
entityManager.persist(brand);
brand.setName("test");
}
如果我交换setName()
和persist()
,一切正常。但是,我不明白为什么反过来没有,因为我认为任何查询都将在方法结束时构建和执行。
有人可以解释一下吗?
答案 0 :(得分:4)
在JPA中,一旦对象传递给persist(),它就会变成“托管”,因为成为托管JPA实现的一部分必须为持久对象生成一个id。
如果id生成基于自动增量(GenerationType.IDENTITY),则需要向db发出insert语句以获取并分配密钥。当id生成基于序列/表时,则由JPA实现管理的id池管理和分配id,在这种情况下,不需要直接插入。
将对象传递给persist()并进行管理后,对其进行的任何更改都必须将持久字段刷新到事务处理中的数据库。在您的情况下,如果id生成为Identity,则必须在插入后执行更新。如果id生成是其他方法,那么单个insert语句就足够了。如果事务被回滚,则根本不应该将SQL发送到数据库。
这是Batoo JPA中的实施。
希望这是有道理的。
答案 1 :(得分:2)
在方法结束时已提交。但是新记录是在持久化的情况下创建的,并且可以抛出任何异常。
在方法结束之前,它仍然可以回滚;我通常使用rollback注释异常。
答案 2 :(得分:0)
持久化执行“插入”查询。事务注释仅用于启动事务,如果发生异常则回滚事务。