MySQL高级

11 篇文章 0 订阅

实验环境

部门表
MariaDB [cr]> CREATE TABLE dept(
    -> deptnu INT PRIMARY KEY comment '部门编号',
    -> dname VARCHAR(50) comment '部门名称',
    -> addr VARCHAR(50) comment '部门地址'
    -> )ENGINE=InnoDB DEFAULT CHARSET=utf8;

员工表
MariaDB [cr]> CREATE TABLE employee(
    -> empno INT PRIMARY KEY comment '雇员编号',
    -> ename VARCHAR(50) comment '雇员姓名',
    -> job VARCHAR(50) comment '雇员职位',
    -> mgr INT comment '雇员上级编号',
    -> hiredate DATE comment '雇佣日期',
    -> sal DECIMAL(7,2) comment '薪资',
    -> deptnu INT comment '部门编号'
    -> )ENGINE=InnoDB DEFAULT CHARSET=utf8;

创建工资等级表
MariaDB [cr]> CREATE TABLE salgrade(
    -> grade INT PRIMARY KEY comment '等级',
    -> lowsal INT comment '最低薪资',
    -> higsal INT comment '最高薪资'
    -> )ENGINE=InnoDB DEFAULT CHARSET=utf8;

插入dept表数据
INSERT INTO dept VALUES (10, '研发部', '北京');
INSERT INTO dept VALUES (20, '工程部', '上海');
INSERT INTO dept VALUES (30, '销售部', '广州');
INSERT INTO dept VALUES (40, '财务部', '深圳');

插入emp表数据
INSERT INTO employee VALUES (1009, '唐僧', '董事长', NULL, '2010-11-17', 50000, 10);
INSERT INTO employee VALUES (1004, '猪八戒', '经理', 1009, '2001-04-02', 29750, 20);
INSERT INTO employee VALUES (1006, '猴子', '经理', 1009, '2011-05-01', 28500, 30);
INSERT INTO employee VALUES (1007, '张飞', '经理', 1009, '2011-09-01', 24500,10);
INSERT INTO employee VALUES (1008, '诸葛亮', '分析师', 1004, '2017-04-19', 30000, 20);
INSERT INTO employee VALUES (1013, '林俊杰', '分析师', 1004, '2011-12-03', 30000, 20);
INSERT INTO employee VALUES (1002, '牛魔王', '销售员', 1006, '2018-02-20', 16000, 30);
INSERT INTO employee VALUES (1003, '程咬金', '销售员', 1006, '2017-02-22', 12500, 30);
INSERT INTO employee VALUES (1005, '后裔', '销售员', 1006, '2011-09-28', 12500, 30);
INSERT INTO employee VALUES (1010, '韩信', '销售员', 1006, '2018-09-08', 15000,30);
INSERT INTO employee VALUES (1012, '安琪拉', '文员', 1006, '2011-12-03', 9500, 30);
INSERT INTO employee VALUES (1014, '甄姬', '文员', 1007, '2019-01-23', 7500, 10);
INSERT INTO employee VALUES (1011, '妲己', '文员', 1008, '2018-05-23', 11000, 20);
INSERT INTO employee VALUES (1001, '小乔', '文员', 1013, '2018-12-17', 8000, 20);

插入salgrade表数据
INSERT INTO salgrade VALUES (1, 7000, 12000);
INSERT INTO salgrade VALUES (2, 12010, 14000);
INSERT INTO salgrade VALUES (3, 14010, 20000);
INSERT INTO salgrade VALUES (4, 20010, 30000);
INSERT INTO salgrade VALUES (5, 30010, 99990);

自定义函数

函数注重返回值,不注重执行过程。

创建函数

DELIMITER //
CREATE 
	[DEFINER = {user | CURRENT_USER}]
	FUNCTION [IF NOT EXISTS] func_name([func_parameter[,...]]) 
	RETURNS type
	[SQL SECURITY {DEFINER | INVOKER}]
	[COMMENT 'string']
		BEGIN
			func_body;
			RETURN value;  #必须要有返回值
		END //
