首页 > 编程 > Java > 正文

Spring+Mybatis+Mysql搭建分布式数据库访问框架的方法

2019-11-26 10:13:26
字体:
来源:转载
供稿:网友

一、前言

用Java开发企业应用软件, 经常会采用Spring+MyBatis+Mysql搭建数据库框架。如果数据量很大,一个MYSQL库存储数据访问效率很低,往往会采用分库存储管理的方式。本文讲述如何通过Spring+Mybatis构建多数据库访问的架构,并采用多线程提升数据库的访问效率。

需要说明一下,这种方式只适合数据库数量、名称固定,且不是特别多的情况。针对数据库数量不固定的情况,后面再写一篇处理方案。

二、整体方案

这里写图片描述

三、开发环境准备

3.1 下载Spring、Mybatis、Mysql组件。

3.2 Eclipse:Java开发IDE。引入如下jar包:

这里写图片描述

代码结构如下:

这里写图片描述

四、构建数据库集群

在MYSQL中创建11个数据库(test1/2/3/4/5/6/7/8/9/10/11)创建一个简单的表:

这里写图片描述

在test1的tbl_Demo表中插入5千万条数据,其它10个数据库的tbl_Demo表中分别插入5百万条数据(用函数)。

在test1的tbl_Demo表中插入5千万条数据,其它10个数据库的tbl_Demo表中分别插入5百万条数据(用函数)。

五、创建Mybatis数据库映射接口

/** * Mybatis 映射接口 *  * * @author elon * @version 1.0, 2015年10月23日 */public interface IDemo {  public void insertDemo(DemoDAO demo); public List<Integer> selectGroup();}/** *  * Mybatis 映射服务接口 * * @author elon * @version 1.0, 2015年10月23日 */public interface IDemoService{  public void insertDemo(DemoDAO demo); public List<Integer> selectGroup();}/** *  * Mybatis 映射服务实现 * * @author elon * @version 1.0, 2015年10月23日 */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<Integer> selectGroup() {   return idemo.selectGroup(); }}

六、创建数据库标识管理和动态数据源

/** *  * 保存数据库标识。每个线程由独立的对象存储 * * @author elon * @version 1.0, 2015年10月23日 */public class DBIndetifier{  private static ThreadLocal<String> dbKey = new ThreadLocal<String>(); public static void setDBKey(final String dbKeyPara) {   dbKey.set(dbKeyPara); } public static String getDBKey() {  return dbKey.get(); }}/** *  * 动态数据源。可根据不同的数据索引连接不同的数据库 * * @author elon * @version 1.0, 2015年10月23日 */public class DynamicDataSource extends AbstractRoutingDataSource{ @Override public Object determineCurrentLookupKey() {  return DBIndetifier.getDBKey(); }}

七、创建数据库访问对象

/** *  * 数据库访问对象。用于插入数据。 * * @author elon * @version 1.0, 2015年10月23日 */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; }}/** *  * 映射结果定义 * * @author elon * @version 1.0, 2015年10月23日 */public class DemoResult implements Serializable{ /**  * Comment for <code>serialVersionUID</code><br>  *   */ private static final long serialVersionUID = -413001138792531448L; private long sum; public long getSum() {  return sum; } public void setSum(long sum) {  this.sum = sum; } @Override public String toString() {  return String.valueOf(sum); }}

八、创建数据库访问任务

/** * 数据库访问任务定义。将每一个对数据库访问的请求包装为一个任务对象,放到任务管理中, * 然后等待任务执行完成,取出执行结果。 * * @author elon * @version 1.0, 2015年10月23日 */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; }}

九、创建数据库任务管理器

/** * 数据库访问任务管理。将数据库访问任务放到线程池中执行。 *  * * @author elon * @version 1.0, 2015年10月23日 */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<Runnable>(10000),          new ThreadPoolExecutor.CallerRunsPolicy()); } public void excute(Runnable task) {  pool.execute(task); }}

十、创建MyBatis配置文件

10.1 mybatis.xml

<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration> <mappers>  <mapper resource="cfg/demoMapper.xml"/> </mappers></configuration>

10.2 demoMapper.xml

<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.elon.IDemo">  <insert id="insertDemo" parameterType="com.elon.DemoDAO">  insert into tbl_demo(a, b, c) values(#{a}, #{b}, #{c}); </insert> <resultMap id="demoResult" type="com.elon.DemoResult">  <id property="sum" column="sumColum"/> </resultMap> <select id="selectGroup" resultMap="demoResult">  select sum(a) as sumColum from tbl_demo group by c; </select></mapper>

