什么是事务?Mysql事务及隔离级别举例说明

什么是事务?

数据库事务( transaction)是访问并可能操作各种数据项的一个数据库操作序列,这些操作要么全部执行,要么全部不执行,是一个不可分割的工作单位。事务由事务开始与事务结束之间执行的全部数据库操作组成。

简单的说,事务就是将多条sql语句的执行绑在一起,要么都执行成功,要么都执行失败,即都执行成功才算成功,否则就会恢复到这堆SQL执行之前的状态。
例:张三转100块到李四的账户,这至少需要两条SQL语句:

  1. 张三账户余额减少100
  2. 李四余额加100

如果执行第一条sql给张三余额减少100的操作成功后程序出现了异常,导致执行第二条给李四余额减少100的余额失败了,那么程序执行后的结果是:张三余额减少了100,李四余额月没有加100。这样的结果显然是不合理的,张三也不会干。

所以这时候我们需要把这两条sql语句的执行绑在一起,当做一个事务执行,这样的话,如果给张三余额减少100的sql执行成功了,给李四的余额加100的操作却失败了,那么他们两的数据都会回滚到sql执行之前的状态,就是两个人的余额都不会变,这样才是合理的结果嘛。

实际上任何一条DML语句(insert、update、delete)的操作都是一个单独的事务,在MySQL中,默认情况下,事务是自动提交的,也就是说,只要执行一条DML语句就开启了事物,并且提交了事务。
例:在mysql里面执行一个更新操作,update table_name set column_name = xx
我们经常执行这样语句,可能这时看不出与事务有什么关系,但是其实mysql默认帮我们开启了事务,开始事务的语句:

  • 开启事务:Start Transaction
  • 事务结束:End Transaction
  • 提交事务:Commit Transaction
  • 回滚事务:Rollback Transaction

意思也就是说上面执行更新操作的sql也相当于:

Start Transaction;
update table_name set column_name = xx;
Commit Transaction;

只是说mysql默认帮我们开启和提交了事务,所以把多条sql的执行绑定在一起执行,就是说需要在Start Transaction和Commit Transaction中执行这多条语句,这样执行之后,如果中途出现异常,所有的数据都会回滚到sql执行钱的状态。

事务的四大特征

  • 原子性(A):事务是最小单位,不可再分,事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节。事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有发生一样。
  • 一致性(C):事务要求所有的DML语句操作的时候,必须保证同时成功或者同时失败,比如张三向李四转账,不可能张三扣了钱,李四却没收到。
  • 隔离性(I): 指在并发操作中,不同事务之间应该隔离开来,使每个并发中的事务不会相互干扰。也就是说,在事务中查看数据更新时,数据所处的状态要么是另一事务修改它之前的状态,要么是另一事务修改它之后的状态,事务不会查看到中间状态的数据。例如:在A事务中,查看另一B事务(正在修改张三的账户金额)中张三的账户金额,要查看到B事务之前的张三的账户金额,要么查看到B事务之后张三的账户金额。
  • 持久性(D):事务完成后,事务对数据库的所有更新将被保存到数据库,不能回滚

事务的并发读问题

多个事务对相同的数据同时进行操作,这叫做事务并发。在事务并发时,如果没有采取必要的隔离措施,可能会导致各种并发问题,破坏数据的完整性等。这些问题中,其中有三类是读问题,分别是:脏读、不可重复读、幻读。

  1. 脏读(dirty read):读到另一个事务的未提交更新数据,即读取到了脏数据;
    例:A给B转账100元但未提交事务,在B查询后,A做了回滚操作,那么B查询到了A未提交的数据,就称之为脏读。
  2. 不可重复读(unrepeatable read):对同一记录的两次读取不一致,因为另一事务对该记录做了修改(是针对修改操作)
    例:在事务1中,前后两次查询A账户的金额,在两次查询之间,另一事物2对A账户的金额做了修改,此种情况可能会导致事务1中,前后两次查询的结果不一致。这就是不可重复度
  3. 幻读(虚读)(phantom read):对同一张表的两次查询不一致,因为另一事务插入了一条记录(是针对插入或删除操作);

事务的隔离级别

