【转载】MySQL事务介绍

事务介绍

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事务介绍)