十一、创建Spring配置文件

11.1 spring.xml

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <bean id="dataSource_1" class="org.apache.commons.dbcp.BasicDataSource">  <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>  <property name="url" value="jdbc:mysql://10.70.69.69:3306/test1"></property>  <property name="username" value="user123"></property>  <property name="password" value="user123"></property>  <property name="maxActive" value="100"></property>  <property name="maxIdle" value="30"></property>  <property name="maxWait" value="500"></property>  <property name="defaultAutoCommit" value="true"></property> </bean> <bean id="dataSource_2" class="org.apache.commons.dbcp.BasicDataSource">  <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>  <property name="url" value="jdbc:mysql://10.70.69.69:3306/test2"></property>  <property name="username" value="user123"></property>  <property name="password" value="user123"></property>  <property name="maxActive" value="100"></property>  <property name="maxIdle" value="30"></property>  <property name="maxWait" value="500"></property>  <property name="defaultAutoCommit" value="true"></property> </bean> <bean id="dataSource_3" class="org.apache.commons.dbcp.BasicDataSource">  <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>  <property name="url" value="jdbc:mysql://10.70.69.69:3306/test3"></property>  <property name="username" value="user123"></property>  <property name="password" value="user123"></property>  <property name="maxActive" value="100"></property>  <property name="maxIdle" value="30"></property>  <property name="maxWait" value="500"></property>  <property name="defaultAutoCommit" value="true"></property> </bean> <bean id="dataSource_4" class="org.apache.commons.dbcp.BasicDataSource">  <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>  <property name="url" value="jdbc:mysql://10.70.69.69:3306/test4"></property>  <property name="username" value="user123"></property>  <property name="password" value="user123"></property>  <property name="maxActive" value="100"></property>  <property name="maxIdle" value="30"></property>  <property name="maxWait" value="500"></property>  <property name="defaultAutoCommit" value="true"></property> </bean> <bean id="dataSource_5" class="org.apache.commons.dbcp.BasicDataSource">  <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>  <property name="url" value="jdbc:mysql://10.70.69.69:3306/test5"></property>  <property name="username" value="user123"></property>  <property name="password" value="user123"></property>  <property name="maxActive" value="100"></property>  <property name="maxIdle" value="30"></property>  <property name="maxWait" value="500"></property>  <property name="defaultAutoCommit" value="true"></property> </bean> <bean id="dataSource_6" class="org.apache.commons.dbcp.BasicDataSource">  <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>  <property name="url" value="jdbc:mysql://10.70.69.69:3306/test6"></property>  <property name="username" value="user123"></property>  <property name="password" value="user123"></property>  <property name="maxActive" value="100"></property>  <property name="maxIdle" value="30"></property>  <property name="maxWait" value="500"></property>  <property name="defaultAutoCommit" value="true"></property> </bean> <bean id="dataSource_7" class="org.apache.commons.dbcp.BasicDataSource">  <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>  <property name="url" value="jdbc:mysql://10.61.67.246:3306/test7"></property>  <property name="username" value="user123"></property>  <property name="password" value="user123"></property>  <property name="maxActive" value="100"></property>  <property name="maxIdle" value="30"></property>  <property name="maxWait" value="500"></property>  <property name="defaultAutoCommit" value="true"></property> </bean> <bean id="dataSource_8" class="org.apache.commons.dbcp.BasicDataSource">  <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>  <property name="url" value="jdbc:mysql://10.61.67.246:3306/test8"></property>  <property name="username" value="user123"></property>  <property name="password" value="user123"></property>  <property name="maxActive" value="100"></property>  <property name="maxIdle" value="30"></property>  <property name="maxWait" value="500"></property>  <property name="defaultAutoCommit" value="true"></property> </bean> <bean id="dataSource_9" class="org.apache.commons.dbcp.BasicDataSource">  <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>  <property name="url" value="jdbc:mysql://10.61.67.246:3306/test9"></property>  <property name="username" value="user123"></property>  <property name="password" value="user123"></property>  <property name="maxActive" value="100"></property>  <property name="maxIdle" value="30"></property>  <property name="maxWait" value="500"></property>  <property name="defaultAutoCommit" value="true"></property> </bean> <bean id="dataSource_10" class="org.apache.commons.dbcp.BasicDataSource">  <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>  <property name="url" value="jdbc:mysql://10.61.67.246:3306/test10"></property>  <property name="username" value="user123"></property>  <property name="password" value="user123"></property>  <property name="maxActive" value="100"></property>  <property name="maxIdle" value="30"></property>  <property name="maxWait" value="500"></property>  <property name="defaultAutoCommit" value="true"></property> </bean> <bean id="dataSource_11" class="org.apache.commons.dbcp.BasicDataSource">  <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>  <property name="url" value="jdbc:mysql://10.61.67.246:3306/test11"></property>  <property name="username" value="user123"></property>  <property name="password" value="user123"></property>  <property name="maxActive" value="100"></property>  <property name="maxIdle" value="30"></property>  <property name="maxWait" value="500"></property>  <property name="defaultAutoCommit" value="true"></property> </bean> <bean id="dataSource" class="com.elon.DynamicDataSource">  <property name="targetDataSources">   <map>    <entry key="test1" value-ref="dataSource_1"/>    <entry key="test2" value-ref="dataSource_2"/>    <entry key="test3" value-ref="dataSource_3"/>    <entry key="test4" value-ref="dataSource_4"/>    <entry key="test5" value-ref="dataSource_5"/>    <entry key="test6" value-ref="dataSource_6"/>    <entry key="test7" value-ref="dataSource_7"/>    <entry key="test8" value-ref="dataSource_8"/>    <entry key="test9" value-ref="dataSource_9"/>    <entry key="test10" value-ref="dataSource_10"/>    <entry key="test11" value-ref="dataSource_11"/>   </map>  </property> </bean> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">  <property name="configLocation" value="classpath:cfg/mybatis.xml"></property>  <property name="dataSource" ref="dataSource" /> </bean> <bean id="iDemo" class="org.mybatis.spring.mapper.MapperFactoryBean">  <property name="mapperInterface" value="com.elon.IDemo"></property>  <property name="sqlSessionFactory" ref="sqlSessionFactory"></property> </bean> <bean id="iDemoService" class="com.elon.DemoServiceImpl">  <property name="idemo" ref="iDemo"></property> </bean></beans>

