声明式事务

编程式事务:需要手动去实现事务的功能呢

声明式事务:只需要声明事务,具体的功能由框架完成。

事务特性:

  1. 原子性:事务被视为一个不可分割的单位,事务中的操作要么都执行,要么都不执行

  2. 一致性:事务将数据库从一个一致性转换到另外一个一致性状态

  3. 隔离性:多个并发执行的事务不会干扰,

    1. 隔离级别
      1. 读未提交 (Read Uncommitted):提供了最低的隔离级别,可能导致脏读、不可重复读和幻读。
      2. 读已提交 (Read Committed):防止脏读,但仍然可能遇到不可重复读和幻读。
      3. 可重复读 (Repeatable Read):防止脏读和不可重复读,但仍然可能发生幻读。==对正在操作的数据加锁。==
      4. 序列化 (Serializable):防止所有并发问题,但可能会引起较高的锁定开销。==对表加锁==
    2. 脏读:读到了未提交的数据
    3. 不可重复读:只能读到已经提交的数据,读两次的数据可能不一样
    4. 幻读:对没有加锁的数据进行操作,当其他事务操作了之后,可能两次读到数据不一样。
  4. 持久性

    一旦事务被提交,它对数据库所做的更改就是永久性的,并且不能因为任何系统故障而丢失。

    即使是在系统崩溃之后,一旦事务提交,它的结果也必须是可用的。

基于注解的声明式事务

  1. 配置事务管理器

    配置连接对象,依赖数据源: 因为事的开启是Connection对象开启的,所以事务管理就依赖数据源管理对象。

    1
    2
    3
    4
    5
    <bean id="transactionManager" class="DataSourceTransactionManager" >
    //数据源
    <property name="DataSource" ref="dataSource"></property>

    </bean>
  2. 开启事务注解驱动(连接点)

    @Transactional 标记连接点的注解。一般是加在Service层

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
       <tx:annotation-driven transaction-manager="transactionManager"/>

    ​ ==标记位置==:类或方法。



    ### 声明式事务属性

    1. **事务只读**:readOnly="false"

    功能:对于==全部都是查询的操作==,可以设置事务只读,此时会通知数据库当前操作为只读操作,会从==数据库层面==优化当前操作。提高效率. 若操作中存在增删改操作时,会报错 Connection is read only

    > 数据库默认的隔离级别为可重复读,会对表加锁。

    2. **超时时间**:超时回滚,释放资源

    timeout="-1"

    -1:一直等 ,默认单位秒。

    场景:事务超过指定时间未执行完毕。强制回滚,并抛出异常TransactionTimeOutException

    3. **回滚策略**:

    rollBackFor = 字节码对象

    rollBackForClassName = 全类名

    noRollBackFor

    noRollBackForClassName

    默认所有运行时异常回滚。

    设置触发或不触发回滚的异常类型:

    4. **隔离级别**:

    isoLation="DEFAULT"

    1. DEFAULT:默认隔离级别,数据库决定
    2. READ_UNCOMMITTED 不可重复读
    3. READ_COMMITTED
    4. Repeatable Read 可重复读
    5. SERVILAZIABLE 序列化

    5. **传播行为**:

    propagation ="REQUIRED "

    1. REQUIRED 调用者的事务

    2. REQUIRES\_NEW 被调用者的事务

    | 名称 | 含义 |
    | -------------------- | ------------------------------------------------------------ |
    | REQUIRED &#xA;默认值 | 当前方法必须工作在事务中 &#xA;如果当前线程上有已经开启的事务可用,那么就在这个事务中运行 &#xA;如果当前线程上没有已经开启的事务,那么就自己开启新事务,在新事务中运行 &#xA;所以当前方法有可能和其他方法共用事务 &#xA;在共用事务的情况下:当前方法会因为其他方法回滚而受连累 |
    | REQUIRES\_NEW | 当前方法必须工作在事务中 &#xA;不管当前线程上是否有已经开启的事务,都要开启新事务 &#xA;在新事务中运行 &#xA;不会和其他方法共用事务,避免被其他方法连累 |

    被传播的事务,默认使用的是事务是其调用者的事务。

    A->B,A和B都有事务,默认B使用的A的事务。==针对B事务设置==,且必须为不同类中的方法。

    ### 基于XMl的声明式事务

    1. **配置事务管理器**

    ```xml
    <bean id="transactionManager" class="DataSourceTransactionManager" >
    //数据源
    <property name="DataSource" ref="dataSource"></property>

    </bean>
  3. 设置事务通知 (连接点)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20

    <tx:advice id="tx" tranaction-manager="transactionManager">
    //事务属性,必须指定。
    <tx:attributes>
    <tx:method name="menthod()" read-only="false"></tx:method>
    <tx:method name="add*" read-only="false"></tx:method>
    </tx:attributes>
    </tx:advice>


    <!--
    <aop:advisor> 标签:用于将一个已经定义好的Advice和一个Pointcut绑定在一起。
    Advisor是一个简单的切面实现,它只需要一个Advice和一个Pointcut就可以工作。
    在配置文件中,你可以通过advice-ref属性引用一个已经定义好的Advice,通过pointcut-expression或pointcut-ref属性来指定Pointcut。
    -->
    <aop:config>
    //
    <aop:advisor advice-ref="tx"
    pointcut="excution(* online.zorange.service..*(..) )"> </aop:advisor>
    </aop:config>