栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

MySQL笔记(事务)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

MySQL笔记(事务)

MySQL笔记(事务)
    • 文章说明
    • 创建(开启)事务
    • 事务回滚
    • 事务自动提交
    • 事务的隔离级别
    • 表锁
    • 事务的四种隔离级别的详细理解

文章说明
要点:
	事物的创建、提交与回滚
	隔离级别
	表锁
	
学习资料为明日科技的《MySQL从入门到精通》
创建(开启)事务
-- 创建测试表格
create table test_trigger(
	ID char(10),
	time char(30)
);
create table test_table(
	name char(10)
);

-- 创建事务
start transaction;
	insert into test_trigger(ID) values('001');
	insert into test_trigger(ID) values('002');

	insert into test_table(name) values('BBYH');
	insert into test_table(name) values('BBEH');
-- 提交事务
commit;
事务回滚
事务回滚通过 rollback; 语句实现,但是不能在 commit 之后再用,不然就是没有效果的

MySQL的事务生命流程如下

-- 测试如下(虽然事务结束了之后,但回滚和提交再执行也不会报错,只是没有效果)
start transaction;
	insert into test_trigger(ID) values('001');
	insert into test_trigger(ID) values('002');

	insert into test_table(name) values('BBYH');
	insert into test_table(name) values('BBEH');
commit;

rollback;	-- 回滚在提交之后

start transaction;
	insert into test_trigger(ID) values('001');
	insert into test_trigger(ID) values('002');

	insert into test_table(name) values('BBYH');
	insert into test_table(name) values('BBEH');
rollback;	--先回滚(此时数据就不会被添加)
commit;
事务自动提交
查看是否开启自动提交(默认是打开的)(每次退出后,再次连接上又会变成开启)
	show variables like '%autocommit%';

设置为关闭:
	set autocommit = off;

自动提交事务被关闭后,每次执行修改操作,则不会在表格中显示出来,需要提交才能看到变化
测试如下:(仍然用上面的那个表格)
insert into test_trigger(ID) values('003');		-- 每次执行后是无法看到变化的
insert into test_table(name) values('BBWH');
commit;	-- 只有在执行了commit之后才能看到变化
事务的隔离级别
隔离级别的查看和修改在这篇文章讲的很好:
	http://c.biancheng.net/view/7266.html

支持四种隔离级别:
	未提交读:(READ UNCOMMITTED)
	提交后读:(READ COMMITTED)
	可重复读:(REPEATABLE READ)
	串行化(序列化):(SERIALIZABLE)

查看当前的隔离级别:(默认为可重复读)
	select @@tx_isolation;	或者  show variables like '%tx_isolation%';

附注:在MySQL 8.0.3 中,tx_isolation 变量被 transaction_isolation 变量替换了;(还未检验)

查看全局和当前会话的隔离级别:
	SELECT @@global.tx_isolation;
	SELECT @@session.tx_isolation;

设置隔离级别:(不加global 或者 session 进行限制的话,则设置仅对当前 session 内下一个还未开启的事务生效)
	设置全局的隔离级别需要 SUPER 用户权限,设置当前会话的隔离级别则不需要权限,每个用户均可

	set global transaction isolation level SERIALIZABLE;
	set session transaction isolation level READ COMMITTED;

示例如下:(隔离级别设置只会对后面开启的事务有效果,之前的不会有影响)
SELECT @@global.tx_isolation;
SELECT @@session.tx_isolation;
set session transaction isolation level READ COMMITTED;

SELECT @@global.tx_isolation;
SELECT @@session.tx_isolation;
表锁
加锁:(可以加 读锁、写锁)
	读锁:只能读,不能改
	写锁:可以写,但只能自己这个会话读写,别的会话不能读,也不能写
解锁
lock table test_table read;
lock table test_table write;

unlock tables;
示例如下:
-- 添加测试数据,方便观察
delete from test_table;
delete from test_trigger;
insert into test_table(name) values('BBYH');
insert into test_table(name) values('BBEH');

lock table test_table read;		-- 加上读锁,则不被允许进行增删改
select * from test_table;
insert into test_table(name) values('BBYH');	-- 进行插入则会报错
unlock tables;	-- 进行解锁
insert into test_table(name) values('BBYH');	-- 再次插入则不会报错


lock table test_table write;	-- 加上写锁,自己会话可以读写,别的会话不能操作
select * from test_table;
insert into test_table(name) values('BBYH');
unlock tables;	-- 进行解锁
事务的四种隔离级别的详细理解
这位博主讲的比较详细,可以看这篇文章:
	https://www.cnblogs.com/huanongying/p/7021555.html

数据库并发带来的四个问题,如下:
	丢失修改
	脏读
	不可重复读
	幻读

名词解释
	丢失修改:修改被覆盖了;举例为,开启了两个事务,都读取了相同的元素,然后第一个对数据进行了修改,得到一个结果,
	写回了,然后第二个事务再次进行修改,同样写回,这时造成数据被覆盖了;
		产生原因:可以允许两个事务同时进行数据修改

	脏读:读取到了还没提交的事务中间结果的值,然而这个值有时候可能是错的,
	例如事务被取消了,或者事务还没完成,后面又修改了值;
		产生原因:能够拿到事务中间结果的值(即未提交的值)

	不可重复读:事务的中间结果不允许读了,但是提交后的结果又可以读了,所以会造成以下情况:
	一个事务完成的较慢,一次又一次的被别的事务提交造成的结果影响
		产生原因:允许在事务中读取别的事务已提交的数据

	幻读:这个过程和不可重复读很类似,但它更严格一些,它不允许在事务过程中被用到的行被别的事物进行修改,
	但没用到的行则不会有这个限制,于是就造成了:一个事务中可以看到别的事物插入或删除的一些行


