springmvc中的配置事务、@Transactional中属性的了解及解决的事务问题(bai)

什么是事务?

在学习springmvc中的事务之前我们首先要了解什么是事务。

1.事务的定义

事务就是用户定义的一系列数据库操作,这些操作可以视为一个完成的逻辑处理工作单元,要么全部执行,要么全部不执行,是不可分割的工作单元。

2.事务的特性

  • 原子性
    不可分割,sql语句 要么执行,要么都不执行
  • 一致性
    事务的一致性要求事务必须满足数据库的完整性约束,且事务执行完毕后会将数据库由一个一致性的状态变为另一个一致性的状态。事务的一致性与原子性是密不可分的
    例如:a 向 b 转 100 a必须减100 b增加100 a和b总数不变
  • 隔离性
    事务的隔离性要求事务之间是彼此独立的,隔离的。即一个事务的执行不可以被其他事务干扰。具体到操作是指一个事务的操作必须在一个事务commit之后才可以进行操作。
    例: 多个sql连接之间的数据影响 一个sql连接 开启事务在修 id 为 1的 学生,改连接未提交事务 ,另外的sql不能访问到 未提交事务的 数据
    sql 各个连接的隔离
    持久性
    提交之后数据可以持久保存,对数据库的改变是永久性的

Springmvc中事务的开启

1.配置事务管理器

在容器中配置


    <!-- 开启事务-->

    <!--1.配置事务管理器-->

    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

        <property name="dataSource" ref="dataSource"></property>

    </bean>


2.让与事务相关注解生效,写在第一步的下边即可

<!-2.让与事务相关注解生效>
```<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>      

使用

简单的转账操作
dao层,service层不在赘述,
sql语句为修改余额的操作
< update id=“updateAccount”>
update account set account =
(account + #{money}) where id = #{id}

< /update>
在需要使用事务的方法上 用 @Transactional开启事务

@Service
public class AccountServiceImpl implements AccountService {

   @Autowired
   private AccountDao accountDao;

   /**
    * propagation  事务的传播行为    调用方法之间  开的事务 是否会 传播其他被调用的方法上
    *               Propagation.REQUIRE  必须开启事务 如果当方法被其他调用 ,但是其他方法 没有开启事务  当前方法自己开启事务
    *                                                如果当方法被其他调用 ,但是其他方法  其他方法开启事务  当前方法使用 被调用方法事务 自己无需开启
    *               SUPPORTS  被调用的方法 开启了事务 就使用原有事务
    *                         被调用的方法 没有事务   不使用事务
    *
    * isolation   隔离级别  解决是 多个sql连接之间 事务允许参数据的程度
    *            Isolation.READ_COMMITTED  读已提交
    *
    * readOnly = false
    *         readOnly true  效率高 主要用于查询
    *                  false       用于修改
    *
    * timeout  未事务设置超时
    *
    * @param fromId
    * @param toId
    * @param money
    * @return
    */
   // 在当前方法开启 事务
   @Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.READ_COMMITTED,readOnly = false)
   @Override
   public boolean transMoney(int fromId, int toId, float money) {

       // 减钱
       int num1 =    accountDao.updateAccount(fromId,-money);
   	//除0异常,为了触发事务的机制
       int a = 1/0;

       // 加钱
       int num2 =  accountDao.updateAccount(toId,money);

       if (num1 >0 & num2>0){
           return  true;
       }

       return false;
   }
}

测试

    public static void main(String[] args) {


        ApplicationContext applicationContext =  new ClassPathXmlApplicationContext("applicationContext.xml");
        //从容器获取
        AccountService accountService =  applicationContext.getBean(AccountService.class);
        //id为1的用户向用户2转账3000
        accountService.transMoney(1,2,3000);
    }

测试前
在这里插入图片描述
结果
在这里插入图片描述
由日志可以看出执行了一次sql语句,用户1的余额减少了3000,然后发生了异常,操作终止,释放交易,同步注销sqlSession,关闭SQLSession链接,但是并未提交事务,所以数据库中的数据未改变。这时候我们这在去看数据库
在这里插入图片描述
数据依旧没任何改变。这时候就是事务起到了作用

正确的结果(注释掉除零异常)
在这里插入图片描述
数据库表中的结果已改变
在这里插入图片描述

@Transactional

@Transactional注解属性的详细了解

首先我们先看@Transactional这个注解里边有哪些字段
在这里插入图片描述
我们在配置是使用了propagation,isolation,readOnly
@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.READ_COMMITTED,readOnly = false)

1.propagation事务传播行为

在这里插入图片描述

propagation 事务的传播行为 调用方法之间 开启的事务 是否会 传播其他被调用的方法上,即事务传播
REQUIRE 必须开启事务 如果当方法被其他调用 ,但是其他方法 没有开启事务 当前方法自己开启事务
如果当方法被其他调用 ,但是其他方法 其他方法开启事务 当前方法使用 被调用方法事务 自己无需开启
*SUPPORTS 被调用的方法 开启了事务 就使用原有事务
被调用的方法 没有事务 不使用事务
其他用到的机会很少,无需了解

2. isolation事务隔离级别

隔离级别由低到高为:read-uncommited < read-commited < repeatable-read < serialized-read
在这里插入图片描述

isolation
隔离级别 解决是 多个sql连接之间 事务允许参数据的程度
default: (默认值)(采用数据库的默认的设置) (建议)
Isolation.READ_COMMITTED : 读已提交
read-uncommited:读未提交
repeatable-read:可重复读 (MySQL数据库默认的隔离级别)
serialized-read:序列化读

3.readOnly

true 效率高 主要用于查询
false 用于修改

4.timeout事务超时时间 (一般不做设置)

当前事务所需操作的数据被其他事务占用,则等待。

  • 100:自定义等待时间100(秒)。
  • -1:由数据库指定等待时间,默认值。(建议)
    弄清楚了这几个参数的意义。就要明白使用这几个参数都解决了哪些问题
5. rollback-for` 回滚属性(一般不做设置)
  • 如果事务中抛出 RuntimeException,则自动回滚
  • 如果事务中抛出 CheckException(非运行时异常 Exception),不会自动回滚,而是默认提交事务
  • 处理方案 : 将CheckException转换成RuntimException上抛,或 设置 rollback-for=“Exception”

了解这些属性后,接下来要弄明白这些属性解决了什么问题

事务并发时的安全问题
问题描述
脏读一个事务读取到另一个事务还未提交的数据。大于等于 read-commited 可防止
不可重复读一个事务内多次读取一行数据的相同内容,其结果不一致。大于等于 repeatable-read 可防止
幻影读一个事务内多次读取一张表中的相同内容,其结果不一致。serialized-read 可防止

脏读:一个事务读到另一个事务未提交的数据
不可重复读:例如查找多次id=1的信息时,多次的结果不一样 针对修改
幻读:同一个事务,按照统一条件查询,有多条结果。但统一条件查询多次结果数量不同 针对因为增加、删除、修改而行数改变

参考:https://www.cnblogs.com/ubuntu1/p/8999403.html

isolation事务隔离级别各个参数解决的问题
属性问题
READ_UNCOMMITTED一个事务可以读到另一个事务为提交的数据
READ_COMMITTED一个事务只能读取另一个事务提交的数据,可以解决脏读,但不能解决不可重读和幻读
REPEATABLE_READ可以解决脏读和不可重读,但不能解决幻读
SERIALIZABLE可以解决幻读
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值