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

WordPress 4.9添加备案号搜索引擎优化报告

WordPress 4.9添加备案号,搜索引擎优化报告,用ps做租房网站里的图标大小,厦门建设工程信息造价网站使用AbstractRoutingDataSource实现多数据源 与 获取mapper上注解 背景 随着业务发展速度越来越快,数据的增长也呈现倍数级别增长,数据库的压力,对于查询和写入等所有操作,都依赖于主库,其实有一些对于时效性要求不高…

使用AbstractRoutingDataSource实现多数据源 与 获取mapper上注解

背景

        随着业务发展速度越来越快,数据的增长也呈现倍数级别增长,数据库的压力,对于查询和写入等所有操作,都依赖于主库,其实有一些对于时效性要求不高的场景,无需使用主库查询,可以使用从库来分摊主库的压力,提升数据库集群整体的吞吐量

处理思路

其实处理思路共有两种

1. 我们创建两个数据源,不同的数据源扫描不同的包.
        也就是查询从库或者查询主库,是通过不同的mapper文件物理隔离的,优势就是开发简单,快速搭建,不用担心侵入原有逻辑。缺点也是显而易见的,如果一个sql在某些场景下需要主库查询,另外场景需要从库查询,那么我们要写两套sql,如果有新增字段等ddl操作时,我们要改两遍sql,由于比较简单,本文不做描述。

2. 使用动态数据源配置
        在多个数据源之上,抽象出来一个虚拟的动态数据源,等到执行sql的前一步,我们才会选择哪个数据源执行,优点是能够更精细化的管控sql执行,缺点的话就是开发稍微复杂些

动态数据源的执行逻辑

我们需要先了解下spring的AbstractRoutingDataSource ,spring提供了一套数据库路由方案,我们重写determineCurrentLookupKey 方法,将想要的数据库返回即可。

以spring boot 为例

一、 mysql的基本配置

  1. 首先配置主库和从库的数据源,这个是前提

    @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;
    }
    
  2. 配置动态数据源,将多数据源注入进动态数据源,并设置默认的数据源

    @Bean(name = "dynamicDataSource")
    public DynamicDataSource dynamicDataSource(@Qualifier("mysqlDataSource") DataSource mysqlDataSource,@Qualifier("mysqlSlaveDataSource") DataSource mysqlSlaveDataSource) {Map<Object, Object> targetDataSources = Maps.newHashMap();targetDataSources.put(DataSourceEnum.MASTER, mysqlDataSource);targetDataSources.put(DataSourceEnum.SLAVE, mysqlSlaveDataSource);return new DynamicDataSource(mysqlDataSource, targetDataSources);
    }
    
  3. 将动态数据源设置到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();
    }
    

二、 新增的配置

  1. 新增加库的枚举定义
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;}
}
  1. 动态数据源的定义,需要继承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, Map<Object, 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();}}
  1. 新增注解

    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;
    }
    
  2. 拦截器改造需要拦截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) {}
    }
    
  3. 在mapper上打注解标记

    @SwitchDataSource(name = DataSourceEnum.SLAVE)
    Long queryTaskOfShopCount(GeneralFeeDetailDTO generalFeeDetailDTO);
    

    至此,mysql 动态路由到指定数据库就讲解完成。

http://www.tj-hxxt.cn/news/17521.html

相关文章:

  • 政府门户网站建设方案公司推广方案
  • 仿v电影的模板 好像是wordpressseo关键词平台
  • 省级政府网站集约化建设网站外包
  • 本地做的网站如何映射出去网络营销方法有哪几种
  • access数据库网站开发百度上看了不健康的内容犯法吗
  • 怎么做网站建设11月将现新冠感染高峰
  • 一家只做家纺的网站怎么seo关键词优化排名
  • 拐角型网站百度关键词排名神器
  • 邯郸网站设计培训机构网站品牌推广策略
  • 做佣金单网站二级域名在线扫描
  • 网站管理后台下载企业自助建站
  • 张家港安监站网址网推什么平台好用
  • 做游戏网站用什么系统做廊坊seo排名
  • 网站开发合肥免费建网站最新视频教程
  • 龙岩网络图书馆注册刷移动端seo软件
  • 孝感网站建设xgsh成都seo经理
  • 国外网站兼职做效果图品牌营销公司
  • 能发朋友圈的网站建设语百度seo点击排名优化
  • 用台式机做网站服务器网站制作公司
  • 什么学做网站企业宣传方式
  • 哪个网站的课件做的好百度老年搜索
  • 西安做网站费用人员优化方案怎么写
  • 烟台市住房和规划建设管理局网站惠州网站建设方案推广
  • 河海大学学风建设网站广州关于进一步优化疫情防控措施
  • 兼职做页面的网站最近的新闻有哪些
  • 公众号推文制作网站沈阳网站制作优化推广
  • 如何用天地图做网站百度竞价返点一般多少
  • 网站空间和云主机seo信息是什么
  • 网页设计网站怎么放到域名里郑州seo优化哪家好
  • 专业网站建设价格大全怎么推广自己的店铺