DELIMITER ;
	

func_parameter:
 param_name type

type:
 Any valid MariaDB data type

func_body:
 Valid SQL procedure statement

DEFINER#创建者
	user:指定'user'@'localhost'
	CURRENT_USER:当前用户

SQL SECURITY { DEFINER | INVOKER }:  #安全方式
	DEFINER:以创建函数的用户权限执行,如果DEFINER用户被删除,当其他用户调用该函数无权限执行
	INVOKER:以调用函数的用户权限执行,如果DEFINER用户被删除,当其他用户调用该函数有权限执行


#注:当开启binlog后,我们创建函数将不被信息,使用下面选项可以解决问题
#set global log_bin_trust_function_creators=TRUE;

查看函数

查看函数内容
show create function func_name;
查看所有函数
show function status like 'func_name';

删除函数

drop function func_name;

函数调用

select func_name([func_parameter[,...]]);

函数语法

  1. 局部变量
变量名不应该和表中字段或表名等相同
声明
DECLARE var_name... date_type [DEFAULT VALUE];
赋值
set var=value;
select col_name into var from tb_name where where_condition;  #通过select语句复制,每次查询只能返回1个值
  1. if语句
if condition then
	statement
elseif condition then
	statement 
else
	statement
end if 

condition:
	is null
	is not null
	true:可由declare var int default true;声明
	false
	not true
	not false
  1. case语句
CASE value 
WHEN value1 THEN
	statement 
WHEN value2 THEN
	statement
ELSE  #other value
	statement
END CASE
  1. leave语句
leave label  #跳出循环(break)
  • iterate语句
iterate label  #跳出循环(continue)
  1. loop语句
[label:] loop  #循环
	statement
	if condition then
		leave label
	end if
end loop

condition:
	is null
	is not null
	true:可由declare var int default true;声明
	false
	not true
	not false
  1. repeat语句
[label:] repeat  #循环
	statement_list 
	until condition  #满足条件退出循环
end repeat

condition:
	is null
	is not null
	true:可由declare var int default true;声明
	false
	not true
	not false
  1. while语句
[label:] while condition do  #循环
	statement_list 
end while

condition:
	is null
	is not null
	true:可由declare var int default true;声明
	false
	not true
	not false

操作

写一个函数根据salgrade表判断各员工的工资等级

delimiter //
MariaDB [cr]> create function judge_salgrade(sal_num int) returns int
    -> begin
    -> declare grade_sal int;
    -> declare low_sal int;
    -> declare hig_sal int;
    -> declare flag int default false;
    -> declare sal_list cursor for select grade,lowsal,higsal from salgrade;
    -> declare continue handler for not found set flag=true;
    -> open sal_list;
    -> while not flag do
    -> fetch sal_list into grade_sal,low_sal,hig_sal;
    -> if sal_num >= low_sal and sal_num <= hig_sal then
    -> return grade_sal;
    -> end if;
    -> end while;
    -> return 0;
    -> end $$
delimiter ;

游标

有数据缓冲的思想:游标的设计是一种数据缓冲区的思想,用来存放SQL语句执行的结果。 先有数据基础:游标是在先从数据表中检索出数据之后才能继续灵活操作的技术。 类似于指针:游标类似于指向数据结构堆栈中的指针,用来pop出所指向的数据,并且只能每次取一个。

  • 语法
游标声明:
declare cur_name cursor for select_statement;

打开游标:
open cur_name;

使用游标:
declare var1 data_type;
declare var2 data_type;
...
fetch cur_name into var1,var2...  #变量对应select获取的值

游标结束:
declare flag int default truedeclare continue handler for not found set flag=false; #

关闭游标:
close cur_name
  • 操作
