经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 数据库/运维 » MySQL » 查看文章
使用Mysql事务可能出现的问题以及解决原理
来源:cnblogs  作者:盛崖余  时间:2021/2/1 11:51:07  对本文有异议

一、什么是数据库事务?

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

  简言之就是,更新、新增、删除的sql要么一起成功,要么一起失败(回滚)。

  事务的ACID是怎么是实现的见我的另一篇文章:Mysql事务中的ACID是怎么实现的

二、使用数据库的事务可能出现什么问题?

  可能会出现脏读、幻读、不可重复读的问题。

  1.什么是脏读?

       比如说A事务修改了一条数据,B事务读取了该条事务,A事务回滚,B事务读取了错误的数据,这叫做脏读。

  例子:数据库中张三的工资为5K,事务B读取成了8k的行为叫做脏读。

时间 事务A 事务B
T1 开始事务  
T2   开始事务
T3 张三的工资从5K改为8K(update操作)  
T4   读取到张三的工资为8k(select操作)
T5    提交事务
T6

事务提交失败回滚,数据库中张三的数据变回5K

 

  2.什么是不可重复读?

  例子:张三在一个事务中前后两次读取的工资的金额不同的情况叫做不可重复读。

时间 事务A 事务B
T1 开始事务  
T2   开始事务
T3 读取张三的工资为5K(select操作)  
T4   修改的张三的工资为8k(update操作)
T5    提交事务
T6

读取张三的工资为8K(select操作)

 

  3.什么是幻读?

  是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入\删除一行数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样。

  例子:初始数据库中,有张三、李四工资为5K的数据

时间 事务A 事务B
T1 开始事务  
T2   开始事务
T3

读取张三李四的工资为5K

 
T4  

添加王五的工资为5K的数据(add操作)

/删除李四的工资为5K的数据(delete操作)

T5    提交事务
T6

修改工资为5k的员工工资改为6K(update操作)

操作影响了3条(添加操作)/1条(删除操作)数据

 
T7

查询员工工资,

(预期张三李四工资6K)

