3

我对 Spring@Transactional注释有误解并坚持下去。我正在使用带有 JPA 和 Hibernate 的 Spring 3.1。我认为持久化意味着将实体添加到持久化上下文中(但在提交或刷新之前不要执行任何查询),并且@Transactional注释意味着用事务包装方法。

但是,在这个简短的示例中,当执行指针到达persist 时,它会因异常而失败,因为名称不能为空(db 约束)。

import javax.persistence.EntityManager;

@PersistenceContext
private EntityManager entityManager;

@Transactional
public void test() {
    Brand brand = new Brand();
    entityManager.persist(brand);
    brand.setName("test");
}

如果我交换setName()and persist(),一切正常。但是,我不明白为什么反过来不行,因为我认为任何查询都会在方法结束时构建和执行。

有人可以解释一下吗?

4

3 回答 3

4

在 JPA 中,一旦将对象传递给 persist(),它就会成为“托管”,作为成为托管 JPA 实现的一部分,必须为持久对象生成一个 id。

如果 id 生成基于自增(GenerationType.IDENTITY),则需要向 db 发出插入语句以获取和分配 key。当 id 生成基于序列/表时,id 由 JPA 实现管理的 id 池管理和分配,在这种情况下,不需要直接插入。

将对象传递给 persist() 并已成为托管对象,对它的任何更改都是持久字段,必须在事务的和处刷新到数据库。在您的情况下,如果 id 生成是 Identity,则必须在插入之后进行更新。如果 id 生成是其他方法,那么单个插入语句就足够了。如果事务回滚,则根本不应该将任何 SQL 发送到数据库。

这是Batoo JPA中的实现。

希望这是有道理的。

于 2012-10-05T18:32:32.090 回答
2

由于事务注释,它在方法结束时提交。但是新记录是在持久化时创建的,并且可以抛出任何异常。

在方法结束之前它仍然可以回滚;我通常用回滚来注释异常。

于 2012-10-05T16:03:26.733 回答
0

持久化执行“插入”查询。事务注释仅用于启动事务,如果发生异常则回滚事务。

于 2012-10-05T16:04:07.530 回答