程序员MySQL最佳实践数据库

【事务笔记】事务的相关整理

2018-11-30  本文已影响2人  58bc06151329

文前说明

作为码农中的一员,需要不断的学习,我工作之余将一些分析总结和学习笔记写成博客与大家一起交流,也希望采用这种方式记录自己的学习之旅。

本文仅供学习交流使用,侵权必删。
不用于商业目的,转载请注明出处。

1. 事务的定义

1.1 事务的特性(ACID 属性)

1.2 事务的隔离

1.2.1 并发事务不进行隔离会产生的问题

时间 事务 A(转账) 事务 B(取款)
1 开始事务
2 开始事务
3 查询账户余额 1000
4 取款 500,账户余额 500
5 查询账户余额 500(脏读)
6 撤销事务,账户余额恢复为 1000
7 汇入 100,账户余额 600
8 提交事务
时间 事务 A(取款) 事务 B(转账)
1 开始事务
2 开始事务
3 查询账户余额 1000
4 汇入 100,账户余额 1100
5 提交事务
6 查询账户余额 1100(不可重复读)
时间 事务 A(统计) 事务 B(创建)
1 开始事务
2 开始事务
3 统计 A 账户总存款 10000
4 创建 B 账户,存款 100
5 提交事务
6 统计 A 账户总存款 10100(幻读)

时间 事务 A(取款) 事务 B(转账)
1 开始事务
2 开始事务
3 查询账户余额 1000
4 查询账户余额 1000
5 汇入 100,账户余额 1100
6 提交事务
7 取出 100,账户余额 900
8 撤销事务,账户余额 1000
时间 事务 A(转账) 事务 B(取款)
1 开始事务
2 开始事务
3 查询账户余额 1000
4 查询账户余额 1000
5 取款 100,账户余额 900
6 提交事务
7 汇入 100,账户余额 1100
8 提交事务

1.2.2 锁机制

1.2.2.1 数据库锁分类

1.2.2.2 悲观锁按使用性质划分

例 1

select * from table

例 2(表级锁)

select * from table(holdlock)

例 3

T1 T2
select * from table update table set column='xx'
T1 运行,加(共享锁)
T1 运行 T2 等待
T1 运行完成,释放(共享锁) T2 运行,加(排他锁)

例 4

T1 T2
select * from table select * from table
T1 运行,加(共享锁) T2 运行,加(共享锁)

例 5

T1 T2 T3
select * from table select * from table update table set column='xx'
T1 运行,加(共享锁) T2 运行加(共享锁)
T1 运行 T2 运行 T3 等待
T1 运行完成,释放(共享锁) T2 运行 T3 等待
T2 运行完成,释放(共享锁) T3 运行,加(排他锁)

例 6(死锁的发生)

T1 T2
select * from table(holdlock) select * from table(holdlock)
T1 运行,加(共享锁) T2 运行加(共享锁)
T1 运行完成,事务未完成,不释放(共享锁)
update table set column='xx' T1 运行完成,事务未完成,不释放(共享锁)
等待(共享锁释放),才能添加(排他锁) update table set column='xx'
继续等待 等待(共享锁释放),才能添加(排他锁)

例 7

T1 T2
update table set column='xx' where id=1 update table set column='xx' where id=2
找到 id=1 这条记录,加(排他锁) 找到 id=2 这条记录,加(排他锁)
T1 T2
update table set column='xx' where id=1 update table set column='xx' where id=2
全表扫描后,加(排他锁) 等待(排他锁释放),才能全表扫描,加(共享锁/更新

锁/排他锁,策略不同,处理不一样)

例 8(解决死锁问题)

T1 T2
select * from table(xlock) select * from table(xlock)
T1 运行,直接加(排他锁) T2 等待
update table set column='xx' T2 等待
T1 运行完成,释放(排他锁) T2 运行,直接加(排他锁)

例 1(行级锁)

select * from table for update

例 2

T1 T2
update table set column='xx' where id<1000 update table set column='xx' where id>1000
T1 运行,对 <1000 数据加(排他锁) T2 运行,对 >1000 数据加(排他锁)
T1 T2
update table set column='xx' where id<1000 update table set column='xx' where id>900
T1 运行,对 <1000 数据加(排他锁) T2 等待
T1 运行完成,释放(排他锁) T2 运行,对 >900 数据加(排他锁)

例 1

T1 T2 T3
select * from table(updlock) select * from table(updlock) select * from table
T1 运行,加(更新锁) T2 等待 T3 运行,加(共享锁)
update table set column='xx' T2 等待 T3 运行完成,释放(共享锁)
T1 运行,加(排他锁) T2 等待
T1 运行完成,释放(排他锁) T2 运行,加(更新锁)

例 2

T1 T2
select * from table(updlock) select * from table
T1 运行,加(更新锁) T2 运行,加(共享锁)
update table set column='xx'
update table set column='xx' T2 等待
T1 运行,加(排他锁) T2 等待
T1 运行完成,释放(排他锁) T2 运行,加(排他锁)

例 1

T1 T2
select * from table(xlock) where id=1 select * from table(tablock)
T1 运行,加(行级排他锁),同时对表加(表级意向排他锁) T2 发现(意向排他锁)等待。

alter table ....


例 1

T1 T2
update table set column='xx' where id=1 select * from table where id=1
T1 运行,数据库自动加(排他锁) T2 等待
T1 运行完成,释放(排他锁) T2 运行,加(共享锁)
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED --事物隔离级别为允许脏读
T1 T2
update table set column='xx' where id=1 select * from table where id=1
T1 运行,数据库自动加(排他锁) T2 运行,不加(共享锁,允许脏读)