实际上张三李四王五工资为6K/张三工资为6K

 

  三、Spring是如何完成事务的,脏读幻读不可重复读是怎么解决的?

  Spring中有一个@Transactional注解/* * Copyright 2002-2016 the original author or authors.

  1. *
  2. * Licensed under the Apache License, Version 2.0 (the "License");
  3. * you may not use this file except in compliance with the License.
  4. * You may obtain a copy of the License at
  5. *
  6. * http://www.apache.org/licenses/LICENSE-2.0
  7. *
  8. * Unless required by applicable law or agreed to in writing, software
  9. * distributed under the License is distributed on an "AS IS" BASIS,
  10. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. * See the License for the specific language governing permissions and
  12. * limitations under the License.
  13. */
  14. //上面就是一些版权说明的内容
  15. package org.springframework.transaction.annotation;
  16. import java.lang.annotation.Documented;
  17. import java.lang.annotation.ElementType;
  18. import java.lang.annotation.Inherited;
  19. import java.lang.annotation.Retention;
  20. import java.lang.annotation.RetentionPolicy;
  21. import java.lang.annotation.Target;
  22. import org.springframework.core.annotation.AliasFor;
  23. import org.springframework.transaction.TransactionDefinition;
  24. /**
  25. * Describes transaction attributes on a method or class.
  26. *
  27. * <p>This annotation type is generally directly comparable to Spring's
  28. * {@link org.springframework.transaction.interceptor.RuleBasedTransactionAttribute}
  29. * class, and in fact {@link AnnotationTransactionAttributeSource} will directly
  30. * convert the data to the latter class, so that Spring's transaction support code
  31. * does not have to know about annotations. If no rules are relevant to the exception,
  32. * it will be treated like
  33. * {@link org.springframework.transaction.interceptor.DefaultTransactionAttribute}
  34. * (rolling back on {@link RuntimeException} and {@link Error} but not on checked
  35. * exceptions).
  36. *
  37. * <p>For specific information about the semantics of this annotation's attributes,
  38. * consult the {@link org.springframework.transaction.TransactionDefinition} and
  39. * {@link org.springframework.transaction.interceptor.TransactionAttribute} javadocs.
  40. *
  41. * @author Colin Sampaleanu
  42. * @author Juergen Hoeller
  43. * @author Sam Brannen
  44. * @since 1.2
  45. * @see org.springframework.transaction.interceptor.TransactionAttribute
  46. * @see org.springframework.transaction.interceptor.DefaultTransactionAttribute
  47. * @see org.springframework.transaction.interceptor.RuleBasedTransactionAttribute
  48. */
    //上面就是说,这个类的方法主要是处理事务的问题,具体使用到的注解去具体的注解类里面看
  49. @Target({ElementType.METHOD, ElementType.TYPE})
  50. @Retention(RetentionPolicy.RUNTIME)
  51. @Inherited
  52. @Documented
  53. public @interface Transactional {
  54. /**
  55. * Alias for {@link #transactionManager}.
  56. * @see #transactionManager
  57. */
      //事务管理器的名字默认是空的,你可以自己赋值
  58. @AliasFor("transactionManager")//这个注解主要是标签的作用,具体实现可以去看他专门的类
  59. String value() default "";
  60. /**
  61. * A <em>qualifier</em> value for the specified transaction.
  62. * <p>May be used to determine the target transaction manager,
  63. * matching the qualifier value (or the bean name) of a specific
  64. * {@link org.springframework.transaction.PlatformTransactionManager}
  65. * bean definition.
  66. * @since 4.2
  67. * @see #value
  68. */
      //去配置文件或者配置类里面找上面定义的那个名字的事务管理器的名字,找到匹配的事务管理器
  69. @AliasFor("value")
  70. String transactionManager() default "";
  71. /**
  72. * The transaction propagation type.
  73. * <p>Defaults to {@link Propagation#REQUIRED}.
  74. * @see org.springframework.transaction.interceptor.TransactionAttribute#getPropagationBehavior()
  75. */
      //定义事务传播方式的方法,默认是Propagation.REQUIRED枚举
      //
    REQUIRED 支持当前事务,如果不存在则创建一个新事务。 类似于同名的EJB事务属性,
              就是说这个传播方式下,事务内是可以嵌套事务的,子事务以主事务管理,
              网上说的事务里面不能嵌套事务操作是片面的,具体是要看事务的传播类型是怎么定义的
      //SUPPORTS 如果上下文存在事物,则支持事物加入,如果没有事物,则使用非事物的方式执行。

      //MANDATORY 该级别的事物要求上下文中必须要存在事物,否则就会抛出异常
      //REQUIRES_NEW 每次都会新建事物,并且上下文的事物挂机,执行当前新建事物完成以后,上下文事物回复再执行。
      //NOT_SUPPORTED 当前级别的特点就是上下文中存在事物,则挂起事物,执行当前逻辑,结束后回复上下文的事物。
      //NEVER 上下文中不能存在事物,一旦有事物,就抛出runtime异常,强制停止执行
      //NESTED 如果上下文中存在事物,则嵌套事物执行,如果不存在事物,则新建事物。
      //具体详情见 org.springframework.transaction.TransactionDefinition类
  1. Propagation propagation() default Propagation.REQUIRED;
  2. /**
  3. * The transaction isolation level.
  4. * <p>Defaults to {@link Isolation#DEFAULT}.
  5. * @see org.springframework.transaction.interceptor.TransactionAttribute#getIsolationLevel()
  6. */
       //事务的隔离级别
       //
    TransactionDefinition.ISOLATION_DEFAULT 使用基础数据存储的默认隔离级别。 所有其他级别对应于JDBC隔离级别。
      //
    TransactionDefinition.ISOLATION_READ_UNCOMMITTED 表示脏读,不可重复读和幻像读的常数可以发生,啥问题都没解决基本不用
      //
    TransactionDefinition.ISOLATION_READ_COMMITTED 一个常量,指示防止脏读;不可重复读取和幻像读取可能会发生。此级别仅禁止事务,读取行中未提交的更改
      //
    TransactionDefinition.ISOLATION_REPEATABLE_READ   指示防止脏读和不可重复读的常量,可能会发生幻像读取
      //
    TransactionDefinition.ISOLATION_SERIALIZABLE 一个常数,指示防止脏读,不可重复读和幻像读
      //具体详情见    org.springframework.transaction.TransactionDefinition
  1. Isolation isolation() default Isolation.DEFAULT;
  1. /**
  2. * The timeout for this transaction.
  3. * <p>Defaults to the default timeout of the underlying transaction system.
  4. * @see org.springframework.transaction.interceptor.TransactionAttribute#getTimeout()
  5. */
       //事务超时时间,默认不设置,默认值为-1
  6. int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;
  7. /**
  8. * {@code true} if the transaction is read-only.
  9. * <p>Defaults to {@code false}.
  10. * <p>This just serves as a hint for the actual transaction subsystem;
  11. * it will <i>not necessarily</i> cause failure of write access attempts.
  12. * A transaction manager which cannot interpret the read-only hint will
  13. * <i>not</i> throw an exception when asked for a read-only transaction
  14. * but rather silently ignore the hint.
  15. * @see org.springframework.transaction.interceptor.TransactionAttribute#isReadOnly()
  16. */
      //是否为只读事务,只读事务一般是通过共享锁,读写事务使用排他锁
  17. boolean readOnly() default false;
  18. /**
  19. * Defines zero (0) or more exception {@link Class classes}, which must be
  20. * subclasses of {@link Throwable}, indicating which exception types must cause
  21. * a transaction rollback.
  22. * <p>By default, a transaction will be rolling back on {@link RuntimeException}
  23. * and {@link Error} but not on checked exceptions (business exceptions). See
  24. * {@link org.springframework.transaction.interceptor.DefaultTransactionAttribute#rollbackOn(Throwable)}
  25. * for a detailed explanation.
  26. * <p>This is the preferred way to construct a rollback rule (in contrast to
  27. * {@link #rollbackForClassName}), matching the exception class and its subclasses.
  28. * <p>Similar to {@link org.springframework.transaction.interceptor.RollbackRuleAttribute#RollbackRuleAttribute(Class clazz)}.
  29. * @see #rollbackForClassName
  30. * @see org.springframework.transaction.interceptor.DefaultTransactionAttribute#rollbackOn(Throwable)
  31. */
      //检查到指定异常后回滚
  32. Class<? extends Throwable>[] rollbackFor() default {};
  33. /**
  34. * Defines zero (0) or more exception names (for exceptions which must be a
  35. * subclass of {@link Throwable}), indicating which exception types must cause
  36. * a transaction rollback.
  37. * <p>This can be a substring of a fully qualified class name, with no wildcard
  38. * support at present. For example, a value of {@code "ServletException"} would
  39. * match {@code javax.servlet.ServletException} and its subclasses.
  40. * <p><b>NB:</b> Consider carefully how specific the pattern is and whether
  41. * to include package information (which isn't mandatory). For example,
  42. * {@code "Exception"} will match nearly anything and will probably hide other
  43. * rules. {@code "java.lang.Exception"} would be correct if {@code "Exception"}
  44. * were meant to define a rule for all checked exceptions. With more unusual
  45. * {@link Exception} names such as {@code "BaseBusinessException"} there is no
  46. * need to use a FQN.
  47. * <p>Similar to {@link org.springframework.transaction.interceptor.RollbackRuleAttribute#RollbackRuleAttribute(String exceptionName)}.
  48. * @see #rollbackFor
  49. * @see org.springframework.transaction.interceptor.DefaultTransactionAttribute#rollbackOn(Throwable)
  50. */
      //上一个方法中异常类的名字
  51. String[] rollbackForClassName() default {};
  52. /**
  53. * Defines zero (0) or more exception {@link Class Classes}, which must be
  54. * subclasses of {@link Throwable}, indicating which exception types must
  55. * <b>not</b> cause a transaction rollback.
  56. * <p>This is the preferred way to construct a rollback rule (in contrast
  57. * to {@link #noRollbackForClassName}), matching the exception class and
  58. * its subclasses.
  59. * <p>Similar to {@link org.springframework.transaction.interceptor.NoRollbackRuleAttribute#NoRollbackRuleAttribute(Class clazz)}.
  60. * @see #noRollbackForClassName
  61. * @see org.springframework.transaction.interceptor.DefaultTransactionAttribute#rollbackOn(Throwable)
  62. */
      //如果你在声明异常类中发生的异常,不回滚
  63. Class<? extends Throwable>[] noRollbackFor() default {};
  64. /**
  65. * Defines zero (0) or more exception names (for exceptions which must be a
  66. * subclass of {@link Throwable}) indicating which exception types must <b>not</b>
  67. * cause a transaction rollback.
  68. * <p>See the description of {@link #rollbackForClassName} for further
  69. * information on how the specified names are treated.
  70. * <p>Similar to {@link org.springframework.transaction.interceptor.NoRollbackRuleAttribute#NoRollbackRuleAttribute(String exceptionName)}.
  71. * @see #noRollbackFor
  72. * @see org.springframework.transaction.interceptor.DefaultTransactionAttribute#rollbackOn(Throwable)
  73. */
       //上一个异常类中的类名
  74. String[] noRollbackForClassName() default {};
  75. }

 

上述主要为Spring中Transactional中的方法使用介绍,现在具体来介绍一下错误读的问题是怎么解决的。

此处要引入三个概念,分别是记录锁,临建锁,间隙锁

 

 

记录锁:记录锁就是为某行记录加锁,列必须为唯一索引列或主键列,否则加的锁就会变成临键锁,
查询语句必须为精准匹配 = ,不能为 >、<、like等,否则也会退化成临键锁。   

 

 

 

 

间隙锁:间隙锁基于非唯一索引,它锁定一段范围内的索引记录。比如查询字段区间为4-7,即1-5内的记录行都会被锁住,5、6 的数据行的会被阻塞,但是 4 和 7 两条记录行并不会被锁住。

 

 

临建锁:临键锁可以理解为一种特殊的间隙锁,上面说过了通过临建锁可以解决幻读的问题。 每个数据行上的非唯一索引列上都会存在一把临键锁,当某个事务持有该数据行的临键锁时,会锁住一段左开右闭区间的数据。

 

原文链接:http://www.cnblogs.com/xuzhenqiang/p/14340447.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号