遍历employee表,返回所有姓名
#字段是中文,变量应设置编码
#同意的代码函数执行返回编码错误,我不明白
\d //
MariaDB [cr]> create procedure getName()
    -> begin
    -> declare name_text text character set utf8 default '';  #必须给初始值,不然返回未null
    -> declare name_char varchar(256) character set utf8;
    -> declare flag int default true;
    -> declare cur_1 cursor for select ename from employee;
    -> declare continue handler for not found set flag=false;
    -> open cur_1;
    -> while flag do
    -> fetch cur_1 into name_char;
    -> set name_text=concat(name_text,",",name_char);
    -> end while;
    -> close cur_1;
    -> select name_text as names;
    -> end //
\d ;

视图

视图是一张虚拟表,是一系列查询的集合,是存储在数据库中的查询语句。

创建视图

CREATE
    [DEFINER = { user | CURRENT_USER }]
    [SQL SECURITY { DEFINER | INVOKER }]
    VIEW [IF NOT EXISTS] view_name [(column_list)]
    AS select_statement

DEFINER#创建者
	user:指定'user'@'localhost'
	CURRENT_USER:当前用户

SQL SECURITY { DEFINER | INVOKER }:  #安全方式
	DEFINER:以创建视图的用户权限执行,如果DEFINER用户被删除,当其他用户调用该视图无权限执行
	INVOKER:以调用视图的用户权限执行,如果DEFINER用户被删除,当其他用户调用该视图有权限执行

查看视图

查看视图内容
show create view view_name;
查看所有视图
show table status where comment='view';

删除视图

drop view view_name;

调用视图

select col_name... from view_name [where where_condition];

操作

创建视图列出所有视图
#表信息都保存在information_shema数据库中
MariaDB [cr]> create view show_view as
    -> select TABLE_NAME as view_name from information_schema.TABLES 
    -> where TABLE_TYPE='VIEW' and TABLE_SCHEMA=database();

触发器

触发器是当增删改时,条件触发,执行定义的SQL语句。一张表只能有一种类型触发器。

创建触发器

DELIMITER //
CREATE
    [DEFINER = { user | CURRENT_USER}]
    TRIGGER [IF NOT EXISTS] trigger_name trigger_time trigger_event
    ON tbl_name FOR EACH ROW
    [{ FOLLOWS | PRECEDES } other_trigger_name ]
    BEGIN
    	trigger_body
    END //
DELIMITER ;

trigger_time:
	before:	#在每行变化之后执行
	after#在每行变化之前执行

trigger_event:
	insert
	update
	delete

FOLLOWS | PRECEDES other_trigger_name:
	follows:	#在一个触发器后执行
	precedes:	#在一个触发器前执行

trigger_body:
	特殊对象:old、new
	old:		#delete事件中表示删除的旧数据,update事件中表示更新删除的旧数据,old.col_name引用
	new:		#insert事件中表示插入的新数据,update事件中表示更新插入的新数据,new.col_name引用

	语法参见 函数语法

查看触发器

查看触发器内容
show create trigger trigger_name;
查看所有触发器
show triggers [from db_name];

删除触发器

drop trigger [if exists] trigger_name;

操作

  1. 使用触发器创建审计
1、创建审计表格
MariaDB [cr]> create table audit(
    -> `aid` int unsigned primary key auto_increment,
    -> `user` varchar(30),
    -> `action` varchar(10),
    -> `empno` int(11),
    -> `time` datetime
    -> ) engine=innodb charset=utf8;
2、创建插入事件
delimiter //
MariaDB [cr]> create trigger audit_insert
    -> after insert on employee for each row
    -> begin
    -> insert into audit(user,action,empno,time) value(user(),'insert',new.empno,now());
    -> end //
delimiter ;
3、创建删除事件
delimiter //
MariaDB [cr]> create trigger audit_delete
    -> after delete on employee for each row
    -> begin
    -> insert into audit(user,action,empno,time) value(user(),'delete',old.empno,now());
    -> end //