1.2.2.3 悲观锁按作用范围划分

表级锁分类 说明
行共享(ROW SHARE) 禁止排他锁定表。
行排他(ROW EXCLUSIVE) 禁止使用排他锁和共享锁。
共享锁(SHARE) 锁定表,对记录只读不写,多个用户可以同时在同一个表上应用此锁。
共享行排他(SHARE ROW EXCLUSIVE) 比共享锁有更多的限制,禁止使用共享锁及更高的锁。
排他(EXCLUSIVE) 限制最强的表级锁,仅允许其他用户查询该表的行。禁止修改和锁定表。

共享锁(S) 排他锁(X) 意向共享锁(IS) 意向排他锁(IX)
共享锁(S) 兼容 冲突 冲突 冲突
排他锁(X) 冲突 冲突 冲突 冲突
意向共享锁(IS) 兼容 冲突 兼容 兼容
意向排他锁(IX) 冲突 冲突 兼容 兼容

1.2.2.4 乐观锁的实现方式


1.2.2.5 并发控制会造成两种锁

1.2.3 隔离级别

是否允许 脏读 不可重复读 幻读
Read UnCommitted
Read Committed(大部分数据库默认级别) ×
Repeatable Read(MySQL 默认级别) × ×
Serializable × × ×

1.2.3 MVCC

1.2.4 MySQL 和 PostgreSQL 对比

隔离级别 MySQL PostgreSQL
Read Uncommitted 支持 不支持,等价于 Read Committed
Read Committed 支持,基于 MVCC 实现 支持,基于 MVCC 实现
Repeatable Read 支持,基于 MVCC 实现了 Snapshot Isolation,可避免幻读 支持,基于 MVCC 实现了 Snapshot Isolation,可避免幻读
Serializable 支持,Repeatable Read + 共享锁 支持,基于 MVCC 实现了 Serialized Snapshot Isolation
默认级别 Repeatable Read Read Committed
MVCC 实现 基于 Undo Log 基于 B+ 树直接记录多个版本

1.3 传播行为

传播行为 说明
PROPAGATION_REQUIRED (支持事物)如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,该设置是最常用的设置。
PROPAGATION_SUPPORTS (支持事物)支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。
PROPAGATION_MANDATORY (支持事物)支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常。
PROPAGATION_REQUIRES_NEW (支持事物)创建新事务,无论当前存不存在事务,都创建新事务。
PROPAGATION_NOT_SUPPORTED (不支持事物)以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER (不支持事物)以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED (不支持事物)如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与 PROPAGATION_REQUIRED 类似的操作。

2. 事务的类型

2.1 JDBC 事务

提供的事务方法 说明
public void setAutoCommit(boolean) 设置自动提交(默认为自动提交)。
public boolean getAutoCommit() 获取是否自动提交。
public void commit() 事务提交。
public void rollback() 事务回滚。

2.2 JTA(Java Transaction API)事务

接口 说明
UserTransaction 接口 让应用程序得以控制事务的开始、挂起、提交、回滚等。由Java 客户端程序或 EJB 调用。
TransactionManager 接口 用于应用服务器管理事务状态。
Transaction 接口 用于执行相关事务操作。
XAResource接口 用于在分布式事务环境下协调事务管理器和资源管理器的工作。
Xid 接口 事务标识符的 Java 映射。

2.2.1 JTA 架构

UserTransaction 定义的方法 说明
begin() 开始一个分布式事务(后台 TransactionManager 会创建一个 Transaction 事务对象并把此对象通过 ThreadLocale 关联到当前线程上)。
commit() 提交事务(后台 TransactionManager 会从当前线程下取出事务对象并把此对象所代表的事务进行提交)。
rollback() 回滚事务(后台 TransactionManager 会从当前线程下取出事务对象并把此对象所代表的事务进行回滚)。
getStatus() 返回关联到当前线程的分布式事务的状态 (Status 对象里边定义了所有的事务状态 )
setRollbackOnly() 标识关联到当前线程的分布式事务将被回滚。
Transaction 定义的方法 说明
commit() 协调不同的事务资源共同完成事务的提交。
rollback() 协调不同的事务资源共同完成事务的回滚。
setRollbackOnly() 标识关联到当前线程的分布式事务将被回滚。
getStatus() 返回关联到当前线程的分布式事务的状态。
enListResource(XAResource xaRes, int flag) 将事务资源加入到当前的事务中。
delistResourc(XAResource xaRes, int flag) 将事务资源从当前事务中删除。
registerSynchronization(Synchronization sync) 回调接口,以便在事务完成时得到通知从而触发一些处理工作,如清除缓存等。可以通过此接口将回调程序注入到事务中,当事务成功提交后,回调程序将被激活。
TransactionManager 定义的方法 说明
begin() 开始事务。
commit() 提交事务。
rollback() 回滚事务。
getStatus() 返回当前事务状态。
setRollbackOnly() 标记当前事务将回滚。
getTransaction() 返回关联到当前线程的事务。
setTransactionTimeout(int seconds) 设置事务超时时间。
resume(Transaction tobj) 继续当前线程关联的事务。
suspend() 挂起当前线程关联的事务。

2.3 容器事务

参考

https://www.jianshu.com/p/cb97f76a92fd
https://www.cnblogs.com/balfish/p/8298296.html

上一篇下一篇

猜你喜欢

热点阅读