制作一个公司网站多少,保定网站制作公司,宝塔怎么做两个网站,网站没有后台登陆文件夹前些天发现了一个巨牛的人工智能学习网站#xff0c;通俗易懂#xff0c;风趣幽默#xff0c;忍不住分享一下给大家。点击跳转到教程。
Transaction 也就是所谓的事务了#xff0c;通俗理解就是一件事情。从小#xff0c;父母就教育我们#xff0c;做事情要有始有终通俗易懂风趣幽默忍不住分享一下给大家。点击跳转到教程。
Transaction 也就是所谓的事务了通俗理解就是一件事情。从小父母就教育我们做事情要有始有终不能半途而废。 事务也是这样不能做一般就不做了要么做完要么就不做。也就是说事务必须是一个不可分割的整体就像我们在化学课里学到的原子原子是构成物质的最小单位。于是人们就归纳出事务的第一个特性原子性Atomicity。我靠一点都不神秘嘛。
特别是在数据库领域事务是一个非常重要的概念除了原子性以外它还有一个极其重要的特性那就是一致性Consistency。也就是说执行完数据库操作后数据不会被破坏。打个比方如果从 A 账户转账到 B 账户不可能因为 A 账户扣了钱而 B 账户没有加钱吧。如果出现了这类事情您一定会非常气愤什么 diao 银行啊
当我们编写了一条 update 语句提交到数据库的一刹那间有可能别人也提交了一条 delete 语句到数据库中。也许我们都是对同一条记录进行操作可以想象如果不稍加控制就会出大麻烦来。我们必须保证数据库操作之间是“隔离”的线程之间有时也要做到隔离彼此之间没有任何干扰。这就是隔离性Isolation。要想真正的做到操作之间完全没有任何干扰是很难的于是乎每天上班打酱油的数据库专家们开始动脑筋了“我们要制定一个规范让各个数据库厂商都支持我们的规范”这个规范就是事务隔离级别Transaction Isolation Level。能定义出这样牛逼的规范真的挺不容易的其实说白了就四个级别
READ_UNCOMMITTEDREAD_COMMITTEDREPEATABLE_READSERIALIZABLE
千万不要去翻译那只是一个代号而已。从上往下级别越来越高并发性越来越差安全性越来越高反之则反。
当我们执行一条 insert 语句后数据库必须要保证有一条数据永久地存放在磁盘中这个也算事务的一条特性 它就是持久性Durability。
归纳一下以上一共提到了事务的 4 条特性把它们的英文单词首字母合起来就是ACID这个就是传说中的“事务 ACID 特性”
真的是非常牛逼的特性啊这 4 条特性是事务管理的基石一定要透彻理解。此外还要明确这四个家伙当中谁才是老大
其实想想也就清楚了原子性是基础隔离性是手段持久性是目的真正的老大就是一致性。数据不一致了就相当于“江湖乱套了流氓戴胸罩”。所以说这三个小弟都是跟着“一致性”这个老大混为他全心全意服务。
这四个家伙当中其实最难理解的反倒不是一致性而是隔离性。因为它是保证一致性的重要手段是工具使用它不能有半点差池否则后果自负怪不得数据库行业专家们都要来研究所谓的事务隔离级别了。其实定义这四个级别就是为了解决数据在高并发下所产生的问题那又有哪些问题呢
Dirty Read脏读Unrepeatable Read不可重复读Phantom Read幻读
首先看看“脏读”看到“脏”这个字我就想到了恶心、肮脏。数据怎么可能脏呢其实也就是我们经常说的“垃圾数据”了。比如说有两个事务它们在并发执行也就是竞争。看看以下这个表格您一定会明白我在说什么 时间事务 A存款事务 B取款T1开始事务 T2 开始事务T3 查询余额1000 元T4 取出 1000 元余额 0 元T5查询余额0 元 T6 撤销事务余额恢复为 1000 元T7存入 500 元余额 500 元 T8提交事务 余额应该为 1500 元才对请看 T5 时间点事务 A 此时查询余额为 0 元这个数据就是脏数据它是事务 B 造成的明显事务没有进行隔离渗过来了乱套了。
所以脏读这件事情是非常要不得的一定要解决掉让事务之间隔离起来才是硬道理。
那第 2 条不可重复读又怎么解释呢还是用类似的例子来说明 时间事务 A存款事务 B取款T1开始事务 T2 开始事务T3 查询余额1000 元T4查询余额1000 元 T5 取出 1000 元余额 0 元T6 提交事务T7查询余额0 元 事务 A 其实除了查询了两次以外其他什么事情都没有做结果钱就从 1000 变成 0 了这就是重复读了。可想而知这是别人干的不是我干的。其实这样也是合理的毕竟事务 B 提交了事务数据库将结果进行了持久化所以事务 A 再次读取自然就发生了变化。
这种现象基本上是可以理解的但在有些变态的场景下却是不允许的。毕竟这种现象也是事务之间没有隔离所造成的但我们对于这种问题似乎可以忽略。
最后一条幻读。我去Phantom 这个单词不就是“幽灵、鬼魂”吗刚看到这个单词时真的把我的小弟弟都给惊呆了。怪不得这里要翻译成“幻读”了总不能翻译成“幽灵读”、“鬼魂读”吧。其实意义就是鬼在读不是人在读或者说搞不清楚为什么它就变了很晕真的很晕。还是用一个示例来说话吧
时间事务 A统计总存款事务 B存款T1开始事务 T2 开始事务T3统计总存款10000 元 T4 存入 100 元T5 提交事务T6统计总存款10100 元 银行工作人员每次统计总存款都看到不一样的结果。不过这也确实也挺正常的总存款增多了肯定是这个时候有人在存钱。但是如果银行系统真的这样设计那算是玩完了。这同样也是事务没有隔离所造成的但对于大多数应用系统而言这似乎也是正常的可以理解也是允许的。银行里那些恶心的那些系统要求非常严密统计的时候甚至会将所有的其他操作给隔离开这种隔离级别就算非常高了估计要到 SERIALIZABLE 级别了。
归纳一下以上提到了事务并发所引起的跟读取数据有关的问题各用一句话来描述一下
脏读事务 A 读取了事务 B 未提交的数据并在这个基础上又做了其他操作。不可重复读事务 A 读取了事务 B 已提交的更改数据。幻读事务 A 读取了事务 B 已提交的新增数据。
第一条是坚决抵制的后两条在大多数情况下可不作考虑。
这就是为什么必须要有事务隔离级别这个东西了它就像一面墙一样隔离不同的事务。看下面这个表格您就清楚了不同的事务隔离级别能处理怎样的事务并发问题 事务隔离级别脏读不可重复读幻读READ_UNCOMMITTED允许允许允许READ_COMMITTED禁止允许允许REPEATABLE_READ禁止禁止允许SERIALIZABLE禁止禁止禁止根据您的实际需求再参考这张表最后确定事务隔离级别应该不再是一件难事了。
JDBC 也提供了这四类事务隔离级别但默认事务隔离级别对不同数据库产品而言却是不一样的。我们熟知的 MySQL 数据库的默认事务隔离级别就是 READ_COMMITTEDOracle、SQL Server、DB2等都有有自己的默认值。我认为 READ_COMMITTED 已经可以解决绝大多数问题了其他的就具体情况具体分析吧。
若对其他数据库的默认事务隔离级别不太清楚可以使用以下代码来获取 DatabaseMetaData meta DBUtil.getDataSource().getConnection().getMetaData();
int defaultIsolation meta.getDefaultTransactionIsolation();
提示在 java.sql.Connection 类中可查看所有的隔离级别。
我们知道 JDBC 只是连接 Java 程序与数据库的桥梁而已那么数据库又是怎样隔离事务的呢其实它就是“锁”这个东西。当插入数据时就锁定表这叫“锁表”当更新数据时就锁定行这叫“锁行”。当然这个已经超出了我们今天讨论的范围所以还是留点空间给我们的 DBA 同学吧免得他没啥好写的了。
除了 JDBC 给我们提供的事务隔离级别这种解决方案以外还有哪些解决方案可以完善事务管理功能呢
不妨看看 Spring 的解决方案吧其实它是对 JDBC 的一个补充或扩展。它提供了一个非常重要的功能就是事务传播行为Transaction Propagation Behavior。
确实够牛逼的Spring 一下子就提供了 7 种事务传播行为这 7 种行为一出现真的是亮瞎了我的狗眼
PROPAGATION_REQUIREDRROPAGATION_REQUIRES_NEWPROPAGATION_NESTEDPROPAGATION_SUPPORTSPROPAGATION_NOT_SUPPORTEDPROPAGATION_NEVERPROPAGATION_MANDATORY
看了 Spring 参考手册之后更是晕了这到底是在干嘛
首先要明确的是事务是从哪里来传播到哪里去答案是从方法 A 传播到方法 B。Spring 解决的只是方法之间的事务传播那情况就多了比如
方法 A 有事务方法 B 也有事务。方法 A 有事务方法 B 没有事务。方法 A 没有事务方法 B 有事务。方法 A 没有事务方法 B 也没有事务。
这样就是 4 种了还有 3 种特殊情况。还是用我的 Style 给大家做一个分析吧
假设事务从方法 A 传播到方法 B您需要面对方法 B问自己一个问题
方法 A 有事务吗
如果没有就新建一个事务如果有就加入当前事务。这就是 PROPAGATION_REQUIRED它也是 Spring 提供的默认事务传播行为适合绝大多数情况。如果没有就新建一个事务如果有就将当前事务挂起。这就是 RROPAGATION_REQUIRES_NEW意思就是创建了一个新事务它和原来的事务没有任何关系了。如果没有就新建一个事务如果有就在当前事务中嵌套其他事务。这就是 PROPAGATION_NESTED也就是传说中的“嵌套事务”了所嵌套的子事务与主事务之间是有关联的当主事务提交或回滚子事务也会提交或回滚。如果没有就以非事务方式执行如果有就使用当前事务。这就是 PROPAGATION_SUPPORTS这种方式非常随意没有就没有有就有有点无所谓的态度反正我是支持你的。如果没有就以非事务方式执行如果有就将当前事务挂起。这就是 PROPAGATION_NOT_SUPPORTED这种方式非常强硬没有就没有有我也不支持你把你挂起来不鸟你。如果没有就以非事务方式执行如果有就抛出异常。这就是 PROPAGATION_NEVER这种方式更猛没有就没有有了反而报错确实够牛的它说我从不支持事务如果没有就抛出异常如果有就使用当前事务。这就是 PROPAGATION_MANDATORY这种方式可以说是牛逼中的牛逼了没有事务直接就报错确实够狠的它说我必须要有事务
看到我上面这段解释小伙伴们是否已经感受到被打通任督二脉的感觉多读几遍体会一下就是您自己的东西了。
需要注意的是 PROPAGATION_NESTED不要被它的名字所欺骗Nested嵌套所以凡是在类似方法 A 调用方法 B 的时候在方法 B 上使用了这种事务传播行为如果您真的那样做了那您就错了。因为您错误地以为 PROPAGATION_NESTED 就是为方法嵌套调用而准备的其实默认的 PROPAGATION_REQUIRED 就可以帮助您做您想要做的事情了。
Spring 给我们带来了事务传播行为这确实是一个非常强大而又实用的功能。除此以外也提供了一些小的附加功能比如
事务超时Transaction Timeout为了解决事务时间太长消耗太多的资源所以故意给事务设置一个最大时常如果超过了就回滚事务。只读事务Readonly Transaction为了忽略那些不需要事务的方法比如读取数据这样可以有效地提高一些性能。
最后推荐大家使用 Spring 的注解式事务配置而放弃 XML 式事务配置。因为注解实在是太优雅了当然这一切都取决于您自身的情况了。
在 Spring 配置文件中使用
...
tx:annotation-driven /
...
在需要事务的方法上使用 Transactional
public void xxx() {...
}
可在 Transactional 注解中设置事务隔离级别、事务传播行为、事务超时时间、是否只读事务。
简直是太完美了太优雅了
最后有必要对本文的内容做一个总结免费赠送一张高清无码思维导图 期盼您的对本文的评价感谢您的关注与支持