delimiter ;
4、创建更新事件
delimiter //
MariaDB [cr]> create trigger audit_update
    -> after update on employee for each row
    -> begin
    -> insert into audit(user,action,empno,time) value(user(),'update',new.empno,now());
    -> end //
delimiter ;
  1. 根据dept表中部门编号,限制插入employee插入的部门编号
1、创建函数判断插入值是否在dept表中
delimiter //
MariaDB [cr]> create function exists_dept(dept_num int)
    -> returns int
    -> begin
    -> declare num int;
    -> declare flag int default 0;
    -> declare s_list cursor for select deptnu from dept;
    -> declare continue handler for not found set flag=1;
    -> open s_list;
    -> while 1 != flag do
    -> fetch s_list into num;
    -> if num = dept_num then
    -> return 1;
    -> end if;
    -> end while;
    -> return 0;
    -> end //
delimiter ;
2、创建触发器限制,如果触发器语句执行过程中错误,则实现事务回滚
delimiter //
MariaDB [cr]> create trigger limit_dept
    -> before insert on employee for each row
    -> begin
    -> declare msg varchar(20);
    -> if exists_dept(new.deptnu) then
    -> set msg='ok';
    -> else
    -> select xxx into msg;  #错误语句
    -> end if;
    -> end //
delimiter ;

存储过程

存储过程是一堆sql语句的集合,经编译保存在数据库中,执行速度块。

创建存储过程

CREATE
    [DEFINER = { user | CURRENT_USER}]
    PROCEDURE sp_name ([proc_parameter[,...]])
    [SQL SECURITY { DEFINER | INVOKER }]
    [COMMENT 'string']
	begin
		routine_body
	end

proc_parameter:
    [ IN | OUT | INOUT ] param_name type

type:
    Any valid MariaDB data type

routine_body:
    Valid SQL procedure statement
    语法参见函数

查看存储过程

查看存储过程内容
show create procedure procedure_name;
查看所有存储过程
show procedure status [like 'pattern' | where expr]

删除存储过程

drop procedure procedure_name;

存储过程调用

drop procedure procedure_name

操作

定期创建employee表的副本

\d $$
MariaDB [cr]> create procedure backTable(in tName char(20))
    -> begin
    -> declare new_tName varchar(36);
    -> set new_tName=concat(tName,replace(replace(replace(now(),"-",""),":","")," ",""));
    -> set @sql_1=concat('create table ', new_tName, ' select * from ', tName);
    -> prepare pp_1 from @sql_1;
    -> execute pp_1;
    -> end $$
\d ;

添加定时任务
crontab -u root -e
* * * * * source /etc/profile;mysql -e 'call cr.backTable("employee")' && echo 'employee backup ok!'

事件

事件是用于执行定时或周期性的任务

创建事件

\d $$
CREATE
    [DEFINER = { user | CURRENT_USER}]
    EVENT 
    [IF NOT EXISTS]
    event_name 
    ON SCHEDULE schedule
    [ON COMPLETION [NOT] PRESERVE]
    [ENABLE | DISABLE | DISABLE ON SLAVE]
    [COMMENT 'comment']
    DO
    BEGIN
    	sql_statement;
    END $$
\d ;
 
schedule:
    AT timestamp [+ INTERVAL interval] ...			#单次执行
    EVERY interval									#重复执行
    STARTS timestamp [+ INTERVAL interval] ...]		#开始执行时间
    ENDS timestamp [+ INTERVAL interval] ...]		#结束时间时间
 
interval:
    quantity {YEAR | QUARTER | MONTH | DAY | HOUR | MINUTE |
    WEEK | SECOND}

ON COMPLETION [NOT] PRESERVE:
	事件到期后,是否保留。

[ENABLE | DISABLE | DISABLE ON SLAVE]:
	enable:启用
	disable:禁用

开启事件

select @@event_scheduler;
+-------------------+
| @@event_scheduler |
+-------------------+
| OFF               |
+-------------------+

