一、概念
- 事务作用:在数据层保障一系列的数据库操作同成功同失败
- Spring事务作用:在数据层或业务层保障一系列的数据库操作同成功同失败
Spring为了管理事务,提供了一个平台事务管理器PlatformTransactionManager
数据库事务:
事务是一组操作的执行单元,相当于数据库操作来讲,事务管理的是一组SQL指令,比如增加,修改,删除等。事务的一致性要求事务内的操作必须全部执行成功,如果在此过程中出现了差错,比如有一条SQL语句没有执行成功,那么一组数据操作都将全部回滚
- 数据库四大特性
- atomic(原子性):要么都发生,要么都不发生
- consistent(一致性):数据应该不被破坏。
- isolate(隔离性):用户间操作不相混淆
- durable(持久性):永久保存,例如保存到数据库中
二、Spring控制事务的方式
spring控制事务是以bean组件的函数为单位的,如果一个函数正常执行完毕,该函数内的全部数据库操作按照一次事务提交,如果抛出异常,全部回滚
- 事务的传播策略
如果两个bean组件都由spring控制事务,且组件的函数之间存在调用关系,(即:bean1函数a调用了bean2函数b),spring提供了一组配置方式供开发者选择,这些配置方式称为:事务的传播策略。 - 事务的传播行为
传播行为 | 意义 |
---|---|
REQUIRED | 业务方法需要在一个事务中运行。如果方法运行时,已经处在一个事务中,那么加入到该事务,否则为自己创建一个新的事务 |
NOT_SUPPORTED | 声明方法不需要事务。如果方法没有关联到一个事务,容器不会为它开启事务。如果方法在一个事务中被调用,该事务会被挂起,在方法调用结束后,原先的事务便会恢复执行 |
REQUIRES-_NEW | 属性表明不管是否存在事务,业务方法总会为自己发起一个新的事务。如果方法已经运行在一个事务中,则原有事务会被挂起,新的事务会被创建,直到方法执行结束,新事务才算结束,原先的事务才会恢复执行 |
MANDATORY | 该属性指定业务方法只能在一个已经存在的事务中执行,业务方法不能发起自己的事务。如果业务方法在没有事务的环境下调用,容器就会抛出例外。 |
三、案例
- 1、定义dao接口
public interface UserDao {
//name1:A同学 name2:B同学 A同学给B同学转帐100块:A同学-100 ;B同学+100
void transMoney(String name1,String name2,BigDecimal money);
}
- 2、编写dao接口的实现类
@Repository
public class UserDaoImpl implements UserDao{
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void transMoney(String name1, String name2, BigDecimal money) {
//B同学收到了100块
String sql1="update user set sal=sal+? where uname=?";
//A同学消失了100块
String sql2="update set sal=sal-? where uname=?";
jdbcTemplate.update(sql1, new Object[] {money,name1});
jdbcTemplate.update(sql2, new Object[] {money,name2});
}
}
- 3:编写数据库连接信息jdbc.properties文件
DRIVER=com.mysql.jdbc.Driver
URL=jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf-8
NAME=root
PWD=root
- 4:Spring配置文件的修改
<!-- 开启SpringIOC注解扫描的包-->
<context:component-scan base-package="com"></context:component-scan>
<!--自动开启aop注解功能 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
<!-- 目的:注入JdbcTemplate -->
<!--3: 加载jdbc.properties 文件 因为注入数据源对象时有参数值在jdbc.properties -->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations" >
<list>
<value>jdbc.properties</value>
</list>
</property>
</bean>
<!--2: 注入数据源框架对象 c3p0 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="${NAME}"></property>
<property name="password" value="${PWD}"></property>
<property name="driverClass" value="${DRIVER}"></property>
<property name="jdbcUrl" value="${URL}"></property>
</bean>
<!--1: 注入jdbcTemplate -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate" autowire="byName">
<constructor-arg index="0" ref="dataSource"></constructor-arg>
</bean>
<!--事务开始-->
<!-- 注入事务管理者对象 -->
<bean id="tx" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 事务作用在哪些方法上 使用注解
注意:使用注解要开启注解
IOC 控制反转:对象的控制权有硬编码程序转交spring容器
依赖注入:set方法 构造方法注入 静态工厂方法注入
AOP
数据源对象 事务
-->
<!-- 开启事务的注解 -->
<tx:annotation-driven transaction-manager="tx"/>
- 5:编写测试类
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-common4.xml");
UserDao ud = (UserDao) ctx.getBean("userDaoImpl");
//转账
ud.transMoney("张三", "李四",new BigDecimal(100));
}