spring mybatis的多线程查询功能

最近几天写我的自己的项目的时候用到数据的实例化,这个要求多张表查询数据源,当时我是想的直接按照顺序进行查询然后在通过map集合返回到前台,但是感觉这样数据量一高 估计前端等待时间有点久。所以我想起用多线程的方式去同时查询数据返回。

* 类名称:ThreadPoolUtil    
 * 类描述:线程池查询    
 * 创建人:fulln    
 * 创建时间:2018年1月25日 下午7:15:22          
 * @version     
 *     
 */
public  class ThreadPoolUtil{
	

	private static final Logger  log = Logger.getLogger(ThreadPoolUtil.class);
	
	ThreadPoolExecutor executor = new ThreadPoolExecutor(5,8, 3000, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(2000)) {
		  protected void afterExecute(Runnable r, Throwable t) {   
		        super.afterExecute(r, t);   
		        printException(r, t);   
		    }   
	};

	LinkedBlockingQueue<Runnable> queue = (LinkedBlockingQueue<Runnable>) executor.getQueue();
	
	List<ThreadEntity> li = new ArrayList<ThreadEntity>();//查询的参数list
	
	Method refle ;

public void getStart() {
		
		Integer countTool = li.size();//决定要启动的线程数量
		
		final CountDownLatch countDownLatch = new CountDownLatch(countTool);//线程计数器
		
		final List<ThreadEntity> Threadli = new ArrayList<ThreadEntity>();//查询的参数list
		
		Threadli.addAll(li);
		
		for ( int i =0 ;i<Threadli.size();i++) {//开始开辟线程
	
		final Object  oc = ApplicationContextProvider.getBean(Threadli.get(i).getClazz());
		Map<String,Object> map = new HashMap<String, Object>();
		List<Object> resultli = new ArrayList<>();

		Class<? extends Object> tgg =  oc.getClass();
		Method[] me = tgg.getDeclaredMethods();
		String name = Threadli.get(i).getMethodName();
		map = Threadli.get(i).getCondition();
		
		for (Method method : me) {
			if(name!=null && method.getName().equals(name)) {
				if(!method.isAccessible()) { //判断是不是公共方法
					method.setAccessible(true);
				}
				Parameter[] p =  method.getParameters();
				for (int j = 0; j < (p==null?0:p.length); j++) { //  将参数全部取出来
					for (Entry<String, Object> e :map.entrySet()) {
					
						if( e.getKey().equals(p[j].getName())) {//1.8提供的新方法可以取出参数名
							resultli.add(e.getValue());
						} 
					}
				}
				setRefle(method);
			}
		}
				executor.execute(new Runnable() {
					@Override
					public void run() {
									meta(oc,resultli.toArray());
									countDownLatch.countDown();
					}
				});
		}
		
		try {
			countDownLatch.await();
			found();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
			
	}

public void meta(Object oc, Object[] objects) {}

public void found() {}

private static void printException(Runnable r, Throwable t) { 
    if (t == null && r instanceof Future<?>) {   
        try {   
            Future<?> future = (Future<?>) r;   
            if (future.isDone())   
                future.get();   
        } catch (CancellationException ce) {   
            t = ce;   
        } catch (ExecutionException ee) {   
            t = ee.getCause();   
        } catch (InterruptedException ie) {   
            Thread.currentThread().interrupt(); // ignore/reset   
        }   
    }   
    if (t != null)   
        log.error(t.getMessage(), t);   
}

		public Method getRefle() {
			return refle;
		}

		public void setRefle(Method refle) {
			this.refle = refle;
		}

		public List<ThreadEntity> getLi() {
			return li;
		}
}
这个是util类,要想完成功能还要一个类去继承它

/**    
 *     
 * 项目名称:QueryDAO    
 * 类名称:ThreadDemo    
 * 类描述:一个多线程连接的sql查询demo
 * 创建人:fulln    
 * 创建时间:2018年1月22日 上午11:17:06          
 * @version     
 *     
 */
public class ThreadDemo extends ThreadPoolUtil{
	
	private WideCls<?> wide;
	
	public WideCls<?> getWide() {
		return wide;
	}

	public void setWide(WideCls<?> wide) {
		this.wide = wide;
	}
	
	
	ConcurrentLinkedQueue<User> cqli = new ConcurrentLinkedQueue<User>();//线程安全的list集合
	
	List<User> usLi = new ArrayList<User>();//装载list返回值集合
	
