2016-02-04 44 views
0

我有理解EJBTransactionRolledbackException問題。追趕EJBTransactionRolledbackException

我有實體:

@Entity 
public class MyEntity { 

    @Id 
    @GeneratedValue 
    private Long id; 
    @Size(max=5) 
    private String name; 
//... 
} 

和資源庫這是因爲易於CMT的SLSB:

@Stateless 
public class ExampleRepository { 
    @PersistenceContext 
    private EntityManager em; 

    public void add(MyEntity me) { 
     em.persist(me); 
    } 
} 

現在我測試的Servlet,當我模擬ConstraintViolation(太長名)。

@WebServlet("/example") 
public class ExampleServlet extends HttpServlet { 
    @Inject 
    private ExampleRepository repo; 

    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
      throws ServletException, IOException { 
     MyEntity me = new MyEntity(); 
     me.setName("TooLongName"); 
     try { 
      repo.add(me); 
     } catch(EJBTransactionRolledbackException e) { 
      System.out.println("Exception caught"); 
     } 
    } 
} 

我知道在這種情況下,EJB容器會包裝ConstraintViolationException,因此我會捕獲EJBTransactionRolledbackException。問題是,在控制檯中,我可以看到來自catch塊的消息(「異常被捕獲」),但在此之前有大量異常日誌產生(link)。 我不太明白髮生了什麼 - 這個異常是否被捕獲?如何在這種簡單的情況下防止控制檯中的所有這些錯誤消息?

回答

2

請看看這樣的解釋:A clear explanation of system exception vs application exception

你必須明白,處理異常和處理事務是兩件不同的事情發生寧一起。 系統異常無條件觸發事務回滾。當你看到一個ConstraintViolationException,這是一個系統異常,因爲它延伸了RuntimeException,它不僅僅是包裝和重新投擲。一路上發生了一件壞事 - 你的交易已被中止。

所以,在回答第一個問題,如果該異常(ConstraintViolationException)被抓了 - 是的,它是由容器抓住了。該事務被中止,並拋出一個新異常來通知應用程序代碼。

您可以抑制記錄這些信息,但你不會知道數據持久性故障。

0

我可以建議你兩個解決方案:

  1. 使用bean管理的事務:

    @Stateless 
    @TransactionManagement(TransactionManagementType.BEAN) 
    public class ExampleRepository { 
        @PersistenceContext(synchronization = SynchronizationType.UNSYNCHRONIZED)) 
        private EntityManager em; 
    
        @Resource 
        private UserTransaction tx; 
    
        public void add(MyEntity me) { 
         try { 
          tx.begin(); 
          em.joinTransaction(); 
          em.persist(me); 
          tx.commit(); 
         } catch (ValidationException ex) { 
          throw new AppValidationException(ex); 
         } 
        } 
    } 
    
  2. 代表/門面模式:

    您留下您的ExampleRepository的是:

    @Stateless 
    public class ExampleRepository { 
        @PersistenceContext 
        private EntityManager em; 
    
        public void add(MyEntity me) { 
         em.persist(me); 
        } 
    } 
    

    沒有事務創建新的EJB(以相同的方法,初始):

    @Stateless 
    @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED) 
    public class ExampleRepositoryDelegate { 
        @EJB 
        private ExampleRepository repository; 
    
        public void add(MyEntity me) { 
         try { 
          repository.add(me); 
         } catch (ValidationException e) { 
          e.printStackTrace(); 
         } 
        } 
    } 
    

    而在servlet的使用新的委託豆:

    @WebServlet("/example") 
    public class ExampleServlet extends HttpServlet { 
        @Inject 
        private ExampleRepositoryDelegate repoDelegate; 
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) 
          throws ServletException, IOException { 
         MyEntity me = new MyEntity(); 
         me.setName("TooLongName"); 
         try { 
          repoDelegate.add(me); 
         } catch(Exception e) { 
          System.out.println("Exception caught"); 
         } 
        } 
    } 
    
+0

其實我知道可能的解決方案,但我不明白爲什麼在我的方案中的異常似乎被捕獲,但控制檯顯示這麼多的日誌,所以它看起來像它沒有被捕獲 – swch

+0

日誌中的消息是由容器寫的交易協調器組件'arjuna'。看看:* WARN ARJUNA012125:TwoPhaseCoordinator.beforeCompletion - SynchronizationImple *失敗。容器報告它已經捕獲系統異常並中止事務。 – nolexa