Spring、mysql事务特性的理解总结(已完成迁移)

导论:Spring事务有四种特性:ACID,五种隔离级别:default(默认为当前数据库使用的隔离级别)、read_uncommitted、read_committed、repeatable_read、serializable,七种传播行为:默认为required

一:事务的传播行为:

        也就是一个事务传到另外一个事务或者没有事务的方法上面。spring默认的事务传播行为为:PROPAGATION_REQUIRED (Propagation_required),对于声明式事务(注解的方式,可以减少代码侵入,保持代码纯粹的业务逻辑)来说,它的含义就是:如果在一个含有事务的方法中调用其他方法(没有事务)时,此时该方法也会被包含在该事务中,也就是会等全部执行完之后再进行事务的提交,而如果两个都有事务,还是methodA中调用methodB时,此时会先产生一个事务,因此methodB也用的是此事务。Spring中使用 Aop支持声明式事务,也就是用注解@Transaction时,此时代码类似于:

Connection con=null;

    try{

       con = getConnection();

        con.setAutoCommit(false);

        //方法调用

        methodB();

        //提交事务

        con.commit();

    } Catch(RuntimeException ex) {

        //回滚事务

        con.rollback();   

    } finally {

        //释放资源

        closeCon();

    }

如下例:

  //转账方法
    @Transactional(isolation =Isolation.REPEATABLE_READ,propagation= Propagation.REQUIRED,readOnly= false)
    public void transfer( Integer from, Integer to, Double money){
                //减钱
                ad.decreaseMoney(from, money);
                int i = 1/0;
                //加钱
                ad.increaseMoney(to, money);
            }

此案例也说明了 注解实现和动态代理之间的联系,只有通过动态代理才能在该方法执行前后添加事务控制代码。

二:关于Spring事务与Mysql事务之间的联系:

     spring事务本质上使用数据库事务,而数据库事务本质上使用数据库锁,所以spring事务本质上使用数据库锁,开启spring事务意味着使用数据库锁。spring只提供统一事务管理接口,具体实现都是由各组件(如:mysql)自己实现

    Spring会在事务开始时,根据当前环境中设置的隔离级别,调整数据库隔离级别,由此保持一致化。
当使用Serializable级别时,Mysql在执行SQL时会自动修改为select .... lock in share mode, 即使用共享锁。此时允许同时读,但只允许一个事务写,且锁的是行而不是整张表。

这意味着:

如果数据库不支持某种隔离级别,那么Spring设置了也无效。
当使用Serializable级别时,如果两个事务读写的不是同一行,那么它们是互不影响的。如果操作同一行记录,那么允许同时读,但如果出现一个对此行的写操作,则在写事务没有提交之前,所有的读事务都会被block。

总结:

      两者本质上其实是同一个概念,spring的事务是对数据库的事务的封装,最后本质的实现还是在数据库,假如数据库不支持事务的话,spring的事务是没有作用的.数据库的事务说简单就只有开启,回滚和关闭,spring对数据库事务的包装,原理就是拿一个数据连接,根据spring的事务配置,操作这个数据连接对数据库进行事务开启,回滚或关闭操作.但是spring除了实现这些,还配合spring的传播行为对事务进行了更广泛的管理

三:mysql数据库事务的隔离级别

       隔离的意义:隔离是相对于数据库事务与事务之间的隔离,如下是mysql的隔离级别:

1:read uncommitted(未提交读):在这个级别中,事务中的修改即使没有提交,对其他事务都是可见的。当一个事务读取到其他事务未提交的数据时,称为脏读

2:read committed(提交读、不可重复读):是大多数数据库系统的默认级别(mysql不是),满足事务隔离性的简单定义:从事务开始到结束之前,所做的任何修改对其他事务都是不可见的。顾名思义就是提交了就可以读取到。这时一个事务可能就会突然读取到另外事务提交的东西。一个有时候也叫不可重复读,因为两次执行同样的查询,可能会得到不一样的结果

3:repeatable read(可重复读):解决了脏读,该级别保证了在同一事务中多次读取同样纪录的结果是一致的(使用了行锁,锁定了某行记录,因此同样记录结果是不会变的),但还是无法解决幻读的问题,幻读:指的是某个事务在读取某个范围内的记录时,另外一个事务又在该范围内插入了新的记录,当之前的事务再次读取时,会产生幻行,innodb通过多版本并发控制(mvcc)解决了幻读的问题。具体应为:间隙锁,锁定范围内的数据

4:serializable(可串行化):是最高的隔离级别,通过强制事务串行执行,避免了幻读的问题。会在读取的每一行数据上都加锁,可能导致大量的超时和锁争用的问题

四:数据库锁:表级锁定,行级锁定和页级锁定。(推荐:https://www.cnblogs.com/sessionbest/articles/8689071.html

      锁介绍:

1.表级锁定(table-level)
表级别的锁定是MySQL各存储引擎中最大颗粒度的锁定机制。该锁定机制最大的特点是实现逻辑非常简单,带来的系统负面影响最小。所以获取锁和释放锁的速度很快。由于表级锁一次会将整个表锁定,所以可以很好的避免困扰我们的死锁问题。
当然,锁定颗粒度大所带来最大的负面影响就是出现锁定资源争用的概率也会最高,致使并大度大打折扣。
2.行级锁定(row-level)
行级锁定最大的特点就是锁定对象的颗粒度很小,也是目前各大数据库管理软件所实现的锁定颗粒度最小的。由于锁定颗粒度很小,所以发生锁定资源争用的概率也最小,能够给予应用程序尽可能大的并发处理能力而提高一些需要高并发应用系统的整体性能。
虽然能够在并发处理能力上面有较大的优势,但是行级锁定也因此带来了不少弊端。由于锁定资源的颗粒度很小,所以每次获取锁和释放锁需要做的事情也更多,带来的消耗自然也就更大了。此外,行级锁定也最容易发生死锁。
使用行级锁定的主要是InnoDB存储引擎。
3.页级锁定(page-level)
页级锁定是MySQL中比较独特的一种锁定级别,在其他数据库管理软件中也并不是太常见。页级锁定的特点是锁定颗粒度介于行级锁定与表级锁之间,所以获取锁定所需要的资源开销,以及所能提供的并发处理能力也同样是介于上面二者之间。另外,页级锁定和行级锁定一样,会发生死锁。
在数据库实现资源锁定的过程中,随着锁定资源颗粒度的减小,锁定相同数据量的数据所需要消耗的内存数量是越来越多的,实现算法也会越来越复杂。不过,随着锁定资源颗粒度的减小,应用程序的访问请求遇到锁等待的可能性也会随之降低,系统整体并发度也随之提升。

     1.什么时候使用表锁:
        对于InnoDB表,在绝大部分情况下都应该使用行级锁,因为事务和行锁往往是我们之所以选择InnoDB表的理由。但在个别特殊事务中,也可以考虑使用表级锁:
      (1)事务需要更新大部分或全部数据,表又比较大,如果使用默认的行锁,不仅这个事务执行效率低,而且可能造成其他事务长时间锁等待和锁冲突,这种情况下可以考虑使用表锁来提高该事务的执行速度。
     (2)事务涉及多个表,比较复杂,很可能引起死锁,造成大量事务回滚。这种情况也可以考虑一次性锁定事务涉及的表,从而避免死锁、减少数据库因事务回滚带来的开销。


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值