Spring的事务管理
1.事务的概念及特性
1. 事务:指的是逻辑上一组操作,组成这个事务的各个执行单元,要么一起成功,要么一起失败!
2. 事务的特性
原子性:组成这个事务的各个执行单元 不可再分割
一致性:
隔离性:
持久性
2.Spring事务管理的相关的类和API
1. PlatformTransactionManager接口 -- 平台事务管理器.(真正管理事务的类)。该接口有具体的实现类,根据不同的持久层框架,需要选择不同的实现类!
2. TransactionDefinition接口 -- 事务定义信息.(事务的隔离级别,传播行为,超时,只读)
3. TransactionStatus接口 -- 事务的状态
4. 总结:上述对象之间的关系:平台事务管理器真正管理事务对象.根据事务定义的信息TransactionDefinition 进行事务管理,在管理事务中产生一些状态.将状态记录到TransactionStatus中
5. PlatformTransactionManager接口中实现类和常用的方法
1. 接口的实现类
* 如果使用的Spring的JDBC模板或者MyBatis框架,需要选择DataSourceTransactionManager实现类
* 如果使用的是Hibernate的框架,需要选择HibernateTransactionManager实现类
2. 该接口的常用方法
* void commit(TransactionStatus status)
* TransactionStatus getTransaction(TransactionDefinition definition)
* void rollback(TransactionStatus status)
6. TransactionDefinition 事务定义信息
1. 事务隔离级别的常量
* static int ISOLATION_DEFAULT -- 采用数据库的默认隔离级别
* static int ISOLATION_READ_UNCOMMITTED
* static int ISOLATION_READ_COMMITTED
* static int ISOLATION_REPEATABLE_READ
* static int ISOLATION_SERIALIZABLE
2. 事务的传播行为常量(不用设置,使用默认值)
* 先解释什么是事务的传播行为:解决的是业务层之间的方法调用!!
* PROPAGATION_REQUIRED(默认值) -- A中有事务,使用A中的事务.如果没有,B就会开启一个新的事务,将A包含进来.(保证A,B在同一个事务中),默认值!!
* PROPAGATION_SUPPORTS -- A中有事务,使用A中的事务.如果A中没有事务.那么B也不使用事务.
* PROPAGATION_MANDATORY -- A中有事务,使用A中的事务.如果A没有事务.抛出异常.
* PROPAGATION_REQUIRES_NEW(记)-- A中有事务,将A中的事务挂起.B创建一个新的事务.(保证A,B没有在一个事务中)
* PROPAGATION_NOT_SUPPORTED -- A中有事务,将A中的事务挂起.
* PROPAGATION_NEVER -- A中有事务,抛出异常.
* PROPAGATION_NESTED(记) -- 嵌套事务.当A执行之后,就会在这个位置设置一个保存点.如果B没有问题.执行通过.如果B出现异常,运行客户根据需求回滚(选择回滚到保存点或者是最初始状态)
3.Spring事务模拟专项业务
1.创建项目,导入jar包
普通项目中
* IOC的6个包
com.springsource.org.apache.commons.logging-1.1.1.jar
com.springsource.org.apache.log4j-1.2.15.jar
spring-beans-5.0.2.RELEASE.jar
spring-context-5.0.2.RELEASE.jar
spring-core-5.0.2.RELEASE.jar
spring-expression-5.0.2.RELEASE.jar
* AOP的4个包
spring-aop-5.0.2.RELEASE.jar
com.springsource.org.aopalliance-1.0.0.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
spring-aspects-5.0.2.RELEASE.jar
* C3P0的1个包
com.springsource.com.mchange.v2.c3p0-0.9.1.2.jar
* MySQL的驱动包
mysql-connector-java-5.1.7-bin.jar
* JDBC模板2个包
spring-jdbc-5.0.2.RELEASE.jar
spring-tx-5.0.2.RELEASE.jar 事务
* 整合JUnit测试包
spring-test-5.0.2.RELEASE.jar
Maven项目中
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.2.1</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.7</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
2.创建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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
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/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!--开启组件扫描-->
<context:component-scan base-package="org.best"/>
<!--配置C3P0数据源-->
<bean class="com.mchange.v2.c3p0.ComboPooledDataSource" id="dataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/spring_test"></property>
<property name="user" value="root"></property>
<property name="password" value="123"></property>
</bean>
<!--将数据源注入到JDBCTemplate中-->
<bean class="org.springframework.jdbc.core.JdbcTemplate" id="jdbcTemplate">
<constructor-arg ref="dataSource"></constructor-arg>
</bean>
</beans>
3.创建对应的包和类
Service接口
package org.best.service;
public interface AccountService {
void accounts(String sendName,String recieveName,Double money);
}
Service实现类
package org.best.service;
import org.best.dao.AccountDao;
import org.best.dao.AccountDaoImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
@Service("accountService")
public class AccountServiceImpl implements AccountService {
@Autowired
@Qualifier("accountDao")
private AccountDaoImpl accountDao;
public void setAccountDao(AccountDaoImpl accountDao) {
this.accountDao = accountDao;
}
public void accounts(String sendName, String recieveName, Double money) {
accountDao.cutMoney(sendName,money);
accountDao.addMoney(recieveName,money);
}
}
Dao接口
package org.best.dao;
public interface AccountDao {
void addMoney(String name,Double money);
void cutMoney(String name,Double money);
}
Dao实现类
package org.best.dao;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import org.springframework.stereotype.Repository;
import javax.annotation.Resource;
@Repository("accountDao")
public class AccountDaoImpl implements AccountDao {
@Resource(name = "jdbcTemplate")
private JdbcTemplate jdbcTemplate;
public void addMoney(String name, Double money) {
jdbcTemplate.update("update account set money=money+? where name =?",money,name);
}
public void cutMoney(String name, Double money) {
jdbcTemplate.update("update account set money=money-? where name =?",money,name);
}
}
4.测试
@org.junit.Test
public void Test(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
AccountService accountService = context.getBean("accountService", AccountService.class);
accountService.accounts("ls","yyp",1500.0);
}
这样来看,转账事务是没有问题,但是当遇到异常就会造成不可挽回的损失,那么如何解决呢?
解决方式1.配置文件中加入
<!--配置事务管理器-->
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="manager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--配置事务增强-->
<tx:advice id="interceptor" transaction-manager="manager">
<tx:attributes>
<!--增删改方法这样配置-->
<tx:method name="account*" isolation="DEFAULT" propagation="REQUIRED" read-only="false"/>
<!--查询-->
<tx:method name="find*" isolation="DEFAULT" read-only="true" propagation="SUPPORTS"/>
</tx:attributes>
</tx:advice>
<!--配置AOP切面产生代理-->
<aop:config>
<aop:advisor advice-ref="interceptor" pointcut="execution(public * org.best.service.AccountService.accounts(..))"/>
</aop:config>
解决方式2:配置文件加注解
配置文件中加入
<!--配置事务管理器-->
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="manager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--开启注解事务-->
<tx:annotation-driven transaction-manager="manager"></tx:annotation-driven>
在所需要类或方法上加@Transactional注解
加在类上表示类中的所有方法都有了事务
加在方法上表示表示某个特定方法有了事务