我正在使用Jax-Rs Web服务和hibernate。我正在进行插入,如果插入失败,我应该捕获异常并在数据库中写入日志。这是下面的代码
@PersistenceContext(unitName = "primary")
private EntityManager em;
@GET
@Produces("application/json")
@Path("/siminsert")
public String testSimInsert()
{
try
{
Query query = em.createNativeQuery("insert into sim(iccid, imsi, msisdn, state) values ('890000000000010000512223334', '001010000100004', '50100005', 'A')");
query.executeUpdate();
}
catch(Exception ex)
{
Query query1 = em.createNativeQuery("insert into notifications(message) values ('An error occured')");
query1.executeUpdate();
}
return "OK";
}
使用此代码,第一个插入将失败,因为我们在iccid字段中插入了多个允许的字符。我希望能够通过在通知表中执行插入来记录该错误,如代码所示,但我收到错误:
javax.persistence.TransactionRequiredException: Executing an update/delete query
关于可以做些什么的任何想法?
答案 0 :(得分:0)
第一个问题是您没有打开事务,这对于DML操作(UPDATE / INSERT / DELETE)是必需的:
每当Hibernate Session操作抛出异常时,您必须丢弃当前Session并重新开始。这是因为失败的操作可能使Session处于不一致状态。
您可以做的是放弃所有更改:
em.clear();
并运行第二个查询。确保您使用2笔交易。如果一个失败,则从一个新的一个开始插入通知表。
EntityTransaction tx = null;
try {
tx = em.getTransaction();
tx.begin();
Query query = em.createNativeQuery("insert into sim(iccid, imsi, msisdn, state) values ('890000000000010000512223334', '001010000100004', '50100005', 'A')");
query.executeUpdate();
tx.commit();
}
catch(Exception ex) {
if(tx != null) {
tx.rollback();
em.clear();
try {
tx.begin();
Query query1 = em.createNativeQuery("insert into notifications(message) values ('An error occured')");
query1.executeUpdate();
tx.commit();
} catch(Exception ex) {
tx.rollback();
}
}
}
finally {
em.close();
}
更好的方法是将所有业务逻辑封装在@Transactional服务中。所以你有一个:
两种方法都是@Transactional,所以如果第一种方法失败并出现异常,你的控制器就可以调用NotificationService。
答案 1 :(得分:0)
问题在于交易处理。虽然从您的代码中看不到它,但要插入SIM记录,您需要开始一个事务。现在,由于发生了错误,此事务将回滚。您需要在单独的事务中编写日志语句。因此在catch块中,您需要启动新事务,编写日志并提交事务,而不触及上一个事务的事务状态。因此,您无法使用相同的休眠会话。
答案 2 :(得分:0)
首先,正如其他答案所指出的那样,请使用交易,回滚等。 为了更好地理解,请阅读有关Container Managed次交易和bean managed次交易的信息。 Vald的代码应该有所帮助。
旁注,
您应该使用finally块来清理您似乎缺少的资源。
您似乎使用@GET插入数据。我假设你刚刚写了这个以方便这个SO问题。如果没有,简要介绍REST和HTTP方法应该有所帮助。
为了更好地理解和维护这段代码几年后,我建议您在两个不同的方法/位置中分离“普通插入”和“异常插入”语句。因此,在这两种情况下,您似乎都会返回“OK”。如果它们位于不同的地方,可能最好将它们分开(正常和特殊情况)。