事务的概述

事务概念:
事务一般特指数据库事务(Database Transaction),是指作为一个程序执行单元执行的一系列操作,要么完全执行,要么完全不执行

事务特性:

  • 原子性(atomicity)

一个事务是一个不可分割的工作单位
从结构上,保证事务只有两种状态:完全执行 和 完全不执行

  • 一致性(consistency)

事务必须是数据库从一个一致性状态变到另一个一致性状态
从业务上,保证事务是合理的

  • 隔离性(isolation)

一个事务的执行不能被其他事务干扰
并发的时候,两个事务之间不能相互干扰,相互影响

  • 持久性(durability)

一个事务一旦提交,它对数据库中数据的改变就应该是永久性的

MySQL事务处理

基本语句

  • MySQL中只有使用了Innodb数据库引擎的数据库或表才支持事务

show engines; => 查看服务器支持的引擎
default-storage0engin = Innodb —my.ini => 修改默认引擎

  • MySQL默认以自动提交(autocommit)模式运行
  1. // 显示地开启一个事务
  2. begin(starttransaction)
  3. // 提交事务,并使已对数据库进行的所有修改变为永久性的
  4. commit
  5. // 回滚事务,并撤销正在进行的素哟有未提交的修改
  6. rollback

并发问题

image.png
解决方案:只能读取永久性数据,不能读取内存中的数据来解决

image.png
解决方案:通过锁行的方式解决

image.png
解决方案:通过锁表的方式解决

事务隔离级别

image.png
#隔离级别越高,处理并发事务执行的时候,效率越低
#所以,隔离级别并不是设置越高越好,而要根据需要合理设置

语句

  1. // 查询默认隔离级别
  2. select @@transaction_isolation;
  3. // 设置当前会话隔离级别(注意没有中线)
  4. set session transaction isolation level read committed

JDBC事务处理

基本语句

  • Connection接口

JDBC的事务处理是基于Connection的,JDBC通过Connection对象进行事务管理
JDBC默认事务处理行为是自动提交

  • 事务相关方法

setAutoCommit => 设置自动提交
commit => 提交事务
rollaback => 回滚事务

  1. package com.imooc.os.dao;
  2. import org.junit.Test;
  3. import java.sql.Connection;
  4. import java.sql.DriverManager;
  5. import java.sql.SQLException;
  6. import java.sql.Statement;
  7. public class OrderTest {
  8. private String driver = "com.mysql.jdbc.Driver";
  9. private String url = "jdbc:mysql://localhost:3306/os?useUnicode=true&characterEncoding=utf8";
  10. private String userName = "root";
  11. private String password = "root";
  12. @Test
  13. public void addOrder(){
  14. try {
  15. Class.forName(driver);
  16. } catch (ClassNotFoundException e) {
  17. e.printStackTrace();
  18. }
  19. Connection connection = null;
  20. try {
  21. connection = DriverManager.getConnection(url,userName,password);
  22. // 设置不要自动提交
  23. connection.setAutoCommit(false);
  24. Statement statement = connection.createStatement();
  25. // 以下两个execute就封装成了一个事务
  26. statement.execute("insert into orders values('100002','100001',2,2499,now(),null,null,'刘备','1330000000','成都','待发货')");
  27. statement.execute("update products set stck=stock-2 where id='100001'");
  28. statement.close();
  29. // 事务提交
  30. connection.commit();
  31. } catch (SQLException e) {
  32. e.printStackTrace();
  33. try {
  34. connection.rollback();
  35. } catch (SQLException e1) {
  36. e1.printStackTrace();
  37. }
  38. }finally {
  39. try {
  40. connection.close();
  41. } catch (SQLException e) {
  42. e.printStackTrace();
  43. }
  44. }
  45. }
  46. }

事务隔离级别

image.png

事务隔离级别设置:
image.png

Spring的事务处理

基本概念

image.png
PlatformTransactionManager
#事务管理器,最核心接口

  • getTransaction => 获取事务
  • commit => 提交事务
  • rollback => 回滚事务

TransactionDefinition
#事务定义,告诉spring开启一个什么特点,什么属性的事务

  1. 隔离级别:

image.png

  1. 默认超时

超时之后会销毁事务
image.png

  1. 事务传播行为

一般会设置为第一种PROPAGATION_REQUIRED
image.png

TransactionStatus
#正在运行的事务的状态

DataSourceTransactionManager
#基于数据源的事务管理器的实现类(一般用这个)

HibernateTransactionManager
#基于hibernate的事务管理器的实现类

JpaTransactionManager
#基于Jpa的事务管理器的实现类

Spring编程式事务处理

  • 基于底层API的编程式事务管理

PlatformTransactionManager
TransactionDefinition
TransactionStatus

  • 基于TransactionTemplate的编程式事务管理

TransactionTemplate

Spring声明式事务处理

Spring的声明式事务处理是建立在AOP的基础之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或加入一个事务,在执行完目标方法之后根据执行情况提交或回滚事务。
建议在开发中使用声明式事务,是因为这样可以使得业务代码纯粹干净,方便后期的代码维护。

  • 基于TransactionInterceptor的声明式事务处理(不建议使用)
  • 基于TransactionProxyFactoryBean的声明式事务处理(不建议使用)

  • 基于命名空间的声明式事务管理

resources/spring-service.xml

<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop.xsd
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx.xsd">
    <import resource="spring-dao.xml"/>
    <context:component-scan base-package="com.imooc.os.service.impl"/>
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="get*" propagation="REQUIRED" read-only="true"/>
            <tx:method name="find*" propagation="REQUIRED" read-only="true"/>
            <tx:method name="search*" propagation="REQUIRED" read-only="true"/>
            <tx:method name="*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>
    <aop:config>
        <aop:pointcut id="pointcut" expression="execution(* com.imooc.os.service.impl.*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"/>
    </aop:config>
</beans>
  • 基于@Transactional的声明式事务管理

    <?xml version="1.0" encoding="UTF-8" ?>
    <beans xmlns="http://www.springframework.org/schema/beans"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns:context="http://www.springframework.org/schema/context"
         xmlns:aop="http://www.springframework.org/schema/aop"
         xmlns:tx="http://www.springframework.org/schema/tx"
         xsi:schemaLocation="http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans.xsd
      http://www.springframework.org/schema/context
      http://www.springframework.org/schema/context/spring-context.xsd
      http://www.springframework.org/schema/aop
      http://www.springframework.org/schema/aop/spring-aop.xsd
      http://www.springframework.org/schema/tx
      http://www.springframework.org/schema/tx/spring-tx.xsd">
      <import resource="spring-dao.xml"/>
      <context:component-scan base-package="com.imooc.os.service.impl6"/>
      <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
          <property name="dataSource" ref="dataSource"/>
      </bean>
      <tx:annotation-driven transaction-manager="transactionManager"/>
    </beans>
    

    个人建议:
    基于命名空间的声明式事务管理(这种方式最好)

  • 业务代码最干净

  • 虽然配置比@Transactional的方式复杂点,但是只需要配置一次就够了

基于@Transactional的声明式事务管理

  • 虽然配置相对简单,但是需要在每个函数之前加上@Transactional注解,函数多的话就比较麻烦