【转载】MySQL事务介绍

作者: 四美_64b9 | 来源:发表于2019-03-05 16:28 被阅读58次

    事务介绍

    MySQL的事务支持不是绑定在MySQL服务器本身,而是与存储引擎相关, 一个事务是一个连续的一组数据库操作,就好像它是一个单一的工作单元进行。换言之,永远不会是完整的事务,除非该组内的每个单独的操作是成功的。如果在事务的任何操作失败,则整个事务将失败

    • MyISAM 不支持事务,用于只读程序提高性能
    • InnoDB 支持ACID事务、行级锁、并发
    • Berkeley DB 支持事务

    事务的特性

    事务有以下四个标准属性的缩写ACID,通常被称为:

    • 原子性: 一组事务,要么成功;要么撤回
    • 一致性: 确保数据库正确地改变状态后,成功提交的事务。
    • 隔离性: 事务独立运行,一个事务处理后的结果,影响了其他事务,那么其他事务会撤回,事务的100%隔离,需要牺牲速度。
    • 持久性: 软、硬件崩溃后,InnoDB数据表驱动会利用日志文件重构修改

    事务使用

    在MySQL中,有两种方法开启事务,第一种,事务使用BEGIN(或者START TRANSACTION)语句开启

    • BEGIN(或者START TRANSACTION) 开启事务
    • COMMIT当一个成功的事务完成后,发出COMMIT命令应使所有参与表的更改才会生效。
    • ROLLBACK 如果发生故障时,应发出一个ROLLBACK命令返回的事务中引用的每一个表到以前的状态
    • SAVEPOINT 发生在折返点 之前的事务被提交,之后的被忽略

    第二种,用set来改变mysql的自动提交模式,set autocommit = 0 禁止自动提交,以后所有的sql都将作为事务处理,直到你用commit确认或 rollback结束,注意当你结束这个事务的同时也开启了新的事务!按第一种方法只将当前的做为一个事务

    事务锁定模式

    1. SELECT …… LOCK IN SHARE MODE(共享锁)
      查询到的数据,就是数据库在这一时刻的数据(其他已commit事务的结果,已经反应到这里了),SELECT 必须等待,某个事务结束后才能执行

    2. SELECT …… FOR UPDATE(排它锁)
      例如 SELECT * FROM tablename WHERE id<200
      那么id<200的数据,被查询到的数据,都将不能再进行修改、删除、SELECT …… LOCK IN SHARE MODE操作,一直到此事务结束,

    3. INSERT / UPDATE / DELETE
      所有关联数据都会被锁定,加上排它锁

    4. 防插入锁
      例如 SELECT * FROM tablename WHERE id>200
      那么id>200的记录无法被插入

    5. 死锁
      自动识别死锁
      先进来的进程被执行,后来的进程收到出错消息,并按ROLLBACK方式回滚
      innodb_lock_wait_timeout = n 来设置最长等待时间,默认是50秒

    共享锁 和 排它锁 的区别:在于是否阻断其他客户发出的 SELECT …… LOCK IN SHARE MODE命令

    事务的并发访问问题

    1.脏读:在一个事务中,当读取数据时,读到了另一个事务未提交的数据。

    比如A账户给B账户转了1块钱,但是A没有提交事务,被B账户通过脏读看到了,这时,B就会以为A已经把钱转过来了,但是这时,A账户回滚事务。其实钱就没给B转过去,但是B自己本身以为A已经转过去了

    看代码:

    update account set money=money+1 where name=’B’ --此时A去通知B
    update account set money=money -1 where name=’A’
    

    2.不可重复读:在一个事务中,两次读取的数据内容不一致,这是因为在查询时,有时间间隔,数据被另一个事务已经修改提交了,那就会出现问题。

    3.幻读/虚读:在一个事务中,两次读取的数据量不一致。

    事务隔离模式

    SET [SESSION|GLOBAL] TRANSACTION ISOLATION LEVEL
    READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE
    1、不带SESSION、GLOBAL的SET命令
    只对下一个事务有效
    2、SET SESSION
    为当前会话设置隔离模式
    3、SET GLOBAL
    为以后新建的所有MYSQL连接设置隔离模式(当前连接不包括在内)

    查看mysql数据库默认的隔离级别:select @@tx_isolation

    隔离模式

    • READ UNCOMMITTED
      不隔离SELECT,其他事务未完成的修改(未COMMIT),其结果也考虑在内,这个最低级,但是效率肯定最高,但是哪一个问题都不能解决
    • READ COMMITTED
      把其他事务的 COMMIT 修改考虑在内,同一个事务中,同一 SELECT 可能返回不同结果,可以解决脏读
    • REPEATABLE READ(默认)
      不把其他事务的修改考虑在内,无论其他事务是否用COMMIT命令提交过,同一个事务中,同一 SELECT 返回同一结果(前提是本事务,不修改),可以解决脏读 和 不可重复读
    • SERIALIZABLE
      和REPEATABLE READ类似,给所有的SELECT都加上了 共享锁,可以解决脏读不可重复读和虚读,效率最差,相当于锁表,开发中一般不用

    Spring声明式事务管理

    基于AOP注解@Transactional的声明式事务管理

    默认情况下,数据库处于自动提交模式,每一条语句处于一个单独的事务中,在这条语句执行完毕时,如果执行成功则隐式的提交事务,如果执行失败则隐式的回滚事务。
    对于正常的事务管理,是一组相关的操作处于一个事务之中,因此必须关闭数据库的自动提交模式。不过,这个我们不用担心,spring会将底层连接的自动提交特性设置为false。
    org/springframework/jdbc/datasource/DataSourceTransactionManager.java

    if (con.getautocommit()) {
          txobject.setmustrestoreautocommit(true);
          if (logger.isdebugenabled()) {
             logger.debug("switching jdbc connection [" + con + "] to manual commit");
         }
         con.setautocommit(false);
     }
    
    用法

    添加位置,接口实现类或接口实现方法上,而不是接口类中,@Transactional 注解应该只被应用到 public 方法上,这是由AOP 的本质决定的。如果你在 protected、private 或者默认可见性的方法上使用 @Transactional 注解,这将被忽略,也不会抛出任何异常

    下期预告:项目上线压测过程中抛出异常,提示record_not_exists_or_version_not_mach,使用了框架的updateByPrimaryKeySelective方法,下期计划介绍一些数据库锁方面和补充一下分布式事务的东西

    转自:https://www.cnblogs.com/hellomandy/p/8068269.html

    相关文章

      网友评论

        本文标题:【转载】MySQL事务介绍

        本文链接:https://www.haomeiwen.com/subject/ktsouqtx.html