	/**
	 * setCondition(设置传入的参数)     
	 * TODO()     
	 * @param name
	 * @param clazz
	 * @param map
	 * void
	 * 2018-01-25
	 */
		public void setCondition(String name,Class<?> clazz,Map<String,Object> map) {
			usLi = new ArrayList<User>();
			ThreadEntity tey = new ThreadEntity();
			tey.setMethodName(name);
			tey.setClazz(clazz);
			tey.setCondition(map);
			getLi().add(tey);
		}
	
	
	@Override
	public void meta(Object oc, Object[] objects) {
		
		try {
			User u = (User)getRefle().invoke(oc, objects);
			cqli.add(u);
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	
	

	@Override
	public void found() {
		usLi.addAll(cqli);
	}
	
	public List<User> getUsLi() {
		return usLi;
	}
	public void setUsLi(List<User> usLi) {
		this.usLi = usLi;
	}
	
}
然后是测试类
	
	@Test
	public void testThread() {
		ThreadDemo t = new ThreadDemo();
		t.setWide(new WideCls<User>());
		
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("tableName", "user_emp");
		map.put("userId",1);
		t.setCondition("findUserByUserid", regService.getClass(), map);
		t.setCondition("findUserByName", regService.getClass(), map);
		t.getStart();
		List<User> li =  t.getUsLi();//获得结果值
		for (User user : li) {
			System.out.println(user);
		}
	}

参数实体类

public class ThreadEntity{
	private String MethodName;
	
	private Class<?> clazz;
	
	private  Map<String, Object> condition;
	
	public String getMethodName() {
		return MethodName;
	}
	public void setMethodName(String methodName) {
		MethodName = methodName;
	}
	public Class<?> getClazz() {
		return clazz;
	}
	public void setClazz(Class<?> clazz) {
		this.clazz = clazz;
	}
	public Map<String, Object> getCondition() {
		return condition;
	}
	public void setCondition(Map<String, Object> condition) {
		this.condition = condition;
	}

	
//	public T getConditionEntity() {
//		return conditionEntity;
//	}
//	public void setConditionEntity(T conditionEntity) {
//		this.conditionEntity = conditionEntity;
//	}

}


讲下写的时候遇见的问题

1,我写第一个demo的时候是直接用的dao层,这导致了一个问题, 我后来想去抽离实体 泛型的时候  dao层写不了反射,因为我用的mybatis注解,dao层直接连接orm了,这样耦合度就有点高了

2.我改用service层后。开始用反射的形式来抽离代码,发现invoke()不能成功,dao层显示为null, 这里我知道是没有引入spring的bean,然后改用获取ApplicationContext的形式获取class对象

@Component
public class ApplicationContextProvider implements ApplicationContextAware{

	private static ApplicationContext applicationContext;
	
    public static Object getBean(String name){
        return getApplicationContext().getBean(name);
    }

    public static <T> T getBean(Class<T> clazz){
        return getApplicationContext().getBean(clazz);
    }


    public static <T> T getBean(String name,Class<T> clazz){
        return getApplicationContext().getBean(name, clazz);
    }
	
	public static ApplicationContext getApplicationContext() {
		return applicationContext;
	}

	@Override
	public  void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		// 
		 this.applicationContext  = applicationContext;
	}

}
直接获取了spring里面的对象后才行

3.当我开启线程时发现主线程等待,threadpoolexcuter 一直处于inwork,debug模式下跳转afterExecute()方法,后面进入死循环出不来,然后在网上找原因,看到一篇说要重写afterExecute()方法的,不然错误在子线程被捕获传入exception类中出不来。这个方法实行后发现并没有报错,我百度了很久,一直没有头绪,最后我想到个方法,因为一开始我用dao层写的时候是能够开启多线程查询的,我开始注释多线程方法里面的代码,看到底是哪一块导致了线程的等待,于是发现我的excute方法在2个for循环里面,虽然我在第二个for循环里面写了条件,满足条件才能开启线程,但是他还是显示是这个多for循环的问题, 于是我将excute提出到最外层for循环中,运行成功。

4. 目前最大的问题是泛型的问题。 由此我只能用map的形式来接受条件,我想象中的最终版本是暴露借口填参数的形式,但是能力问题,一直不能解决泛型实体类,泛型实体类里面的泛型list,泛型queue,invoke的方法返回的类型也没能够用泛型的形式去接收。那就只能在demo中多写一系列代码,这很不爽,我这么懒的人也只能将就,等以后技术好点了再去改。


参考文章:

http://www.jb51.net/article/47300.htm

http://blog.csdn.net/ljy_super/article/details/78813516

http://www.cnblogs.com/dolphin0520/p/3920397.html

http://blog.csdn.net/lexuansweet/article/details/72366877

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值