开启事务在MySQL中是非常重要的,它能起到保证数据的安全。
InnoDB存储引擎支持事务,Myisam不支持,这就是InnoDB比Myisam用的多的主要原因。
通常,在此之前,我们说,一条语句使用一个分号(;)来结束,并得到执行。
那么我们说,这个“一次性执行”的过程,可以称为“一个事务”。
简单来说,“一条sql语句,就是一个事务”。
则:
数据库(自然包括mysql数据库)中的事务,是指,可以将“多条语句”的执行,当作“一条语句”来看到的一种内部机制。
即:“事务”是一种可以保证“多条语句一次性执行完成”或“一条都不执行”的机制,即多条SQL语句要么全部执行成功,要么一个都不执行。
看一个实际应用需求(银行存款):表名cunkuan
银行转账:现在,test1突然需要一笔钱,买iPhone6,向test2借钱4000。
第一步: update cunkuan set 存款=存款-4000 where id=2;
第一步做完,突然断电了或者程序因为其他原因报错了,下面第二步执行不了了。
第二步: update cunkuan set 存款=存款+4000 where id=1;
则如果没有事务,就可能发生这种事情(惨案)。
如果有了事务,则就可以避免该事情(第二步不执行,第一步执行的结果不生效)。
事务可以看作是一个“容器”,将多条语句,放入该容器,最后,只要一个命令行,来决定其中的所有语句是否“执行”。
往深了讲:
执行一条SQL语句,先在内存里运算完得到最终的数据结果,然后把数据结果写入硬盘。
开启事务后,
执行一条SQL语句,先在内存里运算完得到最终的数据结果,暂时不把数据结果写入硬盘。
接着执行下一条,直到整个事务的所有SQL语句执行完毕,一块把数据结果写入硬盘。
如果中间出现了差错,“回滚事务”,整个事务的已经执行的SQL语句作废。
原子性:一个事务中的所有语句,应该做到:要么全做,要么一个都不做。
一致性:让数据保持逻辑上的“合理性”,比如:一个商品出库时,既要让商品库中的该商品数量减1,又要让对应用户的购物车中的该商品加1。
隔离性:如果多个事务同时并发执行,但每个事务就像各自独立执行一样。
持久性:一个事务执行成功,则对数据来说应该是一个明确的硬盘数据更改(而不仅仅是内存中的变化)。
事务模式:就是让每条执行语句是否当作“一个事务”来看到的设定项。
mysql默认安装好之后,其事务模式是:一条语句当作一个事务。
比如:
拿user_info做例子,它是InnoDB存储引擎的表
数据主键ID最高是25
在cmd中插入新数据:
在Navicat中打开:
说明:cmd和Navicat是MySQL两个不同的终端,像这样的情况基本上说明数据已存入到MySQL(硬盘)里了。
我们可以将其修改为:事务需要“认可”模式:
set autocommit = 0;
//false,关闭该模式,即此时不再是一条语句一个事务了。
//结果是:必须使用commit语句才能够生效。
看下面的SQL语句:
关闭自动事务提交,插入新数据,在cmd终端下显示插入成功了,用select查询语句也能查到。
在Navicat下刷新下:
不显示新插入的数据。(不信的话大家自己去做测试)
在cmd下执行:
再刷新Navicat,有了:
注意:
autocommit = 0 时,每条语句的默认行为都不会自动提交,需要commit;来提交。
autocommit = 1 时,我们也仍然可以使用事务的完整流程模式来实现事务,如下:
1,声明事务开始:start transaction; 或者 begin;
2, 设定多条要执行的具体语句,比如:insert, update, delete, select。。。其实就是执行,只是这些执行的语句,并不“生效”——其只是内存状态下的执行,而不是物理状态的执行。
3,判断是否需要执行该些语句,在PHP下的逻辑通常这样:
if( 判断是否有错误){
//执行——才针对执行了物理性改变——即生效。
commit;
}
eslse{
//回滚——不执行任何语句。
rollback;
}
发生错误,cmd中直接观察,php中通过语句的返回结果是否为false判断。
使用事务完整转账这件事情(假设为cmd模式):
start transaction;
#第一步:
update cunkuan set 存款=存款-4000 where id=2;
#第一步做完,突然断电了?
#第二步:
update cunkuan set 存款=存款+4000 where id=1;
则如果这两条语句都没有错误,就可以:
commit;
但,如果其中发生了错误,则可以:
rollback;
额外说明:
1)默认rollback
开启一个事务后,执行了多条SQL语句,既没有commit也没有rollback,就把终端关闭了(适用于所有终端),那MySQL默认rollback,不会提交的。
2)默认commit
在一个事务的结尾直接“begin”开启新的事务,会默认“commit”提交前一个事务的。
有些语句不能被回滚直接提交。通常,这些语句包括数据定义语言(DDL)语句,比如创建或取消数据库的语句,和创建、取消或更改表或存储的子程序的语句。
在设计事务时,不应包含这类语句。如果在事务的过程中发布了一个不能被回滚的语句,则后面的其它语句即便发生错误,在这些情况下,通过发布ROLLBACK语句不能回滚事务的全部效果。
楠神在PHP项目、cmd中都测试过,开启事务后执行了多条SQL语句,因为程序的出错,脚本结束了,也意味着PHP脚本终端关闭了,前面执行的SQL语句都没有执行。
总结:
这节我们先简单了解下事务是什么,怎么用。关于事务的知识远没有结束,MySQL锁的机制就和事务紧密相关,下一章会重点介绍。
什么是锁?
就像上面的转账功能,两个账户一个减一个增,两条update语句,事务能保证两条update语句一块执行。而锁的作用可保证在执行这两条update语句的时候,不让额外的其他SQL语句影响了这两条update语句的执行,确保数据安全。所以在执行这两条update语句时需要给相应的数据加上锁,申明我正在操作,其他的语句先靠边。
楠神觉着MySQL是PHP项目的核心内容,而表结构设计、索引、事务是MySQL的核心内容(表结构设计合理,易读,减少数据量,提高效率;索引添加的好可提高查询效率;事务可保证数据修改的安全性)。我们所学的SQL语句只是让我们学会了怎么用MySQL,而表结构设计、索引、事务的一些相关知识、原理只有了解了,学好了,才能用好MySQL。