spring+mybatis之注解式事務管理初識(小實例)


1.上一章,我們談到了spring+mybatis聲明式事務管理,我們在文章末尾提到,在實際項目中,用得更多的是注解式事務管理,這一章將學習一下注解式事務管理的有關知識.注解式事務管理只需要在上一節的小實例上更改兩個文件就好:

  (1)更改spring配置文件applicationContext.xml:

  

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="
     http://www.springframework.org/schema/beans  
     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
     http://www.springframework.org/schema/context  
     http://www.springframework.org/schema/context/spring-context-3.0.xsd    
     http://www.springframework.org/schema/tx   
     http://www.springframework.org/schema/tx/spring-tx-3.0.xsd ">


    <!-- 加載配置文件 -->
    <context:property-placeholder location="config.properties" />
    <!-- 指定spring注解注入層 -->
    <context:component-scan base-package="com.gnc" />
    <!-- 數據庫連接池管理 -->
    <bean id="c3p0DataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
        destroy-method="close">
        <property name="driverClass" value="${db.driverClass}"></property>
        <property name="jdbcUrl" value="${db.jdbcUrl}"></property>
        <property name="user" value="${db.user}"></property>
        <property name="password" value="${db.password}"></property>


        <property name="initialPoolSize" value="${db.initialPoolSize}"></property>

        <!--最大空閑時間,60秒內未使用則連接被丟棄。若為0則永不丟棄。Default: 0 -->
        <property name="maxIdleTime" value="${db.maxIdleTime}"></property>
        <!--連接池中保留的最大連接數。Default: 15 -->
        <property name="maxPoolSize" value="${db.maxPoolSize}"></property>
        <property name="minPoolSize" value="${db.minPoolSize}"></property>

        <!--當連接池中的連接耗盡的時候c3p0一次同時獲取的連接數。Default: 3 -->
        <property name="acquireIncrement" value="${db.acquireIncrement}"></property>
        <!--兩次連接中間隔時間,單位毫秒。Default: 1000 -->
        <property name="acquireRetryDelay" value="${db.acquireRetryDelay}"></property>
        <!--定義在從數據庫獲取新連接失敗后重復嘗試的次數。Default: 30 -->
        <property name="acquireRetryAttempts" value="${db.acquireRetryAttempts}"></property>
        <!--獲取連接失敗將會引起所有等待連接池來獲取連接的線程拋出異常。但是數據源仍有效保留,並在下次調用getConnection()的時候繼續嘗試獲取連接。如果設為true,那么在嘗試 
            獲取連接失敗后該數據源將申明已斷開並永久關閉。Default: false -->
        <property name="breakAfterAcquireFailure" value="${db.breakAfterAcquireFailure}"></property>
    </bean>

    <!-- ================================事務相關控制================================================= -->

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

    <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />

    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="c3p0DataSource" />
        <property name="configLocation" value="MyBatis-Configuration.xml" />
    </bean>


    <bean class="org.mybatis.spring.mapper.MapperFactoryBean">
        <property name="mapperInterface" value="com.gnc.mapper.UserMapper" />
        <property name="sqlSessionFactory" ref="sqlSessionFactory" />
    </bean>
</beans>

  (2)更改UserServiceImpl.java實現類:

  

package com.gnc.serviceImpl;

import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.gnc.dao.UserDao;
import com.gnc.model.User;
import com.gnc.service.UserService;

@Service("userService")
public class UserServiceImpl implements UserService {
    @Autowired
    private UserDao userDao;

    @Transactional(propagation = Propagation.SUPPORTS)
    public int countAll() {
        return this.userDao.countAll();
    }

    @Transactional(propagation = Propagation.REQUIRED , readOnly = false)
    @Override
    public void insertUser(User user) {
        this.userDao.insertUser(user);
        throw new RuntimeException("Error");
    }

    @Transactional(propagation = Propagation.REQUIRED , readOnly = false)
    @Override
    public void update_insert(Map map, User user) {
        this.userDao.updateUser(map);
        this.userDao.insertUser(user);
        throw new RuntimeException("Error");

    }

}

 

2.注解式事務管理相對聲明式事務管理顯得更加靈活,我們只需要在需要進行事務管理的方法或者類前加上@Transactional+相關控制參數即可,部分常用參數如下表:

