ICode9

精准搜索请尝试: 精确搜索
首页 > 数据库> 文章详细

MySQL的事务和索引

2020-07-20 11:04:26  阅读:266  来源: 互联网

标签:事务 rows MySQL 索引 +----+----------+ sec mysql select


目录

MySQL的事务-TCL(Transaction)

什么是事务

一个事务是一个完整的业务逻辑单元,不可再分。

比如:银行账户转账,从A账户向B账户转账10000,需要执行两条update语句:
	update t_act set balance = balance - 10000 where actno = 'act-001';
	update t_act set balance = balance + 10000 where actno = 'act-001';
	以上两条DML语句必须同时成功,或者同时失败,不允许出现一条成功,一条失败。
	要想保证以上的两条DML语句同时成功或者同时失败,那么就需要使用数据库的“事务机制”。
和事务相关的语句只有:DML语句。(insert delete update)
	为什么?因为它们这三个语句都是和数据库表当中的“数据”相关的。
	事务的存在是为了保证数据的完整性,安全性。

假设所有的业务都能使用1条DML语句搞定,还需要事务机制吗?
	不需要事务。
	但实际情况不是这样的。通常一个事务(业务)需要更多DML语句共同联合完成。

事物的特性

事务包括四大特性:ACID
	A:原子性:事务是最小的工作单元,不可再分。
	C:一致性:事务必须保证多条DML语句同时成功或者同时失败。
	I:隔离性:事务A与事务B之间具有隔离。
	D:持久性:持久性说的是最终数据必须持久化到硬盘文件中,事务才算成功的结束。

事务之间的隔离性

事务隔离性存在隔离级别,理论上隔离级别包括4个:
	第一级别:读未提交(read uncommitted)
		对方事务还没有提交,我们当前事务可以读取到对方未提交的数据。
		对方提交存在脏读(Dirty Read)现象:表示堵到了脏的数据。
		
	第二级别:读已提交(read committed)
		对方事务提交之后的数据我方可以读取到。
		这种隔离级别解决了脏读现象。
		读已提交存在的问题是:不可重复读。
		
	第三级别:可重复读(repeatable read)
		这种隔离级别解决了不可重复读问题。
		这种隔离级别存在的问题是:读取到的数据是幻想。
		
	第四级别:序列化读/串行化读
		解决了所有问题
		效率低,需要事务排队。
		
Oracle数据默认的隔离级别是:读已提交。
MySQL数据库默认的隔离级别是:可重复读。

验证隔离级别

设置事务的全局隔离级别:
	set global transaction isolation level 隔离级别;
查看事务的全局隔离级别:
	select @@global.tx_isolation;
现表内数据:
mysql> select * from person;
+----+----------+
| id | name     |
+----+----------+
|  1 | ZHANGSAN |
|  2 | LISI     |
|  3 | WANGWU   |
+----+----------+
3 rows in set (0.00 sec)

读未提交-read uncommitted

需要先设置隔离级别为read uncommitted(读未提交)set global transaction isolation level read uncommitted 设置完成后需要exit退出一下再进入执行一下命令

image-20200719215053309

读已提交-read committed

image-20200719220510533

序列化-serializable

用户A
mysql> select @@global.tx_isolation;	//第一步:查看到当前隔离级别
+-----------------------+
| @@global.tx_isolation |
+-----------------------+
| SERIALIZABLE          |
+-----------------------+
1 row in set (0.00 sec)

mysql> use test;
Database changed
mysql> select * from person;	//第二步:查询表内容
+----+----------+
| id | name     |
+----+----------+
|  1 | ZHANGSAN |
|  2 | LISI     |
|  3 | WANGWU   |
+----+----------+
3 rows in set (0.00 sec)

mysql> start transaction;	//第三步:关闭自动提交机制
Query OK, 0 rows affected (0.00 sec)

mysql> select * from person;	//第六步:当用户在person表内插入了新的内容,查询person表全部信息会发现光标在闪烁,一直等到用户commit后才会查询到	+----+----------+						person表的全部内容
| id | name     |
+----+----------+
|  1 | ZHANGSAN |
|  2 | LISI     |
|  3 | WANGWU   |
|  9 | XIAOHUA  |
+----+----------+
4 rows in set (10.66 sec)

用户B
mysql> use test;
Database changed
mysql> start transaction;	//第四步:关闭自动提交机制
Query OK, 0 rows affected (0.00 sec)

mysql> insert into person(name) values('XIAOHUA'); //第五步:插入新内容
Query OK, 1 row affected (0.00 sec)

mysql> commit;	//第七步:提交
Query OK, 0 rows affected (0.01 sec)

可重复读-repeatable read

image-20200719223524560

演示事务

  • start transaction 关闭自动提交机制 ,
  • rollback 回滚机制
  • commit 提交机制
mysql事务默认情况下是自动提交的。(什么是自动提交?只要执行任意一条DML语句则提交一次。)怎么关闭自动提交? start transaction;

准备表:
	drop table if exists t_user;
	create table t_user(
        id int primary key auto_increment,
        username varchar(255)
    );
