当前位置: 首页 > news >正文

【源码】Spring Data JPA原理解析之事务注册原理

 Spring Data JPA系列

1、SpringBoot集成JPA及基本使用

2、Spring Data JPA Criteria查询、部分字段查询

3、Spring Data JPA数据批量插入、批量更新真的用对了吗

4、Spring Data JPA的一对一、LazyInitializationException异常、一对多、多对多操作

5、Spring Data JPA自定义Id生成策略、复合主键配置、Auditing使用

6、【源码】Spring Data JPA原理解析之Repository的自动注入(一)

7、【源码】Spring Data JPA原理解析之Repository的自动注入(二)

8、【源码】Spring Data JPA原理解析之Repository执行过程及SimpleJpaRepository源码

9、【源码】Spring Data JPA原理解析之Repository自定义方法命名规则执行原理(一)

10、【源码】Spring Data JPA原理解析之Repository自定义方法命名规则执行原理(二)

11、【源码】Spring Data JPA原理解析之Repository自定义方法添加@Query注解的执行原理

12、【源码】SpringBoot事务注册原理

13、【源码】Spring Data JPA原理解析之事务注册原理

14、【源码】Spring Data JPA原理解析之事务执行原理

前言

JPA是Java Persistence API的简称,中文名Java持久层API。JPA采用ORM对象关系映射,以Java面向对象的编程思想,在javax.persistence包下提供对实体对象的CRUD操作,将开发者从繁琐的JDBC和SQL代码中解脱出来。

在数据库的操作中,为了处理脏读、不可重复读、幻读等问题,需要通过事务来处理。本篇从源码的角度和大家一下分享一下Spring Data JPA中的Repository的事务注册原理。

Repository的事务注册

在Spring框架中,数据操作的事务是通过添加@Transaction注解来实现的。详见:

【源码】SpringBoot事务注册原理-CSDN博客

在Spring Data JPA中,实现事务也是只需要在对应的方法中添加@Transaction注解即可。下面从源码的角度来分析一下事务实现的原理。

【源码】Spring Data JPA原理解析之Repository的自动注入(二)-CSDN博客

在上面的博文中分享了Repository bean的创建。Respository的bean是一个通过ProxyFactory创建的动态代理对象。源码如下:

