/** * 有多少个数据源就要配置多少个bean * @return */ @Bean public AbstractRoutingDataSource roundRobinDataSouceProxy() { int size = Integer.parseInt(dataSourceSize); DynamicDataSource proxy = new DynamicDataSource(size); Map<Object, Object> targetDataSources = new HashMap<>(); // 写 targetDataSources.put(DataSourceType.write.getType(),dataSource); //多个读数据库时 for (int i = 0; i < size; i++) { targetDataSources.put(i, readDataSources.get(i)); } proxy.setDefaultTargetDataSource(dataSource); proxy.setTargetDataSources(targetDataSources); return proxy; }
/** * 有多少个数据源就要配置多少个bean * @return */ @Bean public AbstractRoutingDataSource roundRobinDataSouceProxy() { int size = Integer.parseInt(dataSourceSize); MyAbstractRoutingDataSource proxy = new MyAbstractRoutingDataSource(size); Map<Object, Object> targetDataSources = new HashMap<Object, Object>(); // DataSource writeDataSource = SpringContextHolder.getBean("writeDataSource"); // 写 targetDataSources.put(DataSourceEnums.write.getType(),dataSource); // targetDataSources.put(DataSourceType.read.getType(),readDataSource); //多个读数据库时 for (int i = 0; i < size; i++) { targetDataSources.put(i, readDataSources.get(i)); } proxy.setDefaultTargetDataSource(dataSource); proxy.setTargetDataSources(targetDataSources); return proxy; }
/** * 有多少个数据源就要配置多少个bean * @return */ @Bean public AbstractRoutingDataSource roundRobinDataSouceProxy() { int size = Integer.parseInt(dataSourceSize); MyAbstractRoutingDataSource proxy = new MyAbstractRoutingDataSource(size); Map<Object, Object> targetDataSources = new HashMap<Object, Object>(); // DataSource writeDataSource = SpringContextHolder.getBean("writeDataSource"); //设置写库 targetDataSources.put(DataSourceType.write.getType(),dataSource); // targetDataSources.put(DataSourceType.read.getType(),readDataSource); //设置多读库 for (int i = 0; i < size; i++) { targetDataSources.put(i, readDataSources.get(i)); } proxy.setDefaultTargetDataSource(dataSource); proxy.setTargetDataSources(targetDataSources); return proxy; }
/** * 注入AbstractRoutingDataSource * @param writeDataSource * @param read1DataSource * @param read2DataSource * @return * @throws Exception */ @Bean public AbstractRoutingDataSource routingDataSource( @Qualifier("writeDataSource") DataSource writeDataSource, @Qualifier("read1DataSource") DataSource read1DataSource, @Qualifier("read2DataSource") DataSource read2DataSource ) throws Exception { DynamicDataSource dataSource = new DynamicDataSource(); Map<Object, Object> targetDataSources = new HashMap(); targetDataSources.put(WRITE_DATASOURCE_KEY, writeDataSource); targetDataSources.put(READ1_DATASOURCE_KEY, read1DataSource); targetDataSources.put(READ2_DATASOURCE_KEY, read2DataSource); dataSource.setTargetDataSources(targetDataSources); dataSource.setDefaultTargetDataSource(writeDataSource); return dataSource; }
/** * 根据数据源创建SqlSessionFactory */ @Bean public SqlSessionFactory sqlSessionFactory(AbstractRoutingDataSource routingDataSource) throws Exception { PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean(); factoryBean.setDataSource(routingDataSource);// 指定数据源(这个必须有,否则报错) // 下边两句仅仅用于*.xml文件,如果整个持久层操作不需要使用到xml文件的话(只用注解就可以搞定),则不加 factoryBean.setTypeAliasesPackage("com.tangcheng.datasources.aop.model");// 指定基包 factoryBean.setMapperLocations(resolver.getResources("classpath:mapper/**/*.xml"));// return factoryBean.getObject(); }
@SuppressWarnings("unchecked") @Override public void afterPropertiesSet() { super.afterPropertiesSet(); // 由于父类的resolvedDataSources属性是私有的子类获取不到,需要使用反射获取 Field field = ReflectionUtils.findField(AbstractRoutingDataSource.class, "resolvedDataSources"); field.setAccessible(true); // 设置可访问 try { Map<Object, DataSource> resolvedDataSources = (Map<Object, DataSource>) field.get(this); // 读库的数据量等于数据源总数减去写库的数量 this.slaveCount = resolvedDataSources.size() - 1; for (Map.Entry<Object, DataSource> entry : resolvedDataSources.entrySet()) { if (DynamicDataSourceHolder.MASTER.equals(entry.getKey())) { continue; } slaveDataSources.add(entry.getKey()); } } catch (Exception e) { LOGGER.error("afterPropertiesSet error! ", e); } }
/** * 有多少个数据源就要配置多少个bean * @return */ @Bean(name = "roundRobinDataSouceProxy") public AbstractRoutingDataSource roundRobinDataSouceProxy() { int size = Integer.parseInt(dataSourceSize); MyAbstractRoutingDataSource proxy = new MyAbstractRoutingDataSource(size); Map<Object, Object> targetDataSources = new HashMap<Object, Object>(); DataSource writeDataSource = SpringContextHolder.getBean("writeDataSource"); // 写 targetDataSources.put(DataSourceType.write.getType(), SpringContextHolder.getBean("writeDataSource")); for (int i = 0; i < size; i++) { targetDataSources.put(i, SpringContextHolder.getBean("readDataSource" + (i + 1))); } proxy.setDefaultTargetDataSource(writeDataSource); proxy.setTargetDataSources(targetDataSources); return proxy; }
@SuppressWarnings("unchecked") public static Map<Object, Object> getTargetDataSources() { try { Field field = AbstractRoutingDataSource.class .getDeclaredField("targetDataSources"); field.setAccessible(true); return (Map<Object, Object>) field.get(SpringContextUtils .getBean("dataSource")); } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) { e.printStackTrace(); return null; } }
/** * 注入AbstractRoutingDataSource * @param readDruidDataSource * @param writeDruidDataSource * @return * @throws Exception */ @Bean public AbstractRoutingDataSource routingDataSource( @Qualifier(READ_DATASOURCE_KEY) DataSource readDruidDataSource, @Qualifier(WRITE_DATASOURCE_KEY) DataSource writeDruidDataSource ) throws Exception { DynamicDataSource dataSource = new DynamicDataSource(); Map<Object, Object> targetDataSources = new HashMap(); targetDataSources.put(WRITE_DATASOURCE_KEY, writeDruidDataSource); targetDataSources.put(READ_DATASOURCE_KEY, readDruidDataSource); dataSource.setTargetDataSources(targetDataSources); dataSource.setDefaultTargetDataSource(writeDruidDataSource); return dataSource; }
@Bean public PlatformTransactionManager transactionManager(AbstractRoutingDataSource dataSource) throws Exception { return new DataSourceTransactionManager(dataSource); }
/** * See {@literal http://blog.csdn.net/dream_broken/article/details/72851329} */ @Bean(name="roundRobinDataSouceProxy") public AbstractRoutingDataSource roundRobinDataSouceProxy() { Map<Object, Object> targetDataSources = new HashMap<>(); //把所有数据库都放在targetDataSources中,注意key值要和determineCurrentLookupKey()中代码写的一至, //否则切换数据源时找不到正确的数据源 targetDataSources.put(DataSourceContextHolder.DataSourceType.write.getType(), writeDataSource); targetDataSources.put(DataSourceContextHolder.DataSourceType.read.getType()+"1", readDataSource01); final int readSize = Integer.parseInt(readDataSourceSize); //路由类,寻找对应的数据源 AbstractRoutingDataSource proxy = new AbstractRoutingDataSource(){ private AtomicInteger count = new AtomicInteger(0); /** * 这是AbstractRoutingDataSource类中的一个抽象方法, * 而它的返回值是你所要用的数据源dataSource的key值,有了这个key值, * targetDataSources就从中取出对应的DataSource,如果找不到,就用配置默认的数据源。 */ @Override protected Object determineCurrentLookupKey() { String typeKey = DataSourceContextHolder.getReadOrWrite(); if(typeKey == null){ throw new NullPointerException("数据库路由时,决定使用哪个数据库源类型不能为空..."); } if (typeKey.equals(DataSourceContextHolder.DataSourceType.write.getType())){ return DataSourceContextHolder.DataSourceType.write.getType(); } //读库, 简单负载均衡 int number = count.getAndAdd(1); int lookupKey = number % readSize; return DataSourceContextHolder.DataSourceType.read.getType()+(lookupKey+1); } }; proxy.setDefaultTargetDataSource(writeDataSource);//默认库 proxy.setTargetDataSources(targetDataSources); return proxy; }