- 掌握事务机制,学会创建事务。
- 理解事务并发 *** 作所可能导致的数据不一致性问题。
- 理解锁机制,学会采用锁与事务隔离级别解决数据不一致的问题。
- 了解数据库的事务日志。
假设学校允许学生将yhk和校园卡进行绑定,在student数据库中有如下的基本表,其中校园卡编号cardid即为学生的学号:
create table icbc_card( icbcid int, sno varchar(8), balance int ); create table campus_card( sno varchar(8), balance int ); insert into campus_card values ('20200032', 1); insert into campus_card values ('20200033', 100); insert into icbc_card values (1, '20200032', 300); insert into icbc_card values (2, '20200033', 400);
针对以上数据库按照要求完成下列实验:
- 编写一个事务处理实现如下的 *** 作:某学号为20200032的学生从yhk中转账200元到校园卡中,若中间出现故障则进行rollback。(10分)
CREATE PROCEDURE transfer() BEGIN DECLARE icbc_balance INT DEFAULT 0; SELECt balance FROM icbc_card WHERe sno = '20200032' INTO icbc_balance; IF icbc_balance > 200 THEN UPDATe icbc_card SET balance = balance - 200 WHERe sno = '20200032'; UPDATE campus_card SET balance = balance + 200 WHERe sno = '20200032'; COMMIT; ELSE ROLLBACK; END IF; END
- 针对本题的数据库和表,分别用具体的例子展现几种数据不一致问题:如丢失修改、读脏数据、不可重复读和幻读(删除和插入),注意如有无法展现的情况,请说明原因。(20分,每种数据不一致10分)
两个workbench打开的两个界面都要设置隔离级
set session transaction isolation level READ UNCOMMITTED;
丢失修改:
创建一个先读后写的存储过程
CREATE DEFINER=`root`@`localhost` PROCEDURE `read_and_write`() BEGIN DECLARE campus_balance INT DEFAULT 0; SELECT balance FROM campus_card WHERe sno = '20200032' INTO campus_balance; SELECt sleep(10); UPDATE campus_card SET balance = campus_balance + 1 WHERe sno = '20200032'; END
读写之间用sleep函数留出了10s的时间,你可以打开另一个程序去运行同样的存储过程,查看最后的修改结果。
不可重复读:
先执行1,然后迅速执行2可以看到1读出的balance两次值不同。
CREATE DEFINER=`root`@`localhost` PROCEDURE `non_repeatable_read_1`() BEGIN SELECT balance FROM campus_card WHERe sno = '20200032'; SELECt sleep(10); SELECT balance FROM campus_card WHERe sno = '20200032'; END
CREATE DEFINER=`root`@`localhost` PROCEDURE `non_repeatable_read_2`() BEGIN UPDATe campus_card SET balance = balance + 1 WHERe sno = '20200032'; END
读脏数据:
CREATE DEFINER=`root`@`localhost` PROCEDURE `dirty_read`() BEGIN SELECT balance FROM campus_card WHERe sno = '20200032'; END
CREATE DEFINER=`root`@`localhost` PROCEDURE `dirty_write`() BEGIN UPDATe campus_card SET balance = balance + 1 WHERe sno = '20200032'; SELECT SLEEP(10); ROLLBACK; END
- 利用数据库的隔离级别或者锁机制等,设计方案分别解决上述丢失修改、读脏数据、不可重复读、幻读的数据不一致问题。(20分,每种数据不一致5分)
(1) 丢失修改
set session transaction isolation level READ COMMITTED;
(2) 读脏数据
set session transaction isolation level READ COMMITTED;
(3) 不可重复读
set session transaction isolation level REPEATABLE READ;
(4) 幻读(删除和插入)
set session transaction isolation level SERIALIZABLE;
- 构造两个事务同时更新一条数据,尝试使用以下SQL命令查看和理解当前系统中事务以及锁的状态等信息。(10分)
直接执行下面的语句就行。
- show engine innodb status (MySQL 8.0 or 5.7)
- select * from information_schema.innodb_trx (MySQL 8.0 or 5.7)
- select * from performance_schema.data_locks; (MySQL 8.0)
- select * from sys.innodb_lock_waits; (MySQL 8.0)
- select * from information_schema.innodb_lock_waits (MySQL 5.7)
- select * from information_schema.innodb_locks (MySQL 5.7)
- 构造一个出现死锁的情形。(10分)
防止查重起见,这个我只说一下思路
lock语句可以对表进行锁定,所以可以分两个进程,一个进程对A表先锁定后更新,另一个进程对B表先锁定后更新,然后两者交换,第一个进程更新B表,第二个进程更新A表,这时它们就会进入死锁状态。
- 构造含有savepoint的事物,并在某时刻回滚到某个savepoint。(10分)
这一段借鉴了学长的代码
start transaction; insert into icbc_card values(3,'20200034',900); insert into icbc_card values(4,'20200035',600); savepoint s1; insert into icbc_card values(5,'20200036',400); insert into icbc_card values(6,'20200037',500); savepoint s2; insert into icbc_card values(7,'20200038',200); insert into icbc_card values(8,'20200039',100); select * from icbc_card;
执行后依次回滚到s2,s1,整个事务;
rollback to savepoint s2; select * from icbc_card;
rollback to savepoint s1; select * from icbc_card;
rollback; select * from icbc_card;
- 通过实验查看mysql中的各种日志:查询日志、错误日志、慢查询日志。(10分)
输入以下命令后将给出日志的路径,具体内容可以到指定路径下查看
查询日志:
show variables like 'general_log_file';
错误日志:
show variables like 'log_error';
慢查询日志:
show variables like 'slow_query_log_file';
- 用mysqlbinlog查看数据库的事务日志,并尝试按照以下场景进行数据恢复。(10分)
首先创建日志文件:
flush logs; show master status;
create database db1; use db1; create table t1(id int); create table t2(id int); insert into t1 values(11); insert into t1 values(12); insert into t1 values(13); insert into t2 values(21); insert into t2 values(22); insert into t2 values(23); drop table t1; insert into t2 values(24);
show binlog events in 'binlog.000029';
使用命令行工具将binlog文件中的sql语句导出(需要使用管理员权限)
这个暂时没跑通,跑通了再更新一下
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)