前言
数据库信息查询是大家最经常见到的工作问题。一般是单线程顺序查询,这样查询总时间是所有查询时间之和,消耗时间较长。如果采用多线程并行查询,则时间变成单个功能查询时间最长的。时间大大缩短。依据阿里开发规范,要重新ThreadPoolExecutor线程池,提高可控性。数据库查询还需要活动线程执行完的返回值,这样就不但要重新ThreadPoolExecutor,还得重新CallAble还获得返回值(RunAble不支持获得返回值)。下面给大家介绍一种优雅简洁实现上面功能的例子。
场景:实现多线程并发并获得返回值
代码:
因为大家contorller和dao层都很熟悉了,我这也不涉及他们的改变,就先省略。直接写需要改变的serviceImpl。
serviceImpl层:
package com.asiainfo.cem.uaa.service;
import com.asiainfo.cem.common.util.ParallelUtil;
import com.asiainfo.cem.common.util.ParallelUtil.ParallelJob;
import com.asiainfo.cem.uaa.common.UaaConstants;
import com.asiainfo.cem.uaa.domain.LoginUserDTO;
import com.asiainfo.cem.uaa.domain.SysUser;
import com.asiainfo.cem.uaa.dao.SysPermissionDao;
import com.asiainfo.cem.uaa.dao.SysRoleDao;
import com.asiainfo.cem.uaa.dao.SysUserDao;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
/**
*@program: cem
*@description:
*@author: houzf
*/
@Service
public class UserServiceDetail implements UserDetailsService {
@Autowired
private SysUserDao sysUserDao;
@Autowired
private SysRoleDao sysRoleDao;
@Autowired
private SysPermissionDao sysPermissionDao;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
SysUser userDO = sysUserDao.findByUsername(username);
if (userDO == null) {
throw new UsernameNotFoundException(MessageFormat.format("{0} is empty.", username));
}
ParallelJob> getRoleCodeByUserNameJob = new ParallelJob>()
.setFunction(() -> sysRoleDao.getRoleCodeByUserName(username));
ParallelJob> getPermissionByUserNameJob = new ParallelJob>()
.setFunction(() -> sysPermissionDao.getPermissionByUserName(username));
ParallelJob> getPermissionCodeByUserNameJob = new ParallelJob>()
.setFunction(() -> sysPermissionDao.getPermissionCodeByUserName(username));
ParallelUtil.execute(getRoleCodeByUserNameJob, getPermissionByUserNameJob,getPermissionCodeByUserNameJob);
Setroles=getRoleCodeByUserNameJob.getResutl();
HashMap map=new HashMap(roles.size());
if (roles.size()!=0){
for (String roleCode:roles){
ListpermissionCodeList=new ArrayList<>();
if(UaaConstants.ADMIN.equals(roleCode)||UaaConstants.SUPADMIN.equals(roleCode)){
permissionCodeList.add(UaaConstants.ALL_PERMISSION);
}else {
permissionCodeList = sysPermissionDao.getPermissionByRoleCode(roleCode);
}
map.put(roleCode,permissionCodeList);
}
}
LoginUserDTO loginUserDTO = new LoginUserDTO()
.setPermissionCodes(getPermissionCodeByUserNameJob.getResutl())
.setRoles(roles)
.setRoleAndPermissions(map)
.setUser(userDO);
return loginUserDTO;
}
}
这个是并发任务关键工具类,主要是用泛型和线程池,优雅简洁的解决问题。可以通用于整个项目。
Util:
package com.asiainfo.cem.common.util;
import java.util.Arrays;
import java.util.function.Supplier;
import lombok.Data;
import lombok.NonNull;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;
/**
*@program: cem-service
*@description: 并行任务工具类
*@author: houzf
*/
@Slf4j
public class ParallelUtil {
@FunctionalInterface
public interface ParallelFunction extends Supplier {
}
@Data
@Accessors(chain = true)
public static class ParallelJob {
private ParallelFunction function;
private T resutl;
}
public static void execute(@NonNull ParallelJob... jobs) {
Arrays.stream(jobs).parallel().forEach(job ->
job.setResutl(job.getFunction().get())
);
}
}
再举一个serviceImpl例子
package com.asiainfo.cem.governmental.service.impl;
import com.asiainfo.cem.common.domain.CommonResult;
import com.asiainfo.cem.common.util.ParallelUtil;
import com.asiainfo.cem.common.utils.GetPointSetUtil;
import com.asiainfo.cem.common.utils.PageUtil;
import com.asiainfo.cem.common.utils.StringUtil;
import com.asiainfo.cem.governmental.dao.CemGovernmentalDataMapper;
import com.asiainfo.cem.governmental.domain.dto.GovernmentalScoreInfo;
import com.asiainfo.cem.governmental.domain.query.GovernmentalQueryAllScoreParam;
import com.asiainfo.cem.governmental.domain.query.GovernmentalQueryAllScoreCountParam;
import com.asiainfo.cem.governmental.domain.vo.GovernmentalQueryAllScoreVo;
import com.asiainfo.cem.governmental.service.interfaces.ICemGovernmentalServiceCSV;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.sql.Timestamp;
import java.util.concurrent.*;
@Service
@Transactional
@Slf4j(topic = "Governmental-PERCEPTION")
public class ICemGovernmentalServiceCSVImpl implements ICemGovernmentalServiceCSV {
private static final Logger logger = LoggerFactory.getLogger("GOVERNMENTAL_THREAD_TASK");
@Autowired
private CemGovernmentalDataMapper cemGovermentalDaoMapper;
private static ExecutorService threadPool;
/**
* @param params
* @description:查询政企客户满意度相关评分
* @return: {@link CommonResult}
* @author houzf
*/
@Override
public CommonResult queryAllPerceptionScore(GovernmentalQueryAllScoreVo params) {
Integer pageNum = 1;
if (!StringUtil.isBlank(params.getPageNum())) {
pageNum = Integer.valueOf(params.getPageNum());
}
Integer pageSize = Integer.valueOf(params.getPageSize());
String order = params.getOrder();
String p1 = params.getP1();
String p2 = params.getP2();
String p3 = params.getP3();
String p4 = params.getP4();
Timestamp startTime = Timestamp.valueOf(params.getStartTime() + " 00:00:00");
Timestamp endTime = Timestamp.valueOf(params.getStartTime() + " 23:59:59");
Integer pageIndex = (pageNum - 1) * pageSize;
String[] points = GetPointSetUtil.lngLatSwap(new String[]{p1, p2, p3, p4});
double[] pointSetScope = GetPointSetUtil.
getPointSetScope(new String[]{points[0], points[1], points[2], points[3]});
double maxLongitude = pointSetScope[0];
double minLongitude = pointSetScope[1];
double maxLatitude = pointSetScope[2];
double minLatitude = pointSetScope[3];
GovernmentalQueryAllScoreCountParam perceptionQueryAllScoreCountParam =
GovernmentalQueryAllScoreCountParam.builder()
.maxLongitude(maxLongitude)
.minLongitude(minLongitude)
.maxLatitude(maxLatitude)
.minLatitude(minLatitude)
.startTime(startTime)
.endTime(endTime)
.build();
GovernmentalQueryAllScoreParam perceptionQueryAllScoreParam =
GovernmentalQueryAllScoreParam.builder()
.maxLongitude(maxLongitude)
.minLongitude(minLongitude)
.maxLatitude(maxLatitude)
.minLatitude(minLatitude)
.startTime(startTime)
.endTime(endTime)
.pageSize(pageSize)
.pageIndex(pageIndex)
.order(order)
.build();
//并行查询
ParallelUtil.ParallelJob total
= new ParallelUtil.ParallelJob().setFunction(() ->
cemGovermentalDaoMapper.getQueryAllPerceptionScoreListCount(perceptionQueryAllScoreCountParam));
ParallelUtil.ParallelJob> dataList
= new ParallelUtil.ParallelJob>().setFunction(() ->
cemGovermentalDaoMapper.queryAllPerceptionScore(perceptionQueryAllScoreParam));
ParallelUtil.execute(total, dataList);
PageUtil pageUtil = new PageUtil<>();
pageUtil.setPageNum(pageNum);
pageUtil.setPageSize(pageSize);
pageUtil.setTotal(Integer.valueOf(total.getResutl()));
pageUtil.setData(dataList.getResutl());
pageUtil.getPageCount();
pageUtil.setCurrentTime(System.currentTimeMillis());
return CommonResult.ok(pageUtil);
}
}
主要就是看“//并行查询 ”下面一块。可以用任意类型的返回值,如Integer或者List。
如果帮助到了您,麻烦关注,点赞,收藏,三连。
您的肯定,是我的动力。祝中华民族早日复兴!谢谢大家。
؏؏☝ᖗ乛◡乛ᖘ☝؏؏