參 數 名 稱

功 能 描 述

rollbackForClassName

該屬性用於設置需要進行回滾的異常類名稱數組,當方法中拋出指定異常名稱數組中的異常時,則進行事務回滾。例如:

指定單一異常類名稱:@Transactional(rollbackForClassName="RuntimeException")

指定多個異常類名稱:@Transactional(rollbackForClassName={"RuntimeException","Exception"})

noRollbackFor

該屬性用於設置不需要進行回滾的異常類數組,當方法中拋出指定異常數組中的異常時,不進行事務回滾。例如:

指定單一異常類:@Transactional(noRollbackFor=RuntimeException.class)

指定多個異常類:@Transactional(noRollbackFor={RuntimeException.class, Exception.class})

noRollbackForClassName

該屬性用於設置不需要進行回滾的異常類名稱數組,當方法中拋出指定異常名稱數組中的異常時,不進行事務回滾。例如:

指定單一異常類名稱:@Transactional(noRollbackForClassName="RuntimeException")

指定多個異常類名稱:

@Transactional(noRollbackForClassName={"RuntimeException","Exception"})

propagation

該屬性用於設置事務的傳播行為,具體取值可參考表6-7。

例如:@Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true)

isolation

該屬性用於設置底層數據庫的事務隔離級別,事務隔離級別用於處理多事務並發的情況,通常使用數據庫的默認隔離級別即可,基本不需要進行設置

timeout

該屬性用於設置事務的超時秒數,默認值為-1表示永不超時

readOnly

該屬性用於設置當前事務是否為只讀事務,設置為true表示只讀,false則表示可讀寫,默認值為false。例如:@Transactional(readOnly=true)

rollbackFor

該屬性用於設置需要進行回滾的異常類數組,當方法中拋出指定異常數組中的異常時,則進行事務回滾。例如:

指定單一異常類:@Transactional(rollbackFor=RuntimeException.class)

指定多個異常類:@Transactional(rollbackFor={RuntimeException.class, Exception.class})

 

需要注意的幾點:

1 @Transactional 只能被應用到public方法上, 對於其它非public的方法,如果標記了@Transactional也不會報錯,但方法沒有事務功能.

2用 spring 事務管理器,由spring來負責數據庫的打開,提交,回滾.默認遇到運行期例外(throw new RuntimeException("注釋");)會回滾,即遇到不受檢查(unchecked)的例外時回滾;而遇到需要捕獲的例外(throw new Exception("注釋");)不會回滾,即遇到受檢查的例外(就是非運行時拋出的異常,編譯器會檢查到的異常叫受檢查例外或說受檢查異常)時,需我們指定方式來讓事務回滾 要想所有異常都回滾,要加上 @Transactional( rollbackFor={Exception.class,其它異常}) .如果讓unchecked例外不回滾: @Transactional(notRollbackFor=RunTimeException.class)
如下:
@Transactional(rollbackFor=Exception.class) //指定回滾,遇到異常Exception時回滾
public void methodName() {
throw new Exception("注釋");

}
@Transactional(noRollbackFor=Exception.class)//指定不回滾,遇到運行期例外(throw new RuntimeException("注釋");)會回滾
public ItimDaoImpl getItemDaoImpl() {
throw new RuntimeException("注釋");
}

3、@Transactional 注解可以被應用於接口定義和接口方法、類定義和類的 public 方法上。然而,請注意僅僅 @Transactional 注解的出現不足於開啟事務行為,它僅僅 是一種元數據,能夠被可以識別 @Transactional 注解和上述的配置適當的具有事務行為的beans所使用。上面的例子中,其實正是 <tx:annotation-driven/>元素的出現 開啟 了事務行為

4、Spring團隊的建議是你在具體的類(或類的方法)上使用 @Transactional 注解,而不要使用在類所要實現的任何接口上。你當然可以在接口上使用 @Transactional 注解,但是這將只能當你設置了基於接口的代理時它才生效。因為注解是 不能繼承 的,這就意味着如果你正在使用基於類的代理時,那么事務的設置將不能被基於類的代理所識別,而且對象也將不會被事務代理所包裝(將被確認為嚴重的)。因 此,請接受Spring團隊的建議並且在具體的類上使用 @Transactional 注解。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM