@@ -6881,7 +6881,9 @@ AOP的通知类型共5种:前置通知,后置通知、返回后通知、抛
68816881 <aop:config>
68826882 <aop:pointcut id=" pt" expression=" execution(* *..*(..))" />
68836883 <aop:aspect ref=" myAdvice" >
6884+ <aop:before method=" before" pointcut=" pt" />
68846885 <aop:around method=" around" pointcut-ref=" pt" />
6886+ <aop:after method=" after" pointcut=" pt" />
68856887 <aop:after-returning method=" afterReturning" pointcut-ref=" pt" returning=" ret" />
68866888 <aop:after-throwing method=" afterThrowing" pointcut-ref=" pt" throwing=" t" />
68876889 </aop:aspect>
@@ -7382,39 +7384,79 @@ Spirng可以通过配置的形式控制使用的代理形式,Spring会先判
73827384
73837385### 基本概念
73847386
7387+ #### 事务介绍
7388+
73857389事务:数据库中多个操作合并在一起形成的操作序列
73867390
7391+ Spring事务一般加到业务层,对应着业务的操作,数据层有自己默认的隔离界别
7392+
73877393作用:
73887394
73897395* 当数据库操作序列中个别操作失败时,提供一种方式使数据库状态恢复到正常状态(**A**),保障数据库即使在异常状态下仍能保持数据一致性(**C**)(要么操作前状态,要么操作后状态)
73907396* 当出现并发访问数据库时,在多个访问间进行相互隔离,防止并发访问操作结果互相干扰(**I**)
73917397
73927398事务特征(ACID):
73937399
7394- - 原子性(Atomicity)指事务是一个不可分割的整体,其中的操作要么全执行或全不执行
73957400
7396- - 一致性(Consistency)事务前后数据的完整性必须保持一致
73977401
7398- - 隔离性(Isolation)事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离
73997402
7400- - 持久性(Durability)持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响
74017403
7402- 隔离级别:
7404+ ***
7405+
7406+
7407+
7408+ #### 隔离级别
74037409
7404- * 脏读:允许读取未提交的信息
7405- 原因:Read uncommitted
7406- 解决方案: (表级读锁)
7407- * 不可重复读:读取过程中单个数据发生了变化
7408- 解决方案: Repeatable read (行级写锁)
7409- * 幻读:读取过程中数据条目发生了变化
7410- 解决方案: Serializable(表级写锁)
7410+ TransactionDefinition 接口中定义了五个表示隔离级别的常量:
7411+
7412+ - **TransactionDefinition.ISOLATION_DEFAULT:** 使用后端数据库默认的隔离级别,Mysql 默认采用的 REPEATABLE_READ隔离级别 Oracle 默认采用的 READ_COMMITTED隔离级别.
7413+ - **TransactionDefinition.ISOLATION_READ_UNCOMMITTED:** 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读
7414+ - **TransactionDefinition.ISOLATION_READ_COMMITTED:** 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生
7415+ - **TransactionDefinition.ISOLATION_REPEATABLE_READ:** 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
7416+ - **TransactionDefinition.ISOLATION_SERIALIZABLE:** 最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别
74117417
74127418
74137419
74147420****
74157421
74167422
74177423
7424+ #### 传播行为
7425+
7426+ 事务传播行为描述的是事务协调员对事务管理员所携带事务的处理态度
7427+
7428+ 
7429+
7430+ **支持当前事务的情况:**
7431+
7432+ * TransactionDefinition.PROPAGATION_REQUIRED: 如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务
7433+ * TransactionDefinition.PROPAGATION_SUPPORTS: 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行
7434+ * TransactionDefinition.PROPAGATION_MANDATORY: 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常(mandatory:强制性)
7435+
7436+ **不支持当前事务的情况:**
7437+
7438+ - TransactionDefinition.PROPAGATION_REQUIRES_NEW: 创建一个新的事务,如果当前存在事务,则把当前事务挂起
7439+ - TransactionDefinition.PROPAGATION_NOT_SUPPORTED: 以非事务方式运行,如果当前存在事务,则把当前事务挂起
7440+ - TransactionDefinition.PROPAGATION_NEVER: 以非事务方式运行,如果当前存在事务,则抛出异常
7441+
7442+ **其他情况:**
7443+
7444+ * **TransactionDefinition.PROPAGATION_NESTED:** 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED
7445+
7446+
7447+
7448+
7449+
7450+
7451+
7452+
7453+
7454+
7455+
7456+ ***
7457+
7458+
7459+
74187460### 核心对象
74197461
74207462#### 事务对象
@@ -7452,6 +7494,16 @@ PlatformTransactionManager,平台事务管理器实现类:
74527494
74537495- JPA(Java Persistence API)Java EE 标准之一,为POJO提供持久化标准规范,并规范了持久化开发的统一API,符合JPA规范的开发可以在不同的JPA框架下运行
74547496
7497+ **非持久化一个字段**:
7498+
7499+ ```java
7500+ static String transient1; // not persistent because of static
7501+ final String transient2 = “Satish”; // not persistent because of final
7502+ transient String transient3; // not persistent because of transient
7503+ @Transient
7504+ String transient4; // not persistent because of @Transient
7505+ ```
7506+
74557507- JDO(Java Data Object )是Java对象持久化规范,用于存取某种数据库中的对象,并提供标准化API。与JDBC相比,JDBC仅针对关系数据库进行操作,JDO可以扩展到关系数据库、文件、XML、对象数据库(ODBMS)等,可移植性更强
74567508
74577509- JTA(Java Transaction API)Java EE 标准之一,允许应用程序执行分布式事务处理。与JDBC相比,JDBC事务则被限定在一个单一的数据库连接,而一个JTA事务可以有多个参与者,比如JDBC连接、JDO 都可以参与到一个JTA事务中
@@ -7610,7 +7662,7 @@ TransactionStatus 此接口定义了事务在执行过程中某个时间点上
76107662 <property name=" dataSource" ref=" dataSource" />
76117663 <property name=" typeAliasesPackage" value=" domain" />
76127664 </bean>
7613- <!--扫描映射配置文件 -->
7665+ <!--扫描映射配置和Dao -->
76147666 <bean class=" org.mybatis.spring.mapper.MapperScannerConfigurer" >
76157667 <property name=" basePackage" value=" dao" />
76167668 </bean>
@@ -7764,7 +7816,7 @@ TransactionStatus 此接口定义了事务在执行过程中某个时间点上
77647816 </tx:attributes>
77657817 </tx:advice>
77667818
7767- <!--使用aop:advisor在AOP配置中引用事务专属通知类-->
7819+ <!--使用aop:advisor在AOP配置中引用事务专属通知类,底层invoke调用 -->
77687820 <aop:config>
77697821 <aop:pointcut id=" pt" expression=" execution(* service.*Service.*(..))" />
77707822 <aop:advisor advice-ref=" txAdvice" pointcut-ref=" pt" />
@@ -7773,7 +7825,7 @@ TransactionStatus 此接口定义了事务在执行过程中某个时间点上
77737825
77747826* aop:advice与aop:advisor区别
77757827 * aop:advice配置的通知类可以是普通java对象,不实现接口,也不使用继承关系
7776- * aop:advisor配置的通知类必须实现通知接口
7828+ * aop:advisor配置的通知类必须实现通知接口,底层invoke调用
77777829
77787830 - MethodBeforeAdvice
77797831
@@ -7783,6 +7835,8 @@ TransactionStatus 此接口定义了事务在执行过程中某个时间点上
77837835
77847836 - ……
77857837
7838+ 方法调用:`AbstractAspectJAdvice#invokeAdviceMethod(org.aspectj.weaver.tools.JoinPointMatch, java.lang.Object, java.lang.Throwable)`
7839+
77867840
77877841
77887842***
@@ -7845,6 +7899,7 @@ TransactionStatus 此接口定义了事务在执行过程中某个时间点上
78457899 <tx:method name=" get*" read-only=" true" />
78467900 <tx:method name=" find*" read-only=" true" />
78477901</tx:attributes>
7902+ <aop:pointcut id=" pt" expression=" execution(* service.*Service.*(..))" /><!--标准-->
78487903```
78497904
78507905说明:通常事务属性会配置多个,包含1个读写的全事务属性,1个只读的查询类事务属性
@@ -7865,66 +7920,6 @@ TransactionStatus 此接口定义了事务在执行过程中某个时间点上
78657920
78667921
78677922
7868- ##### 传播行为
7869-
7870- 事务传播行为描述的是事务协调员对事务管理员所携带事务的处理态度
7871-
7872- 
7873-
7874- | 传播属性 | 事务管理员 | 事务协调员 |
7875- | ------------- | ---------- | ------------------------------------------------------------ |
7876- | REQUIRED | 开启T1 | 加入T1 |
7877- | REQUIRED | 无 | 新建T2 |
7878- | REQUIRED_NEW | 开启T1 | 加入T1 |
7879- | REQUIRED_NEW | 开启T1 | 新建T1 |
7880- | SUPPORTS | 开启T1 | 加入T1 |
7881- | SUPPORTS | 无 | 无 |
7882- | NOT_SUPPORTED | 开启T1 | 无 |
7883- | NOT_SUPPORTED | 无 | 无 |
7884- | MANDATORY | 开启T1 | 加入T1 |
7885- | MANDATORY | 无 | ERROR |
7886- | NEVER | 开启T1 | ERROR |
7887- | NEVER | 无 | 无 |
7888- | NESTED | | 设置savePoint,一旦事务回滚<br />事务将回滚到savePoint处,<br />交由客户响应提交/回滚 |
7889-
7890- 应用:
7891-
7892- - 场景A:生成订单业务
7893-
7894- - 子业务S1:记录日志到数据库表X
7895-
7896- - 子业务S2:保存订单数据到数据库表Y
7897-
7898- - 子业务S3:……
7899-
7900- - 如果S2或S3或……事务提交失败,此时S1是否回滚?如何控制?
7901-
7902- - (S1需要新事务)
7903-
7904- - 场景B:生成订单业务
7905-
7906- - 背景1:订单号生成依赖数据库中一个专门用于控制订单号编号生成的表M获取
7907-
7908- - 背景2:每次获取完订单号,表M中记录的编号自增1
7909-
7910- - 子业务S1:从表M中获取订单编号
7911-
7912- - 子业务S2:保存订单数据,订单编号来自于表M
7913-
7914- - 子业务S3:……
7915-
7916- - 如果S2或S3或……事务提交失败,此时S1是否回滚?如何控制?
7917-
7918- - (S1需要新事务)
7919-
7920-
7921-
7922-
7923-
7924- ****
7925-
7926-
7927-
79287923#### 注解
79297924
79307925##### 开启注解
@@ -7998,7 +7993,12 @@ public class TransactionManagerConfig {
79987993public interface AccountService{}
79997994```
80007995
8001- 说明:通常配置在接口上
7996+ 说明:
7997+
7998+ * 接口上配置总体的,方法中配置具体的
7999+ * `@Transactional` 注解只有作用到 public 方法上事务才生效,不推荐在接口上使用;
8000+ * 避免同一个类中调用 `@Transactional` 注解的方法,这样会导致事务失效;
8001+ * 正确的设置 `@Transactional` 的 rollbackFor 和 propagation 属性,否则事务可能会回滚失败
80028002
80038003
80048004
@@ -8024,7 +8024,7 @@ public interface AccountService{}
80248024
80258025 ```java
80268026 //对当前接口的所有方法添加事务
8027- @Transactional
8027+ @Transactional(isolation = Isolation.DEFAULT)
80288028 public interface AccountService {
80298029 //对当前方法添加事务,该配置将替换接口的配置
80308030 @Transactional(
@@ -8110,9 +8110,20 @@ public interface AccountService{}
81108110
81118111### 底层原理
81128112
8113+ TransactionManagementConfigurationSelector类:
8114+
8115+ * 导入AutoProxyRegistrar组件和ProxyTransactionManagementConfiguration组件
8116+
8117+ * AutoProxyRegistrar:利用后置处理器机制在对象创建以后包装对象,返回一个代理对象(增强器),代理对象执行方法利用拦截器链进行调用,通过@Transactional作为方法拦截的标记,把有事务管理的类作为目标类,生成代理对象,然后增强@Transactional标记的方法,在使用目标方法的时候,从IOC容器中获取的其实是被增强的代理类,且事务方法会被代理,跟AOP原理一样
8118+
8119+ * ProxyTransactionManagementConfiguration:向IOC容器中导入事务增强器(BeanFactoryTransactionAttributeSourceAdvisor),事务注解@Transactional的解析器(AnnotationTransactionAttributeSource)和事务方法拦截器(TransactionInterceptor)
8120+
8121+
8122+ 通过AOP动态织入,进行事务开启和提交
8123+
81138124事务底层原理解析:策略模式
81148125
8115- 策略模式(Strategy Pattern)使用不同策略的对象实现不同的行为方式,策略对象的变化导致行为的变化。
8126+ 策略模式(Strategy Pattern)** 使用不同策略的对象实现不同的行为方式** ,策略对象的变化导致行为的变化,每个事务对应一个新的connection对象
81168127
81178128
81188129
@@ -8131,9 +8142,10 @@ public interface AccountService{}
81318142Spring ioc容器就是很多Map集合,保存了单实例Bean,环境信息等资源
81328143
81338144* **BeanDefinition**:是Spring中极其重要的一个概念,它存储了 bean 对象的所有特征信息,如是否单例、是否懒加载、factoryBeanName等
8134-
81358145* **BeanDefinationRegistry**:存放BeanDefination的容器,是一种键值对的形式,通过特定的Bean定义的id,映射到相应的BeanDefination
81368146
8147+ * **BeanDefinitionReader**:读取配置文件,比如xml用dom4j解析,配置文件用io流
8148+
81378149Spring容器的启动流程:三个步骤
81388150
81398151ClassPathXmlApplicationContext同AnnotationConfigApplicationContext
@@ -8787,6 +8799,18 @@ AnnotationAwareAspectJAutoProxyCreator是这种类型的后置处理器:Instan
87878799
87888800
87898801
8802+ ***
8803+
8804+
8805+
8806+ #### Transactional
8807+
8808+ 如果一个类或者一个类中的 public 方法上被标注@Transactional 注解的话,Spring 容器就会在启动的时候为其创建一个代理类,在调用被@Transactional注解的 public 方法的时候,实际调用的是TransactionInterceptor类中的 invoke()方法。这个方法的作用就是在目标方法之前开启事务,方法执行过程中如果遇到异常的时候回滚事务,方法调用完成之后提交事务
8809+
8810+ `TransactionInterceptor` 类中的 `invoke()`方法内部实际调用的是 `TransactionAspectSupport` 类的 `invokeWithinTransaction()`方法
8811+
8812+
8813+
87908814
87918815
87928816
@@ -9093,6 +9117,8 @@ Controller加载控制:SpringMVC的处理器对应的bean必须按照规范格
90939117
90949118### 注解驱动
90959119
9120+ 纯注解开发:
9121+
90969122* 使用注解形式转化SpringMVC核心配置文件为配置类 java / config / SpringMVCConfiguration.java
90979123
90989124 ```java
@@ -13394,7 +13420,7 @@ SpringBoot不能直接获取在其他工程中定义的Bean(pom导入springboo
1339413420三种解决办法:
1339513421
13396134221. 使用@ComponentScan 扫描com. example. config包
13397- 2. 使用import注解 ,加载类,这些类都会被Spring 创建并放入ioc容器
13423+ 2. 使用 Import 注解 ,加载类,这些类都会被Spring 创建并放入ioc容器
13398134243. 对Import 注解进行封装
1339913425 ** 重点:Enable 注解底层原理是使用@Import 注解实现Bean 的动态加载**
1340013426
0 commit comments