Spring二刷笔记-事务(Transaction)概念理解与实现
Posted 滑稽404#
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring二刷笔记-事务(Transaction)概念理解与实现相关的知识,希望对你有一定的参考价值。
文章目录
一、事务概念
1.什么是事务
事务是数据库操作的基本单元,要么都成功,要么都失败
2.事务的四个特性(ACID)
原子性(Atomicity)
原子性是指事务是不可再分,事务中的操作要么都发生,要么都不发生。
一致性(Consistency)
事务前后数据的完整性必须保持一致。
隔离性(Isolation)
多个事务同时进行,互相没有影响
持久性(Durability)
持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响
二、事务场景
银行转账,jack要转给amy100元,jack减少100元,amy增加100元
- dao层有减少钱和增加钱的具体数据操作方法
- service层要根据具体业务使用dao层的方法,如:转账业务,该业务不仅需要减少钱方法,也需要增加钱方法,而且还要通过事务特性保证数据一致性
dao层
@Repository
public class AccountMapper implements AccountDao {
@Autowired
JdbcTemplate jdbcTemplate;
public void addMoney(String id,int money) {
String sql="update account set money=money+? where id=?";
int update=jdbcTemplate.update(sql,money,id);
//System.out.println(update);
}
public void reduceMoney(String id,int money) {
String sql="update account set money=money-? where id=?";
int update=jdbcTemplate.update(sql,money,id);
//System.out.println(update);
}
}
service层
@Service("accountService")
public class AccountServiceImpl implements AccountService {
@Autowired
AccountDao accountDao;
//转账
public void accountMoney(String reduceId,String addId,int money) {
accountDao.reduceMoney(reduceId,money);
System.out.println(reduceId+"转出"+money+"元");
accountDao.addMoney(addId,money);
System.out.println(addId+"收到"+money+"元");
System.out.println(reduceId+"转给"+addId+money+"元");
}
}
转账
ApplicationContext context=new ClassPathXmlApplicationContext("bean3.xml");
AccountService accountService = context.getBean("accountService", AccountService.class);
accountService.accountMoney("1","2",100);//1向2转账100
你会发现执行后数据正常,好像并没有什么错误
看下面这个场景,jack转钱时,金额已经扣了,但是突然停电了(异常中断),钱并没有到amy账上
//转账
public void accountMoney(String reduceId,String addId,int money) {
accountDao.reduceMoney(reduceId,money);
System.out.println(reduceId+"转出"+money+"元");
//模拟异常
int a=2/0;
accountDao.addMoney(addId,money);
System.out.println(addId+"收到"+money+"元");
System.out.println(reduceId+"转给"+addId+money+"元");
}
然后这种情况,就会导致数据不一致,产生错误,所以需要用到事务操作
事务流程
try{
//1、开启事务
//2、具体业务
//3、没有异常,提交事务
}catch(Exception e){
//4、捕获到异常,事务回滚(回到事务执行前的状态)
}
三、事务操作(事务管理)
将事务添加到service层(业务逻辑层),一般事务与具体业务结合起来使用
1.Spring进行事务管理操作
- 编程式事务管理,就是上述的事务流程,这种方式要在每个业务里写大量事务代码,过于繁琐,不推荐使用
- 声明式事务管理
2.声明式事务
Spring实现声明式事务,底层是AOP实现
- 基于注解实现
- xml配置文件实现
<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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
https://www.springframework.org/schema/tx/spring-tx.xsd">
<context:component-scan base-package="com.chime"/>
<context:property-placeholder location="classpath:jdbc.properties"/>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--开启事务注解-->
<tx:annotation-driven transaction-manager="transactionManager"/>
<!--开启事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
</beans>
3.注解实现
(1)添加tx命名空间
(2)开启事务管理器
<!--开启事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
(3)开启事务注解
<!--开启事务注解-->
<tx:annotation-driven transaction-manager="transactionManager"/>
将注解添加到service类上或者具体方法上
添加到类上表示,类中所有方法开启事务操作
@Service("accountService")
@Transactional//开启事务
public class AccountServiceImpl implements AccountService
3.注解参数
(1)propagation:事务传播行为
多事务互相调用,事务怎样管理,如在add中调用update
- REQUIRED:add中调用update,如果add本身有事务,则update使用已有事务,add没有事务,则update开启一个新的事务
- REQUIRED_NEW:无论add有没有事务,update都会开启一个新的事务
@Transactional(propagation = Propagation.REQUIRES_NEW)
默认REQUIRED
(2)isolation(隔离级别)
事务隔离性:多事务操作不会互相影响,不考虑隔离会产生很多影响
三个读问题:脏读、不可重复读、虚读(幻读)
三个读问题
- 脏读:B事务进行操作后数据发生改变 money 500->2000 A事务开启后读到了2000,但是B事务发生事务回滚,A读到了不该读的东西
- 不可重复读:多个事务间不产生影响,B事务提交后500->2000,A事务读到了500,然后读到了2000,B事务对A事务产生了影响
- 虚读:一个未提交事务读取到了已提交事务数据(跟不可重复读过程差不多)
隔离级别
参数默认重复读
(3)timeout
事务超过一定时间没有提交就会回滚
默认是-1,表示不限时
(4)readOnly(是否只读)
(5)rollbackFor (回滚)
(6)noRollbackFor(不回滚)
4.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:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
https://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<context:component-scan base-package="com.chime"/>
<context:property-placeholder location="classpath:jdbc.properties"/>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--1、开启事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--2、配置通知(事务)-->
<tx:advice id="accountAdvice">
<tx:attributes>
<tx:method name="accountMoney" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!--3、配置切面-->
<aop:config>
<!--切入点-->
<aop:pointcut id="accountPoint" expression="execution(* com.chime.service.AccountService.*(..))"/>
<aop:advisor advice-ref="accountAdvice" pointcut-ref="accountPoint"/>
</aop:config>
</beans>
不需要开启事务注解了
以上是关于Spring二刷笔记-事务(Transaction)概念理解与实现的主要内容,如果未能解决你的问题,请参考以下文章