1. 程式人生 > >spring事務(Transaction )報 marked as rollback-only異常的原因及解決方法

spring事務(Transaction )報 marked as rollback-only異常的原因及解決方法

很多朋友在使用spring+hibernate或mybatis等框架時經常遇到報Transaction rolled back because it has been marked as rollback-only的異常,這個異常是怎麼造成的

呢,下面將給大家進行詳細的分析。

    這是專門寫的一個造成該異常的程式碼:

  1. @Transactional
  2. public void add(OperateLog entity)
    throws Exception
    {
  3. // TODO Auto-generated method stub
  4. operateLogDao.add(entity);
  5. }
  1. @Transactional
  2. public
    void save(Member member) throws Exception
    {
  3. memberDao.add(member);
  4. }
  5. @Transactional
  6. public void add(Member member)
    throws Exception
    {
  7. try {
  8. this.save(member);
  9. /*
  10. * 日誌的title長度為10 我把值設定為add111111111111111111是為了造成異常
  11. */
  12. OperateLog entity = new OperateLog( "add111111111111111111", "1111");
  13. operateLogService.add(entity);
  14. } catch (Exception e) {
  15. e.printStackTrace();
  16. // throw e;
  17. }
  18. }
執行以上程式碼就會報改異常,當我把

//throw e;的註釋//去掉,當我執行後就不會有改異常,只會報標題title太長的異常。如下面提示:

  1. Caused by: com.mysql.jdbc.MysqlDataTruncation: Data truncation: Data too long for column '_title' at row 1
  2. at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java: 4072)
  3. at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java: 4006)
  4. at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java: 2468)
  5. at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java: 2629)
  6. at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java: 2719)
  7. at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java: 2155)
  8. at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java: 2450)
  9. at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java: 2371)
  10. at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java: 2355)
  11. at org.apache.commons.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java: 105)
  12. at org.apache.commons.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java: 105)
  13. at org.hibernate.id.IdentityGenerator$GetGeneratedKeysDelegate.executeAndExtract(IdentityGenerator.java: 94)
  14. at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java: 57)

通過以上的問題我們可以發現。在spring中,在事務方法中呼叫多個事務方法時,spring將會把這些事務合二為一。當整個方法中每個子方法沒報錯時,整個方法執行完才提交事務(大家可以使用debug測試),如果某個子方法有異常, spring將該事務標誌為rollback only。如果這個子方法沒有將異常往上整個方法丟擲或整個方法未往上丟擲,那麼改異常就不會觸發事務進行回滾,事務就會在整個方法執行完後就會提交,這時就會造成Transaction rolled back because it has been marked as rollback-only的異常,就如上面程式碼中未拋throw e 一樣。如果我們往上拋了改異常,spring就會獲取異常,並執行回滾。