spring事務實用開發

spring事務實用開發

一、spring事務簡介

spring並不直接管理事務,而是使用事務管理器,本文使用常用的事務管理jdbc.datatsource.DataSourceTransactionManager,該事務管理器支持JDBC、Mybatis。

二、spring事務配置

spring事務配置是在spring配置文件中配置,包含內容如下:

2.1 添加事務管理器

添加事務管理器org.springframework.jdbc.datasource.DataSourceTransactionManager,即

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

2.2 添加支持事務的註解配置

添加支持事務的註解配置,即


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

2.3、註解事務使用

註解事務使用,在方法上加註解@Transactional,如

@Transactional(propagation = Propagation.REQUIRED,timeout = 3)

三、spring事務的傳播行爲(Propagation)

spring事務傳播行爲,缺省的默認值是Propagation.REQUIRED,總的分爲七種。

3.1 Propagation.REQUIRED

Propagation.REQUIRED,即方法必須在事務運行,該事務傳播行爲也是缺省的默認值。表現如下:

  • 如果當前不存在事務,則新啓一個事務;

  • 如果當前存在事務,則在當前事務內運行;

3.2 Propagation.MANDATORY

Propagation.MANDATORY,即方法必須是在事務中運行,如果當前不存在事務,則直接拋出異常;

3.3 Propagation.NEVE

Propagation.NEVER,即方法不能在事務中運行,如果當存在事務,剛直接拋出異常;

3.4 Propagation.SUPPORTS

Propagation.SUPPORTS,即支持事務,表現如下:

  • 如果當前存在事務,則在事務中運行;
  • 如果不存在,在按無事務運行;

3.5 Propagation.NOT_SUPPORTED

Propagation.NOT_SUPPORTED,即不支持事務,如果當前存在事務,則把當前事務掛起,方法正常運行,方法運行結束後,再掛起的事務接着運行;

3.6 Propagation.NESTED

Propagation.NESTED,即嵌套事務,表現如下:

  • 如果當前不存在事務,則行爲與Propagation.REQUIRED一樣;

  • 如果當前存在事務,則在當前事務內新開子事務,同時只有外層事務提交時,子事務纔會提交,

同理,外層事務回滾時,子事物也會回滾,但子事務出異常,外層事務是否回滾取決於對子事務異常的處理,總的說來,它是父事務與子事務的關係,或者說它最終只是一個事務,不存在死鎖;

3.7 Propagation.REQUIRES_NEW

Propagation.REQUIRES_NEW,即新開事務,表示如下:

  • 如果當前存在事務,則當前事務掛起,新開一個全新的事務運行,此時是兩個事務(可能出現兩個事務相互等待而出現死鎖),即掛起的當前事務和新開的事務。
  • 如果當前不存在事務,則新開事務;

四、spring事務超時管理timeout

timeout是spring事務的超時時間值,默認是-1,單位是秒。在事務中,由於各個事務掛起等待,可能出現死鎖,所以設置事務的超時時間是有必要的。

五、注意點

  1. 基於註解的事務,也就是聲明式事務,依賴於aop編程,因此如裏在當前類中,各事務方法相互間調用,則aop配置的expose-proxy應設爲true,調用時也需做相應處理,詳情請查看本博客中的spring中aop開發。

  2. 使用Propagation.REQUIRES_NEW,則是兩個完全獨立的事務,而使用Propagation.NESTED則是父事務與子事務的關係,或者說就只有一個事務。

六、實例

6.1 添maven依賴

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-beans</artifactId>
    <version>4.3.4.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>4.3.4.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>4.3.4.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>1.3.0</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>4.3.4.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-orm</artifactId>
    <version>4.3.4.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-tx</artifactId>
    <version>4.3.4.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>4.3.4.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>4.3.4.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-asm</artifactId>
    <version>3.1.4.RELEASE</version>
</dependency>
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.2.4</version>
</dependency>

<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.4.4</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.34</version>
</dependency>
<dependency>
    <groupId>commons-dbcp</groupId>
    <artifactId>commons-dbcp</artifactId>
    <version>1.4</version>
</dependency>
<dependency>
    <groupId>commons-pool</groupId>
    <artifactId>commons-pool</artifactId>
    <version>1.6</version>
</dependency>

6.2 spring中事務配置

<?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:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
">
    <context:component-scan base-package="com.drogon.mybatisStudy" />
    <aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true" />
    
    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>classpath:properties/env.properties</value>
            </list>
        </property>
    </bean>

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName" value="${driver}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
        <property name="maxActive" value="${maxActive}" />
        <property name="initialSize" value="${initialSize}" />
        <property name="maxWait" value="${maxWait}" />
        <property name="maxIdle" value="${minIdle}" />
    </bean>

    <tx:annotation-driven transaction-manager="transactionManager" />
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>

    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- mybatis配置文件 -->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <property name="dataSource" ref="dataSource"/>
        <property name="mapperLocations" value="mapper/*.xml"/>
        <property name="typeAliasesPackage" value="com.drogon.mybatisStudy.bean"/>
        <property name="typeHandlersPackage" value="com.drogon.mybatisStudy.typeHandler"/>
    </bean>

    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"
          p:sqlSessionFactoryBeanName="sqlSessionFactory"
          p:basePackage="com.drogon.mybatisStudy.mapper"
    />
</beans>

6.3 方法中調用

@Service("stuSerivce")
public class StuServiceImpl implements StuSerivce {
    @Resource
    private StuMapper stuMapper;

    @Transactional(propagation = Propagation.REQUIRED,timeout = 3)
    @Override
    public Stu updateStu(Integer id) {
        Stu stu = stuMapper.selectById(id);
        stu.setAge(stu.getAge()+1);
        stuMapper.upsert(stu);

        try{
            StuSerivce stuSerivceProxy = (StuSerivce) AopContext.currentProxy();
            stuSerivceProxy.updateTution();
        }catch (Exception e){
            this.updateTution();
        }
        return stu;
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW,timeout = 3)
    public void updateTution(){
        Stu stu = stuMapper.selectById(4);
        stu.setTuition(stu.getTuition().add(new BigDecimal(1)));
        stuMapper.upsert(stu);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章