public Pager<Map<String,Object>> queryFlow(Map<String, Object> param, Integer page, Integer pageSize){
String[] sIds = param.get("sId").toString().split(",");
param.put("sIds", param.get("sId"));
List<Map<String,Object>> result = new ArrayList<>();
//单服统计
for (String sId : sIds){
param.put("sId", sId);
try {
result.addAll(statisticsDao.selectFlow(param)) ;
}catch (Exception e){
System.err.println("链接超时区服:-》" + sId);
}
}
//单服统计结果合并
Map<String, List<Map<String, Object>>> slist = result.stream().collect(Collectors.groupingBy(e -> e.get("Id").toString()));
List<Map<String, Object>> finalRes = new ArrayList<>();
slist.forEach((k, slist) -> {
Map<String,Object> nmap=new HashMap<>();
IntSummaryStatistics sumc = slist.stream().collect(Collectors.summarizingInt(e->Integer.valueOf(e.get("uNum").toString())));
nmap.put("Id", slist.get(0).get("Id"));
nmap.put("uNum", sumc.getSum());//求和
finalRes.add(nmap);
});
//list分页
int total = finalRes.size();
Pager<Map<String,Object>> pager = new Pager<>(total,page,pageSize);
int start = pager.getStart() > total ? total : pager.getStart();
int end = page*pageSize > total ? total : page*pageSize;
List<Map<String, Object>> res = finalRes.subList(start, end);
pager.setList(res);
return pager;
}
@ChangeDataSource
List<Map<String,Object>> selectFlow(Map<String, Object> param);
自定义注解
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ChangeDataSource {
String value() default "default";
}
数据源配置
@Configuration
@MapperScan(basePackages = "com.**.dao", sqlSessionFactoryRef = "db1SqlSessionFactory")
public class DataSourceCfg {
@Primary // 表示这个数据源是默认数据源, 这个注解必须要加,因为不加的话spring将分不清楚那个为主数据源(默认数据源)
@Bean("primaryDataSource")
@ConfigurationProperties(prefix = "spring.datasource.db1") //读取application.yml中的配置参数映射成为一个对象
public DataSource getDb1DataSource() {
HikariDataSource datasource = DataSourceBuilder.create().type(HikariDataSource.class).build();
datasource.setIdleTimeout(30000);
datasource.setMaximumPoolSize(60);
datasource.setMinimumIdle(10);
datasource.setMaxLifetime(120000);
//设置默认的数据源
DataSourceCache.put("default", datasource);
ThreadLocalDataSource.setLocalSource("default");
return datasource;
}
/**
* 动态装配所有的数据源
* @param primaryDataSource
* @return
*/
@Bean("dynamicDataSource")
public DynamicChangeDataSourceConfig setDynamicDataSource(@Qualifier("primaryDataSource") DataSource primaryDataSource){
//定义实现了AbstractDataSource的自定义aop切换类
DynamicChangeDataSourceConfig dynamicChangeDataSourceConfig = new DynamicChangeDataSourceConfig();
//设置默认的数据源
dynamicChangeDataSourceConfig.setDefaultTargetDataSource(primaryDataSource);
dynamicChangeDataSourceConfig.setTargetDataSources(DataSourceCache);
return dynamicChangeDataSourceConfig;
}
@Primary
@Bean("db1SqlSessionFactory")
public SqlSessionFactory db1SqlSessionFactory(@Qualifier("dynamicDataSource") DataSource dataSource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
// mapper的xml形式文件位置必须要配置,不然将报错:no statement (这种错误也可能是mapper的xml中,namespace与项目的路径不一致导致)
bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/*.xml"));
return bean.getObject();
}
@Bean
public PlatformTransactionManager transactionManager(DataSource dynamicDataSource) {
return new DataSourceTransactionManager(dynamicDataSource);
}
}
public class DynamicChangeDataSourceConfig extends AbstractRoutingDataSource{
/**
* 定义缓存数据源的变量
*/
public static final Map<Object, Object> DataSourceCache = new ConcurrentHashMap<Object, Object>();
@Override
protected Object determineCurrentLookupKey() {
super.afterPropertiesSet();
return ThreadLocalDataSource.getLocalSource();
}
}
public class ThreadLocalDataSource {
private static final ThreadLocal<String> TYPE = new ThreadLocal<>();
/**
* 修改当前线程内的数据源id
* @param key
*/
public static void setLocalSource(String key){
TYPE.set(key);
}
/**
* 获取当前线程内的数据源类型
* @return
*/
public static String getLocalSource(){
return TYPE.get();
}
/**
* 清空ThreadLocal中的TYPE
*/
public static void clear(){
TYPE.remove();
}
}
注解切换数据源
@Component
@Aspect
@Order(-1 )
public class DataSourceAspect {
@Autowired
private TblGameServerService tblGameServerService;
@Pointcut("@annotation(com.a.DataSourceConfig.ChangeDataSource)")
public void pointCut(){}
@Before(value = "pointCut() && @annotation(changeDataSource)")
public void operateLog(JoinPoint joinPoint, ChangeDataSource changeDataSource){
Object[] args = joinPoint.getArgs();
JSONObject obj = JSONObject.fromObject(args[0]);
String DsKey = obj.get("sId") == null ? null : obj.getString("sId");
if (DsKey == null){
//未传入服务器id参数使用默认数据源
DsKey = changeDataSource.value();
}
try {
initDataSource(DsKey);
} catch (IOException e) {
e.printStackTrace();
}
ThreadLocalDataSource.setLocalSource(DsKey);
}
/**
* 在切入service方法之后执行
* 设置回默认数据源
*/
@After("pointCut()")
public void afterAspect(){
System.err.println("切入方法后,开始切换默认数据源");
ThreadLocalDataSource.clear();
}
/**
* 初始化DataSource
* 当缓存中没有对应的数据源时,需要去默认数据源查询数据库
*
* @param key
* @return
*/
public DataSource initDataSource(String key) throws IOException {
if (DataSourceCache.get(key) != null){ //当前切换数据源是否已缓存,
return (DataSource)DataSourceCache.get(key);
}
HikariDataSource dataSource = new HikariDataSource();
dataSource.setMaxLifetime(15000);
dataSource.setMaximumPoolSize(9);
dataSource.setConnectionTimeout(10000);
dataSource.setIdleTimeout(15000);
//到默认数据库查询服务器信息
ThreadLocalDataSource.setLocalSource("default");
TblServer sDb = tblServerService.queryServerBySId(key);
dataSource.setJdbcUrl(sDb.getDbUrl());
dataSource.setUsername(sDb.getDbUsername());
dataSource.setPassword(sDb.getDbPassword());
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
DataSourceCache.put(key, dataSource);
return dataSource;
}
}