java简单搭建分布式架构

一般来说,数据库的数据过多,查询效率就很慢,这时候我们如果把表分库到不同的数据库,这时候访问速度就会快很多,如果并且采用多线程去访问的话,查询速度也会提高的更快,我这里是运行内存8核电脑进行测试的单个访问mysql数据库的200万数据,时间在8秒左右,但是把表分到10个数据库里面,每张表20万,总共也是200万,并且采用多线程访问,这里只需要3-5秒左右,下面是代码:java简单搭建分布式架构_第1张图片

jar包

java简单搭建分布式架构_第2张图片

数据库:这里我们知道我是把所有数据库都放到一个一个服务器里面,当我们有两个服务器,相当于每个服务器是5个数据库,访问效率会更高,如果在往上加,效率就会更低,但是服务器成本也高。

java简单搭建分布式架构_第3张图片java简单搭建分布式架构_第4张图片

/**
 * 
 */
package com.liuchaojun;

/**
 * @author liuchaojun  数据库访问对象。用于插入数据。
 * @date 2018-3-20 上午10:06:11 
 */
public class DemoDAO
{
    private int a;
    private String b;
    private int c;

    public int getA()
    {
        return a;
    }
    public void setA(int a)
    {
        this.a = a;
    }
    public String getB()
    {
        return b;
    }
    public void setB(String b)
    {
        this.b = b;
    }
    public int getC()
    {
        return c;
    }
    public void setC(int c)
    {
        this.c = c;
    }
}
 /* 
 */
package com.liuchaojun;

/**
 * @author liuchaojun 保存数据库标识。每个线程由独立的对象存储
 * @date 2018-3-20 上午10:05:13 
 */
public class DBIndetifier
{   
    private static ThreadLocal dbKey = new ThreadLocal();

    public static void setDBKey(final String dbKeyPara)
    {   
        dbKey.set(dbKeyPara);
    }

    public static String getDBKey()
    {
        return dbKey.get();
    }
}
/**
 * 
 */
package com.liuchaojun;

import java.lang.reflect.Method;

/**
 * 数据库访问任务定义。将每一个对数据库访问的请求包装为一个任务对象,放到任务管理中, 然后等待任务执行完成,取出执行结果。
 * 
 * @author liuchaojun
 */
public class DBTask implements Runnable {
	// 操作数据库标识,用于指定访问的数据库。与spring配置文件中的数据动态数据源定义一致。
	private final String dbKey;

	// mybatis数据库访问对象
	private final Object dbAccessObject;

	// mysbatis数据库访问方法名称,用于反射调用
	private final String methodName;

	// 存储可变参数的值
	private final Object[] paraArray;

	// 存储可变参数类型
	@SuppressWarnings("rawtypes")
	private final Class[] paraClassArray;

	// 数据库操作结果。查询操作返回查询结果; 插入、删除、修改操作返回null。
	private Object operateResult;

	// 操作数据库抛出的异常信息
	private Exception exception;

	// 标识任务是否已经执行
	private boolean finish;

	/**
	 * 构造函数
	 * 
	 * @param dbKey
	 *            数据库标识
	 * @param dbAccessObject
	 *            数据库访问对象
	 * @param methodName
	 *            数据库访问方法名称
	 * @param paraArray
	 *            参数列表
	 */
	public DBTask(final String dbKey, final Object dbAccessObject,
			final String methodName, final Object... paraArray) {
		this.dbKey = dbKey;
		this.dbAccessObject = dbAccessObject;
		this.methodName = methodName;
		this.paraArray = paraArray;
		finish = false;
		exception = null;

		paraClassArray = new Class[paraArray.length];
		for (int index = 0; index < paraArray.length; ++index) {
			paraClassArray[index] = paraArray[index].getClass();
		}

		operateResult = null;
	}

