昨天说了下MySQL的正则表达式,今天我们来说下事务的基础知识。

  什么是MySQL的事务呢?

  事务是由一步或几步数据库操作序列组成逻辑执行单元,这一系列操作要么全部执行,要么全部放弃执行。  这里我们需要说下程序和事务的区别。

一段程序中可能包含多个事务(n步的数据库操作而构成的逻辑执行单元) ,很像进程和线程的关系。一个进程中可能包含多个线程。


   事务主要用于处理操作量大,复杂度高的数据。举例:人员管理系统中,删除一个人员,不仅需要删除人员的基本资料,也要删除和该人员相关的信息。

在数据库中,相当于不仅仅是删除一个id或者name,而是整个和id对应的数据。删除的这些数据库操作语句就构成了一个事务。

  1. MySQL中只有使用了 Innodb 数据库引擎的数据库或者表才支持事务(可以使用命令来查看你的数据库是什么引擎,都能支持哪些引擎)
  2. 事务处理可以用来维护数据库的完整性,保证成批的SQL语句要么全部执行,要么全部不执行。
  3. 事务用来管理 insert update delete 语句(别的MySQL语句是管不了的)


下面我们说下满足事务的条件(ACID):

A: Atomicity  或称不可分割性

     一个事务(transaction) 中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback) 到事务开始前的状态,就像这个事务从来没有执行过一样。

C: Consistency 

    在事务开始之前和事务结束之后,数据库的完整性没有被破坏。表示写入的资料必须完全符合所有的预设规则。包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。

I: Isolation  又称独立性

   数据库允许多个并发事务同时对其数据进行读写和修改的能力。隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。

事务隔离分为不同级别: 

  1. 读未提交 Read uncommitted
  2. 读提交 read committed
  3. 可重复读 repeatable read
  4. 串行化 Serializable

D: Durability 持久性

     事务处理结束后,对数据的修改就是永久的。即便系统故障也不会丢失

这里我们需要注意的是:

在MySQL命令行的默认设置下,事务都是自动提交的,执行SQL语句后就会马上执行commit操作

因此要显示地开启一个事务必须使用命令 begin 或 start transaction 或者执行命令 set autocommit = 0 用来禁止使用当前会话的自动提交


下面说下 事务的控制语句:

begin 或 start transaction  显式地开启一个事务


commit 可以使用 commit work, 二者是等价的。commit会提交事务,并使已对数据库进行的所有修改成为永久性的。


rollback可以使用 rollback work 二者是等价的。回滚会结束用户的事务,并撤销正在进行的所有未提交的修改。


savepoint identifier, savepoint 允许在事务中创建一个保存点,一个事务中可以有多个savepoint


release savepoint identifier 删除一个事务的保存点,当没有指定的保存点时,执行该语句会抛出一个异常。ERROR 1305 (42000): SAVEPOINT identifier does not exist


rollback to identifier 把事务回滚到标记点


set transaction 用来设置事务的隔离级别: InnoDB 存储引擎提供事务的隔离级别有

read uncommitted

read committed

repeatable read

serializable


MySQL 事务处理主要有两种方法:

1.用 begin rollback commit 来实现

   begin 开始一个事务

   rollback 事务回滚

   commit 事务确认


2.直接用 set 来改变 MySQL的自动提交模式

   set autocommit = 0 禁止自动提交

   set autocommit = 1 开启自动提交


说了这么多,我们来写个实例: 这次我们新建一个数据库表来写

mysql> create table star (

 -> `id` int unsigned auto_increment,

 -> `name` varchar(100) not null,

 -> `time` date,

 -> `scores` int not null,

 -> `country` varchar(30),

 -> primary key (`id`)

 -> )engine= InnoDB default charset = utf8;

Query OK, 0 rows affected (0.07 sec)

在创建数据库表时,直接设置好数据库表的引擎为 InnoDB

来看下数据库表的信息:

mysql> show columns from star;

+---------+------------------+------+-----+---------+----------------+

