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



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");
}
// ...
}

文本:

即使新创建的员工尚未在数据库中auditbean可以找到实体并验证它是否存在。这是有效的因为这两个bean实际上共享相同的持久性上下文

据我所知,Id是由数据库生成的。那么,如果事务还没有提交,id还没有生成,那么如何将emp.getId((传递到audit.logTransaction((中呢?

这取决于GeneratedValue的策略。如果您使用序列或表格策略。通常,持久性提供程序在调用持久性方法后立即将id分配给实体(它有一些基于分配大小的保留id(。

但如果您使用IDENTITY策略id,不同的提供者可能会采取不同的行动。例如,在hibernate中,如果使用Identity策略,它会立即执行insert语句并填充实体的id字段。

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

Hibernate要求每个托管实体都有一个主键值,并且因此必须立即执行insert语句。

但在eclipselink中,如果使用IDENTITY策略,id将在刷新后分配。因此,如果您将flush模式设置为auto(或调用flush方法(,那么在持久化之后您将拥有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-在persist((之后返回自动生成的id是一个与eclipselink有关的问题。

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

我基本上是指Java Persistence中的一些注释冬眠Hibernate的API保证在调用save((之后实体具有指定的数据库标识符。取决于id生成器类型,这意味着Hibernate可能必须发出INSERT调用flush((或commit((之前的语句。这可能导致回滚时出现问题。第页对此进行了讨论490的Java Persistence with Hibernate。

在JPA中,persist((不返回数据库标识符。为此人们可以想象一个实现阻碍生成标识符,直到刷新或提交时间。

你的方法目前可能还可以,但你可能会遇到麻烦当更改id生成器或JPA实现时(从休眠到其他状态(。

也许这对你来说不是问题,但我只是觉得我提出来了。

最新更新