set global event_scheduler=on+-------------------+
| @@event_scheduler |
+-------------------+
| ON                |
+-------------------+

show processlist;  #能看见event_scheduler
+----+-----------------+-----------+------+---------+------+-----------------------------+------------------+----------+
| Id | User            | Host      | db   | Command | Time | State                       | Info             | Progress |
+----+-----------------+-----------+------+---------+------+-----------------------------+------------------+----------+
| 25 | root            | localhost | cr   | Sleep   | 3000 |                             | NULL             |    0.000 |
| 29 | root            | localhost | cr   | Query   |    0 | Init                        | show processlist |    0.000 |
| 30 | event_scheduler | localhost | NULL | Daemon  |  316 | Waiting for next activation | NULL             |    0.000 |
+----+-----------------+-----------+------+---------+------+-----------------------------+------------------+----------+

查看事件

查看事件内容
show create event event_name;
查看全部事件
show events [from schema_name] [like 'pattern']

删除事件

drop event event_name;

修改事件

ALTER
    [DEFINER = { user | CURRENT_USER }]
    EVENT event_name
    [ON SCHEDULE schedule]
    [ON COMPLETION [NOT] PRESERVE]
    [RENAME TO new_event_name]
    [ENABLE | DISABLE | DISABLE ON SLAVE]
    [COMMENT 'comment']
    [DO sql_statement]

操作

1、利用存储过程写的创建副本,在1个月内每天晚上10点和早上6点执行一次

每天6点备份
\d $$
MariaDB [cr]> create event back_event_at_06
    -> on schedule every 1 day
    -> starts date_add(date_add(curdate(), interval 1 day), interval 6 hour)
    -> ends date_add(curdate(),interval 31 day)
    -> on completion preserve enable
    -> do 
    -> begin
    -> call backTable("employee");
    -> end $$
\d ;
每天10点备份
\d $$
MariaDB [cr]> create event back_event_at_22
    -> on schedule every 1 day
    -> starts date_add(date_add(curdate(), interval 1 day), interval 22 hour)
    -> ends date_add(curdate(),interval 31 day)
    -> on completion preserve enable
    -> do 
    -> begin
    -> call backTable("employee");
    -> end $$
\d ;

2、三分钟后创建一次副本

\d $$
MariaDB [cr]> create event show_user
    -> on schedule at now() + interval 3 minute
    -> do 
    -> begin
    -> call backTable("employee");
    -> end $$
\d ;

索引

索引就是根据指定的字段创建一种特殊的数据结构存储,能够减少io次数,提供高效的查询。
我们查询时,要指明where特定的字段才能发挥索引的效果。
索引在增删改表时会重新去计算索引,影响性能。

  • 索引结构
    ◦ hash
    ◦ b+tree
    ◦ b-tree

  • 索引类型
    普通索引:索引定义的单列允许插入空值和重复值
    唯一索引:索引定义的单列允许插入空值,不允许插入重复值
    主键索引:索引定义的单列不允许插入控制和重复值
    组合索引:索引定义的多列,非多个单列索引组成
    全文索引:用在文本字段,检索文本中的字符
    空间索引:支持空间数据

创建索引

CREATE [UNIQUE|FULLTEXT|SPATIAL] INDEX
    [IF NOT EXISTS] index_name
    [index_type]
    ON tbl_name (index_col_name,...)
    [index_option]

index_type:
    USING {BTREE | HASH | RTREE}

index_option:
    WITH PARSER parser_name
    COMMENT 'string'

alter table tb_name add [primary | unique ] fulltext] index index_name (col_name,...);

查看索引

show index from tb_name;

删除索引

drop index index_name on tb_name;

操作

创建测试表
MariaDB [cr]> create table test(
    -> col1 int,
    -> col2 int,
    -> col3 int,
    -> col4 int,
    -> col5 int,
    -> col6 text);
