<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean>
建立事務bean,配置數據源屬性html
<tx:annotation-driven transaction-manager="transactionManager" />
事務註解驅動java
@Transactional public void hasTranInsertData() { Book book = new Book(); book.setIsbn("0002"); book.setBookName("java編程思想"); book.setPrice(79); this.bookMapper.insertSelective(book); int i = 1 / 0; }
public void notHasTranInsertData() { Book book = new Book(); book.setIsbn("0003"); book.setBookName("算法導論"); book.setPrice(109); this.bookMapper.insertSelective(book); int i = 1 / 0; }
以上能夠看出上面的數據回滾了,而下面的保存到數據庫了。mysql
REQUIRED | 若是現有的事務正在進行,當前方法應該在這個事務中運行,不然它該啓動新事務,並在本身的十五中運行。 |
REQUIRES_NEW | 當前方法必須啓動新事務,並在本身的事務中運行,若是現有的事務正在進行,它應該掛起。 |
SUPPORTS | 若是現有事務正在進行,當前方法應該運行在該事務中,不然它沒有必要運行在事務中。 |
NOT_SUPPORTED | 當前方法不該該運行在事務中,若是現有事務正在運行,它應該掛起。 |
MANDATORY | 當前方法必須運行於事務中,若是沒有事務在進行中,將拋出一個異常。 |
NEVER | 當前方法不該該運行於事務中,若是現有事務在運行中,將拋出一個異常。 |
NESTED | 若是現有事務正在進行,當前方法應該運行在嵌套的事務中,不然它應該啓動一個新事務並運行在本身的事務之中。 |
例如:算法
@Override @Transactional public void nestedBook() { Book book = new Book(); book.setIsbn("0004"); book.setBookName("分佈式架構"); book.setPrice(89); this.bookMapper.insertSelective(book); for (int i = 0; i < 10; i ++) { try { this.testService1.nestedAccount(i + 2); } catch (Exception e) { e.printStackTrace(); } } }
@Override @Transactional(propagation=Propagation.NESTED) public void nestedAccount(int i) { System.out.println(i); Account account = new Account(); account.setUsername("user" + i); account.setBalance(new Random().nextInt(100)); this.accountMapper.insertSelective(account); if (7 == i) { int j = 1 / 0; } }
這裏一個REQUIRED事務去調用NESTED事務,NESTED特性是在嵌套的事務裏,若是發生異常他只會回滾他本身的事務,而不會影響調用他的事務。spring
他與REQUIRES_NEW的區別是,前面方法沒有事務是每次須要建立本身的事務,若是前面有事務時,前面方法若是報錯了會回滾全部操做,而REQUIRES_NEW不會回滾操做。sql
NESTED的好處在於既能保證前者方法拋異常時全部數據能回滾,也能保證後者方法一個拋異常不會影響後續的操做,只會回滾後者操做失敗的數據。數據庫
DEFAULT | 使用底層數據庫的默認隔離級別。對於大部分數據庫,默認隔離級別是READ_COMMITED,mysql是REPEATABLE_READ |
READ_UNCOMMITED | 容許事務讀取其餘事務的未提交修改。可能發生髒讀數據、不可重複讀和幻讀問題。 |
READ_COMMITED | 僅容許事務讀取其餘事務已經提交的修改。可以避免髒讀數據問題,可是不可重複讀和幻讀問題仍然可能發生。 |
REPEATABLE_READ | 確保事務可以屢次從一個字段讀到相同值。在本事務期間,其餘事務的更新被禁止。可以避免髒讀數據和不可重複讀問題,可是幻讀問題仍然可能發生。 |
SERIALIZABLE | 確保一個事務能從表中屢次讀取相同的行。在事務期間,其餘事務作出的對該表插入、更新和刪除將被禁止。能避免全部併發性問題,可是性能將會很低。 |
默認狀況下,只有非受控異常(也就是RuntimeException和Error類型)將致使事務回滾,而受控異常不會。編程
@Override @Transactional public void hasTranInsertData() throws FileNotFoundException, ClassNotFoundException { Book book = new Book(); book.setIsbn("0005"); book.setBookName("java編程思想"); book.setPrice(79); this.bookMapper.insertSelective(book); try { int i = 1 / 0; } catch (Exception e) { throw new FileNotFoundException("錯誤"); } }
嚴重警告:上面的這段代碼是不會回滾的,就由於拋出的異常時受控異常架構
rollbackFor:會發生回滾的異常併發
noRollbackFor:不會發生回滾的異常
將@Transaction變爲下面這樣
@Transactional(rollbackFor=FileNotFoundException.class, noRollbackFor=ClassNotFoundException.class)
改變以後就會進行回滾
若是拋出的異常改成
throw new ClassNotFoundException("錯誤");
則又不會回滾
timeout:表示事務在被強制回滾以前存活的時間。這可以避免長時間的事務佔用資源。
readOnly:表示該事務僅僅讀取而不更新數據。只讀標誌只是讓資源優化事務的一個提醒,若是試圖寫入,資源不必定會發生故障。