这里用MySQl为例
事务
作为单个逻辑工作单元执行的一系列操作。
事务特性 ACID
A atomicity 原子性
事务是不可分割的原子单元,要么全部完成,要么全部不完成,不可能停在中间。操作成功 整个事务提交 commit 操作失败 事务回滚 rollback
A给B转账
A扣款 B到账
C consistency 一致性
A给B转账
A转了1000 B只到了500
I isolation 隔离性
多个事务并发访问,事务之间是隔离的
D durabiliy 持久性
事务一旦提交,持久化保存在数据库
断电,重启都不会改变数据
事务控制
隐式事务
单独的insert,update,delete 默认是隐式事务,系统自动提交
set autocommit=0;
insert into orders values(7,200,now(),'danny');
commit;
insert into orders values(8,400,now(),'danny');
rollback;
delete from orders where id=7;
显式事务
用户自定义事务,显式提交
start transaction
insert into orders values(7,200,now(),'danny');
commit;
事务隔离级别
read-uncommitted(读未提交)
最低隔离级别 一个事务可以读到另一个事务未提交的结果,导致 脏读
read-committed(读提交)
只有在事务提交之后,其他事务才能看见,可以避免脏读,会导致 不可重复读
repeatable-read(可重读)
一个事务中,对同一份数据读到的结果总是相同的,可以避免不可重复读 会导致 幻读
serializable(串行化)
事务串行化执行,隔离级别最高,牺牲系统并发性,可以解决并发事务所有问题
脏读: 一个事务可以读取另一个尚未提交的事务数据
不可重复读: 事务A多次读取同一数据, 事务B在事务A多次读取的过程中, 对数据作了更改并提交, 导致事务A多次读取同一数据时, 结果不一致, 可能被更新, 可能被删除。
幻读: 在同一事务中, 同一查询多次进行时候, 由于其他插入操作(insert) 的事务提交,导致每次返回不同的结果集。
不可重复读重点在于 update 和 delete , 幻读的重点在于 insert 。
my.ini
#read-uncommitted
#read-committed
#repeatable-read
#serializable
[mysqld]
transaction-isolation =read-committed
--read uncommited
--read committed
--repeatable read
--serializable
set [global | session] transaction isolation level read committed
--查看会话级隔离级别
select @@session.tx_isolation;
select @@tx_isolation;
--查看全局级隔离级别
select @@global.tx_isolation;
事务隔离级别验证
准备:
create table t1(
id int primary key auto_increment,
name varchar(20),
age int
)engine=innodb default charset=utf8;
insert into t1 values(null,'夏七',38),(null,'danny',40);
验证read uncommitted
set session transaction isolation level read uncommitted;
start transaction;
update t1 set age=18 where id=1;
select age from t1 where id=1;
验证read committed
验证repeatable read
验证serializable
锁
计算机协调多个进程或者线程并发访问某一资源的机制
数据库上操作可以归纳读和写
同时读不会有冲突,同时写或者同时读和写才可能产生冲突
不同的存储引擎支持不同的锁机制
MyISAM和MEMORY存储引擎采用表级锁
BDB存储引擎采用页面锁,也支持表锁
InnoDB存储引擎默认采用的是行级锁,也支持表锁
表级锁 开销小,加锁快,不会出现死锁,锁定粒度大,发生锁冲突概率最高,并发度低
行级锁 开销大,加锁慢,会出现死锁,锁定粒度最小,发生锁冲突概率最低,并发度最高
页面锁 开销和加锁介于表级锁和行级锁之间,会出现死锁,锁定粒度介于表级锁和行级锁之间,并发度一般
死锁 相互等待对方持有的锁
锁定粒度:锁定对象的大小 表 页 行
锁冲突 等待别人释放锁
MyISAM锁
在用户读数据自动加read锁,改数据自动加write锁
lock tables unlock tables
create table t2(
id int primary key auto_increment,
name varchar(20),
age int
)engine=myisam default charset=utf8;
insert into t2 values(null,'夏七',38),(null,'danny',40);
read是共享锁 write是排他锁 独占锁
会话1给表加读锁
会话1只能读加锁的表数据 会话2可以读表
会话1不能改数据 会话2能改数据要等待
会话1给表加写锁
会话1读加锁的表数据 会话2可以读数据要等待
会话1能改数据 会话2可以改数据要等待
锁并发操作
MyISAM存储引擎读锁和写锁互斥,读写是串行的,但是在一定条件下可以实现并发
MyISAM存储引擎提供了一个系统变量concurrent_insert,控制并发插入0,1,2
0 不允许并发
1 如果MyISAM的表没有空洞,允许一个进程读表的同时,另一个进程从表尾插入记录,是MyISAM默认设置
2 不管MyISAM的表有没有空洞,都允许在表尾插入记录
my.ini
concurrent_insert=2 重启MySQL服务允许并发
使用 需要一次锁定用到的所有表,同一表在SQL出现多少次别名,也要对别名锁定多少次