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

化妆品做备案的网站网页模版之家

化妆品做备案的网站,网页模版之家,农村自建房设计图一层半,抖音网络营销案例使用AbstractRoutingDataSource实现多数据源 与 获取mapper上注解 背景 随着业务发展速度越来越快#xff0c;数据的增长也呈现倍数级别增长#xff0c;数据库的压力#xff0c;对于查询和写入等所有操作#xff0c;都依赖于主库#xff0c;其实有一些对于时效性要求不高…使用AbstractRoutingDataSource实现多数据源 与 获取mapper上注解 背景 随着业务发展速度越来越快数据的增长也呈现倍数级别增长数据库的压力对于查询和写入等所有操作都依赖于主库其实有一些对于时效性要求不高的场景无需使用主库查询可以使用从库来分摊主库的压力提升数据库集群整体的吞吐量 处理思路 其实处理思路共有两种 1. 我们创建两个数据源不同的数据源扫描不同的包.         也就是查询从库或者查询主库是通过不同的mapper文件物理隔离的优势就是开发简单快速搭建不用担心侵入原有逻辑。缺点也是显而易见的如果一个sql在某些场景下需要主库查询另外场景需要从库查询那么我们要写两套sql如果有新增字段等ddl操作时我们要改两遍sql由于比较简单本文不做描述。 2. 使用动态数据源配置         在多个数据源之上抽象出来一个虚拟的动态数据源等到执行sql的前一步我们才会选择哪个数据源执行优点是能够更精细化的管控sql执行缺点的话就是开发稍微复杂些 动态数据源的执行逻辑 我们需要先了解下spring的AbstractRoutingDataSource spring提供了一套数据库路由方案我们重写determineCurrentLookupKey 方法将想要的数据库返回即可。 以spring boot 为例 一、 mysql的基本配置 首先配置主库和从库的数据源这个是前提 Bean(name mysqlDataSource) Primary public DataSource mysqlDataSource() {DruidDataSource dataSource new DruidDataSource();dataSource.setDriverClassName(driverClass);dataSource.setUrl(url);dataSource.setUsername(user);dataSource.setPassword(password);dataSource.setMaxActive(300);dataSource.setKeepAlive(true);dataSource.setMaxWait(60000);dataSource.setValidationQuery(SELECT x);dataSource.setMinEvictableIdleTimeMillis(300000);dataSource.setTestWhileIdle(true);dataSource.setTestOnBorrow(true);dataSource.setTestOnReturn(false);return dataSource; } /*** 从库主库数据源*/ Bean(name mysqlSlaveDataSource) public DataSource mysqlSlaveDataSource() {DruidDataSource dataSource new DruidDataSource();dataSource.setDriverClassName(driverClass);dataSource.setUrl(url);dataSource.setUsername(readUser);dataSource.setPassword(passwordRead);dataSource.setMaxActive(300);dataSource.setKeepAlive(true);dataSource.setMaxWait(60000);dataSource.setValidationQuery(SELECT x);dataSource.setMinEvictableIdleTimeMillis(300000);dataSource.setTestWhileIdle(true);dataSource.setTestOnBorrow(true);dataSource.setTestOnReturn(false);return dataSource; }配置动态数据源将多数据源注入进动态数据源并设置默认的数据源 Bean(name dynamicDataSource) public DynamicDataSource dynamicDataSource(Qualifier(mysqlDataSource) DataSource mysqlDataSource,Qualifier(mysqlSlaveDataSource) DataSource mysqlSlaveDataSource) {MapObject, Object targetDataSources Maps.newHashMap();targetDataSources.put(DataSourceEnum.MASTER, mysqlDataSource);targetDataSources.put(DataSourceEnum.SLAVE, mysqlSlaveDataSource);return new DynamicDataSource(mysqlDataSource, targetDataSources); }将动态数据源设置到sql的sessionFactory Bean(name mysqlSqlSessionFactory) Primary public SqlSessionFactory masterSqlSessionFactory(Qualifier(dynamicDataSource) DataSource dynamicDataSource) throws Exception {final SqlSessionFactoryBean sessionFactory new SqlSessionFactoryBean();sessionFactory.setDataSource(dynamicDataSource);sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(MysqlDataSourceConfig.MAPPER_LOCATION));// 配置org.apache.ibatis.session.Configuration configuration new org.apache.ibatis.session.Configuration();configuration.setMapUnderscoreToCamelCase(true);configuration.setDefaultStatementTimeout(30);configuration.addInterceptor(new MybatisUMPInterceptor());sessionFactory.setConfiguration(configuration);return sessionFactory.getObject(); }二、 新增的配置 新增加库的枚举定义 package com.common.enums;/*** 数据源配置枚举** author wangzym*/ public enum DataSourceEnum {/*** 使用主库*/MASTER(1, 主库),/*** 使用从库*/SLAVE(2, 从库);/*** /*** 编码*/private Integer code;/*** 描述*/private String desc;DataSourceEnum(Integer code, String desc) {this.code code;this.desc desc;}public Integer getCode() {return this.code;}public String getDesc() {return this.desc;}public static DataSourceEnum getByCode(Integer code) {if (code null) {return null;}for (DataSourceEnum dataSourceEnum : DataSourceEnum.values()) {if (dataSourceEnum.getCode().equals(code)) {return dataSourceEnum;}}return null;} }动态数据源的定义需要继承spring的AbstractRoutingDataSource package com.test.datasource;import com.alibaba.fastjson.JSON; import com.test.SettleCheckException; import lombok.extern.slf4j.Slf4j; import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;import javax.sql.DataSource; import java.util.Map;/*** 动态切换数据源类** author wangzym*/ Slf4j public class DynamicDataSource extends AbstractRoutingDataSource {public DynamicDataSource(DataSource defaultTargetDataSource, MapObject, Object targetDataSources) {//不符合配置条件直接中断启动流程if (defaultTargetDataSource null || targetDataSources null || targetDataSources.isEmpty()) {throw new SettleCheckException(默认数据源和可切换的数据源不允许为空!请检查 spring-config-datasource-druid.xml - dynamicDataSource 对应配置);}//设置默认数据源super.setDefaultTargetDataSource(defaultTargetDataSource);//设置用于切换的数据源super.setTargetDataSources(targetDataSources);//初始化本地的数据源记录super.afterPropertiesSet();}Overrideprotected Object determineCurrentLookupKey() {log.debug(当前线程使用SQL的数据库是:{}, JSON.toJSONString(DynamicDataSourceHolder.getDataSource()));return DynamicDataSourceHolder.getDataSource();}}新增注解 package com.test.datasource;import com.test.DataSourceEnum;import java.lang.annotation.*;/*** 切换数据源注解默认连接主库* 要在mapper上加此注解才可以* p*/ Inherited Retention(RetentionPolicy.RUNTIME) Target(ElementType.METHOD) Documented public interface SwitchDataSource {DataSourceEnum name() default DataSourceEnum.MASTER; }拦截器改造需要拦截sql此方法可以直接拦截sql执行此方法要重点理解是mybatis的拦截方案其中Intercepts可以通过不同的类型来进行不同的拦截此处拦截所有执行的sql直接获取mapper上的注解会获取不到需要通过反射的方式来获取需要重点注意此处不是本文的重点有兴趣可以了解mybatis源码。 package com.test.interceptor;import com.test.DuccConstants; import com.test.enums.DataSourceEnum; import com.test.datasource.DynamicDataSourceHolder;Intercepts({Signature(type Executor.class, method query, args {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),Signature(type Executor.class, method query, args {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}),Signature(type Executor.class, method update, args {MappedStatement.class, Object.class}),}) Slf4j public class MybatisUMPInterceptor implements Interceptor {Value(${test.current.env:pre})private static String env;static {env System.getProperty(current.env, pre);log.info(当前切面的环境为:{}, env);}Overridepublic Object intercept(Invocation invocation) throws Throwable {CallerInfo callerInfo null;try {//1.处理数据源切换SwitchDataSource chooseDataSource getSwitchDbAnnotation((MappedStatement) invocation.getArgs()[0]);if (null ! chooseDataSource DuccConstants.allowedMultiDb()) {//默认会使用MASTER数据源 如果开启事务了,而且当前数据源不是MASTER会强制切换为MASTERDynamicDataSourceHolder.setDataSource(chooseDataSource.name());if (TransactionSynchronizationManager.isActualTransactionActive() DataSourceEnum.SLAVE.equals(chooseDataSource.name())) {DynamicDataSourceHolder.setDataSource(DataSourceEnum.MASTER);}} else {DynamicDataSourceHolder.setDataSource(DataSourceEnum.MASTER);}//2.埋点监控Object[] args invocation.getArgs();MappedStatement ms (MappedStatement) args[0];//ump key可以自定义String jKey String.format(%s_MyBatis.%s, env, ms.getId());if (DynamicDataSourceHolder.getDataSource() ! null DynamicDataSourceHolder.getDataSource().equals(DataSourceEnum.SLAVE)) {jKey jKey _slave;}callerInfo Profiler.registerInfo(jKey, false, true);} catch (Exception ignore) {//ignorelog.warn(切面执行出现异常:{}, ignore.getStackTrace(), ignore);}try {return invocation.proceed();} catch (Throwable e) {try {if (null ! callerInfo) {Profiler.functionError(callerInfo);}} catch (Exception ignore) {//ignore}throw e;} finally {try {if (null ! callerInfo) {Profiler.registerInfoEnd(callerInfo);}} catch (Exception ignore) {//ignore}}}private SwitchDataSource getSwitchDbAnnotation(MappedStatement mappedStatement) {SwitchDataSource annotation null;try {String id mappedStatement.getId();String className id.substring(0, id.lastIndexOf(.));String methodName id.substring(id.lastIndexOf(.) 1);final Method[] method Class.forName(className).getMethods();for (Method me : method) {if (me.getName().equals(methodName) me.isAnnotationPresent(SwitchDataSource.class)) {return me.getAnnotation(SwitchDataSource.class);}}} catch (Exception ex) {log.error(, ex);}return annotation;}Overridepublic Object plugin(Object target) {return Plugin.wrap(target, this);}Overridepublic void setProperties(Properties properties) {} }在mapper上打注解标记 SwitchDataSource(name DataSourceEnum.SLAVE) Long queryTaskOfShopCount(GeneralFeeDetailDTO generalFeeDetailDTO);至此mysql 动态路由到指定数据库就讲解完成。
http://www.dnsts.com.cn/news/189597.html

