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

互联网整合营销推广/郴州seo网络优化

互联网整合营销推广,郴州seo网络优化,下载别人做的ppt的网站,bootstrap响应式网站欢迎关注微信公众号:冬瓜白 相关文章: 自己动手写一个分库分表中间件(一)思考自己动手写一个分库分表中间件(二)数据源定义和分片代理层设计自己动手写一个分库分表中间件(三)数据源…

欢迎关注微信公众号:冬瓜白

相关文章:

  • 自己动手写一个分库分表中间件(一)思考
  • 自己动手写一个分库分表中间件(二)数据源定义和分片代理层设计
  • 自己动手写一个分库分表中间件(三)数据源路由实现
  • 自己动手写一个分库分表中间件(四)表路由、SQL 重写和结果集处理思路
  • 自己动手写一个分库分表中间件(五)分布式事务问题解决思路<一>基于 Spring 编程式事务
  • 自己动手写一个分库分表中间件(六)分布式事务问题解决思路<二>动态事务管理器
  • 自己动手写一个分库分表中间件(七)分布式事务问题解决思路<三>动态 Connection
  • 自己动手写一个分库分表中间件(八)测试过程中的特殊 BUG<一>加解密拦截器的兼容问题

兼容是本次分库分表项目中非常重要的一点,本文探讨的议题是兼容中的事务问题。

实在是不知道这个标题名称该怎么取。直接看一个例子吧,这也是是很多朋友经常有疑问的一个点。

//srvService1Mapper和srvService2Mapper分别配置了不同的数据源、事务管理器,srvService1Mapper的事务管理器标注了@Primary
@Transactional
public void bbb(String sId1,String sId2) {srvService1Mapper.updateByid(sId1);   srvService2Mapper.updateByid(sId2);   int i = 1/0;
}

这个方法非常简单,一个被 @Transactional 标注的方法,内部调用了两个配置了不同数据源和事务管理器的 Mapper ,要注意的是,这里的 @Transactional 并未设置任何参数,即属性参数都用默认的。

那么这个方法在执行后,是 srvService1Mapper 会回滚还是 srvService2Mapper 会回滚呢?

@Transactional 会使用哪个事务管理器?

先看第一个问题:@Transactional 会使用哪个事务管理器?很明显,如果指定了事务管理器的 BeanName,那么肯定就是对应的事务管理器。如果没有指定的话就会使用默认事务管理器,那么默认事务管理器是什么呢,可以看下这个方法:

