购物商城网站搭建,可以做配音兼职的网站,网上商城如何推广,揭阳做网站设计2019独角兽企业重金招聘Python工程师标准 最近在做保证金余额查询优化#xff0c;在项目启动时候需要把余额全量加载到本地缓存#xff0c;因为需要全量查询所有骑手的保证金余额#xff0c;为了不影响主数据库的性能#xff0c;考虑把这个查询走从库。所以涉… 2019独角兽企业重金招聘Python工程师标准 最近在做保证金余额查询优化在项目启动时候需要把余额全量加载到本地缓存因为需要全量查询所有骑手的保证金余额为了不影响主数据库的性能考虑把这个查询走从库。所以涉及到需要在一个项目中配置多数据源并且能够动态切换。 设计总体思路 Spring-BootAOP方式实现多数据源切换继承AbstractRoutingDataSource实现数据源动态的获取在service层使用注解指定数据源。 步骤 一、多数据源配置 在application.properties中我们的配置是这样的 #主数据源druid.master.urljdbc:mysql://url/masterdb?useUnicodetrueamp;characterEncodingutf8amp;zeroDateTimeBehaviorconvertToNulldruid.master.usernamexxxdruid.master.password123druid.master.driver-class-namecom.mysql.jdbc.Driverdruid.master.max-wait5000druid.master.max-active100druid.master.test-on-borrowtruedruid.master.validation-querySELECT 1#从数据源druid.slave.urljdbc:mysql://url/slavedb?useUnicodetrueamp;characterEncodingutf8amp;zeroDateTimeBehaviorconvertToNulldruid.slave.usernamexxxdruid.slave.password123druid.slave.driver-class-namecom.mysql.jdbc.Driverdruid.slave.max-wait5000druid.slave.max-active100druid.slave.test-on-borrowtruedruid.slave.validation-querySELECT 1读取配置 !-- master数据源 --bean primarytrue idmasterdb classcom.alibaba.druid.pool.DruidDataSource init-methodinit destroy-methodclose!-- 基本属性 url、user、password --property namedriverClassName valuecom.mysql.jdbc.Driver/property nameurl value${druid.master.url}/property nameusername value${druid.master.username}/property namepassword value${druid.master.password}/!-- 配置初始化最大 --property namemaxActive value${druid.master.max-active}/!-- 配置获取连接等待超时的时间 --property namemaxWait value${druid.master.max-wait}/property namevalidationQuery value${druid.master.validation-query}/property nametestOnBorrow value${druid.master.test-on-borrow}//bean!-- slave数据源 --bean primarytrue idslavedb classcom.alibaba.druid.pool.DruidDataSource init-methodinit destroy-methodclose!-- 基本属性 url、user、password --property namedriverClassName valuecom.mysql.jdbc.Driver/property nameurl value${druid.slave.url}/property nameusername value${druid.slave.username}/property namepassword value${druid.slave.password}/!-- 配置初始化大小、最小、最大 --property namemaxActive value${druid.slave.max-active}/!-- 配置获取连接等待超时的时间 --property namemaxWait value${druid.slave.max-wait}/property namevalidationQuery value${druid.slave.validation-query}/property nametestOnBorrow value${druid.slave.test-on-borrow}//bean!-- 动态数据源根据service接口上的注解来决定取哪个数据源 --bean iddataSource classdatasource.DynamicDataSourceproperty nametargetDataSourcesmap key-typejava.lang.Stringentry keyslave value-refslavedb/entry keymaster value-refmasterdb//map/propertyproperty namedefaultTargetDataSource refmasterdb//bean!-- Spring JdbcTemplate --bean idjdbcTemplate classorg.springframework.jdbc.core.JdbcTemplateproperty namedataSource refdataSource //bean!-- Spring事务管理器 --bean idtransactionManager classorg.springframework.jdbc.datasource.DataSourceTransactionManagerproperty namedataSource refdataSource //beanbean idtransactionTemplate classorg.springframework.transaction.support.TransactionTemplateproperty nametransactionManager reftransactionManager//beantx:annotation-driven transaction-managertransactionManager proxy-target-classtrue order2 /!-- depositdbSqlSessionFactory --bean idsqlSessionFactory classorg.mybatis.spring.SqlSessionFactoryBeanproperty namedataSource refdataSource /property namemapperLocations valueclasspath*:mapper-xxdb/*Mapper*.xml //beanbean classorg.mybatis.spring.mapper.MapperScannerConfigurerproperty namebasePackage valuexxdb.mapper/property namesqlSessionFactoryBeanName valuesqlSessionFactory//bean二. 数据源动态切换类 动态数据源切换是基于AOP的所以我们需要声明一个AOP切面并在切面前做数据源切换切面完成后移除数据源名称。 Order(1) //设置AOP执行顺序(需要在事务之前否则事务只发生在默认库中)AspectComponentpublic class DataSourceAspect {private Logger logger LoggerFactory.getLogger(this.getClass());//切点Pointcut(execution(* com.xxx.service.*.*(..)))public void aspect() { }Before(aspect())private void before(JoinPoint point) {Object target point.getTarget();String method point.getSignature().getName();Class? classz target.getClass();// 获取目标类Class?[] parameterTypes ((MethodSignature) point.getSignature()).getMethod().getParameterTypes();try {Method m classz.getMethod(method, parameterTypes);if (m ! null m.isAnnotationPresent(MyDataSource.class)) {MyDataSource data m.getAnnotation(MyDataSource.class);logger.info(method :{},datasource:{},m.getName() ,data.value().getName());JdbcContextHolder.putDataSource(data.value().getName());// 数据源放到当前线程中}} catch (Exception e) {logger.error(get datasource error ,e);//默认选择masterJdbcContextHolder.putDataSource(DataSourceType.Master.getName());// 数据源放到当前线程中}}AfterReturning(aspect())public void after(JoinPoint point) {JdbcContextHolder.clearDataSource();}}三、数据源管理类 public class JdbcContextHolder {private final static ThreadLocalString local new ThreadLocal();public static void putDataSource(String name) {local.set(name);}public static String getDataSource() {return local.get();}public static void clearDataSource() {local.remove();}}四、动态数据源 spring为我们提供了AbstractRoutingDataSource即带路由的数据源。继承后我们需要实现它的determineCurrentLookupKey()该方法用于自定义实际数据源名称的路由选择方法由于我们将信息保存到了ThreadLocal中所以只需要从中拿出来即可。 public class DynamicDataSource extends AbstractRoutingDataSource {private Logger logger LoggerFactory.getLogger(this.getClass());Overrideprotected Object determineCurrentLookupKey() {String dataSource JdbcContextHolder.getDataSource();logger.info(数据源为{},dataSource);return dataSource;}}五、数据源注解和枚举 我们切换数据源时一般都是在调用具体接口的方法前实现所以我们定义一个方法注解当AOP检测到方法上有该注解时根据注解中value对应的名称进行切换。 Retention(RetentionPolicy.RUNTIME)Target(ElementType.METHOD)public interface MyDataSource {DataSourceType value();}public enum DataSourceType {// 主表Master(master),// 从表Slave(slave);private String name;private DataSourceType(String name) {this.name name;}public String getName() {return name;}public void setName(String name) {this.name name;}}六、切点注解 由于我们的动态数据源配置了默认库所以如果方法是操作默认库的可以不需要注解如果要操作非默认数据源我们需要在方法上添加MyDataSource(数据源名称)注解这样就可以利用AOP实现动态切换了 Componentpublic class xxxServiceImpl {Resourceprivate XxxMapperExt xxxMapperExt;MyDataSource(value DataSourceType.Slave)public ListObject getAll(){return xxxMapperExt.getAll();}}转载于:https://my.oschina.net/stephenzhang/blog/1786156