相关文章:

  • 陕西网站建设方案高端企业网站建设蓦然郑州网站建设6
  • 自己建设网站需要哪些cpanel应用不显示wordpress
  • 推荐设计网站黄骅港务
  • 成都的网站店铺网站怎么建
  • python制作视频网站开发插画师零基础自学
  • 高端网站鉴赏做网站投资多少钱
  • wordpress本地数据库密码忘记长沙seo优化首选
  • 新网站做百度推广 收录做化工回收上什么网站
  • 做网站一般按什么报价pc端移动端网站怎么做的
  • 一 网站建设的总体目标网站用html做的怎么弄后台
  • 网站怎么备案在哪里自助建站源码下载
  • 商城网站管理系统安溪网页定制
  • 网站维护怎么收费h5页面制作教程
  • 如何开通个人网站嘉兴网站建设定制
  • 做网站那个程序好搭建网站是什么意思
  • seo优化网站多少钱商标在线注册平台
  • 商标注册网站缴费入口网站开发 动易
  • 实例网站制作教程在虚拟主机上建设多个网站
  • 家里做服务器开网站广东建设监理协会网站题库
  • 自己做微博的网站天津网站建设运营方案
  • 自己建网站的费用在线写作网站
  • 在哪可以建一个网站系统开发流程8个步骤
  • 杭州知名网站建设wordpress 即时站内搜索
  • net和cn哪个做网站好网站建设买服务器还是数据库
  • 做高端品牌网站定西网站建设公司
  • 万网的怎么做网站地图怎样进行公司网站建设
  • 学设计的网站广告logo图片大全
  • 给朋友做的相册网站没有了厦门网站建设兼职
  • 做微网站的第三方西安市社交网站制作公司
  • 网站建设全攻略wordpress中文书籍