MYSQL的事务、隔离级别、锁

事务的四大特性

一提到数据库事务,没错,我们首先会想到ACID,也就是事务的四个特性。
A原子性 C一致性 I隔离性 D持久性

与之带来的问题

具体内容不再赘述,事务的这四个特性会带来什么问题呢?
脏读,不可重复读,幻读

1.脏读:一个事务读取到另外一个事务未提交的内容
2.不可重复读:一个事务内前后两次读取到的内容不一致。产生的原因是该事务前后两次读取的时间段内,另外一个事务对该条数据进行了修改。
3.幻读:一个事务A进行范围查询时得到M条数据,另一个事务B在符合事务A的范围内插入了N条数据,导致事务A再次进行查询时会得到M+N条数据,产生幻读。

不可重复读和幻读有类似之处,本质差别在于,前者针对update,后者针对insert

MYSQL的四种隔离级别:

1.读未提交(READ UNCIMMITTED):可以读取别的事务未commit的内容,会导致脏读的问题。
2.读已提交(READ COMMITTED):可以读取别的事务已commit的内容,会导致不可重复读的问题。常用的就是该级别。
3.可重复读(REPEATABLE READ):可以保证该事务内,前后两次读取的内容一致。即使另一事物对该条数据进行了修改。
4.可串行化(SERIALIZABLE):可串行化是事务的最高隔离级别,事务在读取或者修改表数据时,都会增加表级锁,防止幻读。与此同时,会大大影响性能。

这四种隔离级别可根据自身业务需要进行设置,最常用的是READ COMMITTED。

事务的隔离级别主要是通过锁来控制的,下面介绍一下锁。

不同的存储引擎对锁的处理方式不一样,MYSQL5版本之后默认采用Innodb,InnoDB支持表锁和行锁。

下面进行几个实验:

准备:
1.建表

CREATE TABLE
    user_info
    (
        userid VARCHAR(40) NOT NULL ,
        username VARCHAR(40),
        sex INT(1),
        certtype VARCHAR(10),
        certid VARCHAR(20),
        phoneno VARCHAR(11),
        age INT(3),
        PRIMARY KEY (userid),
        INDEX certtype_id (certid, certtype)
    )
    ENGINE=InnoDB DEFAULT CHARSET=utf8;

2.准备几条数据

