mysql如何定义事物_MySQL入门之事务(下)

数据库内部定义了四种隔离级别,用于解决三种隔离问题

1 Serializable:可避免脏读、不可重复读、虚读情况的发生。(串行化)

2 Repeatable read:可避免脏读、不可重复读情况的发生。(可重复读)不可以避免虚读

3 Read committed:可避免脏读情况发生(读已提交)

4 Read uncommitted:最低级别,以上情况均无法保证。(读未提交)

怎样设置事务的隔离级别?

mysql中设置

1.查看事务隔离级别

select @@tx_isolation查询当前事务隔离级别

mysql中默认的事务隔离级别是 Repeatable read.

扩展:oracle 中默认的事务隔离级别是 Read committed

2.mysql中怎样设置事务隔离级别

set session transaction isolation level 设置事务隔离级别

jdbc中设置

JDBC程序中能否指定事务的隔离级别 ?

Connection接口中定义事务隔离级别四个常量:

static int TRANSACTION_READ_COMMITTED

指示不可以发生脏读的常量;不可重复读和虚读可以发生。

static int TRANSACTION_READ_UNCOMMITTED

指示可以发生脏读 (dirty read)、不可重复读和虚读 (phantom read) 的常量。

static int TRANSACTION_REPEATABLE_READ

指示不可以发生脏读和不可重复读的常量;虚读可以发生。

static int TRANSACTION_SERIALIZABLE

指示不可以发生脏读、不可重复读和虚读的常量。

通过 void setTransactionIsolation(int level) 设置数据库隔离级别

如果不考虑隔离性,可能会引发如下问题

1、脏读 :指一个事务读取另一个事务未提交的数据

A 转账 给B 100,未提交

B 查询账户多了100

A 回滚

B 查询账户那100不见了

2、不可重复读:在一个事务先后两次读取发生数据不一致情况,第二次读取到另一个事务已经提交数据 (强调数据更新 update)

A 查询账户 5000

B 向 A 账户转入 5000

A 查询账户 10000

3、虚读(幻读) : 在一个事务中,第二次读取发生数据记录数的不同 ,读取到另一个事务已经提交数据 (强调数据记录变化 insert )

A 第一次读取 存在5条记录

B 向 A 插入一条新的记录

A 第二次读取 存在6条记录

4、丢失更新:两个事务对同一条记录进行操作,后提交的事务,将先提交的事务的修改覆盖了。

演示:脏读

一个事务读取到另一个事务的未提交数据

设置A,B事务隔离级别为 Read uncommitted

set session transaction isolation level read uncommitted;

在A事务中

start transaction;

update account set money=money-500 where name='aaa';

update account set money=money+500 where name='bbb';

在B事务中

start transaction;

select * from account;

这时,B事务读取时,会发现,钱已经汇完。那么就出现了脏读。

当A事务提交前,执行rollback,在commit, B事务在查询,就会发现,钱恢复成原样

也出现了两次查询结果不一致问题,出现了不可重复读.

解决脏读问题

将事务的隔离级别设置为 read committed来解决脏读

设置A,B事务隔离级别为 Read committed

set session transaction isolation level read committed;

在A事务中

start transaction;

update account set money=money-500 where name='aaa';

update account set money=money+500 where name='bbb';

在B事务中

start transaction;

select * from account;

这时B事务中,读取信息时,是不能读到A事务未提交的数据的,也就解决了脏读。让A事务,提交数据 commit;

这时,在查询,这次结果与上一次查询结果又不一样了,还存在不可重复读。

解决不可重复读

将事务的隔离级别设置为Repeatable read来解决不可重复读。

设置A,B事务隔离级别为 Repeatable read;

set session transaction isolation level Repeatable read;

1.在A事务中

start transaction;

update account set money=money-500 where name='aaa';

update account set money=money+500 where name='bbb';

2.在B事务中

start transaction;

select * from account;

当A事务提交后commit;B事务在查询,与上次查询结果一致,解决了不可重复读。

设置事务隔离级别

Serializable ,它可以解决所有问题

set session transaction isolation level Serializable;

如果设置成这种隔离级别,那么会出现锁表。也就是说,一个事务在对表进行操作时,其它事务操作不了。

总结:

脏读:一个事务读取到另一个事务未提交数据

不可重复读:两次读取数据不一致(读提交数据)---update

虚读:两次读取数据不一致(读提交数据)----insert

事务隔离级别:

read uncommitted 什么问题也解决不了.

read committed 可以解决脏读,其它解决不了.

Repeatable read 可以解决脏读,可以解决不可重复读,不能解决虚读.

Serializable 它会锁表,可以解决所有问题.

安全性:serializable > repeatable read > read committed > read uncommitted

性能:serializable < repeatable read < read committed < read uncommitted

结论: 实际开发中,通常不会选择 serializable 和 read uncommitted ,

mysql默认隔离级别 repeatable read ,oracle默认隔离级别 read committed

丢失更新:多个事务对同一条记录进行了操作,后提交的事务将先提交的事务操作覆盖了。

问题:怎样解决丢失更新问题?

解决丢失更新可以采用两种方式:

1.悲观锁

悲观锁 (假设丢失更新一定会发生 ) ----- 利用数据库内部锁机制,开启事务之后提供的锁机制

1.共享锁

select * from 表名 lock in share mode(读锁、共享锁)

2.排它锁

select * from 表名for update (写锁、排它锁)

update语句默认添加排它锁

2.乐观锁

乐观锁 (假设丢失更新不会发生)------- 采用程序中添加版本字段解决丢失更新问题

create table product (

id int,

name varchar(20),

updatetime timestamp

);

insert into product values(1,'冰箱',null);

update product set name='洗衣机' where id = 1;

解决丢失更新:在数据表添加版本字段,每次修改过记录后,版本字段都会更新,如果读取是版本字段,与修改时版本字段不一致,说明别人进行修改过数据 (重改)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值