1. 什么叫做事务?
2.默认情况下每一条sql语句都是一个事务,然后自动提交事务 ps:如果想多条语句占一个事务,则可以手动设置SetAutoCommit为false
3.关键字 start transaction;rollback;commit
3.1 练习 创建account表(id,name,money),插入两条数据(a,b);start transaction;set a+100,set b-100;commit rollback
create table account( id int primary key auto_increment, name varchar(20), money double //在MySQL中没有money类型 ); insert into account values(null,'a',1000),(null,'b',1000) start transaction update account set money = money -100 where name='a'; update account set money = money +100 where name='b'; commit;
4.jdbc中事务管理
5. 设置回滚点
6.事务的四大特性(ACID)
总结:这一节主要讲了事务的概念;jdbc中使用事务;事务的四大特性
二、隔离性
事务的四大特性,前三点数据库能很好的帮我实现,我们重点来谈下隔离性。
ps:如果用单线程来实现隔离性的话(也就是用lock的方式),会降低数据库的性能和效率
1.不考虑隔离性可能造成的问题 ps:我们只要考虑这三个方面的问题两个人同时修改,两个人同时读,一读一改,这三种情况都考虑到了那么所有的问题都考虑到了
1.1 两个人同时修改
用lock来解决两个人同时修改的线程安全问题
1.2 两个人同时读
两个人同时读不存在线程安全问题
1.3 一读一改 ps:一读一改会出现三个问题:脏读、不可重复读、虚读
1.3.1 脏读
脏读就是读到了其他事务没有提交的数据 ps:比如a(淘宝买家)、b(淘宝卖家),a开启事务向b打了100块钱但是事务还未提交然后告诉b说我已经向你支付了100请你发货,这个时候b去账户查了一下果然多了100块于是给a发了货,但是这个时候a做了rollback操作,结果b亏了100钱的货(事务举例常用银行转账跟购物)
b卖家进行的操作: select @@tx_isolation; set transaction isolation level read uncommitted; start transaction; //b一直在等待a付款,当a付款后告诉b发货时b去查了一下自己的账号 select * from account where name='b'; //这个时候b发现自己的账户中确实多了100快,当时万万没有想到此时a做了rollback的操作 a买家进行的操作: start transaction; update account set money = money -100 where name='a'; update account set money = money +100 where name ='b'; //这个时候a告诉卖家b说我已经给你打款了,你赶快给我发货吧 //当b发货之后a做了rollback的操作 rollback;
1.3.2 不可重复读
在同一个事务中多次读取的结果不一样,原因就是有人修改了数据 ps:举例,银行工作人员报表统计
b卖家进行的操作:(b开始的) select @@tx_isolation; set transaction isolation level read uncommitted; //一开始b就在等待其他买家付款,所以一开始就开启了一个事务查询了自己的账户 start transaction; select * from account where name='b'; //这个时候查到的钱是1100,之后一直在等待买家a付款 …… //卖家b在接到买家a的付款通知之后查询了下自己的账户 select * from account where name='b'; //这个时候得到的金额数为1200了这个时候就出现了同一个事务类查询的结果不一样了,也就是不可重复读(在有些情况下这种不可重复是正确的) a买家进行的操作: //买家a向卖家b付了一百块钱 start transaction; update account set money = money -100 where name='a'; update account set money = money +100 where name ='b'; commit; //买家a提交事务之后就通知卖家b
1.3.3 虚读(幻读)
一个事务读取了别的事务插入的 数据,导致前后读取不一致(读到不存在的数据,所以叫虚读)
b银行业务员进行的操作:(b开始的) select @@tx_isolation; set transaction isolation level read uncommitted; //一开始b就开启一个事务,统计开户总数 start transaction; select count(*) from account; //这个时候查到的个数是2,正在这个时候用户a在银行开一新户 …… select count(*) from account; ////这个时候查到的个数是3,这个时候就出现了幻读虚读,读取了其他事务新插入的数据 a用户进行的操作: //用户a开户 start transaction; insert into account values(null,'c',1300); commit; //用户a开了户之后,业务员b又做了一次统计
2.数据库的四大隔离级别(read uncommitted、read committed、repeateable read、serializable)
2.1 read uncommitted 不防止任何隔离性的问题(脏读、不可重复读、虚读的问题都存在)
2.2 read committed 能防止脏读,但是不能防止不可以重复读和虚读
2.3 repeatable read 能脏读、不可重复读,但是不能防止虚读
2.4 serializable 能防脏读、不可重复读、虚读,但是效率是最低的
2.5 补充
2.5.1 查询数据库的隔离级别 select @@tx_isolation
2.5.2 设置数据库的隔离级别 set [global/session] transaction isolaiton level XXX 不加global和session的话指修改客户端的隔离级别
2.5.3 个人对隔离性的理解 PS:其实就是利用锁机制控制我在进行事务的时候你能做什么操作(读、写、修改、插入crud)
开启一个事务就好像复制了一份数据,该事务设置的隔离级别就是该数据被其他事务影响的程度。read uncommitted 则其他事务为提交的事务也能影响到改数据,read committed 则是提交后的数据能影响到,repeatable read 则未提交和已经提交的修改数据都不能影响到该数据但是新插入的数据可以影响到,serializable则该数据不受任何的影响
三、数据库中的锁机制
1.共享锁:在非serializable隔离i级别下做查询不加任何锁,而在serializable隔离级别下做查询加共享锁
1.1 共享锁的特点:共享锁可以与共享锁共存,共享锁不能排他锁共存
2. 排他锁:在所有隔离级别下做修改都会加排他锁
2.1 排他锁和其他任何锁都不能共存
3.补充
3.1 sql语句的执行顺序
from where select group by having order by
3.2 用sql语句选出每个科目成绩最好的
select max(socre) from t_score group by subject ps:按照sql语句的执行顺序先from表在内存中有一段数据块然后根据subject分组,摞成一小堆(在数据库查询的时候我们只能看到最上面那个),然后我们再在一摞摞的小组中选出分数最大的
3.3 选出各个科目成绩前两名的学生 问题拆分:先选出一门具体学科成绩的前两名;各个学科相当于条件扩大到了所有学科如select top 2 from score where subject in(select subject from score )
四、更新丢失问题
1.问题描述:不同的用户,基于相同的查询结果,更新时(多个线程)出现覆盖的问题