我想写一个像这样的方法<T> T getOrCreate(Class<T> klass, Object primaryKey)
这并不容易。
一种幼稚的方法是做这样的事情(假设该方法在事务中运行):
public <T> T findOrCreate(Class<T> entityClass, Object primaryKey) {
T entity = em.find(entityClass, primaryKey);
if ( entity != null ) {
return entity;
} else {
try {
entity = entityClass.newInstance();
/* use more reflection to set the pk (probably need a base entity) */
return entity;
} catch ( Exception e ) {
throw new RuntimeException(e);
}
}
}
但在并发环境中,此代码可能会由于某些争用条件而失败:
T1: BEGIN TX;
T2: BEGIN TX;
T1: SELECT w/ id = 123; //returns null
T2: SELECT w/ id = 123; //returns null
T1: INSERT w/ id = 123;
T1: COMMIT; //row inserted
T2: INSERT w/ name = 123;
T2: COMMIT; //constraint violation
而且,如果您正在运行多个 JVM,则同步将无济于事。如果不获得表锁(这非常可怕),我真的看不出你如何解决这个问题。
在这种情况下,我想知道是否最好先系统地插入并处理可能的异常以执行后续选择(在新事务中)。
您可能应该添加一些有关上述约束(多线程?分布式环境?)的详细信息。