public abstract class RepositoryFactorySupport implements BeanClassLoaderAware, BeanFactoryAware {/*** 返回给定接口的存储库实例,该实例由为自定义逻辑提供实现逻辑的实例支持。*/@SuppressWarnings({ "unchecked" })public <T> T getRepository(Class<T> repositoryInterface, RepositoryFragments fragments) {if (logger.isDebugEnabled()) {logger.debug(LogMessage.format("Initializing repository instance for %s…", repositoryInterface.getName()));}Assert.notNull(repositoryInterface, "Repository interface must not be null");Assert.notNull(fragments, "RepositoryFragments must not be null");ApplicationStartup applicationStartup = getStartup();StartupStep repositoryInit = onEvent(applicationStartup, "spring.data.repository.init", repositoryInterface);repositoryBaseClass.ifPresent(it -> repositoryInit.tag("baseClass", it.getName()));StartupStep repositoryMetadataStep = onEvent(applicationStartup, "spring.data.repository.metadata",repositoryInterface);// 获取repository元数据,包括Repository<T, ID>中的T类型、ID类型、接口类型(如GoodsRepository)等RepositoryMetadata metadata = getRepositoryMetadata(repositoryInterface);repositoryMetadataStep.end();StartupStep repositoryCompositionStep = onEvent(applicationStartup, "spring.data.repository.composition",repositoryInterface);repositoryCompositionStep.tag("fragment.count", String.valueOf(fragments.size()));// 获取RepositoryComposition composition = getRepositoryComposition(metadata, fragments);// 获取Repository信息,getRepositoryInformation()返回一个RepositoryInformation对象。// 如子类JpaRepositoryFactory,指定baseClass为SimpleJpaRepository.classRepositoryInformation information = getRepositoryInformation(metadata, composition);repositoryCompositionStep.tag("fragments", () -> {StringBuilder fragmentsTag = new StringBuilder();for (RepositoryFragment<?> fragment : composition.getFragments()) {if (fragmentsTag.length() > 0) {fragmentsTag.append(";");}fragmentsTag.append(fragment.getSignatureContributor().getName());fragmentsTag.append(fragment.getImplementation().map(it -> ":" + it.getClass().getName()).orElse(""));}return fragmentsTag.toString();});repositoryCompositionStep.end();StartupStep repositoryTargetStep = onEvent(applicationStartup, "spring.data.repository.target",repositoryInterface);// 获取目标Repository对象,SimpleJpaRepository对象Object target = getTargetRepository(information);repositoryTargetStep.tag("target", target.getClass().getName());repositoryTargetStep.end();RepositoryComposition compositionToUse = composition.append(RepositoryFragment.implemented(target));validate(information, compositionToUse);// Create proxy// 创建代理对象StartupStep repositoryProxyStep = onEvent(applicationStartup, "spring.data.repository.proxy", repositoryInterface);ProxyFactory result = new ProxyFactory();result.setTarget(target);// 代理对象实现的接口result.setInterfaces(repositoryInterface, Repository.class, TransactionalProxy.class);if (MethodInvocationValidator.supports(repositoryInterface)) {result.addAdvice(new MethodInvocationValidator());}// 添加界面result.addAdvisor(ExposeInvocationInterceptor.ADVISOR);if (!postProcessors.isEmpty()) {StartupStep repositoryPostprocessorsStep = onEvent(applicationStartup, "spring.data.repository.postprocessors",repositoryInterface);// 执行后置处理// CrudMethodMetadataPostProcessor// TransactionalRepositoryProxyPostProcessor// JpaRepositoryFactory构造方法中加入的内部处理器,// 添加SurroundingTransactionDetectorMethodInterceptor,记录是否处理状态// PersistenceExceptionTranslationRepositoryProxyPostProcessor// EventPublishingRepositoryProxyPostProcessorpostProcessors.forEach(processor -> {StartupStep singlePostProcessor = onEvent(applicationStartup, "spring.data.repository.postprocessor",repositoryInterface);singlePostProcessor.tag("type", processor.getClass().getName());processor.postProcess(result, information);singlePostProcessor.end();});repositoryPostprocessorsStep.end();}if (DefaultMethodInvokingMethodInterceptor.hasDefaultMethods(repositoryInterface)) {// 添加DefaultMethodInvokingMethodInterceptor拦截器result.addAdvice(new DefaultMethodInvokingMethodInterceptor());}Optional<QueryLookupStrategy> queryLookupStrategy = getQueryLookupStrategy(queryLookupStrategyKey,evaluationContextProvider);// 添加QueryExecutorMethodInterceptor拦截器result.addAdvice(new QueryExecutorMethodInterceptor(information, getProjectionFactory(), queryLookupStrategy,namedQueries, queryPostProcessors, methodInvocationListeners));// 添加ImplementationMethodExecutionInterceptor拦截器result.addAdvice(new ImplementationMethodExecutionInterceptor(information, compositionToUse, methodInvocationListeners));T repository = (T) result.getProxy(classLoader);repositoryProxyStep.end();repositoryInit.end();if (logger.isDebugEnabled()) {logger.debug(LogMessage.format("Finished creation of repository instance for %s.",repositoryInterface.getName()));}return repository;}
}

在生成代理对象之前,如果有后置处理器postProcessors,则执行后置处理器的postProcess()方法。在后置处理器中,有一个TransactionalRepositoryProxyPostProcessor。

JpaRepositoryFactoryBean

【源码】Spring Data JPA原理解析之Repository的自动注入(一)-CSDN博客

在上面的博文中分享了JpaRepositoriesAutoConfiguration的源码,在Spring Data JPA自动注入时,会自动注入JpaRepositoryConfigExtension,在JpaRepositoryConfigExtension中getRepositoryFactoryBeanClassName()方法,返回JpaRepositoryFactoryBean.class.getName(),该类最终会被装载到Spring IOC容器中。

JpaRepositoryFactoryBean初始化时,执行父父类RepositoryFactoryBeanSupport的afterPropertiesSet()方法,在该方法中,主要执行如下:

3.1)调用抽象方法createRepositoryFactory()创建Repository工厂对象,在TransactionalRepositoryFactoryBeanSupport中实现了该方法;

