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,單位是秒。在事務中,由於各個事務掛起等待,可能出現死鎖,所以設置事務的超時時間是有必要的。
五、注意點
-
基於註解的事務,也就是聲明式事務,依賴於aop編程,因此如裏在當前類中,各事務方法相互間調用,則aop配置的expose-proxy應設爲true,調用時也需做相應處理,詳情請查看本博客中的spring中aop開發。
-
使用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);
}
}