侧边栏壁纸
博主头像
老十三

敬年少热诚!

  • 累计撰写 30 篇文章
  • 累计创建 35 个标签
  • 累计收到 7 条评论

目 录CONTENT

文章目录

数据库安全性问题

老十三
2022-02-12 / 0 评论 / 6 点赞 / 301 阅读 / 2,808 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2022-03-26,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

数据库安全性问题

准备数据

创建一张账户表,并添加数据

create table account(
    id int primary key auto_increment,
    name varchar(20),
    money double
);

insert into account values (null,'zs',1000);
insert into account values (null,'ls',1000);
insert into account values (null,'ww',1000);

演示脏读

一个事物里面读到了另外一个事物没有提交的数据:read uncommitted(读未提交)

  • 开启A,B命令行窗口,连接登录MySQL

  • 分别查询A,B窗口的隔离级别

    select @@tx_isolation;
    

    image-20220212184424226

  • 设置A窗口的隔离级别为:read uncommitted(读未提交)

    set session transaction isolation level read uncommitted;
    

    image-20220212184815778

  • A,B窗口都开启事物

    start transaction;
    

    image-20220212185223503

  • 在B窗口中操作zs向ls转账100,事物不提交

    -- 操作前先查询表中数据
    select * from account;
    -- zs向ls转账100,即zs账户减少100,而ls账户增加100
    update account set money = money - 100 where name = 'zs';
    update account set money = money + 100 where name = 'ls';
    
  • 在A窗口中查询账户

    select * from account;
    

    image-20220212191134163

    可以看到在B窗口中转账操作完成后并没有提交事务,但是在A窗口中查询到了B窗口没有提交的事务,即一个事物里面读到了另外一个事物没有提交的数据,叫做脏读


演示不可重复读并解决脏读

在一个事物里面,同一条语句,两次查询的结果不一致:Read committed(读已提交)

  • 开启A,B命令行窗口,连接登录MySQL

  • 分别查询A,B窗口的隔离级别

    select @@tx_isolation;
    

    image-20220212203228804

  • 设置A窗口的隔离级别为:Read committed(读已提交)

    set session transaction isolation level Read committed;
    

    image-20220212203403100

  • A,B窗口都开启事物

    start transaction;
    

    image-20220212203522111

  • 在B窗口中操作zs向ls转账100,事物不提交

    -- 操作前先查询表中数据
    select * from account;
    -- zs向ls转账100,即zs账户减少100,而ls账户增加100
    update account set money = money - 100 where name = 'zs';
    update account set money = money + 100 where name = 'ls';
    

    image-20220212203841620

  • 在A窗口中查询账户【可以看到此时已经避免了脏读发生】

    select * from account;
    

    image-20220212204335276

  • 在B窗口中提交事物

    commit;
    
  • 在A窗口中查询账户【两次查询的结果不一致,不可重复读发生】

    select * from account;
    

    image-20220212204859574

    可以看到在B窗口提交事务后查询出的数据和在提交事务前查询出的数据不一致,即发生了不可重复读


演示避免不可重复读

  • 开启A,B命令行窗口,连接登录MySQL

  • 分别查询A,B窗口的隔离级别

    select @@tx_isolation;
    

    image-20220212210242465

  • 设置A窗口的隔离级别为:Repeatable read(可重复读)

    set session transaction isolation level Repeatable read;
    

    image-20220212211010190

  • A,B窗口都开启事物

    start transaction;
    

    image-20220212211250049

  • 在B窗口中操作zs向ls转账100,事物不提交

    -- 操作前先查询表中数据
    select * from account;
    -- zs向ls转账100,即zs账户减少100,而ls账户增加100
    update account set money = money - 100 where name = 'zs';
    update account set money = money + 100 where name = 'ls';
    

    image-20220212211713522

  • 在A窗口中查询账户【没有发生脏读】

    select * from account;
    

    image-20220212212134405

  • 在B窗口中提交事物

    commit;
    
  • 在A窗口中查询账户【没有发生不可重复读】

    select * from account;
    

    image-20220212212649466

    可以看到在B窗口提交事务后查询出的数据和在提交事务前查询出的数据一致,即没有发生不可重复读

  • A窗口中结束事物,再重新查询

    commit;
    select * from account;
    

    image-20220212213140772

    在A窗口提交事务之后再次查询,此时A窗口的事务已经结束,查询到了B窗口中提交的事务,可以看出两个事务并没有相互影响,而是保持了互相隔离,即没有发生不可重复读

    MySQL数据库默认隔离级别:Repeatable read(可重复读)


演示隔离级别Serializable(串行化)

通过强制事务排序,让事务必须以顺序的方式执行,使之不可能相互冲突,在前一个事务提交之前后面的事务无法进行提交,从而解决了幻读的问题。

它在每个读的数据行上面加上了共享锁,但是可能会导致超时和锁竞争(这种隔离级别太极端,实际生产基本不使用),而且不能并发操作,导致效率低下。

  • 开启A,B命令行窗口,连接登录MySQL

  • 分别查询A,B窗口的隔离级别

    select @@tx_isolation;
    

    image-20220212222032097

  • 设置A窗口的隔离级别为:Serializable(串行化)

    set session transaction isolation level Serializable;
    

    image-20220212222257130

  • A,B窗口都开启事物

    start transaction;
    

    image-20220212222449614

  • 在B窗口中向account账户插入一条数据,事务不提交

    -- 操作前先查询表中数据
    select * from account;
    -- 在account表中插入一条数据
    insert into account values (null,'zl',1000);
    

    image-20220212230817950

  • 在A窗口中结束事物

    commit;
    

    image-20220212232516027

    当在B窗口中执行插入数据操作后,会发现任务进程卡住,这是因为A窗口下隔离级别为 Serializable(串行化) ,在这种情况下,只有当A窗口中的事务结束后,B窗口的事务操作才能继续进行

  • 在A窗口中查询账户

    select * from account;
    

    image-20220212233130865

  • 在B窗口中结束事物

    commit;
    
  • 在A窗口中查询

    select * from account;
    

    image-20220212233436740

    注意:

    • 隔离级别为 Read committed(读已提交)read uncommitted(读未提交)Repeatable read(可重复读) 时,都可能会发生幻读,即一个事务中两次读取的数据的数量不一致,这是由于insert或delete时引发的问题;而不可重复读是因为一个事务中两次读取的数据的内容不一致,这是由于update时引发的问题。
    • 设置隔离级别为 Serializable(串行化) 可以解决幻读的问题。

6

评论区