演示:当没有使用 回滚和提交机制
	mysql> insert into t_user(username) values('zhangsan');
    Query OK, 1 row affected (0.01 sec)

    mysql> select * from t_user;
    +----+----------+
    | id | username |
    +----+----------+
    |  1 | zhangsan |
    +----+----------+
    1 row in set (0.00 sec)

    mysql> rollback;				//回滚后数据没有发生改变
    Query OK, 0 rows affected (0.00 sec)

    mysql> select * from t_user;
    +----+----------+
    | id | username |
    +----+----------+
    |  1 | zhangsan |
    +----+----------+
    1 row in set (0.00 sec)
    
演示:使用 start transaction; 关闭自动提交机制.
    mysql> start transaction;
    Query OK, 0 rows affected (0.00 sec)

    mysql> insert into t_user(username) values('lisi');
    Query OK, 1 row affected (0.00 sec)

    mysql> select * from t_user;
    +----+----------+
    | id | username |
    +----+----------+
    |  1 | zhangsan |
    |  2 | lisi     |
    +----+----------+
    2 rows in set (0.00 sec)

    mysql> rollback;	//因为关闭了自动提交机制,所以回滚后发现刚才插入的数据删除了。
    Query OK, 0 rows affected (0.01 sec)

    mysql> select * from t_user;
    +----+----------+
    | id | username |
    +----+----------+
    |  1 | zhangsan |
    +----+----------+
    1 row in set (0.00 sec)
	
演示:使用 commit; 提交机制
	mysql> start transaction;
	Query OK, 0 rows affected (0.00 sec)
	
	mysql> insert into t_user(username) values('jack'),('rose');
	Query OK, 2 rows affected (0.00 sec)
	Records: 2  Duplicates: 0  Warnings: 0
	
	mysql> select * from t_user;
    +----+----------+
    | id | username |
    +----+----------+
    |  1 | zhangsan |
    |  3 | jack     |
    |  4 | rose     |
    +----+----------+
    3 rows in set (0.00 sec)
	
	mysql> commit;
    Query OK, 0 rows affected (0.01 sec)

    mysql> rollback;	//当commit提交过后 就会发现回滚数据没有发生改变
    Query OK, 0 rows affected (0.00 sec)

    mysql> select * from t_user;
    +----+----------+
    | id | username |
    +----+----------+
    |  1 | zhangsan |
    |  3 | jack     |
    |  4 | rose     |
    +----+----------+
    3 rows in set (0.00 sec)

索引

什么是索引?有什么用?

索引就相当于一本书的目录,通过目录可以快速的找到对应的资源。
在数据库方面,查询一张表的时候有两种检索方式:
	第一种方式:全表扫描
	第二种方式:根据索引检索(效率很高)
	
索引为什么可以提高检索效率呢?
	其实最根本的原理是缩小了扫描的范围。
索引虽然可以提高检索效率,但是不能随意的添加索引,因为索引也是数据库当中的对象,也需要数据库不断的维护。是有维护成本的。比如:表中的数据经常被修改这样就不适合添加索引,因为数据一旦修改,索引需要重新排列,进行维护。

如何创建和删除索引?

创建索引对象:
	create index 索引名称 on 表名(字段名;
删除索引对象:
	drop index 索引名称 on 表名;

什么时候给字段添加索引?

数据量庞大(根据客户的要求,根据线上的环境)
该字段很少的DML操作(因为字段进行修改操作,索引也需要维护)
该字段经常出现在where子句中(经常根据哪个字段查询)

注意:主键和具有unique约束的字段自动回添加索引。
根据主键查询效率较高,尽量根据主键检索。

查看sql语句的执行计划

mysql> explain select ename,sal from emp where sal=5000;
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | emp   | ALL  | NULL          | NULL | NULL    | NULL |   14 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+

给薪资sal字段添加索引:
mysql> create index emp_sal_index on emp(sal);
mysql> explain select ename,sal from emp where sal=5000;  	//	查询后会发现检索方式不是ALL而是ref了 检索条目rows不是14而是1了
+----+-------------+-------+------+---------------+---------------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key           | key_len | ref   | rows | Extra       |
+----+-------------+-------+------+---------------+---------------+---------+-------+------+-------------+
|  1 | SIMPLE      | emp   | ref  | emp_sal_index | emp_sal_index | 9       | const |    1 | Using where |
+----+-------------+-------+------+---------------+---------------+---------+-------+------+-------------+

索引的实现原理

索引的底层采用的数据结构是:B + Tree

通过B Tree缩小扫描范围,底层索引进行了排序、分区,索引回携带数据在表中的“物理地址”,最终通过索引检索到数据之后,获取到关联的物理地址,通过物理地址定位表中的数据,效率是最高的。
	select ename from emp where ename = 'SMITH';
	通过索引转换为:
		select ename from emp where 物理地址 = 0x123;

索引的分类

单一索引:给单个字段添加索引
复合索引:给多个字段联合添加1个索引
主键索引:主键上会自动添加索引
唯一索引:有unique约束的字段上会自动添加索引

索引什么时候会失效?

select ename from emp where ename like '%A%';
模糊查询的时候,第一个通配符使用的是%,这个时候索引是失效的。

标签:事务,rows,MySQL,索引,+----+----------+,sec,mysql,select
来源: https://www.cnblogs.com/xiaokw/p/13343896.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有