org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction->org.springframework.transaction.interceptor.TransactionAspectSupport#determineTransactionManager

	protected PlatformTransactionManager determineTransactionManager(TransactionAttribute txAttr) {// Do not attempt to lookup tx manager if no tx attributes are setif (txAttr == null || this.beanFactory == null) {return getTransactionManager();}String qualifier = txAttr.getQualifier();if (StringUtils.hasText(qualifier)) {return determineQualifiedTransactionManager(qualifier);}else if (StringUtils.hasText(this.transactionManagerBeanName)) {return determineQualifiedTransactionManager(this.transactionManagerBeanName);}else {PlatformTransactionManager defaultTransactionManager = getTransactionManager();if (defaultTransactionManager == null) {defaultTransactionManager = this.transactionManagerCache.get(DEFAULT_TRANSACTION_MANAGER_KEY);if (defaultTransactionManager == null) {defaultTransactionManager = this.beanFactory.getBean(PlatformTransactionManager.class);this.transactionManagerCache.putIfAbsent(DEFAULT_TRANSACTION_MANAGER_KEY, defaultTransactionManager);}}return defaultTransactionManager;}}

这个方法说白了就是先解析 @Transactional 的属性,解析不出来就走默认的,这里的默认其实就是从 Bean 容器中找到就是被 @Primary 标注的事务管理器,这个就看我们是怎么配置的,如果没有配置被 @Primary 标注的事务管理器,那么就会报错:

No qualifying bean of type 'org.springframework.transaction.PlatformTransactionManager' available: expected single matching bean but found 7:

上面也提到了,srvService1Mapper 的事务管理器标注了 @Primary

这个问题确定了,那么再看第二个问题。

怎么看是同一个事务

我们都知道,Spring 的声明式事务是通过 @Transactional 来实现的,现在已经确定了,这里的 @Transactional 使用的是 srvService1Mapper 的事务管理器。

这里“同一个事务”的指的是, @Transactional 的事务管理器和被 @Transactional 标注方法内部的 Mapper 使用的事务是否是同一个。在这个例子中,很明显 srvService1Mapper@Transactional 是同一个。

事务的本质是什么

在“《从单机事务到分布式事务》分享文档”中提到过,事务是 Connection 级别的,Connection 从哪里来?从 DataSource 里面来。这里有个要注意的是,MapperSqlSessionFactory 要配置 DataSource,同时事务管理器也是要配置 DataSource的:

org.mybatis.spring.SqlSessionFactoryBean#setDataSource

  public void setDataSource(DataSource dataSource) {if (dataSource instanceof TransactionAwareDataSourceProxy) {// If we got a TransactionAwareDataSourceProxy, we need to perform// transactions for its underlying target DataSource, else data// access code won't see properly exposed transactions (i.e.// transactions for the target DataSource).this.dataSource = ((TransactionAwareDataSourceProxy) dataSource).getTargetDataSource();} else {this.dataSource = dataSource;}}

org.springframework.jdbc.datasource.DataSourceTransactionManager#DataSourceTransactionManager(javax.sql.DataSource)

	public DataSourceTransactionManager(DataSource dataSource) {this();setDataSource(dataSource);afterPropertiesSet();}

@Transactional 从哪里获取 Connection

@Transactional 开启的时候一开始就会去获取 Connection,即从 @Transactional 配置的事务管理器中配置的 DataSource 中获取 Connection

srvService1Mapper 从哪里获取 Connection

很明显,从配置的 SqlSessionFactory 中配置的 DataSource 中获取 ConnectionsrvService2Mapper同理。

MapperConnection 怎么和 @Transactional 结合起来

这里有个注意点,就是 Spring 与不同的数据库访问框架,实现细节会略有不同,但总体流程其实差不多。

上面已经提到过,事务是 Connection 级别,也就是说这个 Mapper 的事务要想生效,必须和 @TransactionalConnection 是同一个。

流程实在太复杂,直接看最关键的:

org.apache.ibatis.session.defaults.DefaultSqlSessionFactory#openSessionFromDataSource

  private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {Transaction tx = null;try {final Environment environment = configuration.getEnvironment();final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);final Executor executor = configuration.newExecutor(tx, execType);return new DefaultSqlSession(configuration, executor, autoCommit);} catch (Exception e) {closeTransaction(tx); // may have fetched a connection so lets call close()throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);} finally {ErrorContext.instance().reset();}}

可以看到是从 MyBatis 的 Configuration 获取的 DataSource,再看 org.springframework.jdbc.datasource.DataSourceUtils#doGetConnection

public static Connection doGetConnection(DataSource dataSource) throws SQLException {Assert.notNull(dataSource, "No DataSource specified");ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);....
}

可以看到是从 TransactionSynchronizationManager 中获取 Connection,即 ThreadLocal,简单点说就是从一个内存 Map 中获取 Connection,key 是 DataSource

但这里是不是就很通透了,即只要 DataSource 是一致的,那么 Connection 就是一致的(当然这块是可以重写的,具体可以参看自己动手写一个分库分表中间件(七)分布式事务问题解决思路<三>动态 Connection),那么就可以被 @Transactional 所管理。

再回过头看文章最开头的例子,很明显,只有 srvService1Mapper 的事务会回滚,因为 srvService2Mapper 的事务已经不受 @Transactional 管理了。

这里可能还有朋友有疑问,不受 @Transactional 管理了,那么这个事务怎么提交的呢,其实事务只要没有设置非自动提交,那么就会自动提交了。

本文比较详细的分析了 DataSource 在事务管理中的重要性,而这一点也是设计分库分表中间件中兼容历史场景的重要原理之一。

References

  • https://mp.weixin.qq.com/s?__biz=MzU1OTgyMDc3Mg==&mid=2247485239&idx=1&sn=e2e54f7ad284e4266309953a199789fd&chksm=fc103dbccb67b4aa91737765caacea66574975600c9636fda527561978f70993c83fc68d3018&token=405931768&lang=zh_CN#rd
http://www.lbrq.cn/news/6967.html

相关文章:

  • 武汉网站设计公司官网/上海网络优化seo
  • 好孩子官方网站王建设/怎么样做网站推广
  • 建设厅和住建厅有什么区别/广州百度seo排名
  • 建站宝盒源代码/seo关键字排名
  • 杨浦网站建设_网站外包/国内最新新闻事件
  • 网址的格式是什么样的/淄博seo
  • 网站建设完成确认书/营销型网站建设目标
  • 江苏建设招标信息网站/百度搜索引擎官网入口
  • 什么网站可以做兼职设计/营业推广经典案例
  • 连云港做网站多少钱/信息流广告推广
  • 如何做国外的电商网站设计/搜索引擎网站提交入口
  • 哪个网站是vue做的/网络优化工程师有前途吗
  • 邢台做移动网站的公司/百度100%秒收录
  • 文件注入网站/百度推广的广告靠谱吗
  • php创建网站/西安seo招聘
  • 做阿里巴巴的网站的费用吗/模板免费下载网站
  • python做网站的好处/奇零seo赚钱培训
  • 山东省政府采购网 网站建设 招标/做专业搜索引擎优化
  • 政府网站集约化建设技术方案/网站性能优化
  • wordpress文章复制粘贴图片保存/廊坊关键词排名优化
  • 常规网站服务器/互联网推广方案怎么写
  • 专业型网站网站/十大跨境电商erp排名
  • 网络营销策略4p4c/seo快速优化报价
  • 九江建设监督网站/全网营销系统是干什么的
  • 企业网站建设劣势/营销引流都有什么方法
  • b站必看的纪录片/淘宝代运营
  • 甘肃省建设厅特种工查询网站/网站seo是干什么的
  • 顺义网站制作/页面优化的方法
  • 科技未来网站建设/网站搜索引擎优化的步骤
  • 二手车网站开发多少钱/企业网站建设目标
  • 考研408《计算机组成原理》复习笔记,第五章(3)——CPU的【数据通路】
  • 主进程如何将客户端连接分配到房间进程
  • 零信任架构(Zero Trust Architecture, ZTA)(通过动态验证和最小权限控制,实现对所有访问请求的严格授权和持续监控)
  • 北京JAVA基础面试30天打卡09
  • 【Python办公】Mermaid代码转图片工具 - Tkinter GUI版本
  • IIS Express中可以同时加载并使用.net4.0和.NET 2.0的 DLL