十二、测试代码

public class TestMain{ /**  * 测试代码  *   *  * @param args  */ public static void main(String[] args) {  @SuppressWarnings("resource")  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 task11 = new DBTask("test11", service1, "selectGroup");  DemoDAO demo = new DemoDAO();  demo.setA(10000000);  demo.setB("12121212");  demo.setC(100);  DBTask taskInsert = new DBTask("test2", service1, "insertDemo", demo);  SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  System.out.println("开始插入数据:" + format.format(new Date()));  DBTaskMgr.instance().excute(taskInsert);  while (true)  {   if (!taskInsert.isFinish())   {    try    {     Thread.sleep(1000);    }    catch (InterruptedException e)    {     e.printStackTrace();    }   }   else   {    break;   }  }  System.out.println("插入数据结束:" + format.format(new Date()));  System.out.println("开始查询5千万数据表:" + format.format(new Date()));  DBTaskMgr.instance().excute(task1);  while (true)  {   if (!task1.isFinish())   {    try    {     Thread.sleep(1000);    }    catch (InterruptedException e)    {     e.printStackTrace();    }   }   else   {    break;   }  }  System.out.println(task1.getRetValue());  System.out.println("查询5千万数据表结束:" + format.format(new Date()));  List<DBTask> taskList = new ArrayList<DBTask>();  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);  taskList.add(task11);  System.out.println("开始查询10个5百万数据表:" + format.format(new Date()));  for (DBTask task : taskList)  {   DBTaskMgr.instance().excute(task);  }  while (true)  {   int success = 0;   for (DBTask task : taskList)   {    if (!task.isFinish())    {      try     {      Thread.sleep(1000);     }     catch (InterruptedException e)     {      e.printStackTrace();     }    }    else    {     ++success;    }   }   if (success == 10)   {    break;   }  }  for (DBTask task : taskList)  {   System.out.println(task.getRetValue());;  }  System.out.println("10个5百万数据表查询结束:" +format.format(new Date())); }}

十三、测试结果

这里写图片描述

直接查询一个5千万条数据的数据库用时:45s。

多线程同步查询10个5百万数据的数据库用时: 22s。

由于10个数据库放在两台服务器上,一个服务器5个数据库。如果将10个数据分别部署到10个服务器,效率将更高。

总结

以上所述是小编给大家介绍的Spring+Mybatis+Mysql搭建分布式数据库访问框架,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对武林网网站的支持!

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表