对于看过的,如何整理出来,如何记住,如果说出,如何使用,如何读源码呢? 在开始的入口看一下,然后时对应的resource,config,filter,intercepter,listener这些看一下 先看一下大体的流程时做什么的?先不要看细节哦! 入口怎么找?回归最初的Spring xml配置的时候
mybatis-plus source code 解读
事务传播
7种,默认Propagation.REQUIRED
- REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED)
Spring默认事务传播方式,当处于事务中,新的开始事务时,加入该事务
- SUPPORTS(TransactionDefinition.PROPAGATION_SUPPORTS)
有事务就加入事务,没有就无事务运行
- MANDATORY(TransactionDefinition.PROPAGATION_MANDATORY)
- REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW)
有事务就新建事务
- NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED)
有事务就事务指向,没有就无事务执行
- NEVER(TransactionDefinition.PROPAGATION_NEVER)
无事务就指向,有事务报异常
- NESTED(TransactionDefinition.PROPAGATION_NESTED)
嵌套事务
隔离级别
5种,默认Default级别 MySQL的4种事务,加上Spring的默认Default级别
DEFAULT(TransactionDefinition.ISOLATION_DEFAULT)
Spring默认级别,分别对应不同数据库对应不同的默认级别
READ_UNCOMMITTED(TransactionDefinition.ISOLATION_READ_UNCOMMITTED),
读未提交
READ_COMMITTED(TransactionDefinition.ISOLATION_READ_COMMITTED),
读已提交
REPEATABLE_READ(TransactionDefinition.ISOLATION_REPEATABLE_READ),
可重复读
SERIALIZABLE(TransactionDefinition.ISOLATION_SERIALIZABLE);
串行化
数据库异常
1. 脏读
定义:读到另一个事务未提交的数据
读已提交可解决脏读问题
2. 不可重复读
定义:同一行数据,第一次读取出后,另一个线程修改了数据,再次读取该数据时,获取到的结果不一样
可重复读级别解决不可重复读问题
3. 幻读
定义:读取一批数据,第一次读取时是10条,另一个线程新增或删除了其中的数据,再次读取的时候,数据量变了
串行化可解决幻读问题
事务所需要的基础配置
org.springframework.transaction.annotation.SpringTransactionAnnotationParser.parseTransactionAnnotation(org.springframework.core.annotation.AnnotationAttributes)
protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
// 配置事务所需,传递性,隔离性,超时,只读,
Propagation propagation = attributes.getEnum("propagation");
rbta.setPropagationBehavior(propagation.value());
Isolation isolation = attributes.getEnum("isolation");
rbta.setIsolationLevel(isolation.value());
rbta.setTimeout(attributes.getNumber("timeout").intValue());
rbta.setReadOnly(attributes.getBoolean("readOnly"));
rbta.setQualifier(attributes.getString("value"));
// 配置发生异常时操作
List<RollbackRuleAttribute> rollbackRules = new ArrayList<>();
for (Class<?> rbRule : attributes.getClassArray("rollbackFor")) {
rollbackRules.add(new RollbackRuleAttribute(rbRule));
}
for (String rbRule : attributes.getStringArray("rollbackForClassName")) {
rollbackRules.add(new RollbackRuleAttribute(rbRule));
}
for (Class<?> rbRule : attributes.getClassArray("noRollbackFor")) {
rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
}
for (String rbRule : attributes.getStringArray("noRollbackForClassName")) {
rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
}
rbta.setRollbackRules(rollbackRules);
return rbta;
}
@Transactional注解使用的是切面进行实现
Spring AOP切面
| 前置 | 后置 | 环绕 | 异常 | return返回 |
|---|---|---|---|---|
| 增强(通知类型) |
| AOP切面实现方式 | ||
| JDK动态代理(运行时增强) | CGLIB代理(运行时增强) | AspectJ代理(编译时增强) |
| 动态代理使用 | ||
| 日志 | 鉴权 | 事务 |
术语:切面,切点,织入,引入,增强,连接点。
记忆:AOP通过在 【连接点】【引入】属性和方法,得到【增强】的对象 ---切点,切面,织入
如何查看源码? 从基础配置开始
<!--配置事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--控制住数据源-->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--开启基于注解的事务,使用xml形式配置的事务(必要主要的都是使用配置式)-->
<!--可以使用注解@Transactional开启事务-->
<tx:annotation-driven/>
1.找到事务管理类 2.找到解析 annotation-driven 的类(找到spring的tx包,然后,在META-INF中的spring.handlers中找到对应的TxNamespaceHandler类 spirng.handlers,spring.scheme配置增强的xml自定义标签 tx:annotation-driven/便是这样的增强标签
org.springframework.transaction.config.AnnotationDrivenBeanDefinitionParser.parse
/**
* Parses the {@code <tx:annotation-driven/>} tag. Will
* {@link AopNamespaceUtils#registerAutoProxyCreatorIfNecessary register an AutoProxyCreator}
* with the container as necessary.
*/
@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
registerTransactionalEventListenerFactory(parserContext);
String mode = element.getAttribute("mode");
if ("aspectj".equals(mode)) {
// mode="aspectj"
registerTransactionAspect(element, parserContext);
if (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader())) {
registerJtaTransactionAspect(element, parserContext);
}
}
else {
// 一般默认的时JDK动态代理
// mode="proxy"
AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);
/**
* AopAutoProxyConfigurer 的工作
* 1.创建 TransactionAttributeSource
* 2.创建 TransactionInterceptor 进行具体的方法进行代理工作
* 3.创建 TransactionAttributeSourceAdvisor 用于切点,织入
* 4.嵌套在 CompositeComponentDefinition 将1.2.3创建的组件组合在一起,注册到context中
* 5.注册到 ParserContext
*/
}
return null;
}
Spring AOP 通过【连接点】【引入】属性和方法,【增强】代理类 切点,切面,织入
Spring AOP 的 org.springframework.aop.config.AopNamespaceHandler
Spring.handlers, Spring.schemas 自定义xml注解