如果不在数据库中,则如何在事务范围持久性上下文中找到ID

时间:2018-12-17 14:43:44

标签: jpa transactions

来自Pro JPA的示例:

@Stateless
public class AuditServiceBean implements AuditService {
    @PersistenceContext(unitName = "EmployeeService")
    EntityManager em;

    public void logTransaction(int empId, String action) {
        // verify employee number is valid
        if (em.find(Employee.class, empId) == null) {
            throw new IllegalArgumentException("Unknown employee id");
        }
        LogRecord lr = new LogRecord(empId, action);
        em.persist(lr);
    }
}

@Stateless
public class EmployeeServiceBean implements EmployeeService {
    @PersistenceContext(unitName = "EmployeeService")
    EntityManager em;
    @EJB
    AuditService audit;

    public void createEmployee(Employee emp) {
        em.persist(emp);
        audit.logTransaction(emp.getId(), "created employee");
    }
    // ...
}

文字:

  

即使新创建的Employee尚未在数据库中,   审计Bean可以找到该实体并验证其存在。这有效   因为这两个bean实际上共享相同的持久性   上下文。

据我了解,Id是由数据库生成的。那么,如果尚未提交事务并且尚未生成ID,如何将emp.getId()传递到audit.logTransaction()中?

1 个答案:

答案 0 :(得分:0)

这取决于GeneratedValue的策略。如果您使用诸如Sequence或Table策略之类的东西。通常,持久性提供程序会在调用persist方法后立即将ID分配给实体(它会根据分配大小保留一些ID)。

但是,如果您使用IDENTITY策略ID,则其他提供商可能会采取不同的行动。例如在休眠模式下,如果您使用身份策略,它将立即执行插入语句并填充实体的id字段。

https://thoughts-on-java.org/jpa-generate-primary-keys/说:

  

休眠需要每个管理实体的主键值,并且   因此必须立即执行插入语句。

但是在eclipselink中,如果您使用IDENTITY策略,则ID将在刷新后分配。因此,如果您将冲洗模式设置为自动(或调用冲洗方法),则在持久化后将具有id。

https://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Entities/Ids/GeneratedValue说:

  

使用IDENTITY和其他ID生成之间有区别   策略:只有等到   发生插入-是插入操作导致了   标识符生成。由于实体的插入是   通常将其推迟到提交时间之前,标识符不会   在刷新或提交交易之前可用。

在实现中,UnitOfWorkChangeSet具有新实体的集合,这些实体在插入之前将没有真实身份。

// This collection holds the new objects which will have no real identity until inserted.
    protected Map<Class, Map<ObjectChangeSet, ObjectChangeSet>> newObjectChangeSets;

JPA - Returning an auto generated id after persist()是一个与eclipselink相关的问题。

https://forum.hibernate.org/viewtopic.php?p=2384011#p2384011

有个优点
  

我基本上是指Java Persistence中的一些言论,   冬眠。 Hibernate的API保证在调用save()之后   实体具有分配的数据库标识符。取决于ID   生成器类型,这意味着Hibernate可能必须发出INSERT   调用flush()或commit()之前的语句。这可能导致   回滚时出现问题。页面上有关于此的讨论   Hibernate的Java持久性490。

     

在JPA中,persist()不返回数据库标识符。为了那个原因   原因是可以想象实现会阻碍   标识符的生成,直到刷新或提交时间为止。

     

您的方法目前可能行之有效,但您可能会遇到麻烦   更改ID生成器或JPA实现时(从   休眠到其他事物)。

     

也许这对您来说不是问题,但我只是想提出来。