网站开发属于什么类型软件,建站之星如何建网站,全网营销销售,无锡论坛网站建设本地事务简介
1 事务基本性质
数据库事务的几个特性#xff1a;原子性(Automicity)、一致性(Consistency)、隔离性或独立性(islation)和持久性(Durability)#xff0c;简称ACID。 原子性#xff1a;一系列的操作#xff0c;其整体不可拆分#xff0c;要么同时成功#…本地事务简介
1 事务基本性质
数据库事务的几个特性原子性(Automicity)、一致性(Consistency)、隔离性或独立性(islation)和持久性(Durability)简称ACID。 原子性一系列的操作其整体不可拆分要么同时成功要么同时失败。 一致性数据在事务的前后业务整体一致。 转账 。A1000 B1000 转200 事务成功。 A800 B1200 隔离性事务之间互相隔离。 持久性一旦事务成功数据一定会记录在数据库。
2 事务的隔离级别
隔离级别特点Read Uncommitted允许读取未提交的数据Read committed只能读取已提交的数据Repeatable Read同一事务中多次读取同一数据结果一致Serializable事务完全串行化按顺序执行
2.1 Read Uncommitted
场景描述
假设有一个银行账户表 accounts记录用户的账户余额。现在有两个并发事务
事务 A从账户中扣除 100 元。事务 B查询账户余额。
数据库初始状态
假设账户初始余额为 1000 元。
事务操作步骤
事务 A 开始 查询账户余额SELECT balance FROM accounts WHERE account_id 1;结果为 1000 元扣除 100 元UPDATE accounts SET balance balance - 100 WHERE account_id 1;此时账户余额变为 900 元但事务 A 还未提交 事务 B 开始 查询账户余额SELECT balance FROM accounts WHERE account_id 1;结果为 900 元因为事务 A 的未提交数据被读取到了 事务 A 回滚 由于某些原因事务 A 回滚撤销了之前的更新操作。此时账户余额恢复为 1000 元。 事务 B 结束 事务 B 查询到的余额是 900 元但实际上账户的真实余额是 1000 元。
问题分析
脏读事务 B 读取到了事务 A 未提交的数据900 元而事务 A 最终回滚导致事务 B 查询到的数据是不正确的。这种现象称为脏读。
Read Uncommitted 的特点
在 Read Uncommitted 隔离级别下事务可以读取到其他事务尚未提交的数据。这种隔离级别允许并发性能最高但数据一致性最差容易出现脏读问题。
2.2 Read Committed
场景描述
假设有一个库存表 inventory记录商品的数量。现在有两个并发事务
事务 A更新商品的数量。事务 B查询商品的数量。
数据库初始状态
假设商品的初始数量为 100。
事务操作步骤
事务 A 开始 查询商品数量SELECT quantity FROM inventory WHERE product_id 1;结果为 100更新商品数量UPDATE inventory SET quantity quantity - 10 WHERE product_id 1;此时商品数量变为 90但事务 A 还未提交 事务 B 开始 查询商品数量SELECT quantity FROM inventory WHERE product_id 1;结果为 100因为事务 A 的更新尚未提交 事务 A 提交 提交事务 A更新操作生效商品数量变为 90。 事务 B 再次查询 再次查询商品数量SELECT quantity FROM inventory WHERE product_id 1;结果为 90因为事务 A 已提交
问题分析
避免脏读事务 B 在事务 A 提交之前查询到的商品数量是 100而不是事务 A 未提交的 90。这避免了脏读问题。不可重复读事务 B 在事务 A 提交后再次查询结果从 100 变为 90。这种现象称为不可重复读因为同一个事务在不同时间读取到的数据不一致。幻读如果事务 B 在事务 A 提交之前查询商品数量然后事务 A 插入了一条新的商品记录事务 B 再次查询时可能会发现多了一条记录。这种现象称为幻读。
Read Committed 的特点
避免脏读事务只能读取到其他事务已经提交的数据。可能出现不可重复读和幻读由于事务 B 在事务 A 提交前后读取到的数据不一致可能会出现不可重复读和幻读问题。并发性能较好相比更高隔离级别如 Repeatable Read 和 SerializableRead Committed 的并发性能更好因为它允许更多的并发操作。
2.3 Repeatable Read
场景描述
假设有一个商品库存表 inventory记录商品的数量。现在有两个并发事务
事务 A查询并更新商品的数量。事务 B查询商品的数量。
数据库初始状态
假设商品的初始数量为 100。
事务操作步骤
事务 A 开始 查询商品数量SELECT quantity FROM inventory WHERE product_id 1;结果为 100更新商品数量UPDATE inventory SET quantity quantity - 10 WHERE product_id 1;此时商品数量变为 90但事务 A 还未提交 事务 B 开始 查询商品数量SELECT quantity FROM inventory WHERE product_id 1;结果为 100因为事务 A 的更新尚未提交 事务 A 提交 提交事务 A更新操作生效商品数量变为 90。 事务 B 再次查询 再次查询商品数量SELECT quantity FROM inventory WHERE product_id 1;结果仍为 100因为事务 B 在同一个事务中读取到的结果是一致的
问题分析
避免脏读事务 B 在事务 A 提交之前查询到的商品数量是 100而不是事务 A 未提交的 90。这避免了脏读问题。避免不可重复读事务 B 在同一个事务中多次查询商品数量结果始终为 100即使事务 A 已提交事务 B 仍然读取到的是事务开始时的一致数据。这避免了不可重复读问题。可能出现幻读虽然 Repeatable Read 避免了不可重复读但在某些数据库实现中如果事务 A 插入或删除了记录事务 B 可能会看到不同的结果集。这种现象称为幻读。
Repeatable Read 的特点
避免脏读和不可重复读事务在同一个事务中多次读取同一数据的结果是一致的。可能出现幻读在某些数据库实现中如果事务 A 插入或删除了记录事务 B 可能会看到不同的结果集。并发性能较好相比 SerializableRepeatable Read 的并发性能更好因为它允许更多的并发操作。
2.4 Serializable
场景描述
假设有一个商品库存表 inventory记录商品的数量。现在有两个并发事务
事务 A查询并更新商品的数量。事务 B查询商品的数量。
数据库初始状态
假设商品的初始数量为 100。
事务操作步骤
事务 A 开始 查询商品数量SELECT quantity FROM inventory WHERE product_id 1;结果为 100更新商品数量UPDATE inventory SET quantity quantity - 10 WHERE product_id 1;此时商品数量变为 90但事务 A 还未提交 事务 B 开始 查询商品数量SELECT quantity FROM inventory WHERE product_id 1;事务 B 会被阻塞直到事务 A 提交或回滚 事务 A 提交 提交事务 A更新操作生效商品数量变为 90。 事务 B 继续执行 查询商品数量SELECT quantity FROM inventory WHERE product_id 1;结果为 90因为事务 A 已提交
问题分析
避免脏读事务 B 在事务 A 提交之前无法读取数据因此不会读取到事务 A 未提交的数据。避免不可重复读事务 B 在同一个事务中多次查询商品数量结果始终为 90即使事务 A 已提交事务 B 仍然读取到的是事务开始时的一致数据。避免幻读事务 B 在事务 A 提交之前无法读取数据因此不会看到事务 A 插入或删除的记录。
Serializable 的特点
完全避免并发问题Serializable 确保所有事务按顺序执行完全避免了脏读、不可重复读和幻读。并发性能最低由于事务必须按顺序执行不能并行因此并发性能最低。适用场景适用于对数据一致性要求极高的场景如金融交易系统、账务系统等。
3 事务的传播行为
在 Spring 中事务传播行为Transaction Propagation Behavior定义了在一个事务中调用另一个事务方法时事务如何被传播和管理。Spring 提供了多种事务传播行为每种行为都对应不同的事务管理策略。以下是常见的事务传播行为及其解释
传播行为当前有事务时当前无事务时PROPAGATION_REQUIRED加入当前事务创建新事务PROPAGATION_SUPPORTS加入当前事务非事务执行PROPAGATION_MANDATORY加入当前事务抛出异常PROPAGATION_REQUIRES_NEW创建新事务挂起当前事务创建新事务PROPAGATION_NOT_SUPPORTED挂起当前事务非事务执行非事务执行PROPAGATION_NEVER抛出异常非事务执行PROPAGATION_NESTED创建嵌套事务创建新事务
实例代码
#在注解上指定事务的传播行为
Transational(PropagationPropagation.REQUIRES_NEWS)
#方法签名
public void transaction(){...}4 代理对象
在同一个类中编写两个方法内部调用的时候会导致事务设置失效。原因是没有用到代理对象。
// TODO ps貌似新版spring已经优化了可以内部调用了。
解决方法通过代理对象调用方法
①引入依赖
dependencygroupIdorg.springframe.boot/groupIdartifactIdspring-boot-starter-aop/artifactId
/dependency②在启动类上加上注解EnableAspectJAutoProxy(exposeProxytrue)
EnableAspectJAutoProxy(exposeProxytrue)
SpringBootApplication
public class Application {...}③在类中使用代理对象如下
OrderServiceImpl orderService (OrderServiceImpl) AopContext.currentProxy();
// 在OrderServiceImpl类内部通过代理对象调用自身的method1方法和method2方法
orderService.method1();
orderService.method2();