| Field  | Type  | Null | Key | Default | Extra |

+---------+------------------+------+-----+---------+----------------+

| id | int(10) unsigned | NO  | PRI | NULL | auto_increment |

| name | varchar(100)  | NO  |  | NULL | |

| time | date  | YES |  | NULL | |

| scores | int(11) | NO  |  | NULL | |

| country | varchar(30) | YES |  | NULL | |

+---------+------------------+------+-----+---------+----------------+

5 rows in set (0.02 sec)

通过插入数据(insert into)来查看begin和rollback的用法:

mysql> begin

 -> ;

Query OK, 0 rows affected (0.00 sec)


mysql> insert into star (name,time,scores,country) values ("LG",now(),78,"中国");

Query OK, 1 row affected, 1 warning (0.02 sec)


mysql> select * from star;

+----+------+------------+--------+---------+

| id | name | time  | scores | country |

+----+------+------------+--------+---------+

| 1 | LG  | 2020-07-03 |  78 | 中国 |

+----+------+------------+--------+---------+

1 row in set (0.00 sec)


可以看出,成功向数据库中插入了一条语句,然后我们使用rollback语句进行回滚

mysql> rollback;

Query OK, 0 rows affected (0.01 sec)


mysql> select * from star;

Empty set (0.00 sec)

可以看出star数据库表的内容又是空的了


我们再看看commit的用法

mysql> begin;

Query OK, 0 rows affected (0.00 sec)

事务开始,然后插入一条数据

mysql> insert into star (name,time,scores,country) values ("李大志",now(),88,"俄罗斯");

Query OK, 1 row affected, 1 warning (0.00 sec)

我们查询下数据库表:

mysql> select * from star;

+----+-----------+------------+--------+-----------+

| id | name | time  | scores | country  |

+----+-----------+------------+--------+-----------+

| 2 | LG | 2020-07-03 |  78 | 中国 |

| 4 | 李大志 | 2020-07-03 |  88 | 俄罗斯 |

+----+-----------+------------+--------+-----------+

2 rows in set (0.00 sec)

然后提交完成事务

mysql> commit;

Query OK, 0 rows affected (0.01 sec)


mysql> select * from star;

+----+-----------+------------+--------+-----------+

| id | name | time  | scores | country  |

+----+-----------+------------+--------+-----------+

| 2 | LG | 2020-07-03 |  78 | 中国 |

| 4 | 李大志 | 2020-07-03 |  88 | 俄罗斯 |

+----+-----------+------------+--------+-----------+

2 rows in set (0.00 sec)

再查下数据,插入的数据还在,然后我们回滚下

mysql> rollback;

Query OK, 0 rows affected (0.00 sec)


mysql> select * from star;

+----+-----------+------------+--------+-----------+

| id | name | time  | scores | country  |

+----+-----------+------------+--------+-----------+

| 2 | LG | 2020-07-03 |  78 | 中国 |

| 4 | 李大志 | 2020-07-03 |  88 | 俄罗斯 |

+----+-----------+------------+--------+-----------+

2 rows in set (0.00 sec)

commit后,即使运行回滚代码,数据也不会被回滚,因为已经commit了


这里我们需要着重点说下 set autocommit的用法

首先,我们需要先知道所在的表的autocommit值为多少,如果为0,则是禁止自动提交;

如果为1,是允许主动提交。

mysql> show variables like 'autocommit';

+---------------+-------+

| Variable_name | Value |

+---------------+-------+

| autocommit | ON  |

+---------------+-------+

1 row in set (0.01 sec)

可以看出来,数据库表是可以主动提交的。我们来将这个值设置为OFF

mysql> set autocommit = 0;

Query OK, 0 rows affected (0.00 sec)

然后我们查看下autocommit的值

mysql> show variables like 'autocommit';

+---------------+-------+

| Variable_name | Value |

+---------------+-------+

| autocommit | OFF  |

+---------------+-------+

1 row in set (0.01 sec)

嗯,已经关闭了。然后我们怎么查看事务呢?

