Hibernate在catch块中插入

时间:2014-08-17 17:58:02

标签: java hibernate

我正在使用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

关于可以做些什么的任何想法?

3 个答案:

答案 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服务中。所以你有一个:

  1. SimService.insert(Sim sim);
  2. NotificationService.error(ErrorMessage message);
  3. 两种方法都是@Transactional,所以如果第一种方法失败并出现异常,你的控制器就可以调用NotificationService。

答案 1 :(得分:0)

问题在于交易处理。虽然从您的代码中看不到它,但要插入SIM记录,您需要开始一个事务。现在,由于发生了错误,此事务将回滚。您需要在单独的事务中编写日志语句。因此在catch块中,您需要启动新事务,编写日志并提交事务,而不触及上一个事务的事务状态。因此,您无法使用相同的休眠会话。

答案 2 :(得分:0)

首先,正如其他答案所指出的那样,请使用交易,回滚等。 为了更好地理解,请阅读有关Container Managed次交易和bean managed次交易的信息。 Vald的代码应该有所帮助。

旁注,

  1. 您应该使用finally块来清理您似乎缺少的资源。

  2. 您似乎使用@GET插入数据。我假设你刚刚写了这个以方便这个SO问题。如果没有,简要介绍REST和HTTP方法应该有所帮助。

  3. 为了更好地理解和维护这段代码几年后,我建议您在两个不同的方法/位置中分离“普通插入”和“异常插入”语句。因此,在这两种情况下,您似乎都会返回“OK”。如果它们位于不同的地方,可能最好将它们分开(正常和特殊情况)。