Spring+Mybatis+Mysql搭建分布式数据库访问框架的方法
作者:ElonII 发布时间:2024-01-19 07:46:18
一、前言
用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搭建分布式数据库访问框架网站的支持!
来源:http://blog.csdn.net/ylforever/article/details/49430603


猜你喜欢
- 前记在Python中, Dict是一系列由键和值配对组成的元素的集合, 它是一个可变容器模型,可以存储任意类型对象. Dict的存取速度非常
- 一、常见反爬机制及其破解方式封禁IP,使用cookie等前面文章已经讲过现在主要将下面的:~ 验证码 —> 文字验证码 —> O
- 本文实例为大家分享了python+tkinter实现学生管理系统的具体代码,供大家参考,具体内容如下 from tkinter i
- 1、现象a.用localhost访问,正常b.用IP地址访问,则出现403错误2、分析a.怀疑是ACL问题,设置Everyone为完全控制,
- 学习Python数据分析挖掘实战一书时,在数据预处理阶段,有一节要使用拉格朗日插值法对缺失值补充,代码如下:#-*- coding:utf-
- 前言Python 有 while 语句和 for 语句作为循环处理。虽然 for 语句具有一定数量的进程,但 while 语句是『直到满足条
- C# 连接oracle数据库常用的三种方法有三种:一、Oracle.ManagedDataAccess.dll:Oracle官方提供的ora
- pytest的setup与teardown1)pytest提供了两套互相独立的setup 与 teardown和一对相对自由的setup与t
- 在数据处理与分析领域,对数值型与字符型类别变量加以编码是不可或缺的预处理操作;这里介绍两种不同的方法。1 OneHotEncoder首先导入
- 前言最近在爬行 nosec.org 的数据,看了下需要模拟登录拿到cookie后才能访问想抓的数据,重要的是 nosec.org 的登录页面
- 网上存在这么一个例子 obj = pd.Series([7,-5,7,4,2,0,4])obj.rank()输出为:0 6.51
- 概述虽然现在关系型数据库越来越相似,但其背后的实现机制可能大相径庭。实际使用方面,因为SQL语法规范的存在使得我们熟悉多种关系型数据库并非难
- 1.前言 &n
- Python 正则表达式正则表达式是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式匹配。Python 自1.5版本起增加了
- 先介绍下什么是协程:协程,又称微线程,纤程,英文名Coroutine。协程的作用,是在执行函数A时,可以随时中断,去执行函数B,然后中断继续
- 代码import imutilsimport cv2image = cv2.imread('') # translate t
- 前言相信大家在日常的web开发中,作为前端经常会遇到处理图片拉伸问题的情况。例如banner、图文列表、头像等所有和用户或客户自主操作图片上
- 本文实例讲述了Python实现更改图片尺寸大小的方法。分享给大家供大家参考,具体如下:1、PIL包推荐Pillow 。2、源码:#encod
- 本文实例为大家分享了python实现网页录音效果的具体代码,供大家参考,具体内容如下服务器:tornado语言:python,JS,html
- 一.基本数据类型整数:int字符串:str(注:\t等于一个tab键)布尔值: bool列表:list (元素的集合)列表用[]元祖:tup