JPA - 在persist()之后返回自动生成的ID
Posted
技术标签:
【中文标题】JPA - 在persist()之后返回自动生成的ID【英文标题】:JPA - Returning an auto generated id after persist() 【发布时间】:2012-04-01 17:05:18 【问题描述】:我正在使用 JPA (EclipseLink) 和 Spring。假设我有一个带有自动生成 ID 的简单实体:
@Entity
public class ABC implements Serializable
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
// ...
在我的 DAO 类中,我有一个在此实体上调用 persist()
的插入方法。我希望该方法返回为新实体生成的 ID,但是当我对其进行测试时,它会返回 0
。
public class ABCDao
@PersistenceContext
EntityManager em;
@Transactional(readOnly=false)
public int insertABC(ABC abc)
em.persist(abc);
// I WANT TO RETURN THE AUTO-GENERATED ID OF abc
// HOW CAN I DO IT?
return abc.id; // ???
我还有一个包装 DAO 的服务类,如果这有影响的话:
public class ABCService
@Resource(name="ABCDao")
ABCDao abcDao;
public int addNewABC(ABC abc)
return abcDao.insertABC(abc);
【问题讨论】:
类似,可以参考***.com/q/3328813/366964 感谢您的回答。作为一个棘手的解决方案(不是 JPA),我们可以使用另一个唯一的 id,比如 unix 时间戳。 When does the JPA set a @GeneratedValue @Id的可能重复 请参考下面的链接,貌似是同一个问题***.com/questions/9732453/… 【参考方案1】:ID 只保证在刷新时生成。持久化实体只会使其“附加”到持久化上下文。因此,要么显式刷新实体管理器:
em.persist(abc);
em.flush();
return abc.getId();
或者返回实体本身而不是它的 ID。当事务结束时,会发生flush,事务外实体的用户将因此看到实体中生成的ID。
@Override
public ABC addNewABC(ABC abc)
abcDao.insertABC(abc);
return abc;
【讨论】:
注意:这需要用@GeneratedValue
注释 id 字段 - 无论需要什么
您能否解释一下尝试使用复合 ID ***.com/questions/31362100/…实现这一目标时遇到的问题
在持久化后手动刷新是否有性能损失(或任何其他负面影响)?
是的,如果事务最终被回滚,则存在不必要的数据库往返,如果持久实体(或其他刷新的实体)尚未处于有效状态,则可能出现异常。序列或 uuid 生成器更简单、更高效,并且不存在这些问题,因为 ID 是在实体写入数据库之前生成和分配的。
@JBNizet,您需要返回实例还是传递的引用仍然有效?我的意思是,insertABC
会创建一个新对象吗?还是修改旧的?【参考方案2】:
em.persist(abc);
em.refresh(abc);
return abc;
【讨论】:
这个方法对我不起作用。得到这个错误:javax.persistence.PersistenceException: org.hibernate.HibernateException: 这个实例在数据库中还没有作为一行存在] @rtcarlson,是的,这行不通。如果你正在创建一个新对象,你需要的是em.flush()
而不是em.refresh(abc)
。【参考方案3】:
您也可以使用 GenerationType.TABLE 代替 IDENTITY,后者仅在插入后可用。
【讨论】:
请注意。当我尝试 GenerationType.TABLE 时,它创建了一个名为 hibernate_sequences 的单独表并从 1 重新启动序列。【参考方案4】:我就是这样做的:
EntityManager entityManager = getEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
entityManager.persist(object);
transaction.commit();
long id = object.getId();
entityManager.close();
【讨论】:
在将数据持久保存到表中后,它无法将零作为返回值。在这种情况下,刷新都不起作用..我该怎么办。请提出一种方法...谢谢 @VikrantKashyap 请用小代码发布一个新问题并提及我,以便我看看。【参考方案5】:@Entity
public class ABC implements Serializable
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
检查您的实体类中是否存在@GeneratedValue 表示法。这会告诉 JPA 您的实体属性自动生成的行为
【讨论】:
【参考方案6】:另一个兼容 4.0 的选项:
在提交更改之前,您可以从关联到上下文的集合中恢复新的 CayenneDataObject
对象,如下所示:
CayenneDataObject dataObjectsCollection = (CayenneDataObject)cayenneContext.newObjects();
然后为集合中的每个访问ObjectId
,例如:
ObjectId objectId = dataObject.getObjectId();
最后,您可以在值下进行迭代,通常生成的 ID 将是 getIdSnapshot()
返回的 Map 中的第一个值(对于单个列键),它还包含列名称( s) 与 PK 作为键关联:
objectId.getIdSnapshot().values()
【讨论】:
【参考方案7】:我就是这样做的。你可以试试
public class ABCService
@Resource(name="ABCDao")
ABCDao abcDao;
public int addNewABC(ABC abc)
ABC.setId(0);
return abcDao.insertABC(abc);
【讨论】:
所以每次你在DB上插入一些东西你应该设置那个id?应该有更好的方法,不用你设置 ID 一旦记录被持久化,id由hibernate设置以上是关于JPA - 在persist()之后返回自动生成的ID的主要内容,如果未能解决你的问题,请参考以下文章
怎样用JPA的EntityManager执行原生sql返回ResultSet-CSDN论坛
JPA中,在调用persist()时,数据库自动增长的主键如何处理
javax.persistence.Query.getResultList() 可以返回 null 吗?
DB 列上的 Spring JPA 错误返回与列名相关的错误
jpa遇到的 org.hibernate.PersistentObjectException: detached entity passed to persist异常