数据库事务的隔离级别有4种,由低到高分别为Read uncommittedRead committedRepeatable readSerializable 。在事务的并发操作中,可能会出现上述并发读问题,下面通过举例说明。

  1. READ UNCOMMITTED(读未提交)
    指一个事务可以读取另一个未提交事务的数据。
    例:
    张三要给李四转账100块钱,要执行两条sql,一条是张三余额减100,第二条是李四余额加100,如果在执行完了第一条sql给张三余额减了100,还没有执行第二条sql给李四余额加100的时候,张三查看自己的余额发现自己的余额少了100,以为转账成功了,但是执行第二条sql的时候出错了,导致事务回滚了,所以实际上转账并没有成功。
    分析:
    实际上转账并没有成功,张三看到了事务未提交的数据,这就是脏读。
    读未提交性能最好,安全级别最低, 可能出现任何事务并发问题(比如脏读、不可以重复读、幻读等),Read committed(读已提交),能解决脏读问题。

  2. READ COMMITTED(读已提交数据)(Oracle默认)
    指 一个事务要等另一个事务提交后才能读取数据
    例:
    张三卡里余额有100块,准备给李四转100块,他到达ATM开始操作(事务开始),首先ATM显示余额还有100块,足够转给李四,正在这个时候李四的女朋友网购需要100块正好提交了付款,这时ATM准备给张三的余额减去100块,再次检测余额的时候,发现余额就只有已经为0了。
    分析:
    这就是读已提交,若有事务对数据进行更新(UPDATE)操作时,读操作事务要等待这个更新操作事务提交后才能读取数据,可以解决脏读问题。但在这个事例中,出现了一个事务范围内两个相同的查询却返回了不同数据,这就是不可重复读。
    防止脏读,性能比REPEATABLE READ好,没有处理不可重复读,REPEATABLE READ可以处理这个问题。

  3. REPEATABLE READ(可重复读)(MySQL默认)
    重复读,就是在开始读取数据(事务开启)时,不再允许修改操作
    例:
    张三卡里余额有100块,准备给李四转100块,他到达ATM开始操作(事务开始),首先ATM显示余额还有100块,足够转给李四,正在这个时候李四的女朋友网购需要100块正好提交了付款,但是这个时候付款操作必须等待转账操作之后才能进行。
    性能比SERIALIZABLE好
    分析:
    重复读可以解决不可重复读问题。写到这里,应该明白的一点就是,不可重复读对应的是修改,即UPDATE操作。但是可能还会有幻读问题。因为幻读问题对应的是插入INSERT操作,而不是UPDATE操作。

  4. SERIALIZABLE(串行化)
    不会出现任何并发问题,因为它是对同一数据的访问是串行的,非并发访问的;性能最差;

MySQL的默认隔离级别为REPEATABLE READ,即可以防止脏读和不可重复读

Spring事务的隔离级别

  1. DEFAULT
    默认隔离级别

  2. READ_UNCOMMITTED
    读未提交 ,对应MySQL的READ UNCOMMITTED。

  3. READ_COMMITTED
    读已提交 ,对应MySQL的READ COMMITTED。

  4. REPEATABLE_READ
    可重复读,对应MySQL的REPEATABLE READ。

  5. SERIALIZABLE
    串行化 ,对应MySQL的SERIALIZABLE。

Spring事务的传播机制

事务的传播机制表示当前事务方法被另一个事务方法调用时,指定事务应该如何传播。

  1. PROPAGATION.REQUIRED
    必须运行在事务中。当前存在事务,则在该事务中运行,不存在,则创建新的事务。

  2. PROPAGATION.REQUIRED_NEW
    必须运行在自己的事务中。无论存不存在事务,都会创建新的事务。当前事务会被挂起。

  3. PROPATATION.SUPPORTS
    单纯自己方法运行,不需要事务。如果当前存在事务,则在事务中运行,不存在,则不在事务中运行。

  4. PROPAGATION.NOT_SUPPORTED
    不运行在事务中。如果存在事务,当前事务将被挂起,自己非事务的运行。

  5. PROPAGATION.MANDATORY
    必须在事务中运行,如果不存在事务,抛异常。

  6. PROPAGATION.NESTED
    如果当前不存在事务,行为和PROPAGATION.REQUIRED一样。
    当前存在事务,创建新的事务,嵌套在事务中(savepoint),外层事务失败,会回滚内层事务,内层事务失败,不会回滚外层事务。

  7. PROPAGATION.NEVER
    总是非事务的进行,如果当前存在事务,抛异常。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值