	/**
	 * 
	 * 任务执行函数
	 * 
	 */
	@Override
	public void run() {
		try {
			DBIndetifier.setDBKey(dbKey);
			Method method = dbAccessObject.getClass().getMethod(methodName,
					paraClassArray);

			// 查询操作返回查询结果; 插入、删除、修改操作返回null
			operateResult = method.invoke(dbAccessObject, paraArray);
		} catch (Exception e) {
			exception = e;
			e.printStackTrace();
		}

		finish = true;
	}

	/**
	 * 
	 * 返回操作结果。查询操作返回查询结果; 插入、删除、修改操作返回null
	 * 
	 * @return 操作结果
	 */
	public Object getRetValue() {
		return operateResult;
	}

	/**
	 * 抛出数据库操作异常
	 * 
	 * @return 异常
	 */
	public Exception getException() {
		return exception;
	}

	/**
	 * 
	 * 返回任务是否已执行
	 * 
	 * @return 标记
	 */
	public boolean isFinish() {
		return finish;
	}
}
/**
 * 
 */
package com.liuchaojun;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author liuchaojun 数据库访问任务管理。将数据库访问任务放到线程池中执行。
 * @date 2018-3-20 上午10:07:58
 */
public class DBTaskMgr {
	private static class DBTaskMgrInstance {
		public static final DBTaskMgr instance = new DBTaskMgr();
	}

	public static DBTaskMgr instance() {
		return DBTaskMgrInstance.instance;
	}

	private ThreadPoolExecutor pool;

	public DBTaskMgr() {
		pool = new ThreadPoolExecutor(10, 50, 60, TimeUnit.SECONDS,
				new ArrayBlockingQueue(10000),
				new ThreadPoolExecutor.CallerRunsPolicy());
	}

	public void excute(Runnable task) {
		pool.execute(task);
	}
}
/**
 * 
 */
package com.liuchaojun;

import java.io.Serializable;

/**
 * @author liuchaojun 映射结果定义
 * @date 2018-3-20 上午10:06:39 
 */
public class DemoResult implements Serializable
{
    /**
     * Comment for serialVersionUID
* */ private static final long serialVersionUID = -413001138792531448L; private DemoDAO demoDAO; /** * @return the demoDAO */ public DemoDAO getDemoDAO() { return demoDAO; } /** * @param demoDAO the demoDAO to set */ public void setDemoDAO(DemoDAO demoDAO) { this.demoDAO = demoDAO; } }
package com.liuchaojun;

import java.util.List;

/**
 * @author liuchaojun Mybatis 映射服务实现
 * @date 2018-3-20 上午09:50:26 
 */
public class DemoServiceImpl implements IDemoService
{
    private IDemo idemo = null;

    public void setIdemo(IDemo idemo) {
        this.idemo = idemo;
    }

    @Override
    public void insertDemo(DemoDAO demo)
    {
        idemo.insertDemo(demo);
    }

    @Override
    public List selectGroup()
    {   
        return idemo.selectGroup();
    }
}

package com.liuchaojun;

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

/**
 * @author liuchaojun 动态数据源。可根据不同的数据索引连接不同的数据库
 * @date 2018-3-20 上午10:05:48 
 */
public class DynamicDataSource extends AbstractRoutingDataSource
{
    @Override
    public Object determineCurrentLookupKey()
    {
        return DBIndetifier.getDBKey();
    }
}
package com.liuchaojun;

import java.util.List;

/**
 * @author liuchaojun Mybatis 映射接口
 * @date 2018-3-20 上午09:44:03 
 */
public interface IDemo 
{   
    public void insertDemo(DemoDAO demo);
    public List selectGroup();
}
package com.liuchaojun;

import java.util.List;

/**
 * @author liuchaojun Mybatis 映射服务接口
 * @date 2018-3-20 上午09:45:34 
 */
public interface IDemoService
{   
    public void insertDemo(DemoDAO demo);
    public List selectGroup();
}
package com.liuchaojun;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author liuchaojun
 * @date 2018-3-20 上午10:09:12
 */