再创建一个终端B,一直输入命令到查询star表的内容

mysql> select * from star;

+----+-----------+------------+--------+-----------+

| id | name | time  | scores | country  |

+----+-----------+------------+--------+-----------+

| 2 | LG | 2020-07-03 |  78 | 中国 |

| 4 | 李大志 | 2020-07-03 |  88 | 俄罗斯 |

+----+-----------+------------+--------+-----------+

2 rows in set (0.00 sec)


在终端A中,输入begin,然后插入数据,此时在终端B中查询数据,看是否已经插入

mysql> begin;

Query OK, 0 rows affected (0.00 sec)

mysql> insert into star (name,time,scores,country) values ("葫芦",now(),77,"英国");

Query OK, 1 row affected, 1 warning (0.01 sec)

在终端A中查询下star表的内容:

mysql> select * from star;

+----+-----------+------------+--------+-----------+

| id | name | time  | scores | country  |

+----+-----------+------------+--------+-----------+

| 2 | LG | 2020-07-03 |  78 | 中国 |

| 4 | 李大志 | 2020-07-03 |  88 | 俄罗斯 |

| 5 | 葫芦 | 2020-07-03 |  77 | 英国 |

+----+-----------+------------+--------+-----------+

3 rows in set (0.00 sec)

是有id = 5的数据


在终端B中输入查询语句

mysql> select * from star;

+----+-----------+------------+--------+-----------+

| id | name | time  | scores | country  |

+----+-----------+------------+--------+-----------+

| 2 | LG | 2020-07-03 |  78 | 中国 |

| 4 | 李大志 | 2020-07-03 |  88 | 俄罗斯 |

+----+-----------+------------+--------+-----------+

2 rows in set (0.01 sec)

发现还是2条数据


然后在终端A中commit下

mysql> commit;

Query OK, 0 rows affected (0.00 sec)


在终端B中查看下数据:

mysql> select * from star;

+----+-----------+------------+--------+-----------+

| id | name | time  | scores | country  |

+----+-----------+------------+--------+-----------+

| 2 | LG | 2020-07-03 |  78 | 中国 |

| 4 | 李大志 | 2020-07-03 |  88 | 俄罗斯 |

| 5 | 葫芦 | 2020-07-03 |  77 | 英国 |

+----+-----------+------------+--------+-----------+

3 rows in set (0.00 sec)

也有数据了


如果我们设置 set autocommit = 1呢(开启自动提交),再重复下上面的步骤

mysql> set autocommit = 1;

Query OK, 0 rows affected (0.00 sec)


mysql> show variables like 'autocommit';

+---------------+-------+

| Variable_name | Value |

+---------------+-------+

| autocommit | ON |

+---------------+-------+

1 row in set (0.00 sec)


在终端A中begin后插入数据,然后在终端B中进行查看

mysql> 

mysql> begin;

Query OK, 0 rows affected (0.00 sec)


mysql> insert into star (name,time,scores,country) values ("王五子",now(),77,"挪威");

Query OK, 1 row affected, 1 warning (0.01 sec)


在终端B中,输入查询语句,查不到已经输入的值


mysql> commit;

Query OK, 0 rows affected (0.00 sec)

还是在终端A中commit后,终端B可以查到了

mysql> select * from star;

+----+-----------+------------+--------+-----------+

| id | name | time  | scores | country  |

+----+-----------+------------+--------+-----------+

| 2 | LG | 2020-07-03 |  78 | 中国 |

| 4 | 李大志 | 2020-07-03 |  88 | 俄罗斯 |

| 5 | 葫芦 | 2020-07-03 |  77 | 英国 |

| 6 | 王五子 | 2020-07-03 |  77 | 挪威 |

+----+-----------+------------+--------+-----------+

4 rows in set (0.00 sec)


这是为什么呢?那这个 set autocommit有什么意义呢?


今天先到这里

(九)MySQL基础知识之 事务(commit, rollback,begin,set autocommit)_测试开发