MySQL在5.5版本之前,默认的存储引擎是MyISAM,它是不支持事务的,而5.5版本之后默认的引擎是InnoDB,这个是支持事务的,这也是InnoDB最终取代MyISAM称为主流引擎的重要原因。
事务的真实情况,比我下面写的还要更复杂,所以需要另外再自行查找资料。
事务,即transaction,是数据库的一个逻辑工作单元,是一组不可分割的操作集合,也是数据库进行一次处理的基本单元,要不完全执行,要么都不执行。
事务是数据库区别于文件系统的重要特性之一。有了事务,我们可以保证数据库始终保持一致性;有了事务,我们可以使得数据库恢复到任意有记录的时间点;有了事务,我们可以保证已经提交的修改不会因为中途断电而丢失(不完整)。
事务的四大特性:ACID。
这四个特性中,原子性是基础,隔离性是手段,一致性是约束条件,持久性是目的。
比较难理解的是一致性和持久性。
一致性,意味着任何写入数据库的数据都需要满足我们事先定义的约束规则。
比如说,事先我们设置name字段为唯一性约束(如主键约束),如果事务提交后或者回滚的时候,若name非唯一,就算打破了事务的一致性要求。
数据库常见的约束有:
事务执行前,数据库符合这些约束,事务执行后,数据库同样需要符合这些约束,这就是事务的一致性。如果事务中的某个操作执行失败了,系统就会自动回滚,撤销当前执行的事务,返回事务操作之前的一致性状态。
持久性,持久性是通过事务日志来保证的。事务日志包括回滚日志和重做日志。当我们通过事务对数据进行修改的时候,首先会将数据库需要做的修改信息记录到重做日志中,然后再对数据库中相应的行做改变。这样的好处是,如果执行中途数据库发生了故障而崩溃了,数据库重启后也能找到重做日志,重新执行没有执行完的修改,从而使事务具有了持久性。(提交之后100%会被执行完毕,即使数据库崩了,重启之后照样给你写进去。
)
首先你需要有一个支持事务的数据库引擎。
以MySQL举例,InnoDB引擎是支持事务的,但是MyISAM引擎就不支持事务。我们可以通过show engines
来查看当前的MySQL支持的存储引擎都有哪些,以及这些引擎是否支持事务。
常见的事务控制语句有:
使用事务有两种方式,分别为隐式事务和显式事务。
隐式事务实际上就是自动提交。Oracle中默认是不支持自动提交的,需要手写commit来显式提交。MySQL中默认自动提交(通过set autocommit =0或1来关闭开启自动提交)。
让我们看几个例子:
-- autocommit=1,即自动提交开启
CREATE TABLE test(name varchar(255), PRIMARY KEY (name)) ENGINE=InnoDB;
BEGIN;
INSERT INTO test SELECT '关羽';
COMMIT;
BEGIN;
INSERT INTO test SELECT '张飞';
INSERT INTO test SELECT '张飞';
ROLLBACK;
SELECT * FROM test;
上面其实执行了两个事务。第一个事务insert了关羽,然后正常commit了。第二个事务在第一个insert的时候正常,但是第二个insert插入张飞,打破了事务的主键约束,所以回滚整个事务。因此最终的表里只有一行“关羽”。
然后第二个例子:
-- autocommit=1,即自动提交开启
CREATE TABLE test(name varchar(255), PRIMARY KEY (name)) ENGINE=InnoDB;
BEGIN;
INSERT INTO test SELECT '关羽';
COMMIT;
INSERT INTO test SELECT '张飞';
INSERT INTO test SELECT '张飞';
ROLLBACK;
SELECT * FROM test;
由于自动commit的情况,上面实际上执行了三个事务。第一个是显式begin的那个事务,成功插入了一行关羽。第二个事务是第二个insert,因为自动提交,所以这个“张飞”也成功插入了。第三个事务是第三个insert,由于主键约束,insert失败,因此回滚了第三个事务。
事务在commit之后,就没法再回滚了!!! 那如果开了自动commit的话,除非事务出错,才会引起自动回滚,显式rollback是没用的?是这样理解吗?
第三个例子:
CREATE TABLE test(name varchar(255), PRIMARY KEY (name)) ENGINE=InnoDB;
SET @@completion_type = 1;
BEGIN;
INSERT INTO test SELECT '关羽';
COMMIT;
INSERT INTO test SELECT '张飞';
INSERT INTO test SELECT '张飞';
ROLLBACK;
SELECT * FROM test;
在MySQL中,如果是连续BEGIN,开启了第一个事务,还没有进行COMMIT提交,而直接进行第二个事务的BEGIN,数据库会隐式的帮助COMMIT第一个事务,然后进入到第二个事务
第三个例子跟第二个例子只有一点不同,就是多了一个@@completion_type
这个变量。这个参数的取值及作用有3种可能:
commit;begin
,提交事务后会再开启一个相同隔离级别的链式事务。commit and release
,提交后会自动与服务器断开连接;所以上面的例子,实际上只插入了关羽一行,因为第一个commit = commit and begin,后面两个insert被自动包括进一个事务了。
当设置autocommit=0的时候,取消自动提交,那么不论是否采用begin的方式显示开启事务,都需要手动commit来提交,使得事务生效,使用rollback来对事务回滚。
不过,当设置autocommit=1的时候,允许自动提交,那当显式使用start transaction或者begin的方式开启事务时,只有在显式commit的时候才会生效,显式rollback的时候才会回滚
在MySQL中,当取消自动提交时,连续begin,第二个begin会自动commit第一个事务,保证每次只处理一个事务。
2021-7-4 17:15:01 事务这里还是很重要的,推荐后续大块时间走一遍