文章目录
什么是事务
事务是数据库操作最基本单位,逻辑上是一组操作,要么都成功,要么都失败。
典型场景:银行转账
事务四特性—ACID
原子性
要么都成功要么都失败
一致性
操作前后总量不变
隔离性
多事务之间互不影响
持久性
提交事务后,从内存到磁盘,关闭电脑数据也不会丢失。
案例模拟转账—搭建事务操作环境
1、创建数据库,添加记录
2、搭建Mapper层,在里面写添加账余额和减少账户余额两个方法。
注入JdbcTemplate对象,在JdbcTemplate中注入DataSource,进而对数据库进行操作
public interface AccountMapper {
void addMoney(String name,String money);
void reduceMoney(String name,String money);
}
@Repository
public class AccountMapperImpl implements AccountMapper {
@Autowired
JdbcTemplate jdbcTemplate;
//账户余额增加
@Override
public void addMoney(String name,String money){
String sql = "update t_account set count=count+? where name=?";
jdbcTemplate.update(sql,name,money);
}
//账户余额减少
@Override
public void reduceMoney(String name, String money) {
String sql = "update t_account set count=count-? where name=?";
jdbcTemplate.update(sql,name,money);
}
}
3、搭建Service层,里面创建转账方法,注入Mapper层
@Service
public class AccountService {
@Autowired
AccountMapper mapper;
//创建转账功能
public void changeMoney(){
//让Lucy少100
mapper.reduceMoney("Lucy","100");
//让Mary多100
mapper.addMoney("Mary","100");
}
}
4、创建测试类测试
@Test
public void testAccount(){
ApplicationContext context =
new ClassPathXmlApplicationContext("bean01.xml");
AccountService accountService = context.getBean("accountService", AccountService.class);
accountService.changeMoney();
System.out.println("转账成功");
}
5、异常演示
//创建转账功能
public void changeMoney(){
//让Lucy少100
mapper.reduceMoney("Lucy","100");
int result = 10/0;
//让Mary多100
mapper.addMoney("Mary","100");
}
此时会发现Lucy账户少了100元,但是,Mary并未收到100元。这个问题该如何解决呢??
使用事务进行解决
事务操作过程
//创建转账功能
public void changeMoney(){
try{
//1、开启事务
//2、进行业务操作
//让Lucy少100
mapper.reduceMoney("Lucy","100");
int result = 10/0;
//让Mary多100
mapper.addMoney("Mary","100");
//3.1 没有发生异常,提交事务
}catch (Exception e){
//3.2 出现异常,事务回滚
}
}
事务操作
1、事务操作一般添加在三层结构的service层(业务逻辑层)
2、在spring中进行事务管理操作有编程式事务管理和声明式事务管理两种方式。
3、完成声明式事务管理:
3.1基于注解方式
3.2基于xml配置文件方式
4、在spring进行声明式事务管理底层使用了AOP原理
5、spring事务管理API
提供了一个接口,代表事务管理器,这个接口针对不同的框架提供不同的实现类
如图:
基于注解方式进行事务管理
1、在spring配置文件中配置事务管理器
<!--创建事务管理器-->
<bean id="transactionManage"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入数据源-->
<property name="dataSource" ref="dataSource"></property>
</bean>
2、在spring配置文件中开启事务注解
2.1、在spring配置文件中引入tx名称空间
<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: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/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
2.2、开启事务注解
<!--开启事务注解-->
<tx:annotation-driven transaction-manager="transactionManage"></tx:annotation-driven>
3、在service类上面或具体的方法上面添加注解
3.1 @Transactional,这个注解既可以放在类上,也可以放在方法上。
3.2 放在类上时,把类中所有方法都添加了事务。
如图:
3.3 放在方法上时,只是为该方法添加事务。
如图:
声明式事务管理中的参数
@Transactional中事务相关的参数配置
propagation:事务传播行为
当一个事务方法被另一个事务方法调用时,这个事务方法是如何进行的。
1、
2、
3、事务传播行为可以有传播属性指定。spring中定义了7中传播行为。
设置传播行为:
isolation:事务隔离级别
事务有隔离性,让多事务操作之间不会相互影响。但是如果不考虑隔离性,将产生很多问题。
三个读问题:脏读、不可重复读、幻(虚)读
1、脏读:一个未提交事务读取到了另一个未提交事务的数据
2、不可重复读:一个未提交的事务读取到另一个提交事务修改的数据
3、幻读:一个未提交的事务读取到另一个提交事务添加的数据
解决读问题,可以通过设计事务隔离级别
如图:4、案例:将隔离级别设置为可串行化
timeout:超时时间
1、事务需要在一定时间内进行提交,如果不提交进行回滚
2、默认值是-1.设置时间是以秒为单位
readOnly:是否只读
读:查询操作,写:增删改操作
默认值为false,表既可以查询也可以增删改
rollbackFor:回滚
设置出现哪些异常进行事务回滚
noRollbackFor:不会滚
设置出现哪些异常不进行事务回滚