詳解Java的MyBatis架構中的交易處理_java

來源:互聯網
上載者:User

一、MyBatis單獨使用時,使用SqlSession來處理事務:

public class MyBatisTxTest {    private static SqlSessionFactory sqlSessionFactory;   private static Reader reader;    @BeforeClass   public static void setUpBeforeClass() throws Exception {     try {       reader = Resources.getResourceAsReader("Configuration.xml");       sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);     } finally {       if (reader != null) {         reader.close();       }     }   }      @Test   public void updateUserTxTest() {     SqlSession session = sqlSessionFactory.openSession(false); // 開啟會話,事務開始          try {       IUserMapper mapper = session.getMapper(IUserMapper.class);       User user = new User(9, "Test transaction");       int affectedCount = mapper.updateUser(user); // 因後面的異常而未執行commit語句       User user = new User(10, "Test transaction continuously");       int affectedCount2 = mapper.updateUser(user2); // 因後面的異常而未執行commit語句       int i = 2 / 0; // 觸發運行時異常       session.commit(); // 提交會話,即事務提交     } finally {       session.close(); // 關閉會話,釋放資源     }   } } 


二、和Spring整合後,使用Spring的交易管理:
一個使用MyBatis-Spring的主要原因是它允許MyBatis參與到Spring的交易管理中。而不是給MyBatis建立一個新的特定的交易管理員,MyBatis-Spring利用了存在於Spring中的DataSourceTransactionManager。
一旦DataSourceTransactionManager配置好了,你可以在Spring中以你通常的做法來配置事務。@Transactional註解和AOP樣式的配置都是支援的。在交易處理期間,一個單獨的SqlSession對象將會被建立和使用。當事務完成時,這個session會以合適的方式提交或復原。
一旦事務建立之後,MyBatis-Spring將會透明的管理事務。在你的DAO或Service類中就不需要額外的代碼了。

1.標準配置
要開啟Spring的交易處理,在Spring的XML設定檔中簡單建立一個DataSourceTransactionManager對象:

<bean id="transactionManager" class="org.springframework.jdbc.datasource   .DataSourceTransactionManager">   <property name="dataSource" ref="dataSource"/> </bean> 

指定的DataSource一般可以是你使用Spring的任意JDBC DataSource。這包含了串連池和通過JNDI尋找獲得的DataSource。
要注意,為交易管理員指定的DataSource必須和用來建立SqlSessionFactoryBean的是同一個資料來源,否則交易管理員就無法工作了。
 
2.容器管理事務
如果你正使用一個JEE容器而且想讓Spring參與到容器管理事務中,那麼Spring應該使用JtaTransactionManager或它的容器指定的子類來配置。做這件事情的最方便的方式是用Spring的事務命名空間:

<tx:jta-transaction-manager/> 

在這種配置中,MyBatis將會和其它由容器管理事務配置的Spring事務資源一樣。Spring會自動使用任意存在的容器事務,在上面附加一個SqlSession。 如果沒有開始事務,或者需要基於事務配置,Spring會開啟一個新的容器管理事務。
注意,如果你想使用容器管理事務,而不想使用Spring的交易管理,你就必須配置SqlSessionFactoryBean來使用基本的MyBatis的ManagedTransactionFactory而不是其它任意的Spring交易管理員: 

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">   <property name="dataSource" ref="dataSource"/>   <property name="transactionFactoryClass">     <value>org.apache.ibatis.transaction.managed.ManagedTransactionFactory"/>   </property> </bean> 

 
3.編程式交易管理
MyBatis的SqlSession提供指定的方法來處理編程式的事務。但是當使用MyBatis-Spring時,bean將會使用Spring管理的SqlSession或映射器來注入。那就是說Spring通常是處理事務的。你不能在Spring管理的SqlSession上調用SqlSession.commit(),SqlSession.rollback()或SqlSession.close()方法。如果這樣做了,就會拋出UnsupportedOperationException異常。注意在使用注入的映射器時不能訪問那些方法。無論串連是否設定為自動認可,SqlSession資料方法的執行或在Spring事務之外任意調用映射器方法都將會自動被提交。下面是一個編程式事務樣本:

DefaultTransactionDefinition def = new DefaultTransactionDefinition(); def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); TransactionStatus status = txManager.getTransaction(def); try{   userMapper.insertUser(user); }catch(MyException ex){   throw ex; } txManager.commit(status); 