在createRepositoryFactory()方法中,创建了Repository工厂之后,添加了两个后置处理器,其中一个为TransactionalRepositoryProxyPostProcessor。

3.2)为3.1)中的Repository工厂对象设置查询查找策略、NamedQueries、后置处理器等;

3.3)调用3.1)中的Repository工厂对象,调用getRepository()创建代理的Repository对象;

详细可以看【源码】Spring Data JPA原理解析之Repository的自动注入(二)

TransactionalRepositoryFactoryBeanSupport

TransactionalRepositoryFactoryBeanSupport的源码如下:

package org.springframework.data.repository.core.support;public abstract class TransactionalRepositoryFactoryBeanSupport<T extends Repository<S, ID>, S, ID>extends RepositoryFactoryBeanSupport<T, S, ID> implements BeanFactoryAware {private String transactionManagerName = TxUtils.DEFAULT_TRANSACTION_MANAGER;private @Nullable RepositoryProxyPostProcessor txPostProcessor;private @Nullable RepositoryProxyPostProcessor exceptionPostProcessor;private boolean enableDefaultTransactions = true;// 忽略其他@Overrideprotected final RepositoryFactorySupport createRepositoryFactory() {// 调用抽象方法,创建一个RepositoryFactorySupport对象,JpaRepositoryFactory对象RepositoryFactorySupport factory = doCreateRepositoryFactory();// 添加两个后置处理器,分别为PersistenceExceptionTranslationRepositoryProxyPostProcessor// 和TransactionalRepositoryProxyPostProcessor。在setBeanFactory()方法中初始化RepositoryProxyPostProcessor exceptionPostProcessor = this.exceptionPostProcessor;if (exceptionPostProcessor != null) {factory.addRepositoryProxyPostProcessor(exceptionPostProcessor);}RepositoryProxyPostProcessor txPostProcessor = this.txPostProcessor;if (txPostProcessor != null) {factory.addRepositoryProxyPostProcessor(txPostProcessor);}return factory;}protected abstract RepositoryFactorySupport doCreateRepositoryFactory();public void setBeanFactory(BeanFactory beanFactory) {Assert.isInstanceOf(ListableBeanFactory.class, beanFactory);super.setBeanFactory(beanFactory);// 创建后置处理器ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;this.txPostProcessor = new TransactionalRepositoryProxyPostProcessor(listableBeanFactory, transactionManagerName,enableDefaultTransactions);this.exceptionPostProcessor = new PersistenceExceptionTranslationRepositoryProxyPostProcessor(listableBeanFactory);}
}

1)TransactionalRepositoryFactoryBeanSupport实现了BeanFactoryAware,在初始化前,会执行setBeanFactory()方法,在该方法中,创建了两个后置处理器,分别为PersistenceExceptionTranslationRepositoryProxyPostProcessor和TransactionalRepositoryProxyPostProcessor;

2)在createRepositoryFactory()方法中,执行子类JpaRepositoryFactoryBean的doCreateRepositoryFactory()方法,创建JpaRepositoryFactory对象。并添加了1)中创建的两个后置处理器,其中一个为TransactionalRepositoryProxyPostProcessor;

TransactionalRepositoryProxyPostProcessor

在TransactionalRepositoryProxyPostProcessor处理器中,会向代理工厂添加TransactionInterceptor拦截器。

TransactionalRepositoryProxyPostProcessor的代码如下:

