1、CURD操作不加控制时,可能会出现什么问题
即:类似于线程安全问题,可能会导致数据不一致问题。
因为,MySQL内部本身就是多线程服务。
1.1、CURD满足什么属性时,才能避免上述问题
1、买票的过程得是原子的吧。
2、买票互相应该不能影响吧。
3、买完票应该要永久有效吧。
4、买前,和买后都要是确定的状态吧。
2、什么是事务
1、事务就是一组DML(数据操作语言)语句组成,这些语句在逻辑上存在相关性。
2、这一组DML语句要么全部成功,要么全部失败,是一个整体。
3、MySQL提供一种机制,保证我们达到这样的效果。
4、事务还规定不同的客户端看到的 数据是不相同的。
因此,一个完整的事务,绝对不是一个简单的sql语句的组成,还需要满足以下4个属性:
2.1、事务的4个属性 -- ACID
原子性(Atomicity) | 一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成。 在执行过程中如果出错,会回滚到事务开始的时候。就像似事务根本没有开始。 |
一致性(Consistency) | 在事务开始之前和结束之后,数据库的完整性没有发生破坏。 这表示写入的资料必须完 全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工 作。 |
隔离性(Isolation) | 数据库允许多个并发事务同时对其数据进行读写和修改的能力。 隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。 事务的隔离分为不同的级别。 |
持久性(Durability) | 事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。 |
上面的四个属性,可简称为ACID。
2.2、为什么会出现事务
事务被 MySQL 编写者设计出来,本质是为了当应用程序访问数据库的时候,事务能够简化我们的编程模型, 不需要我们去考虑各种各样的潜在错误和并发问题。
可以想一下当我们使用事务时,要么提交,要么回滚,我 们不会去考虑网络异常了,服务器宕机了,同时更改一个数据怎么办对吧。
因此事务本质上是为了应用层服 务的.而不是伴随着数据库系统天生就有的
备注:我们后面把 MySQL 中的一行信息,称为一行记录。
2.3、事务的版本支持--InnoDB
在 MySQL 中只有使用了InnoDB数据库引擎的数据库或表才支持事务,MyISAM不支持。
查看数据库引擎:
mysql> show engines; --- 表格显示
mysql> show engines \G --- 行显示
*************************** 1. row ***************************Engine: InnoDB -- 引擎名称
Support: DEFAULT -- 默认引擎
Comment: Supports transactions, row-level locking, and foreign keys -- 描述
Transactions: YES -- 支持事务
XA: YESSavepoints: YES -- 支持事务保存点
*************************** 2. row ***************************Engine: MRG_MYISAMSupport: YESComment: Collection of identical MyISAM tablesTransactions: NOXA: NOSavepoints: NO*************************** 3. row ***************************Engine: MEMORY --内存引擎
Support: YESComment: Hash based, stored in memory, useful for temporary tablesTransactions: NOXA: NOSavepoints: NO*************************** 4. row ***************************Engine: BLACKHOLESupport: YESComment: /dev/null storage engine (anything you write to it disappears)
Transactions: NOXA: NOSavepoints: NO*************************** 5. row ***************************Engine: MyISAM
Support: YESComment: MyISAM storage engineTransactions: NO -- MyISAM不支持事务
XA: NOSavepoints: NO*************************** 6. row ***************************Engine: CSVSupport: YESComment: CSV storage engineTransactions: NOXA: NOSavepoints: NO*************************** 7. row ***************************Engine: ARCHIVESupport: YESComment: Archive storage engineTransactions: NOXA: NOSavepoints: NO*************************** 8. row ***************************Engine: PERFORMANCE_SCHEMASupport: YESComment: Performance SchemaTransactions: NOXA: NOSavepoints: NO*************************** 9. row ***************************Engine: FEDERATEDSupport: NOComment: Federated MySQL storage engineTransactions: NULLXA: NULLSavepoints: NULL9 rows in set (0.00 sec)
3、事务的提交方式
事务的提交方式常见有两种:
自动提交。
手动提交。
查看当前事务的提交方式:
mysql> show variables like 'autocommit';+---------------+-------+| Variable_name | Value |+---------------+-------+| autocommit | ON |+---------------+-------+1 row in set (0.41 sec)
此时就是显示,打开了自动提交方式。
通过SET来改变提交方式:
1、AUTOCOMMIT = 0,禁止自动提交 -- 即手动提交。
mysql> SET AUTOCOMMIT=0;
Query OK, 0 rows affected (0.00 sec)#SET AUTOCOMMIT=0 禁止自动提交
mysql> show variables like 'autocommit';+---------------+-------+| Variable_name | Value |+---------------+-------+| autocommit | OFF |+---------------+-------+1 row in set (0.00 sec)
2、AUTOCOMMIT = 1,开启自动提交。
mysql> SET AUTOCOMMIT=1;
#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.01 sec)
4、事务的常见操作方式
1、便于演示,将隔离级别设置为读未提交:
mysql> set global transaction isolation level READ UNCOMMITTED;
Query OK, 0 rows affected (0.01 sec)设置完成后需要重新登陆mysql才生效
mysql> select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| READ-UNCOMMITTED |
+-------------------------+
1 row in set (0.00 sec)
2、创建测试表account:
mysql> create table if not exists account(-> id int primary key,-> name varchar(50) not null default '',-> balance decimal(10,2) not null default 0.0-> )ENGINE=InnoDB;
Query OK, 0 rows affected (0.08 sec)
4.1、正常演示:证明事务的开始和回滚:
查看事务的提交方式,故意设置为自动提交,看是否影响begin
mysql> show variables like 'autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit | ON |
+---------------+-------+
1 row in set (0.10 sec)开启事务,推荐使用begin
mysql> start transaction;
Query OK, 0 rows affected (0.02 sec)设置一个回滚点
mysql> savepoint save1;
Query OK, 0 rows affected (0.00 sec)插入一条数据
mysql> insert into account values (1,'张三',1000);
Query OK, 1 row affected (0.01 sec)再设置一个回滚点
mysql> savepoint save2;
Query OK, 0 rows affected (0.00 sec)再插入一条数据
mysql> insert into account values (2,'李四',2000);
Query OK, 1 row affected (0.00 sec)查看数据是否都存在
mysql> select * from account;
+----+--------+---------+
| id | name | balance |
+----+--------+---------+
| 1 | 张三 | 1000.00 |
| 2 | 李四 | 2000.00 |
+----+--------+---------+
2 rows in set (0.00 sec)回滚到第二个回滚点
mysql> rollback to save2;
Query OK, 0 rows affected (0.00 sec)再查看数据,第二条数据没了
mysql> select * from account;
+----+--------+---------+
| id | name | balance |
+----+--------+---------+
| 1 | 张三 | 1000.00 |
+----+--------+---------+
1 row in set (0.00 sec)直接rollback,回滚到最开始
mysql> rollback;
Query OK, 0 rows affected (0.00 sec)数据全都没了
mysql> select * from account;
Empty set (0.00 sec)
4.2、非正常演示1 - 证明未commit,客户端崩溃,MySQL自动会回滚(隔离级别设置为读未提交):
终端A:
当前表内没数据
mysql> select * from account;
Empty set (0.00 sec)提交方式为自动提交
mysql> show variables like 'autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit | ON |
+---------------+-------+
1 row in set (0.00 sec)开启事务
mysql> begin;
Query OK, 0 rows affected (0.00 sec)插入数据
mysql> insert into account values (1,'张三',1000);
Query OK, 1 row affected (0.01 sec)查看数据存在,但是没有commit
mysql> select * from account;
+----+--------+---------+
| id | name | balance |
+----+--------+---------+
| 1 | 张三 | 1000.00 |
+----+--------+---------+
1 row in set (0.00 sec)然后使用ctrl + \ 来异常终止MySQL服务
mysql> Aborted
终端B:
终端A崩溃前查看数据 --- 存在
mysql> select * from account;
+----+--------+---------+
| id | name | balance |
+----+--------+---------+
| 1 | 张三 | 1000.00 |
+----+--------+---------+
1 row in set (0.00 sec)终端A崩溃后查看数据 --- 数据自动回滚
mysql> select * from account;
Empty set (0.00 sec)
4.3、非正常演示2 - 证明commit了,客户端崩溃,MySQL数据不会在受影响,已经持久化
终端A:
mysql> select * from account;
Empty set (0.00 sec)mysql> show variables like 'autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit | ON |
+---------------+-------+
1 ro