事务是什么
第一次接触事务的概念,来自于慕课网的教程Spring中的事务,从该教程中可以得知事务分为
- 编程式事务
- 配置式事务
- 注解式事务
其中编程式事务和配置式事务相对来讲用的比较少,注解式事务比较常见,但是不管是哪一种都保持着事务的本性
一组数据库操作,要么全部成功,要么全部失败
ps:教程中也是以转账进行的举例,Transaction本来的含义就是转移和转账,我感觉这个概念的提出就是为了解决 数据的移动 只不过后来慢慢对 一组动作的原子性 有了明确的定义,才翻译成事务
事务如何进行逻辑控制
玩过游戏的都知道有个必杀技叫S/L大法,事务说白了就是存档/读档,也和Git的概念十分相似。那么我就通俗的讲下如何进行逻辑控制
以S/L大法进行举例
数据库的存档叫Commit,数据库的读档叫做Rollback,一旦通过3种方式中任何一个开启事务,将进行以下逻辑操作
游戏逻辑 | 数据库逻辑 |
---|---|
卧槽前面有个BOSS可能打不过 | 转账操作,可能不能顺利完成 |
打之前存一下 | 数据库进行Commit |
开始打BOSS | 数据库开启事务,进行转账 |
BOSS挂了,赶紧存一下,别停电了还要重新打 | 再次Commit结束事务,数据库更变为新状态 |
你挂了,胜败乃兵家常事,大侠请从新来过 | 事务发生异常 |
卧槽,用了三个道具还没打过,赶紧读档,不然这三个道具浪费了 | 进行回滚Rollback结束事务,数据库保持旧状态 |
以Git进行举例
巧合的是Git中也有Commit指令,就是对当前的状态进行快照,如果代码写乱了还可以进行Discard和Rollback操作,只不过
事务的Rollback = Git的Discard
Git的逻辑 | 数据库的逻辑 |
---|---|
这代码好狗屎,我要重构它,但是又怕出问题 | 有个转账交易,不知道能不能成功 |
先Commit保存一下 | 先保存当前数据库状态Commit |
重构代码 | 数据库开启事务,进行转账操作 |
重构的完毕,竟然没BUG,赶快再次Commit | 再次Commit结束事务,数据库更变为新状态 |
卧槽,这是什么意思,卧槽,为什么我这个值有问题,怎么跑不起来了 | 事务发生异常 |
卧槽,算了,别给自己找不自在了,还是用旧代码吧,Discard All | 进行回滚Rollback结束事务,数据库保持旧状态 |
事务的传播性和隔壁级别
事务的传播性和隔离级别理解起来比较晦涩,还牵扯到数据库的脏读/不可重复读/幻读,需要在实际编程中自己理解,这里仅仅提醒下比较容易混淆的概念
传播性中”支持”
事务隔离级别 | 名次解释 |
---|---|
PROPAGATION_REQUIRED | 如果存在一个事务,则支持当前事务。如果没有事务则开启 |
PROPAGATION_SUPPORTS | 如果存在一个事务,支持当前事务。如果没有事务,则非事务的执行 |
PROPAGATION_NOT_SUPPORTED | 总是非事务地执行,并挂起任何存在的事务 |
PROPAGATION_NESTED | 如果一个活动的事务存在,则运行在一个嵌套的事务中. 如果没有活动事务,按PROPAGATION_REQUIRED 属性执行 |
这里好多人都是复制过来复制过去,其中最让人难以理解的是 支持当前事务 这是个什么鬼。。。
Speak In Chinese 应该是说 不会对当前事务产生影响 ,所谓产生影响是指不会像 PROPAGATION_NOT_SUPPORTED 一样把另外一个事务暂停,也不会像 PROPAGATION_NESTED 一样,因为自己事务出错,连累另外一个正在运行对事务一起回滚
脏读/不可重复读/幻读
这三个坑爹的名次是英文直译,比较容易让人晕,这里列个表区别下
脏读和不可重复读
相同点 | 不同点 |
---|---|
读数据的时候,被人改了 | 脏读是只读一次,不可重复读读了多次 |
不可重复读和幻读
相同点 | 不同点 |
---|---|
都是读取多次 | 两次读的内容不一样是不可重复读,两次读的条数不一样(有增删操作)是幻读 |
流程模拟
1 | 事务1:更新一条数据 |
Spring的事务和数据库的事务的区别
在了解了事务的工作机制,好多人都会产生一个疑问,Spring中也有事务,数据库也有事务,他们的区别和联系是什么?这里首先明确一个概念
事务是一个仅仅存在于数据库的概念,Spring的事务本质也是数据库进行的
如何链接到数据库
在我们想要通过某种方式(比如客户端)连接到数据库时,需要知道以下的属性
- IP地址
- 端口
- 帐号
- 密码
既然有了IP地址和端口号,这分明就是IP协议嘛,所以说 无论以何种方式接入数据库,都是基于传输层的TCP/IP协议
正式由于如此,除了通过设定好的IP和端口链接数据库,也可以使用某个Socket,详细参见Sokcet与TCP/IP的关系
Spring如何连接到数据库
在Spring的事务中,必须配置的类是 transactionManager 它有一个属性叫 datasource,而datasource又是一个jdbc的数据源,我们通过配置datasource的URL可以知道
1 | jdbc:mysql://127.0.0.1:3306/database |
是不是感觉和 http://xxxx 有种似曾相识的感觉,所以说Spring在 连接到数据库之后,使用了应用层的jdbc:mysql:协议 对数据库进行操作
Spring操作数据库
这样以来也就不难发现,所谓Spring的事务——其实就是Spring通过与数据库的链接,使用某种应用层协议操作数据库事务本身
除了Spring可以操作数据库的事务以外,MyBatis,Hibernate,Jdbc等等都有事务的概念,但是它们同Spring一样 仅仅是操作数据库
事务实际逻辑运行的地方,还是数据库本身
Spring事务的坑
我在编程中碰到过两次大坑导致事务失效
在填坑之前,首先看看如何检查事务是否正常开启