MySQL中的事务

Posted funtrin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQL中的事务相关的知识,希望对你有一定的参考价值。

mysql中的事务

什么是事务

一组不可分割的操作就是事务。目前支持事务的MySQL存储引擎只有InnoDBNDB

事务的特性

我们知道现在的程序基本都是都是并发运行的,数据库当然也不例外,往往数据库要同时处理多个操作数据库的请求,然后同时执行多个数据库操作,所以在这种并发情况下,事务应当具备如下几个特性:

原子性

事务是一组操作的集合,在执行事务的过程中,事务不能中断,要么全部执行,要么全不执行。

隔离性

一个事务的执行不会影响另一个事务的执行,包括事务中用到的数据。

一致性

一致性就是指数据是满足某些约束条件的。比如说表中的字段不能为空,表中的字段的值要具有唯一性,不能重复,而满足这些约束条件的数据我们就说它具有一致性。数据库是为了存储现实生活中的数据的,而现实生活中的很多约束是数据库不具备的,所以我们就需要在业务代码中来对存入数据库中的数据做约束。可以说原子性和隔离性的保证,都是为了保证数据的一致性。

持久性

一个事务一旦提交,那么它对数据库中数据的改变就是永久性的。也就是说改变要立即写到磁盘中,即使关机了,即使电脑被砸了,只要硬盘还在,事务对数据的操作就会一直存在。

事务的状态

事务在不同的状态下有不同的状态:

  • active(存活的)
  • partially committed(部分提交)
  • failed(失败)
  • aborted(终止的)
  • committed(提交的)

事务在并发执行时的一致性问题

脏写

一个事务修改了另一个未提交事务的数据。

脏读

一个事务读到了另一个未提交事务修改过的数据。

不可重复读

一个事务修改了另一个未提交事务读取的数据。

幻读

一个事务根据某些条件查询出数据,另一个事务写入了和条件相符的数据。

问题产生的原因?

在并发环境中,我们没法完全保证隔离性,因为一旦完全保证隔离性,那就是串行了,但是串行的性能比较差,所以为了性能就难以避免的出现的一致性的问题。

如何保证一致性?

为了避免某些一致性问题,隔离级别应运而生。

隔离级别 脏读 不可重复读 幻读
READ UNCOMMITTED 可能 可能 可能
READ COMMITTED 不可能 可能 可能
REPEATABLE READ 不可能 不可能 可能
SERIALIZABLE 不可能 不可能 不可能

从上到下隔离级别逐渐提高,对应的性能也就逐渐下降。之所以没有脏写,是因为脏写对数据一致性的影响巨大,所以不论哪种隔离级别都不允许脏写。

如何保证持久性?

事务的执行过程:

  1. 开启事务
  2. 执行事务中的操作
  3. 提交

这是数据库使用者感觉的操作过程,但实际上InnoDB并不是如此执行的,而是先把操作的结果缓存到内存中(部分提交状态),等到时机合适,再刷新到磁盘中去,这样就可以避免频繁随机I/O,造成性能浪费。试想一下,你执行完一个事务,然后突然断电了,你以为数据已经保存在了磁盘上,结果来电后发现数据库里什么也没有。。。

redo日志

redo日志就是为了保证持久性而生,它只记录每一次事务执行后数据有哪些改变,因为只记录有哪些改变,所以redo日志体积小,每个事务执行后产生的日志为一,redo日志也是先存在内存中,等日志攒够了,再写入磁盘。即使出现了意外也可以通过redo日志来恢复数据,不过话又说回来了,如果redo日志在还没写入磁盘时断电了怎么办呢?

如何保证原子性?

事务的原子性就是一个事务要么全部执行,要么全不执行,但是事务执行到一半的时候如果发生点意外事务被迫中断就需要进行回滚,或者是执行到一半手动回滚。但这时已经执行了很多操作,数据产生了很大的改变,这是undo日志就应运而生,他记录了事务执行前的数据,一旦要回滚的时候就可以快速回到原来的样子。

mysql中的事务

mysql中的事务

1.mysql中的innodb存储引擎才支持事务。

2.事务就是一组sql语句,只要全部的sql语句执行成功,事务才会提交(COMMIT),只要有一条sql语句执行失败,则事务不成功,需要回滚(rolback)。

3.对于事务而言,它需要满足ACID特性,下面就简要的说说事务的ACID特性。

  1)A,表示原子性;原子性指整个数据库事务是不可分割的工作单位。只有使事务中所有的数据库操作都执行成功,整个事务的执行才算成功。事务中任何一个sql语句执行失败,那么已经执行成功的sql语句也必须撤销,数据库状态应该退回到执行事务前的状态;

  2)C,表示一致性;也就是说一致性指事务将数据库从一种状态转变为另一种一致的状态,在事务开始之前和事务结束以后,数据库的完整性约束没有被破坏;

  3)I,表示隔离性;隔离性也叫做并发控制、可串行化或者锁。事务的隔离性要求每个读写事务的对象与其它事务的操作对象能相互分离,即该事务提交前对其它事务都不可见,这通常使用锁来实现;

  4)D,持久性,表示事务一旦提交了,其结果就是永久性的,也就是数据就已经写入到数据库了,如果发生了宕机等事故,数据库也能将数据恢复。

4.默认的事务都是开启的 可以通过 set autocommit = 0取消自动提交事务。

5.可以为不同的地方设置回滚点

设置回滚点:save point 保存点名称;
回滚到此:rollback 保存点名称;


6.案例

sql文件:

--
-- 数据库: `test`
--

-- --------------------------------------------------------

--
-- 表的结构 `orders`
--

CREATE TABLE IF NOT EXISTS `orders` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `num` int(10) unsigned NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=0 ;

--
-- 表的结构 `goods`
--

CREATE TABLE IF NOT EXISTS `goods` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `num` int(10) unsigned NOT NULL COMMENT 商品库存,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;

--
-- 转存表中的数据 `goods`
--

INSERT INTO `goods` (`id`, `num`) VALUES
(1, 100);

 

php文件:

<?php
/*
    事务测试
 */
$handle = mysql_connect(‘localhost‘,‘root‘,‘root‘);//mysql中的外键
mysql_query(‘set names utf8‘);//设置字符集
mysql_query(‘use test‘);//选择数据库
mysql_query("SET AUTOCOMMIT=0");//设置事务不自定提交
mysql_query("BEGIN");//开启事务
$sql1 = "insert into orders(id,num) values(null,2)";//添加订单信息
if(!mysql_query($sql1))
{
    mysql_query(‘ROLLBACK‘);//判断当执行失败时回滚
    exit;
}
$sql2 = "update goods set num = num - 2";//减少库存信息
if(!mysql_query($sql2))
{
    mysql_query(‘ROLLBACK‘);//判断当执行失败时回滚
    exit;
}
mysql_query("COMMIT");
mysql_close($handle);

 

执行结果如下:

技术分享

技术分享

 

      

以上是关于MySQL中的事务的主要内容,如果未能解决你的问题,请参考以下文章

基础-事务

片段事务分离和附加后ListView不工作?

BottomNavigationView 滞后于片段事务

理解片段事务期间片段的生命周期方法调用

深入理解mysql事务

提交带有全屏片段的片段事务