插入20万条数据
\d //
MariaDB [cr]> create procedure insert_test() 
    -> begin
    -> declare i int default 0;
    -> while i < 200000 do
    -> insert into test value(i,i,i,i,i,md5(i));
    -> set i=i+1;
    -> end while;
    -> end //
\d ;
执行存储过程
MariaDB [cr]> call insert_test();
Query OK, 200000 rows affected (5 min 15.038 sec)
MariaDB [cr]> select * from test where col1=199900;
+--------+--------+--------+--------+--------+----------------------------------+
| col1   | col2   | col3   | col4   | col5   | col6                             |
+--------+--------+--------+--------+--------+----------------------------------+
| 199900 | 199900 | 199900 | 199900 | 199900 | d95920548730019743e68d131488bed4 |
+--------+--------+--------+--------+--------+----------------------------------+
1 row in set (0.140 sec)   #没有索引耗时0.14秒


创建普通索引
MariaDB [cr]> create index col1 on test(col1);
Query OK, 0 rows affected (0.562 sec)
MariaDB [cr]> select * from test where col1=199900;
+-------+-------+-------+-------+-------+----------------------------------+
| col1  | col2  | col3  | col4  | col5  | col6                             |
+-------+-------+-------+-------+-------+----------------------------------+
| 19990 | 19990 | 19990 | 19990 | 19990 | 482018fcb72d6725497bebbe9bb83833 |
+-------+-------+-------+-------+-------+----------------------------------+
1 row in set (0.001 sec)  #普通索引耗时0.001秒

创建主键索引
MariaDB [cr]> alter table test add primary key(col2);
Query OK, 0 rows affected (2.374 sec)
MariaDB [cr]> select * from test where col2=199900;
+--------+--------+--------+--------+--------+----------------------------------+
| col1   | col2   | col3   | col4   | col5   | col6                             |
+--------+--------+--------+--------+--------+----------------------------------+
| 199900 | 199900 | 199900 | 199900 | 199900 | d95920548730019743e68d131488bed4 |
+--------+--------+--------+--------+--------+----------------------------------+
1 row in set (0.001 sec)  #主键索引耗时0.001秒

创建唯一索引
MariaDB [cr]> create unique index col3 on test(col3);
Query OK, 0 rows affected (0.566 sec)
MariaDB [cr]> select * from test where col3=199900;
+--------+--------+--------+--------+--------+----------------------------------+
| col1   | col2   | col3   | col4   | col5   | col6                             |
+--------+--------+--------+--------+--------+----------------------------------+
| 199900 | 199900 | 199900 | 199900 | 199900 | d95920548730019743e68d131488bed4 |
+--------+--------+--------+--------+--------+----------------------------------+
1 row in set (0.001 sec)  #唯一索引耗时0.001秒

创建组合索引
MariaDB [cr]> create index col4_col5 on test(col4,col5);
Query OK, 0 rows affected (0.623 sec)
MariaDB [cr]> select * from test where col4=199900;
+--------+--------+--------+--------+--------+----------------------------------+
| col1   | col2   | col3   | col4   | col5   | col6                             |
+--------+--------+--------+--------+--------+----------------------------------+
| 199900 | 199900 | 199900 | 199900 | 199900 | d95920548730019743e68d131488bed4 |
+--------+--------+--------+--------+--------+----------------------------------+
1 row in set (0.001 sec)  #组合索引最左前缀原则,耗时0.001秒
MariaDB [cr]> select * from test where col5=199900;
+--------+--------+--------+--------+--------+----------------------------------+
| col1   | col2   | col3   | col4   | col5   | col6                             |
+--------+--------+--------+--------+--------+----------------------------------+
| 199900 | 199900 | 199900 | 199900 | 199900 | d95920548730019743e68d131488bed4 |
+--------+--------+--------+--------+--------+----------------------------------+
1 row in set (0.135 sec)  #而组合索引右边这个字段耗时和没有索引一样

