简洁风格的网站模板免费下载,淄博百度,浅谈网站开发的意义,郑州网站建设外贸目录
一、数据库多客户端访问问题
1. 数据库的CURD无限制带来的问题
2. 如何解决CURD导致的问题
二、事务的概念
1. 什么是事务
2. 事务的四个属性
3. mysql对事务的管理
4. 为什么会有事务
5. 事务的版本支持
三、事务的操作
1. 事务提交方式
2. 事务操作的准备工…目录
一、数据库多客户端访问问题
1. 数据库的CURD无限制带来的问题
2. 如何解决CURD导致的问题
二、事务的概念
1. 什么是事务
2. 事务的四个属性
3. mysql对事务的管理
4. 为什么会有事务
5. 事务的版本支持
三、事务的操作
1. 事务提交方式
2. 事务操作的准备工作
2.1 数据库是网络服务
2.2 设置全局事务隔离界别
2.3 创建一个测试用的表
3. 事务的开始与结束
4. 事务的回滚正常情况
4.1 设置回滚点
4.2 直接回滚
4.3 结束事务后再回滚
5. 事务回滚非正常情况
6. mysql中设置自动提交的作用
6.1 自动提交在手动启动事务中无效
6.2 单条sql语句与事务的关系
7. 总结
8. 事务操作注意事项 一、数据库多客户端访问问题
1. 数据库的CURD无限制带来的问题
在了解什么是事务之前我们要先了解一下数据库中可能出现的CURD问题。
大家知道 一个数据库是可能同时被多个客户端访问的这些客户端在访问时就可能会对数据库进行CURD操作如果不对客户端的CURD操作加以限制就可能出现各种问题。
举个例子假设现在有一个火车票的购票系统里面只剩1张票。此时分别有客户端A和客户端B要通过这个购票系统买票。当客户端A买完票后购票系统就需要修改数据库中的剩余票数为0。但是在购票系统修改数据库中的剩余票数之前客户端B也要买票。由于此时数据库中的剩余票数还没有更新依然是1此时客户端B就也会买到票。这就导致了客户端A和客户端B买到了同一张票出现问题。 2. 如何解决CURD导致的问题
看了上面的问题 大家如果学过线程就应该会发现数据库中的CURD问题本质上就是多个客户端在没有限制的情况下随意访问导致的不就和线程安全如出一辙么。因此要解决这个问题第一个方面就是要让这个购票过程是原子的。
在上面的购票过程中如果客户端A在买票出票的过程中客户端B也过来买票出票很明显就会出问题。因此第二个方面就是要让买票双方不能互相影响。
当我们买完票后这张票在理论上就已经是永久属于我了无论这张票有没有过期只要我买下了这张票它就是我的。不能说我买了票这张票却不属于我。因此买完票后这张票应该是永久的是持久化的。
当我们在买票的过程中我们的状态只会存在没买票就是没买买了票就是买了。不存在说什么可能买了或没买。这就意味着在购票的过程中我们的状态应该是明确的是确定的。
只要解决了上面的四个问题整个买票过程就是有效的没有问题的。而这四个问题也就是数据库CURD需要解决的问题。
二、事务的概念
1. 什么是事务
举个例子假设现在我们要向一个人转账在这个转账的过程中就需要对数据库中保存的数据做修改。当我们转账时在程序员的角度来看就是先通过一条update语句减去一方的金额再用一条update语句增加另一方的金额。即用两条sql语句完成。但是从用户的角度来看这两条sql语句组合起来才能完成一次转账是一个整体。
通过这个例子我们就应该知道在现实中很多工作是无法用一条sql语句完成的而需要用一批sql语句完成。虽然在程序员眼中这两条sql语句并没有什么但是在用户的眼中却是构成“转账”所必须的操作。因此在这个例子中这两条sql语句合在一起我们就不将它们叫做“两条sql语句”而是叫做“事务”。
要理解“事务”就不能站在底层语言的角度而需要站在上层用户的角度来看。“事务”其实就是上层用户需要具体完成的一个应用层的功能这个功能可能需要由多条sql语句构成。简单来讲“事务”其实就是一条或多条sql语句组合起来所能完成的一个具体业务。例如转账这个具体业务就需要两条sql语句完成此时这两条sql语句就在数据库中构成一个“事务”。
总的来说事务就是一组由DML语句组成的这些语句在逻辑上存在相关性这一组DML语句要么全部成功要么全部失败是一个整体。mysql中提供了一种机制保证我们达到这样的效果。事务还规定不同的客户端能看到的数据是不相同的。
一般来讲事务就是要做的或所做的事情主要用于处理操作量大复杂度高的数据。举个例子。例如有一个人在网络上发表了一些不当言论需要被封号处理。此时平台就可能需要删除这个人在这个平台上的所有相关信息如姓名、电话、以前发表的各种评论等等。这些操作就需要多条mysql语句构成这些所有操作合起来就构成了一个事务。
同时我们要知道一个mysql数据库中往往不止一个事务在运行。在同一时刻可能有大量的请求被包装成事务向mysql服务器发起事务处理请求。此时就可能出现不同的事务需要通过sql语句获取或修改同一份数据此时如果不对加以保护就会出现问题。甚至于由于一个事务有多条sql语句组成就可能出现事务中的sql语句才执行一部分发起事务的客户端就因为某种原因崩溃退出了那这些已经处理过的数据和已经执行过的sql语句该怎么办呢
因此虽然事务由多条sql语句组成但它绝对不是简单的sql语句集合还需要有其他东西来保证它的安全。保证事务安全的方法其实就是让事务拥有四个属性。
2. 事务的四个属性 1原子性 一个事务中的所有操作要么全部完成要么全部不完成不会结束在中间的某个环节。事务在执行过程中发生错误会被“回滚Roolback”到事务开始前的状态就像这个事务从来没有执行过一样。 2一致性 在事务开始之前和事务结束以后数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则这包含资料的精确度、串联性以及后续数据库可以自发性的完成预定的工作。 简单来讲一致性就是指事务处理后的结果是可预期的。例如你要向你朋友转100元你的预期就是在转账后你的账户会少100对方的账户会多100。数据库在处理完这个事务后数据库中的结果和预期一样这就被称作一致性。 3隔离性 数据库允许多个并发事务同时对其数据进行读写和修改。隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别包括“读未提交Read uncommitted”、“读提交read committed”、“可重复读repeatable read”和“串行化Serializable”。 4持久性 事务处理结束后对数据的修改就是永久的即便系统故障也不会丢失。可以理解为一个事务处理完后它的处理结果才会真正的写入到数据库中。 在这四个属性中原子性、隔离性和持久性都是需要数据库能够做到的。而一致性数据库中没有对其进行任何处理。原因就是当数据库中保证了事务的原子性、隔离性和持久性后也就能在很大程度上保证一致性。但要完全保证一致性单靠数据库是不行的还需要用户的配合。
在这上面的原子性Atomicity、一致性Consistency、持久性Isolation和持久性Durability共同简称为“ACID”。
3. mysql对事务的管理
在上文中说了一条或多条sql语句的组合就被称为“事务”。但我们知道一个数据库在同一时刻是可能被多个客户端访问的这就意味着在数据库中一定会存在大量的事务这些事务属于不同的客户端。由此数据库就必然需要将这些事务通过某种方式组织并管理起来即“先描述再组织”。因此在数据库看来事务就是就是客户端请求中来了一批sql数据库将这些sql打包成一个事务对象然后将这个事务对象放入对应的事务执行列表中执行。
4. 为什么会有事务
事务这个东西其实并不是在数据库设计之初就有的而是在数据库的不断使用中发现需要有事务之后才被设计出来的。
试想一下假设你在要用C\C这类编程语言连接数据库在你写对应的程序的时候还需要你自己去处理数据库中的并发访问问题、网络异常后的处理问题等等无疑会在很大程度上增加程序员的负担。
因此事务被mysql编写者设计出来之后其本质是为了当应用程序访问数据库的时候事务能够简化上层的编程模型不需要让程序员去考虑各种各样的潜在错误和并发问题。当我们在使用事务时要么提交要么回滚我们不需要去考虑网络异常、服务器宕机等等问题。因此事务的本质就是为应用层服务的并不是伴随着数据库系统天生就有的。
5. 事务的版本支持
虽然事务很有用但并不是每个引擎都支持事务的。在mysql常用的引擎中只有Innodb引擎才支持事务MyISAM引擎不支持。其他不常用的引擎也不支持事务。
大家可以在linux中登录mysql输入“show engines \G”命令查看mysql数据库下的数据库引擎支持情况 因为在mysql中最常用的就是innodb和MyISAM引擎所以这里就只截了这两个引擎的内容。
可以看到在InnoDB引擎中明确写了“supports transaction”即支持事务。而MySIAM引擎则是不支持。
三、事务的操作
1. 事务提交方式
在mysql中要提交一个事务有两种提交方式分别为“自动提交”和“手动提交”。
要知道mysql中是否开启了自动提交输入“show variables like autocommit;”命令查看 显示为ON就是已开启显示为OFF则为已关闭。
当然我们也可以手动修改事务的提交方式。通过“set autocommit0\1;”命令即可。0表示关闭1表示开启。 可以看到当设置为0时就关闭了自动提交。当然我们最好还是将其设置回开启自动提交比较好。
2. 事务操作的准备工作
2.1 数据库是网络服务
首先大家要知道数据库在本质上是一个网络服务大家的linux上在启动了mysqld后其实就是启动了mysql的服务端。大家登陆mysql其实就是用mysql的客户端登陆服务端。 这就意味着这个网络服务在未来是可以被多个客户端从远端访问的。当然要从远端登录数据库除了用户名和密码还需要在数据库中对特定账户进行一些设置该账户才能从远端登录这里就不再多讲。
然后在进行实际的事务操作前我们要先将事务的隔离级别设置为“读未提交”即“read uncommitted”。这个隔离级别是最低级别方便我们看到事务的实际情况。
2.2 设置全局事务隔离界别
设置方法很简单用“set global transaction isolation level 隔离级别;”命令即可 这条sql语句的意思就是设置全局事务隔离级别等级为”读未提交”。
当设置好后我们可以用“select tx_isolation;”查看当前的会话的事务隔离级别 此时就很奇怪了明明在上面将隔离级别设置为了读未提交为什么这里查出来的结果还是可重复读呢这是因为在mysql中重新设置了全局事务隔离级别后需要重新登录mysql对应的事务隔离级别才会在当前会话生效 为了方便后续测试大家可以在linux中打开两个会话窗口并登录mysql。
2.3 创建一个测试用的表
在这里就先创建如下一个user表在后面的几乎所有关于事务的操作都是在这个表中完成的。 3. 事务的开始与结束 在开始事务之前我们先来看看当前的事务自动提交是否开启 可以看到自动提交是开启了的。这个东西大家要先记住。
要开启事务有两种方法第一种是“start transaction;”第二种是“begin;”。这两条sql语句都可以用于开始一个事务。
当开始一个事务后在开始事务的sql语句后面的sql语句都属于同一个事务。要结束一个事务输入“commit;”即可。
4. 事务的回滚正常情况
4.1 设置回滚点
在事务中我们可以用“savepoint 回滚点名;”来设置一个回滚点。为了方便后面的讲解在这里做一个规定在后面的内容中执行插入、更新、删除等会修改数据的操作的事务叫做事务a而查看表的事务叫做事务b。
先开始事务a 然后设置一个回滚点 设置好后再向继续插入数据并继续设置一个回滚点 设置完成后再在另一个窗口中开启事务b并查看user表中的数据 可以看到在事务b中是能够看到事务a刚刚插入的数据的。
在上面的插入数据和设置回滚点的事务a中这些sql语句共同组成了一个事务。在事务b中也能看到它刚刚插入的数据。但如果我们现在后悔了不想插入id为3的数据而是想回到插入id为3的数据之前该怎么办呢
此时就可以使用刚刚设置的回滚点了。使用“rollback to 回滚点名;”就可以回到指定的回滚点 再在事务b中次查看user表 可以看到此时就事务b查询到的表中的内容就没有了id为3的数据。那如果我们想回滚到s1的位置呢 可以看到此时表中的数据就回到了设置回滚点s1时的状态了。对于回滚点可以理解为游戏的存档点即通过选择一个存档点来回到游戏的某个位置回滚点也是如此。但不同的是回滚点只能先前回滚不能向后回滚。 可以看到当回滚到s1后因为s2是在s1之后设置的所以此时无法从s1位置回滚到s2。
当回滚到表的开始时我们再执行commit分别结束事务a和事务b。 结束事务后我们在查看user表的内容 4.2 直接回滚
可以发现依然为空。这也就说明了事务中的回滚操作确实会影响到数据库中的数据。但现在我们还有一个问题那就是要实现事务的回滚难道一定要设置通过savepoint设置回滚点吗如果不设置会怎么样
我们再次启动事务a然后插入如下数据 然后启动事务b查看user表 数据正常插入。然后我们再在事务a中直接回滚并在事务b中查看user表 可以看到如果不明确要回滚到哪个位置而直接使用rollback就是回到打开事务时表的初始状态。
4.3 结束事务后再回滚
上面的回滚都是在事务运行期间回滚的那如果在事务结束后回滚呢
开启事务a然后向里面插入如下数据后 然后打开事务b查看表中的数据 结束事务a然后执行一次回滚 再在事务b中查看一次user表的数据 表中的数据没有变化。
通过上面的实验就可以知道当对一个结束后的事务进行回滚是无效的。换言之事务回滚只能在一个事务运行的过程中回滚。
5. 事务回滚非正常情况
当前有以下user表表中的数据如下所示 启动事务a向里面插入如下数据 插入完成后在另一个窗口启动事务b并查询user表中的数据 可以看到当前是能够在user表中看到id为4的数据的。然后我们直接关闭掉事务a的窗口再在事务b中查看user表的数据 此时id为4的数据就没有变为了插入数据之前的状态。这就是事务的原子性。一个事务要么做完要么就不做如果在中间过程中出现了异常就会将数据回滚到这个事务启动之前的状态。mysql中的数据不会受到该事务的影响。
6. mysql中设置自动提交的作用
6.1 自动提交在手动启动事务中无效
通过上面的实验可以发现当我们手动开启一个事务后如果这个事务还没有提交但客户端出现异常的时候mysql就会将数据回滚到启动这个事务之前。但这里有一个问题。
输入“show variables like autocommit;”指令可以看到自动提交是打开的那为什么当客户端异常的时候我们所执行的事务客户端没有帮我们自动提交已经完成的内容呢 那如果将自动提交关闭后mysql会不会在客户端出异常的时候帮我们自动提交呢
先将自动提交关闭 继续测试一下。还是用上面的user表 插入如下数据 继续在另一个窗口中查看user表的内容同样可以看到插入的数据。 此时我们再将事务a的窗口关闭并在事务b中查看user表 同样的事务a中插入的数据还是被回滚了。那这个自动提交到底有什么用呢很明显在这里这个自动提交是否开启并没有起到任何作用。
6.2 单条sql语句与事务的关系
在上文中说了事务的提交方式分为“手动提交”和“自动提交”。其实这个手动提交和自动提交就分别对应了事务的手动开启和自动开启。在上文中我们用“start transaciton;”和“beign;”这两种方式启动事务其实都属于是“手动开始事务”。同时我们知道“事务”其实就是一个或多个sql语句的组合。这就意味着一个sql语句其实也可以是一个事务。因此其实我们在mysql中输入的每一个sql语句都会被mysql自动识别为一个事务。
查询当前的自动提交 再查看当前的user表数据 可以看到当前的自动提交是关闭的。在这里我们不再手动启动一个事务而是直接在mysql中执行一条sql语句 然后在另一个窗口中查看user表中的数据 可以看到确实删除了id为2的数据。此时在执行了delete语句的窗口下按“ctrl \”,强制结束掉mysql服务再在这个窗口中查看表中的数据 可以发现刚刚删除的数据又重新回来了。这其实就是因为刚刚执行的delete语句在mysql中其实也是一个事务但是我们将mysql的自动提交关闭了导致这条sql语句在执行完后并没有结束事务。因此当我们强制结束mysql时这个事务由于没有结束数据库中的数据就会被回滚到delete语句执行之前。
当然如果将自动提交打开就不会出现这种情况。因为在没有手动开始事务的情况下执行完一条sql语句后mysql会自动执行commit帮我们结束该事务。
总的来讲我们只需要记住手动启动的事务必须要我们手动commit自动启动的事务在自动提交启动时mysql会自动提交。但如果自动提交关闭就需要我们自行执行commit结束事务。
7. 总结
1只要输入begin或者start transaction 事务便必须要通过commit提交才会持久化与是否设置set autocommit无关。
2事务可以手动回滚。同时当操作异常时mysql会自动回滚。
3对于InnoDB每一条sql语言都默认封装成事务自动提交。select有特殊情况因为mysql有MVCC
8. 事务操作注意事项
1在一个事务中如果没有设置保存点也可以回滚但只能回滚到事务的开始。直接使用rollback前提是事务还没有提交。
2如果一个事务已经执行commit提交了则无法使用rollback回滚。
3可以通过set savepoint语句自行设置回滚点然后通过rollback to语句选择回到哪个回滚点。
4InnoDB支持事务但MyISAM不支持事务。
5开始事务可以使用start transaction或begin语句。