INSERT INTO user_info (userid, username, sex, certtype, certid, phoneno, age) VALUES ('000007c2b80f11e99a9454ee755d5b38', 'demo', 1, 'Ind02', '539452823381361', '13756168529', 66);
INSERT INTO user_info (userid, username, sex, certtype, certid, phoneno, age) VALUES ('00000a39b81511e99a9454ee755d5b38', 'fru', 1, 'Ind02', '535322313695514', '14297850313', 38);
INSERT INTO user_info (userid, username, sex, certtype, certid, phoneno, age) VALUES ('00000ba7b81011e99a9454ee755d5b38', 'hlz', 1, 'Ind02', '535322313695514', '14027724002', 85);
INSERT INTO user_info (userid, username, sex, certtype, certid, phoneno, age) VALUES ('0000161bb81911e99a9454ee755d5b38', 'diu', 1, 'Ind02', '838336353039682', '14279925806', 38);
INSERT INTO user_info (userid, username, sex, certtype, certid, phoneno, age) VALUES ('0000197cb81811e99a9454ee755d5b38', 'dsf', 1, 'Ind02', '748854264383068', '14433861050', 42);
INSERT INTO user_info (userid, username, sex, certtype, certid, phoneno, age) VALUES ('00004862b81311e99a9454ee755d5b38', 'udi', 1, 'Ind02', '533297220741675', '13796868687', 88);
INSERT INTO user_info (userid, username, sex, certtype, certid, phoneno, age) VALUES ('000052bab81611e99a9454ee755d5b38', 'l', 1, 'Ind02', '119285593851735', '14114443115', 71);
INSERT INTO user_info (userid, username, sex, certtype, certid, phoneno, age) VALUES ('0000580eb81111e99a9454ee755d5b38', 'hhi', 1, 'Ind02', '644459799532275', '14241303402', 77);
INSERT INTO user_info (userid, username, sex, certtype, certid, phoneno, age) VALUES ('00005edfb81711e99a9454ee755d5b38', 'fwu', 1, 'Ind02', '792649599530407', '14394181380', 9);
INSERT INTO user_info (userid, username, sex, certtype, certid, phoneno, age) VALUES ('00007186b81211e99a9454ee755d5b38', 'irl', 1, 'Ind02', '112327407218820', '13599040961', 15);
INSERT INTO user_info (userid, username, sex, certtype, certid, phoneno, age) VALUES ('0000808fb81411e99a9454ee755d5b38', 'ufi', 1, 'Ind02', '185371452183808', '13841946470', 15);
INSERT INTO user_info (userid, username, sex, certtype, certid, phoneno, age) VALUES ('00008719b80e11e99a9454ee755d5b38', 'wre', 2, 'Ind02', '707119444112404', '13864141398', 69);
INSERT INTO user_info (userid, username, sex, certtype, certid, phoneno, age) VALUES ('00008c62b81011e99a9454ee755d5b38', 'udh', 1, 'Ind02', '978111704791068', '14234926100', 74);
INSERT INTO user_info (userid, username, sex, certtype, certid, phoneno, age) VALUES ('00008f70b80f11e99a9454ee755d5b38', 'hus', 1, 'Ind02', '948014209929867', '14153437874', 42);
INSERT INTO user_info (userid, username, sex, certtype, certid, phoneno, age) VALUES ('00009aecb81511e99a9454ee755d5b38', 'uey', 1, 'Ind02', '376089044265532', '14118677569', 96);
INSERT INTO user_info (userid, username, sex, certtype, certid, phoneno, age) VALUES ('0000a956b81911e99a9454ee755d5b38', 'off', 1, 'Ind02', '179309141989153', '13898109495', 45);
INSERT INTO user_info (userid, username, sex, certtype, certid, phoneno, age) VALUES ('0000c7acb81811e99a9454ee755d5b38', 'eed', 1, 'Ind02', '928275743432599', '13858352803', 0);
INSERT INTO user_info (userid, username, sex, certtype, certid, phoneno, age) VALUES ('0000c918b81a11e99a9454ee755d5b38', 'ggi', 1, 'Ind02', '705640666843988', '13662965102', 69);
INSERT INTO user_info (userid, username, sex, certtype, certid, phoneno, age) VALUES ('0000cbbcb81611e99a9454ee755d5b38', 'yfu', 1, 'Ind02', '56476028688695', '13849848820', 57);
INSERT INTO user_info (userid, username, sex, certtype, certid, phoneno, age) VALUES ('0000d9bdb81111e99a9454ee755d5b38', 'di', 1, 'Ind02', '134768997444556', '14454071981', 36);

3.开始实验

开启一个事务,将这行数据的username更新为“fru1”

 start transaction; --开启事务
    update user_info set username='fru1' where userid='00000a39b81511e99a9454ee755d5b38';  --更新数据,锁数据
    暂不提交或者回滚

另外开启一个session,也就是重新打开一个窗口。执行下列语句,将名字更新为“fru2”

update user_info set username='fru2' where userid='00000a39b81511e99a9454ee755d5b38';

效果是什么呢?

在这里插入图片描述卡在这里了,无法更新,前一个事务提交后,后一个事务继续执行。执行后的结果:
在这里插入图片描述
更新成功。 这个很容易理解,第一个事务中,update语句加了行锁。
这个理解了,暂且一放,进行下一个实验。

执行下一个语句:

start transaction;
update user_info set username='fru1' where username='fru2';

在另一个窗口执行:

update user_info set username='fru2' where userid='0000161bb81911e99a9454ee755d5b38';

执行效果如下:
在这里插入图片描述
卡住了!!加锁了?但是更新的不是一条数据为什么也会被加锁?

原因是:

在mysql中,InnoDB实现行锁并是不锁记录,而是锁索引。如果一条语句,操作了主键索引,MYSQL就是锁该条主键索引。如果操作了非主键索引,MYSQL会先索引该非主键索引,再通过非主键索引,锁定相关主键索引。如果操作不是通过索引,那就会锁表。

所以后面的crud操作中,更新语句是不是会去留意一下这点呢?如果留意了,我的目的也就达到了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值