与四个隔离级别相对应,每个隔离级别解决了一个问题
	未提交读:解决了丢失修改的问题,因为现在只允许读,而不允许修改,所以事务的修改结果不会被覆盖,
		但毫无疑问的,它没有解决脏读问题(当然后面的不可重复读和幻读肯定都没有解决的)

	提交后读:解决了脏读问题,因为现在只允许读取提交后的结果,事务的中间结果是不能够被读取的,
		但毫无疑问的,它相较于未提交读提升的不多,仍然会被别的事务不断提交而影响结果,
			所以任意两次读到的数据可能都不相同,没有解决不可重复读的问题

	可重复读:解决了不可重复读的问题,因为现在对正在操作的行进行了上锁,别的行不允许进行读取与修改
		这样就保证了任意两次读取到的数据都一致,但它只对自己操作的行进行了锁定,对表却没有,
			所以仍然会因为别的行增加、删除而造成数据奇怪性的出现与消失

	可串行化:可串行化实际非常简单,它的级别很高,原因是它不允许别的事务与它操作相同的表,即我用了,你就别用了,
		保证最后的结果(即事务结果)是与正常按顺序执行的结果是一样的


示例如下:(在MySQL5.6版本下测试)(实际操作需要多个会话开启,实际是不太方便进行代码编写的)
	以下用代码进行说明,加上序号表明顺序

附注:每次进行测试都要开启新的窗口,不然会出错,我也不知道为啥,开启新的则更正确
-- 创建测试表格及添加测试数据
create table test_table(
	ID char(10),
	name char(10)
);
insert into test_table values('001','BBYH');
  • 未提交读
-- 查看当前隔离界别及设置会话隔离级别(每个打开的会话均要设置)
select @@tx_isolation;
set session transaction isolation level READ UNCOMMITTED;
select @@tx_isolation;
show VARIABLES like '%autocommit%';		-- 自动提交默认开启
set autocommit = off;
show VARIABLES like '%autocommit%';

-- 以下为测试代码
-- 会话一
start TRANSACTION;
select * from test_table;
update test_table set name = 'BBEH' where ID = '001';
select * from test_table;
rollback;
commit;

-- 会话二(会话一执行更新结果还没被提交的时候就可以被事务二看到,回滚后也会被看到)
start TRANSACTION;
select * from test_table;	-- 这里只是读取,还没进行操作修改,如果修改的话,则两个事务都会对彼此造成影响
commit;
  • 已提交读
-- 查看当前隔离界别及设置会话隔离级别(每个打开的会话均要设置)
select @@tx_isolation;
set session transaction isolation level READ COMMITTED;
select @@tx_isolation;
show VARIABLES like '%autocommit%';		-- 自动提交默认开启
set autocommit = off;
show VARIABLES like '%autocommit%';

-- 以下为测试代码(采用和上面一样的流程)
-- 会话一
start TRANSACTION;
select * from test_table;
update test_table set name = 'BBEH' where ID = '001';
select * from test_table;
rollback;
commit;

-- 会话二(会话一执行更新结果还没被提交的时候这时不可以被事务二看到,事务结束后才会被看到)
start TRANSACTION;
select * from test_table;
commit;
  • 可重复读
-- 查看当前隔离界别(默认为可重复读)及设置不自动提交(每个打开的会话均要设置)
select @@tx_isolation;
show VARIABLES like '%autocommit%';		-- 自动提交默认开启
set autocommit = off;
show VARIABLES like '%autocommit%';

-- 这次结果就和上面不一样了,自己没提交不仅看不到别的事物提交后的结果,且不会受到影响(仅是用到的行不受影响)
-- 会话1
start TRANSACTION;
select * from test_table;
update test_table set name = 'BBEH' where ID = '001';
insert into test_table VALUES('002','BBWH');	-- 会对别的提交的事务产生影响,但如果是删除则不会
select * from test_table;
rollback;
commit;

-- 会话二
start TRANSACTION;
select * from test_table;	-- 未提交前,就算会话1的事务提交了,结果也不会刷新到该事务
commit;
select * from test_table;	-- 提交后,才能看到事务一刷新出来的结果
-- 这个地方就演示出来幻读的情况了,虽说要提交之后才能看到结果,但也胜在受到了事务中间的操作的影响
  • 串行化
-- 查看当前隔离界别及设置会话隔离级别(每个打开的会话均要设置)
select @@tx_isolation;
set session transaction isolation level SERIALIZABLE;
select @@tx_isolation;
show VARIABLES like '%autocommit%';		-- 自动提交默认开启
set autocommit = off;
show VARIABLES like '%autocommit%';

-- 会话1
start TRANSACTION;
select * from test_table;
update test_table set name = 'BBEH' where ID = '001';
insert into test_table VALUES('002','BBWH');
select * from test_table;
rollback;
commit;

-- 会话2:(这时候两个事务就进行了表的所有权争抢,任何一个事务占用了表
--	(不管是读还是写),其余事务均无法访问表)
start TRANSACTION;
select * from test_table;
commit;
select * from test_table;
以上为MySQL的事务隔离性的全部内容了,如果文字理解不透测,可以结合代码运行实际情况进行理解
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/873840.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号