dynamicdatasource 切换不成功_浅析动态切换数据源的原理(接上篇)

本文深入探讨了动态数据源切换的原理,针对dynamicdatasource切换不成功的问题进行了分析。文章介绍了如何管理多个数据源,并强调了默认数据源的重要性。
提前祝大家双节快乐e753d28954c193b44d23a5514f77de46.png上一篇我们实现了多数据源动态切换的功能,这次我们来看一下是如何实现的。没看过上一篇的点击这里8e4d6edb9819b13afa48b4ff994dbecd.png中秋快乐ff005b39ac3e1f9b52d53709d9700d35.png我们在DynamicDataSourceConfig中配置了所有数据源信息,并存在一个map中27bd3648ecbcfdcd03063383c85d058a.png5a048be5fe992f0a8125f583520fbc27.png因为我们的DynamicDataSource继承了AbstractRoutingDataSource抽象类,AbstractRoutingDataSource中有几个重要的属性在这里我们用到了
@Nullableprivate Map targetDataSources;@Nullableprivate Object defaultTargetDataSource;
  • targetDataSources:持有我们多数据源的所有数据源,key为不重复的对象用于唯一标识一个数据源,value为数据源DataSource实例
  • defaultTargetDataSource:默认的数据源实例
可以看到我们在配置类中new DynamicDataSource在构造方法中传了两个参数,就对应了defaultTargetDataSourcetargetDataSources,这样DynamicDataSource就持有了我们的默认数据源和所有数据源。然后我们可以看到DynamicDataSource实现了AbstractRoutingDataSource抽象类的抽象方法determineCurrentLookupKey()f7d0339439a203ab748b2412c7607af0.png这个方法的作用就是返回一个key,该key对应当前你希望使用的DataSource。在这个里,我们优化了一下,使用一个类DataSourceHolder持有我们的这个key,所以DynamicDataSource方法就变得很简洁了,就是在determineCurrentLookupKey方法中调用DataSourceHolder的静态方法getDataSourceName获取到当前用户想要使用的DataSourcekey。在AbstractRoutingDataSourcedetermineTargetDataSource方法中调用了determineCurrentLookupKey方法:55f10aa99237440daf0e46e129851566.png我们可以看到拿到key后,是从resolvedDataSources(一个map对象)中get对应的DataSource,get不到返回resolvedDefaultDataSource,看样子是默认数据源
@Nullableprivate Map resolvedDataSources;
但是resolvedDataSourcesresolvedDefaultDataSource都不是刚刚我们所介绍的targetDataSourcesdefaultTargetDataSource。那是因为做了赋值操作,org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource#afterPropertiesSet
9281c2fbbb4d5825bba0bfd1d179ca29.pngAbstractRoutingDataSource实现了InitializingBean接口的afterPropertiesSet,会在实例化bean后调用此方法(AbstractAutowireCapableBeanFactory#invokeInitMethods方法调用的),所以resolvedDataSourcesresolvedDefaultDataSource就有值了。继续回到determineTargetDataSource方法,该返回DataSource实例,既然是返回实例,肯定是有地方去获取DataSource,因为我们用的持久层框架是mybatis,所以获取DataSource的这个操作势必是mybatis发起的。清楚了这一点就好办了,那就要看mybatis了,查阅资料我们可以发现,mybatis包中有这样一个类负责管理JDBC连接的生命周期,它就是org.mybatis.spring.transaction.SpringManagedTransaction(mybatis-spring.jarspring集成mybatis的jar包)它实现了mybatis中的Transaction接口0a8a68ee39cd2a72e13616f43608cfeb.png我们可以看到接口中有一个getConnection()方法,即是要从数据库连接池中获取一个连接:
@Overridepublic Connection getConnection() throws SQLException {if (this.connection == null) {
    openConnection();
  }return this.connection;
}
在连接为空时,调用openConnection()方法获取连接,我们看看openConnection方法做了什么操作:2faecd17070d826da1e95f65eff30645.png该方法第一个调用DataSourceUtils.getConnection(this.dataSource)获取连接,其调用DataSourceUtils中的doGetConnection(dataSource)获取连接0bdba8148e22a0ec0303f74d8b070e72.png然后在这个方法内部又调用fetchConnection(dataSource)方法获取连接680221f83cbaaa26841da9695c1c1265.pngfetchConnection(datasource)内直接就调用了DataSource对象的getConnection方法e3ae495f01706ad448515ae6f73b6b72.png因为我们的DynamicDataSource没有重写getConnection方法,那么就会调父类的
@Overridepublic Connection getConnection() throws SQLException {return determineTargetDataSource().getConnection();
}
可以看到先调了determineTargetDataSource方法获取DataSourcegetConnection()determineTargetDataSource方法刚刚我们已经看过了。总结大致思想就是,mybatis执行SQL时会从DataSource拿一个JDBC连接,所以spring巧妙的利用了这个特点,它提前拿到多个数据源的实例信息,在mybatis获取连接时根据用户的指令,动态的选择返回哪个连接,这些操作对mybatis是透明的。spring把一些通用方法高度抽象到AbstractRoutingDataSource抽象类中,使用两个变量管理数据源,targetDataSourcesdefaultTargetDataSource,然后再预留出determineCurrentLookupKey方法供我们实现,即只需要返回一个key就可以,返回的key用于从targetDataSources中选取出我们指定的数据源。所以,除了determineCurrentLookupKey方法外,其他的操作对于使用者来说也是透明的,使用者只需要关心如何在determineCurrentLookupKey方法中实现自己的选择数据源的规则即可。只不过,我们是通过AOP切面拦截的方式增强方法,在持久层方法执行前即在mybatis执行SQL前我们事先把DataSource换成我们指定的即可。在这里我们换数据源的方式是通过一个DataSourceHolder类中的ThreadLocal实现的,原因是为了保证多线程并发环境下不同线程切换数据源时不会乱,Threadlocal线程独有的一个对象,在其内部保存我们的key,在determineCurrentLookupKey中获取并返回即可。代码已上传到码云,springboot版本和SSM都有感兴趣的可以去下载https://gitee.com/itwalking/springboot-dynamic-datasourcehttps://gitee.com/itwalking/ssm-dynamic-datasource不要吝啬你的赞?,求三连,点赞、收藏、转发

9e359ca81fdd150807dab8792d28a700.png

### 数据增强概念 数据增强是指通过对原始图像样本施加一系列变换操作来增加训练集中可用的数据量的技术[^1]。这些变换旨在保持目标对象的关键特征变的同时引入合理的变异,从而提高模型泛化能力并减少过拟合现象。 ### 数据增强的作用 通过适当的数据增强手段可以有效提升计算机视觉任务中的模型性能: - **扩充数据多样性**:模拟同拍摄条件下的变化情况; - **改善模型鲁棒性**:使网络能够更好地应对现实世界中存在的各种干扰因素; - **缓解标注成本压力**:利用较少的人工标记获取更广泛的有效信息源; ### 增强方式分类 #### 在线增强 在线增强是在每次迭代过程中动态生成新的训练样例的方法。这种方式具备较高的灵活性和即时调整的能力,可以根据当前学习状态自适应地改变参数设置或选择特定类型的转换效果。 优点包括但限于: - 实时性强,便于快速响应算法需求的变化; - 可针对具体问题定制个性化的增广方案; 缺点在于可能消耗较多计算资源,在某些硬件环境下运行效率较低。 #### 离线增强 离线增强则是预先对整个数据集执行固定模式的一系列处理后再投入后续流程使用。这种方法适用于那些希望简化前期准备工作或是受限于设备配置无法支持复杂实时运算的情形下。 其特点如下: - 准备阶段耗时较长但之后可显著加快实验进度; - 对存储空间有一定占用,需权衡利弊做出合理规划; ### 具体实现方法 常见的图像级数据增强技术有以下几种形式: - **几何变换** - 平移、旋转、缩放和平滑滤波等基本操作; ```python import torchvision.transforms as transforms transform = transforms.Compose([ transforms.RandomRotation(30), ]) ``` - **颜色抖动** 改变亮度、对比度、饱和度及色调属性以模仿光照差异带来的影响; ```python color_jitter = transforms.ColorJitter(brightness=0.5, contrast=0.5, saturation=0.5, hue=0.5) image_transformed = color_jitter(image) ``` - **噪声注入** 向图片中加入随机扰动成分如高斯白噪点或者椒盐型杂质颗粒,以此测试系统的抗干扰水平; ```python noise_level = 0.1 * torch.randn_like(tensor_image) noisy_tensor = tensor_image + noise_level ``` - **裁剪填充** 随机选取部分区域作为新视图或将边界扩展至指定尺寸范围之内; ```python random_crop = transforms.RandomResizedCrop(size=(224, 224)) cropped_image = random_crop(image) ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值