mysql事务:
就是把mysql的多条操作语句视为一个整体单元,多条语句中全部执行成功才视为成功,若其中一条语句失败就视为多个语句组成的操作整体失败。这种批量操作叫做事务。
事务主要用于处理操作量大,复杂度高的数据
在 MySQL 中只有使用了 Innodb 数据库引擎的数据库或表才支持事务。
事务处理可以用来维护数据库的完整性,保证成批的 SQL 语句要么全部执行,要么全部不执行。
事务用来管理 insert,update,delete 语句
一个完整的业务需要批量的DML(insert、update、delete)语句共同联合完成
事务只和DML语句有关,或者说DML语句才有事务。这个和业务逻辑有关,业务逻辑不同,DML语句的个数不同
两台DML语句必须同时成功或者同时失败。最小单元不可再分,当第一条DML语句执行成功后,并不能将底层数据库中的第一个账户的数据修改,
只是将操作记录了一下;这个记录是在内存中完成的;
当第二条DML语句执行成功后,和底层数据库文件中的数据完成同步。
若第二条DML语句执行失败,则清空所有的历史操作记录,要完成以上的功能必须借助事务
(在事务进行过程中,未结束之前,DML语句是不会更改底层数据,只是将历史操作记录一下,在内存中完成记录。
只有在事务结束的时候,而且是成功的结束的时候,才会修改底层硬盘文件中的数据)
操作:
begin or start transaction 开启事务
commit:提交确认 (COMMIT 会提交事务,并使已对数据库进行的所有修改成为永久性的)
rollback:回滚 (回滚会结束用户的事务,并撤销正在进行的所有未提交的修改)
在 MySQL 命令行的默认设置下,事务都是自动提交的,即执行 SQL 语句后就会马上执行 COMMIT 操作。
因此要显式地开启一个事务务须使用命令 BEGIN 或 START TRANSACTION,或者执行命令 SET AUTOCOMMIT=0,用来禁止使用当前会话的自动提交。
直接用 SET 来改变 MySQL 的自动提交模式:
SET AUTOCOMMIT=0 禁止自动提交(set session autocommit=0;)
SET AUTOCOMMIT=1 开启自动提交(set global autocommit=0;)
注意,上述SQL修改会话系统变量或全局系统变量,只对当前实例有效,如果MySQL服务重启的话,这些设置就会丢失,如果要永久生效,就必须在配置文件中修改系统变量。
查看隔离级别:
show session variables like 'autocommit'; 当前会话
show global variables like 'autocommit'; mysql全局
Value的值为ON,表示autocommit开启。OFF表示autocommit关闭。
事务四大特征(ACID)
原子性(A):事务是最小单位,不可再分(多条语句视为一个操作单元)
一致性(C):事务要求所有的DML语句操作的时候,必须保证同时成功或者同时失败
隔离性(I):事务A和事务B之间具有隔离性
持久性(D):是事务的保证,事务终结的标志(内存的数据持久到硬盘文件中)
原子性:一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,
会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
一致性:在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,
这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。
隔离性:数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。
事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。
持久性:事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
隔离性有隔离级别(4个)
读未提交:read uncommitted
读已提交:read committed
可重复读:repeatable read
串行化:serializable
读未提交:
-事务A和事务B,事务A未提交的数据,事务B可以读取到
- 这里读取到的数据叫做“脏数据”
- 这种隔离级别最低,这种级别一般是在理论上存在,数据库隔离级别一般都高于该级别
读已提交:
- 事务A和事务B,事务A提交的数据,事务B才能读取到
- 这种隔离级别高于读未提交
- 换句话说,对方事务提交之后的数据,我当前事务才能读取到
- 这种级别可以避免“脏数据”
- 这种隔离级别会导致“不可重复读取”
可重复读:
- 事务A和事务B,事务A提交之后的数据,事务B读取不到
- 事务B是可重复读取数据
- 这种隔离级别高于读已提交
- 换句话说,对方提交之后的数据,我还是读取不到
- 这种隔离级别可以避免“不可重复读取”,达到可重复读取
- 比如1点和2点读到数据是同一个
- MySQL默认级别
- 虽然可以达到可重复读取,但是会导致“幻像读”
串行化:
- 事务A和事务B,事务A在操作数据库时,事务B只能排队等待
- 这种隔离级别很少使用,吞吐量太低,用户体验差
- 这种级别可以避免“幻像读”,每一次读取的都是数据库中真实存在数据,事务A与事务B串行,而不并发
1.查看当前会话隔离级别
select @@tx_isolation;
2.查看系统当前隔离级别
select @@global.tx_isolation;
设置隔离级别:
可以在my.ini文件中使用transaction-isolation选项来设置服务器的缺省事务隔离级别。
[mysqld]
transaction-isolation = READ-UNCOMMITTED|READ-COMMITTED|REPEATABLE-READ|SERIALIZABLE
通过命令动态设置隔离级别
隔离级别也可以在运行的服务器中动态设置,应使用SET TRANSACTION ISOLATION LEVEL语句。
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
事务隔离级别
– 全局级:对所有的会话有效
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
– 会话级:只对当前的会话有效
SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
1.什么是索引?
索引就是类似书的目录,提高检索数据的效率。
索引是系统按照某个具体的算法(哈希,散列,二叉树),将数据从全部数据里进行提取,维护成一个索引文件,然后系统在进行数据查询的时候,
发现如果查询条件刚好满足索引条件,就可以从索引文件中快速的定位的数据所在位置。
主键索引(primary key效率最高的索引)
唯一索引(unique key):不为空的情况下效率最高
普通索引(index)对数据没有要求,文件很大,效率比较低
复合索引
全文索引(fulltext),对整个文章内部进行关键字索引(mysql5.5以后InnoDB支持全文索引)
英文的全文索引很简单:英文单词默认是用空格分离的
中文的全文索引很难:中文的词组成很麻烦,需要利用分词工具(sphinx,es,xs)
唯一索引(unique key):字段数据是唯一的,数据内容里面能为null,在一张表里面,是可以添加多个唯一索引,数值不能重复。
主键索引(primary key ):数据记录里面不能有null,数据内容不能重复,在一张表里面不能有多个主键索引。
普通索引(index ):使用字段关键字建立的索引,主要是提高查询速度。
全文索引(fulltext index):在比较老的版本中,只有myisam引擎支持全文索引,在最新的版本中(可能是mysql.5.6)innodb引擎也支持全文索引,在mysql中全文索引不支持中文。
添加索引的注意事项:
(1)较频繁的作为查询条件字段应该创建索引
select * from emp where empno = 1
唯一性太差的字段不适合单独创建索引,即使频繁作为查询条件
select * from emp where sex = '男‘
更新非常频繁的字段不适合创建索引
select * from emp where logincount = 1
(2)不会出现在WHERE子句中字段不该创建索引
添加索引:
在创建表的时候,同时创建索引,
1)create table stu(
id int primary key auto_increment,
name varchar(32) not null,
age tinyint unsigned not null,
email varchar(32) not null,
intro text,
unique key (name),
index (email),
fulltext index (intro)
)engine=myisam charset=utf8
2)alter table 表名 add 索引名称 (字段名);
alter table 表名 add unique key (name), add index (email), add fulltext index (intro);
查看索引:
show index form 表名\G;
show indexes from 表名;
desc 表名;
show create table 表名;
删除索引:
alter table 表名 drop index 索引名字
分析SQL语句:
主要用于分析sql语句的执行情况(并不执行sql语句)得到sql语句是否使用了索引,使用了哪些索引。
语法:explain sql语句\G;
或 desc sql语句\G;
对于创建的多列(复合)索引,只要查询条件使用了最左边的列,索引一般就会被使用。 (最左原则)
因为复合索引是需要按顺序执行的,比如c1234组合索引,要想在c2上使用索引,必须先在c1上使用索引,要想在c3上使用索引,必须先在c2上使用索引,依此。
对于使用like的查询,查询如果是”%aaa”,不会使用到索引,‘aaa%’会使用到索引。
用like查询的时候当取出的数据量超过表中数据的20%,优化器就不会使用索引,而是全表扫描。
如果条件中有or,则要求or的索引字段都必须有索引,否则不能用到索引。
如果列类型是字符串,一定要在条件中将数据使用引号引用起来,否则不使用索引。
优化group by语句。
默认情况下, mysql对所有的group by col1,col2进行排序。如果查询中包括group by 但用户想要避免排序结果的消耗,则可以使用order by null禁止排序。
索引覆盖是指:如果查询的列恰好是索引的一部分,那么查询只需要在索引文件上进行,不需要回行到磁盘再找数据,这种查询速度非常快,称为“索引覆盖”
案例1,如下对name字段添加了普通索引,要查询name字段信息。
select name from student where name='zhangsan';
注意: 如果要使用覆盖索引,一定要注意SELECT 列表值取出需要的列,不可以是SELECT *,因为如果将所有字段一起做索引会导致索引文件过大,
查询性能下降,不能为了利用覆盖索引而这么做
truncate table table_name;
清空表数据,主键自增id从新开始。
因为数据在磁盘中被删除掉了(物理删除),结构发生改变,两者的查询的结果不一致,
要想使结果一致,不能进行物理删除,给表增加一个字段来区分是否删除。
使用optimize table 表名;
执行optimize table 表名,命令后,把原来的碎片空间给释放掉
注意:修复表的数据及索引碎片,就会把所有的数据文件重新整理一遍,使之对齐,这个过程,如果表的行数比较大,也是比较耗费资源的操作,所以,不能频繁的修复。
如果表的update操作很频繁,可以按周月来修复
锁机制
mysql 的锁有以下几种形式:
表级锁:开销小,加锁快,发生锁冲突的概率最高,并发度最低。myisam引擎属于这种类型。
行级锁:开销大,加锁慢,发生锁冲突的概率最低,并发度也最高。innodb属于这种类型。
对myisam表的读操作(加读锁),不会阻塞其他进程对同一表的读请求,但会阻塞对同一表的写请求。只有当读锁释放后,才会执行其他进程的操作。
对myisam表的写操作(加写锁),会阻塞其他进程对同一表的读和写操作,只有当写锁释放后,才会执行其他进程的读写操作。
read:所有人都只可以读,但是不能进行写操作,只有释放锁之后才可以写。
write:只有锁表的客户可以操作这个表读写都可以,其他客户读都不能读写
语法:
lock table 表名 read|write,
解锁:
unlock table
对表添加锁定后,只能操作锁定的表,如果想要操作其他表,则可以在锁定表时,一次性锁定多张表。语法:lock table 表1 read,表2 read;
存储引擎 innoDB
事务和锁共存(事务本身就是利用锁机制来完成)
1、共享锁: 又称读锁
①当前事务可以进行查询和修改操作,其他事务(线程)必须等当前事务提交后才能进行操作,查询可以查,但是结果并不是当前事务提交前结果(两者数据不同步),修改必须等当前事务提交后才能正常操作
②如果给当前事务加了共享锁,其他事务(线程)也可以加共享锁,但是不能加排他锁
2、排他锁 又称写锁
①给当前事务(线程)加上排他锁后,其他事务(线程)既不能加共享锁也不能加排他锁,只有当前事务提交后才能操作
②当前事务可以进行查询和修改操作,其他事务(线程)必须等当前事务提交后才能进行操作,查询可以查,但是结果并不是当前事务提交前结果(两者数据不同步),
修改必须等当前事务提交后才能正常操作
1.共享锁只用于表级,排他锁用于行级。
2.加了共享锁的对象,可以继续加共享锁,不能再加排他锁。加了排他锁后,不能再加任何锁。
3.比如一个DML操作,就要对受影响的行加排他锁,这样就不允许再加别的锁,也就是说别的会话不能修改这些行。同时为了避免在做这个DML操作的时候,有别的会话执行DDL,修改表的定义,所以要在表上加共享锁,这样就阻止了DDL的操作。
4.当执行DDL(写操作)操作时,就需要在全表上加排他锁