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

电商网站建设案例百度公司怎么样

电商网站建设案例,百度公司怎么样,app设计的基本流程,泰兴做网站的公司使用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.wooajung.com/news/32530.html

相关文章:

  • 网站的安全度亚马逊开店流程及费用
  • 东莞住房和城乡建设网seo智能优化公司
  • 长沙网络营销哪家平台专业seo网站排名优化教程
  • 慈利县建设局网站品牌策划是做什么的
  • 简单做任务赚钱网站百度新闻
  • 帮公司做网站深圳网站页面设计
  • wordpress在页眉加载js某个网站seo分析实例
  • 简网app工场官网注册淄博网站seo
  • 网站侧边 跟随 样式可以进入任何网站的浏览器
  • 1688创业商机网西安seo顾问
  • 桓台网站建设长沙seo顾问
  • 品牌网站的愿望清单怎么做产品推广策划
  • 男女做暖暖不要钱的试看网站建设一个网站的具体步骤
  • 页面编辑wordpress海外seo培训
  • fullpage.js wordpressseo优化一般包括哪些内容()
  • 平台b2c网站semiconductor
  • 日本做a的动画视频在线观看网站报个电脑培训班要多少钱
  • wordpress 屏蔽搜索引擎seo营销优化
  • 域名最新通知网站搜索关键词优化
  • 自己开个网站网页查询
  • 阴阳师网站怎么做优化深圳seo
  • 云南网站建设一条龙郑州网站seo
  • 内网怎么做网站第三方平台推广
  • 学校网站模板常州百度seo排名
  • 放单网站百度云搜索引擎入口 百度网盘
  • 宝鸡网站建设东东中国十大营销策划机构
  • 网站推广费用ihanshi外贸出口平台网站
  • 企业咨询管理师超级推荐的关键词怎么优化
  • 做推广优化的网站有哪些内容百度营销登录
  • 洪梅网站仿做合肥瑶海区