创建全文索引
create fulltext index index_name on tb_name(col_name);   #innodb不支持,myisam支持
select * from tb_name where match(col_name) against('string');   #测试语句

实现对统一数据占用时并发控制。

锁级别
  共享锁(读锁):其他事务可读不可写
  排他锁(写锁):其他事务不可读不可写

锁粒度
  行级锁
  粒度小,锁冲突概率低,并发能力高,但开销大,加锁慢,有死锁。
  在引擎层面实现,自动加锁。对于insert、delete、update语句在通过索引条件检索数据时使用行级锁,否则使用表锁;对于select语句不会加锁。
  
  表级锁
  开销小,加锁快,无死锁;但粒度大,锁冲突概率高,并发能力低。
  自动加锁。对于select语句会自动给涉及的所有表加读锁,insert、delete、update语句会自动给涉及的表加写锁。

显示加锁

  • 全局

读锁

flush tables with read lock;
  • 行级

读锁

select * from tb_name where where_condition lock in share mode;

写锁

select * from tb_name where where_condition for update;
  • 表级

读锁

lock table tb_name read;
flush tables tb_name with read lock;

写锁

lock table tb_name write;
flush tables tb_name with write lock;

解锁

unlock tables;

事务

事务是一组原子性的SQL操作,这些语句要么都成功执行,要么都失败回滚。默认自动提交autocommit打开,mysql的每条sql语句都是一条单独的事务。

ACID

  • 原子性(A):atomicity
    事务一个最基本执行单位,语句要么全执行,要么全不执行,最核心的特性。
  • 一致性(C):consistency
    数据库总是从一个一致性状态转换为另一个一致性状态,保证事务执行前后都是合法的数据状态。
  • 隔离性(I):isolation
    事务之间在提交前互不可见,保证事务执行尽可能不受其他事务影响。
    隔离有多种隔离级别。
  • 持久性(D):durability
    一旦事务提交,其所做的修改会永久保存于数据库中,保证事务提交后不会因为宕机等原因导致数据丢失。

隔离级别

  • READ UNCOMMITTED (读未提交)
    存在脏读、不可重复度、幻读问题
  • READ COMMITTED (读提交)
    存在不可重复度、幻读问题
  • REPEATABLE READ (可重读)
    存在幻读问题
  • SERIALIZABILE (可串行化)
    存在加锁读问题

隔离带来的问题

  • 脏读
    A事务未提交数据,B事务读到了A未提交的数据称之为脏读。
  • 不可重复度
    A事务提交前和提交后,B事务两次读同一条记录,由于A事务提交了update,导致B事务两次读到的条目数据不同,称为不可重复读。
  • 幻读
    A事务提交前和提交后,B事务两次读同一张表,由于A事务提交了insert、delete,导致B事务两次读到的表显示条目增多或减少,称之为幻读。
  • 加锁读
    解决上诉问题,但加锁读使操作串行化,严重影响并行,同时锁本身需要消耗相当系统资源。

undo log 和 redo log

  • undo log
    undo log实现原子性的关键,事务对数据库所有修改,InnoDB都会生成对应的undo log,如果事务执行失败或调用了rollback,便可根据undo log回滚数据。
  • redo log
    redo log实现持久性的关键,redo log采用的是WAL(Write-ahead logging,预写式日志),事务提交对数据库的所有修改,InnoDB都会先将修改写入日志,如果数据写入到磁盘时宕机,便可根据redo log重做修改。

隔离级别设置

set tx_isolation='isolation_level'

isolation_level:
	READ-UNCOMMITTED
	READ-COMMITTED
	REPEATABLE-READ
	SERIALIZABLE

事务操作

设置自动提交
set autocommit={on | off}  #本次会话生效,写入配置文件永久有效
MariaDB [cr]> show variables like 'autocommit';

开始事务
start transaction

保存节点
savepoint identifier

回滚节点
rollback TO identifier

释放节点
RELEASE SAVEPOINT identifier

回滚事务
rollback

提交事务
commit
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值