package org.springframework.data.repository.core.support;class TransactionalRepositoryProxyPostProcessor implements RepositoryProxyPostProcessor {private final BeanFactory beanFactory;private final String transactionManagerName;private final boolean enableDefaultTransactions;public TransactionalRepositoryProxyPostProcessor(ListableBeanFactory beanFactory, String transactionManagerName,boolean enableDefaultTransaction) {Assert.notNull(beanFactory, "BeanFactory must not be null");Assert.notNull(transactionManagerName, "TransactionManagerName must not be null");this.beanFactory = beanFactory;this.transactionManagerName = transactionManagerName;this.enableDefaultTransactions = enableDefaultTransaction;}public void postProcess(ProxyFactory factory, RepositoryInformation repositoryInformation) {// 定义一个TransactionInterceptor对象TransactionInterceptor transactionInterceptor = new TransactionInterceptor();// 设置RepositoryAnnotationTransactionAttributeSourcetransactionInterceptor.setTransactionAttributeSource(new RepositoryAnnotationTransactionAttributeSource(repositoryInformation, enableDefaultTransactions));transactionInterceptor.setTransactionManagerBeanName(transactionManagerName);transactionInterceptor.setBeanFactory(beanFactory);transactionInterceptor.afterPropertiesSet();// 添加TransactionInterceptor拦截器factory.addAdvice(transactionInterceptor);}static class RepositoryAnnotationTransactionAttributeSource extends AnnotationTransactionAttributeSource {private static final long serialVersionUID = 7229616838812819438L;private final RepositoryInformation repositoryInformation;private final boolean enableDefaultTransactions;public RepositoryAnnotationTransactionAttributeSource(RepositoryInformation repositoryInformation,boolean enableDefaultTransactions) {// 执行父类AnnotationTransactionAttributeSource,事务的分析器// 为JtaTransactionAnnotationParser和SpringTransactionAnnotationParser。// 即支持javax.transaction.Transactional的@Transactional注解和spring的@Transactionalsuper(true);Assert.notNull(repositoryInformation, "RepositoryInformation must not be null");// enableDefaultTransactions默认为truethis.enableDefaultTransactions = enableDefaultTransactions;// DefaultRepositoryInformation对象this.repositoryInformation = repositoryInformation;}@Override@Nullableprotected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {// Don't allow no-public methods as required.if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {return null;}// Ignore CGLIB subclasses - introspect the actual user class.Class<?> userClass = targetClass == null ? targetClass : ProxyUtils.getUserClass(targetClass);// The method may be on an interface, but we need attributes from the target class.// If the target class is null, the method will be unchanged.Method specificMethod = ClassUtils.getMostSpecificMethod(method, userClass);// If we are dealing with method with generic parameters, find the original method.// 如果正在处理具有泛型参数的方法,请找到原始方法。specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);TransactionAttribute txAtt = null;if (specificMethod != method) {// Fallback is to look at the original method.txAtt = findTransactionAttribute(method);if (txAtt != null) {return txAtt;}// Last fallback is the class of the original method.txAtt = findTransactionAttribute(method.getDeclaringClass());if (txAtt != null || !enableDefaultTransactions) {return txAtt;}}// First try is the method in the target class.txAtt = findTransactionAttribute(specificMethod);if (txAtt != null) {return txAtt;}// Second try is the transaction attribute on the target class.txAtt = findTransactionAttribute(specificMethod.getDeclaringClass());if (txAtt != null) {return txAtt;}if (!enableDefaultTransactions) {return null;}// Fallback to implementation class transaction settings of nothing found// return findTransactionAttribute(method);Method targetClassMethod = repositoryInformation.getTargetClassMethod(method);if (targetClassMethod.equals(method)) {return null;}txAtt = findTransactionAttribute(targetClassMethod);if (txAtt != null) {return txAtt;}txAtt = findTransactionAttribute(targetClassMethod.getDeclaringClass());if (txAtt != null) {return txAtt;}return null;}}
}

5.1 在postProcess()方法中,执行如下:

1)声明一个TransactionInterceptor对象;

2)声明一个RepositoryAnnotationTransactionAttributeSource对象;

3)添加transactionManagerName和beanFactory;

4)在ProxyFactory添加TransactionInterceptor拦截器;

5.2 RepositoryAnnotationTransactionAttributeSource注解事务属性资源类为内部类,该类继承AnnotationTransactionAttributeSource。RepositoryAnnotationTransactionAttributeSource的构造方法中,执行父类的构造方法。