public class TestMain {
	/**
	 * 测试代码
	 * 
	 * @param args
	 */
	public static void main(String[] args) {
		ApplicationContext context = new ClassPathXmlApplicationContext(
				"cfg/spring.xml");
		IDemoService service1 = (IDemoService) context.getBean("iDemoService");

		// 创建任务对象
		DBTask task1 = new DBTask("test1", service1, "selectGroup");
		DBTask task2 = new DBTask("test2", service1, "selectGroup");
		DBTask task3 = new DBTask("test3", service1, "selectGroup");
		DBTask task4 = new DBTask("test4", service1, "selectGroup");
		DBTask task5 = new DBTask("test5", service1, "selectGroup");
		DBTask task6 = new DBTask("test6", service1, "selectGroup");
		DBTask task7 = new DBTask("test7", service1, "selectGroup");
		DBTask task8 = new DBTask("test8", service1, "selectGroup");
		DBTask task9 = new DBTask("test9", service1, "selectGroup");
		DBTask task10 = new DBTask("test10", service1, "selectGroup");
		DBTask task_single = new DBTask("test_single", service1, "selectGroup");

		// 单个线程直接查询单表
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		DBTaskMgr.instance().excute(task_single);
		System.out.println("开始查询test_single表中的200万数据:"+ format.format(new Date()));
		while (true) {
			if (!task_single.isFinish()) {
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			} else {
				break;
			}
		}
		System.out.println("结束查询test_single表中的200万数据结束:"+ format.format(new Date()));

		// 多个线程查询多个数据库中的表数据
		List taskList = new ArrayList();
		taskList.add(task1);
		taskList.add(task2);
		taskList.add(task3);
		taskList.add(task4);
		taskList.add(task5);
		taskList.add(task6);
		taskList.add(task7);
		taskList.add(task8);
		taskList.add(task9);
		taskList.add(task10);
		for (DBTask task : taskList) {
			DBTaskMgr.instance().excute(task);
		}
		System.out.println("开始查询10个数据库中的t_test_table表中的20万数据表:"+ format.format(new Date()));
		while (true) {
			int success = 0;
			for (DBTask task : taskList) {
				if (!task.isFinish()) { // 运行线程run方法这里为false,没有运行择true
					continue;
				} else {
					++success;
				}
			}
			if (success == 10) {
				break;
			}
		}
        System.out.println("结束查询10个数据库中的t_test_table表中的20万数据表:"+ format.format(new Date()));
	}
}
demoMapper.xml
 
  
  
 
    
    
        insert into t_test_table(a, b, c) values(#{a}, #{b}, #{c});
    

    
        
        
        
    
 

    
mybatis.xml
  
 
    
    
        insert into t_test_table(a, b, c) values(#{a}, #{b}, #{c});
    

    
        
        
        
    
 

    


spring.xml




    
        
    



    
        
        
        
        
        
        
        
        
    

    
        
        
        
        
        
        
        
        
    

    
        
        
        
        
        
        
        
        
    

    
        
        
        
        
        
        
        
        
    

    
        
        
        
        
        
        
        
        
    

    
        
        
        
        
        
        
        
        
    


    
        
        
        
        
        
        
        
        
    

    
        
        
        
        
        
        
        
        
    

    
        
        
        
        
        
        
        
        
    

    
        
        
        
        
        
        
        
        
    

    
        
        
        
        
        
        
        
        
    

    
        
            
                
                
                
                
                
                
                
                
                
                
                
            
        
    

    
        
        
    

    
        
        
    

    
        
    

数据表的批量插入数据存储过程:
DROP PROCEDURE IF EXISTS pro_test1_insert;
DELIMITER //
CREATE PROCEDURE pro_test1_insert(cnt int)
  BEGIN 
    DECLARE i int DEFAULT 0;
    START TRANSACTION;
    WHILE i
      DO 
          INSERT INTO t_test_table(b,c) VALUES(i,'168');
      set i=i+1;
      end WHILE;
    COMMIT;
    end //
DELIMITER;

CALL pro_test1_insert(1000000);
 
  

项目源代码资源下载地址:https://download.csdn.net/download/qq_27026603/10298566

你可能感兴趣的:(java简单搭建分布式架构)