4.@Transactional方式:

在類路徑下建立beans-da-tx.xml檔案,在beans-da.xml(系列五)的基礎上加入事務配置:

<!-- 交易管理員 --> <bean id="txManager"   class="org.springframework.jdbc.datasource.DataSourceTransactionManager">     <property name="dataSource" ref="dataSource" /> </bean>  <!-- 事務註解驅動,標註@Transactional的類和方法將具有事務性 --> <tx:annotation-driven transaction-manager="txManager" />  <bean id="userService" class="com.john.hbatis.service.UserService" /> 

服務類:

@Service("userService") public class UserService {    @Autowired   IUserMapper mapper;    public int batchUpdateUsersWhenException() { // 非事務性     User user = new User(9, "Before exception");     int affectedCount = mapper.updateUser(user); // 執行成功     User user2 = new User(10, "After exception");     int i = 1 / 0; // 拋出運行時異常     int affectedCount2 = mapper.updateUser(user2); // 未執行     if (affectedCount == 1 && affectedCount2 == 1) {       return 1;     }     return 0;   }    @Transactional   public int txUpdateUsersWhenException() { // 事務性     User user = new User(9, "Before exception");     int affectedCount = mapper.updateUser(user); // 因後面的異常而復原     User user2 = new User(10, "After exception");     int i = 1 / 0; // 拋出運行時異常,交易回復     int affectedCount2 = mapper.updateUser(user2); // 未執行     if (affectedCount == 1 && affectedCount2 == 1) {       return 1;     }     return 0;   } } 

在測試類別中加入:

@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = { "classpath:beans-da-tx.xml" }) public class SpringIntegrateTxTest {    @Resource   UserService userService;    @Test   public void updateUsersExceptionTest() {     userService.batchUpdateUsersWhenException();   }    @Test   public void txUpdateUsersExceptionTest() {     userService.txUpdateUsersWhenException();   } } 


5.TransactionTemplate方式

在beans-da-tx.xml中添加:

<bean id="txTemplate" class="org.springframework.transaction.support.TransactionTemplate">   <constructor-arg type="org.springframework.transaction.PlatformTransactionManager" ref="transactionManager" /> </bean> 

在UserService類加入:

@Autowired(required = false) TransactionTemplate txTemplate;  public int txUpdateUsersWhenExceptionViaTxTemplate() {   int retVal = txTemplate.execute(new TransactionCallback<Integer>() {      @Override     public Integer doInTransaction(TransactionStatus status) { // 事務操作       User user = new User(9, "Before exception");       int affectedCount = mapper.updateUser(user); // 因後面的異常而復原       User user2 = new User(10, "After exception");       int i = 1 / 0; // 拋出運行時異常並復原       int affectedCount2 = mapper.updateUser(user2); // 未執行       if (affectedCount == 1 && affectedCount2 == 1) {         return 1;       }       return 0;     }        });   return retVal; } 

在SpringIntegrateTxTest類中加入:

@Test public void updateUsersWhenExceptionViaTxTemplateTest() {   userService.txUpdateUsersWhenExceptionViaTxTemplate(); //  } 

註:不可catch Exception或RuntimeException而不拋出:

@Transactional public int txUpdateUsersWhenExceptionAndCatch() { // 事務性操作,但是外圍架構捕獲不到異常,認為執行正確而提交。   try {     User user = new User(9, "Before exception");     int affectedCount = mapper.updateUser(user); // 執行成功     User user2 = new User(10, "After exception");     int i = 1 / 0; // 拋出運行時異常     int affectedCount2 = mapper.updateUser(user2); // 未執行     if (affectedCount == 1 && affectedCount2 == 1) {       return 1;     }   } catch (Exception e) { // 所有異常被捕獲而未拋出     e.printStackTrace();   }   return 0; } 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.