在AnnotationTransactionAttributeSource的构造方法中,会添加注解事务的解析器。添加了SpringTransactionAnnotationParser和JtaTransactionAnnotationParser。分别用于解析org.springframework.transaction.annotation包和javax.transaction包下的@Transactional注解。即在代码中使用两个包的@Transactional注解都可以实现事务。

在RepositoryAnnotationTransactionAttributeSource的computeTransactionAttribute()方法中,会调用父类AnnotationTransactionAttributeSource的findTransactionAttribute(),进而执行determineTransactionAttribute()方法,遍历解析器,解析对应的@Transactional注解。

结尾

限于篇幅,本篇先分享到这里。

关于本篇内容你有什么自己的想法或独到见解,欢迎在评论区一起交流探讨下吧。

相关文章:

  • SHELL脚本学习(六) 呈现数据
  • 联想测开一面(电话面试)笔试60%
  • WPS JSA 宏脚本入门和样例
  • 【AI应用探讨】— GPT-4o模型应用场景
  • Synchronized 用过吗,其原理是什么???
  • 理解数学概念——线性(线性性)
  • Android: Null extracted folder for artifact: ResolvedArtifact(xxx 项目编译失败
  • Socket编程学习笔记之TCP与UDP
  • LabVIEW结构体内部缺陷振动检测
  • Android之保存图片到相册之前兼容不同机型需要注意的配置
  • 上岸北科大计算机专业难度有多大?北京科技大学计算机考研考情分析!
  • 【kubernetes】k8s集群安全机制 保姆级攻略
  • yg校园易购电商系统(Go+Vue)
  • DevExpress Installed
  • 人邮学院明日科技web前端开发案例教程(慕课版)第六章习题
  • Facebook AccountKit 接入的坑点
  • Iterator 和 for...of 循环
  • JavaScript设计模式与开发实践系列之策略模式
  • JavaScript中的对象个人分享
  • JSDuck 与 AngularJS 融合技巧
  • React Transition Group -- Transition 组件
  • Spark VS Hadoop:两大大数据分析系统深度解读
  • Webpack 4 学习01(基础配置)
  • 阿里云ubuntu14.04 Nginx反向代理Nodejs
  • 产品三维模型在线预览
  • 解决iview多表头动态更改列元素发生的错误
  • 如何用Ubuntu和Xen来设置Kubernetes?
  • 协程
  • 用Node EJS写一个爬虫脚本每天定时给心爱的她发一封暖心邮件
  • 栈实现走出迷宫(C++)
  • 回归生活:清理微信公众号
  • 支付宝花15年解决的这个问题,顶得上做出十个支付宝 ...
  • #我与Java虚拟机的故事#连载11: JVM学习之路
  • (2)Java 简介
  • (HAL库版)freeRTOS移植STMF103
  • (ibm)Java 语言的 XPath API
  • (论文阅读26/100)Weakly-supervised learning with convolutional neural networks
  • (转) RFS+AutoItLibrary测试web对话框
  • (转)为C# Windows服务添加安装程序
  • .NET Core 实现 Redis 批量查询指定格式的Key
  • .NET LINQ 通常分 Syntax Query 和Syntax Method
  • .NET 应用启用与禁用自动生成绑定重定向 (bindingRedirect),解决不同版本 dll 的依赖问题
  • .NET的微型Web框架 Nancy
  • .net企业级架构实战之7——Spring.net整合Asp.net mvc
  • ?php echo $logosrc[0];?,如何在一行中显示logo和标题?
  • [18] Opencv_CUDA应用之 基于颜色的对象检测与跟踪
  • [Bug]使用gradio创建应用提示AttributeError: module ‘gradio‘ has no attribute ‘inputs‘
  • [BZOJ3223]文艺平衡树
  • [C# 开发技巧]实现属于自己的截图工具
  • [dart学习]第四篇:函数
  • [GDMEC-无人机遥感研究小组]无人机遥感小组-000-数据集制备
  • [Git 1]基本操作与协同开发
  • [Go WebSocket] 多房间的聊天室(五)用多个小锁代替大锁,提高效率
  • [ITIL学习笔记]之事件管理(2)
  • [JS7] 显示从0到99的100个数字