spring-mvc+mybatis注解方式事務管理


配置文件:

<!-- dataSource -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        <property name="url" value="${db.master.url}" />
        <property name="username" value="${db.master.user}" />
        <property name="password" value="${db.master.password}" />
        <!-- 配置監控統計攔截的filters -->
        <property name="filters" value="mergeStat,wall,log4j2" />
        <property name="initialSize" value="5" />
        <property name="maxActive" value="100" />
        <property name="minIdle" value="10" />
        <property name="maxWait" value="60000" />
        <property name="validationQuery" value="SELECT 'x'" />
        <property name="testOnBorrow" value="true" />
        <property name="testOnReturn" value="true" />
        <property name="testWhileIdle" value="true" />
        <property name="timeBetweenEvictionRunsMillis" value="60000" />
        <property name="minEvictableIdleTimeMillis" value="300000" />
        <property name="removeAbandoned" value="true" />
        <property name="removeAbandonedTimeout" value="1800" />
        <property name="logAbandoned" value="true" />
    </bean>

    <!-- Spring整合Mybatis -->
    <bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <!-- 自動掃描Mapping.xml文件 -->
        <property name="mapperLocations" value="classpath*:/sqlMapperXml/*.xml"></property>
        <property name="configLocation" value="classpath:xml/mybatis-config.xml"></property>
        <property name="typeAliasesPackage" value="com.mingwork.model"/>
        <property name="globalConfig" ref="globalConfig"/>
        <property name="plugins">
            <array>
                <!-- 分頁插件配置 -->
                <bean id="paginationInterceptor" class="com.baomidou.mybatisplus.plugins.PaginationInterceptor">
                    <property name="dialectType" value="mysql"/>
                    <property name="optimizeType" value="aliDruid" />
                </bean>
            </array>
        </property>
    </bean>

    <!-- MP 全局配置 -->
    <bean id="globalConfig" class="com.baomidou.mybatisplus.entity.GlobalConfiguration">
        <property name="idType" value="0"/>
        <property name="dbColumnUnderline" value="true"/>
    </bean>

    <!-- MyBatis 動態實現  -->
    <bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!-- 對Dao 接口動態實現,需要知道接口在哪  -->
        <property name="basePackage" value="com.mingwork.mapper"/>
    </bean>
    <!-- 事務管理 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!-- 事務注解 -->
    <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
    <!-- 事務管理 屬性 -->
    <tx:advice id="transactionAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="select*" propagation="REQUIRED" read-only="true" />
            <tx:method name="delete*" propagation="REQUIRED" rollback-for="Exception" />
            <tx:method name="update*" propagation="REQUIRED" rollback-for="Exception" />
            <tx:method name="insert*" propagation="REQUIRED" rollback-for="Exception" />
            <tx:method name="*" propagation="REQUIRED" />
        </tx:attributes>
    </tx:advice>

    <!-- 配置切面 -->
    <aop:config expose-proxy="true" proxy-target-class="true">
        <aop:advisor advice-ref="transactionAdvice" pointcut="execution(* com.mingwork.service..*.*(..))"/>
    </aop:config>

  

上面配置的意思就是配置面向切面,只要servcie中的方法拋出Exception,那么insert,update,delete的sql方法都會回滾。測試時,可以在service方法中故意拋出一個異常,throw new Exception("test"); 那么數據庫就不會執行成功。所以在開發時,如果需要對多張表進行操作,而又需要保持事務的一致性的時候,我們就可以把對多張表的操作,寫在一個service中的方法中,這樣如果有一張表執行失敗,拋出異常,其他表的操作也會跟着回滾。

@Transactional參數說明

參數 說明
readOnly 是否是只讀事務,true表示只讀,false表示讀寫
timeout 事務超時秒數,默認值-1表示永不超時
isolation 隔離級別,例如(isolation = Isolation.READ_UNCOMMITTED)
propagation 事務傳播行為,見表propagation說明,例如@Transactional(propagation=Propagation.REQUIRED)
rollbackFor 需要回滾的異常類數組,例如</br>單一異常類:@Transactional(rollbackFor=RuntimeException.class)</br> 多個異常類:@Transactional(rollbackFor={IndexOutOfBoundsException.class, OutOfMemoryException.class})
noRollbackFor 不需要進行回滾的異常類數組,......
rollbackForClassName 需要進行回滾的異常類名稱數組,例如</br>單一異常類名稱:@Transactional(rollbackForClassName="RuntimeException") </br>多個異常類名稱:@Transactional(rollbackForClassName={"IndexOutOfBoundsException","OutOfMemoryException.class"})
noRollbackForClassName 不需要進行回滾的異常類名稱數組,......

propagation說明

參數 說明
REQUIRED 有事務,加入事務,沒有新建一個
NOT_SUPPORTED 以非事務方式執行操作,如果當前存在事務,就把當前事務掛起
REQUIRES_NEW 新建事務,如果當前存在事務,把當前事務掛起
MANDATORY 使用當前的事務,如果當前沒有事務,就拋出異常
NEVER 以非事務方式執行,如果當前存在事務,則拋出異常
SUPPORTS 支持當前事務,如果當前沒有事務,就以非事務方式執行
NESTED 如果當前存在事務,則在嵌套事務內執行,如果當前沒有事務,則執行與REQUIRED類似的操作

 

 

 

 

 

 

Q:我們的工程里,事務的開啟跟關閉是由Spring負責的,但具體的SQL語句卻是由Mybatis執行的。那么問題來了,Mybatis怎么保證自己執行的SQL語句是處在Spring的事務上下文中?

仔細思考一下這個過程,@Transactional是由spring進行處理的,spring做的事情是從數據源(一般為數據庫連接池,比如說druid,c3p0等)獲取一個數據庫連接,然后在進入方法邏輯前執行setAutoCommit(false)操作,最后在處理成功或者出現異常的時候分別執行commit或者rollback操作。
那么問題來了,開啟跟結束事務是由spring獲取到數據庫連接以后進行操作的,但我們實際執行的update或者insert語句卻是由mybatis獲取數據庫連接進行操作的,可以想到如果想讓事務生效,那么spring跟mybatis使用的必須是同一個連接,真實情況是什么樣呢?它們之間如何進行無縫銜接?讓我們通過源碼來分析一下。
具體可以參考下面的鏈接
https://www.jianshu.com/p/6a880d20a61f

 


免責聲明!

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



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