简介

   前面两篇文章主要讲了数据库读写分离分表分库的一些问题,这篇文章主要讲一下我个人实现的一个分表分库项目。
    在此之前,我有写过一个.Net的分库,最近在做Java的项目,就顺便做出一个Java版本,这个项目源于我另外的一个业务项目,在这个业务项目中有分表(在一个数据库下有多张表),当时写了一套基于分表的帮助类,随着这个业务的的发展,基于分表的解决方案有一定的弊端,主要有两个:
    1.  不能很好的扩展,在一个数据库下面有20张表,当业务繁忙的时候,数据库出现了压力(公司里面多个项目共用一个数据库服务器,有可能是其他项目影响了我的项目),这个时候想要扩展就比较麻烦了, 我可以将其中10张表迁移到另外的机器,同时我的代码路由算法就要改,其实将其中10张表迁移到另外服务器上,就已经类似于分库了。 
    2. 基于分表对业务的侵入性较高,我要先通过算法得到具体的表索引(即表的编号,比如user_15),然后要将整个索引和表前缀进行拼接才能得到真正的表名。 
    所以在开源分表分库的项目的时候,我对项目进行了升级,改为分库模式,即有多个数据库,每个数据库一张表,表名都一样,这样你就可以在mybatis中不需要再对表名进行修改。 降低了浸入性,同时也方便后续的扩展,你可以将这些数据库放在一台机器上,也可以在后续数据库服务器性能紧张的时候,将一部分数据库迁移到其他机器上。 
    最后说一下我当时为什么没有选择开源的解决方案,目前我知道的开源方案包括 sharding-jdbc ,mycat ,但是当时时间紧,任务重,研究熟悉部署这些项目,可能需要1-2天的时间,并且后续使用过程中,出了问题,还需要花时间排查,mycat 是基于分库的,所以并不适合我这个项目,而我的项目中,在操作数据库之前,已经可以知道具体要操作哪张表,对分表的操作也比较简单,但是要得到具体的表索引比较麻烦,是要经过多个key运算得到的,综合所有,我选择了自己写了一个。 

项目介绍

项目比较简单,所有和分库相关的都在shardingcore中。 test是测试用的。 

 shardingcore的项目结构。
其中MultipleDataSource是为了实现切换数据库连接,这块代码是参考网上数据库读写分离的。

 ShardingDBAspect是分库的核心代码。 

使用shardingcore

我们假设要对user进行分库,分3个库

 下面是test工程,比较简单就是操作数据库。 
这里重点看一下UserDao,如果你想在项目中用到分库,只需要引入shardingcore,对于dao层的需要分库的方法,比如addUser方法,需要有两个地方需要修改,一个是通过@Sharding来标示出分库的基本信息。 ,第二个通过@ShardingKey来标示出要根据哪个参数来分库。其他的代码都不需要动。 
 
最后要对配置文件做一些修改。 
 <!-- aop配置,主要是拦截dao层的方法 -->
<aop:config>
<aop:pointcut
expression="execution(public * com.sharpframework.test.repository.*Dao.*(..)) and @annotation(com.sharpframework.shardingcore.shardingannotation.Sharding)"
id="shardingpoint"/>
<aop:aspect id="adviceRespect" ref="sharding" order="1">
<aop:before pointcut-ref="shardingpoint" method="shardingDB"/>
<aop:after pointcut-ref="shardingpoint" method="cleanshardingDB"/>
</aop:aspect> </aop:config> <bean id="sharding" class="com.sharpframework.shardingcore.ShardingDBAspect"></bean> <!-- 因为会有多个数据库连接,所有会有一个抽象连接 配置可以从外部文件读取-->
<bean id="db" class="com.alibaba.druid.pool.DruidDataSource"
destroy-method="close" abstract="true">
<!-- 初始化连接大小 -->
<property name="initialSize" value="${initialSize}"></property>
<!-- 连接池最大数量 -->
<property name="maxActive" value="${maxActive}"></property>
<!-- 连接池最大空闲 -->
<property name="maxIdle" value="${maxIdle}"></property>
<!-- 连接池最小空闲 -->
<property name="minIdle" value="${minIdle}"></property>
<!-- 获取连接最大等待时间 -->
<property name="maxWait" value="${maxWait}"></property> <property name="minEvictableIdleTimeMillis" value="60000"></property>
<property name="testWhileIdle" value="true"></property>
<property name="timeBetweenEvictionRunsMillis" value="45000"></property>
<property name="validationQuery" value="select 'x'"></property>
<property name="testOnBorrow" value="false"></property>
<property name="defaultAutoCommit" value="false"></property>
</bean> <!-- 数据库连接 -->
<bean id="db-0" parent="db">
<property name="driverClassName" value="${user.db0.driver}"/>
<property name="url" value="${user.db0.url}"/>
<property name="username" value="${user.db0.username}"/>
<property name="password" value="${user.db0.password}"/>
</bean> <!-- 数据库连接 -->
<bean id="db-1" parent="db">
<property name="driverClassName" value="${user.db1.driver}"/>
<property name="url" value="${user.db1.url}"/>
<property name="username" value="${user.db1.username}"/>
<property name="password" value="${user.db1.password}"/> </bean> <!-- 数据库连接 -->
<bean id="db-2" parent="db">
<property name="driverClassName" value="${user.db2.driver}"/>
<property name="url" value="${user.db2.url}"/>
<property name="username" value="${user.db2.username}"/>
<property name="password" value="${user.db2.password}"/>
</bean> <!-- 多数据源,注入到sqlSesionFactory,注意targetDataSources中key的名称,这里和@Sharding中dataSource 有关联 -->
<bean id="multipleDataSource" class="com.sharpframework.shardingcore.multippledb.MultipleDataSource" primary="true">
<property name="defaultTargetDataSource" ref="db-0"/>
<property name="targetDataSources">
<map>
<entry key="db-0" value-ref="db-0"/>
<entry key="db-1" value-ref="db-1"/>
<entry key="db-2" value-ref="db-2"/>
</map>
</property>
</bean>
下面是测试代码。 

 操作结果:
目前该项目已经开源,代码地址:https://github.com/zhaoyb/sharp-sharding

后记

这个分库项目的原理就是抽象数据连接,当要操作数据库的时候根据指定的shardingkey计算出具体的数据连接,所以也就有了一定的限制,那就是在操作数据前,一定要知道具体要操作哪个库,其实对于分库分库的项目,大部分在执行sql语句前,就已经知道要操作哪张表,否则你就只能并行查所有的表。

Java下一个简单的数据库分库帮助类的更多相关文章

  1. 使用Java编写一个简单的Web的监控系统cpu利用率,cpu温度,总内存大小

    原文:http://www.jb51.net/article/75002.htm 这篇文章主要介绍了使用Java编写一个简单的Web的监控系统的例子,并且将重要信息转为XML通过网页前端显示,非常之实 ...

  2. Linux下一个简单的日志系统的设计及其C代码实现

    1.概述 在大型软件系统中,为了监测软件运行状况及排查软件故障,一般都会要求软件程序在运行的过程中产生日志文件.在日志文件中存放程序流程中的一些重要信息, 包括:变量名称及其值.消息结构定义.函数返回 ...

  3. 使用 java 实现一个简单的 markdown 语法解析器

    1. 什么是 markdown Markdown 是一种轻量级的「标记语言」,它的优点很多,目前也被越来越多的写作爱好者,撰稿者广泛使用.看到这里请不要被「标记」.「语言」所迷惑,Markdown 的 ...

  4. java:jsp: 一个简单的自定义标签 tld

    java:jsp: 一个简单的自定义标签 tld 请注意,uri都是:http://www.tag.com/mytag,保持统一,要不然报错,不能访问 tld文件 <?xml version=& ...

  5. 使用JAVA写一个简单的日历

    JAVA写一个简单的日历import java.text.DateFormat;import java.text.ParseException;import java.text.SimpleDateF ...

  6. Java实现一个简单的网络爬虫

    Java实现一个简单的网络爬虫 import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileWri ...

  7. Java实现一个简单的文件上传案例

    Java实现一个简单的文件上传案例 实现流程: 1.客户端从硬盘读取文件数据到程序中 2.客户端输出流,写出文件到服务端 3.服务端输出流,读取文件数据到服务端中 4.输出流,写出文件数据到服务器硬盘 ...

  8. 自己整理的一个访问SQLite3数据库的C++类

    原文地址:自己整理的一个访问SQLite3数据库的C++类作者:vigra 近日,对SQLite3的使用进行了研究.真不愧是优秀的嵌入数据库,API接口也极其简捷.基本上只要使用以下几个接口就能完成数 ...

  9. 实现一个简单的http请求工具类

    OC自带的http请求用起来不直观,asihttprequest库又太大了,依赖也多,下面实现一个简单的http请求工具类 四个文件源码大致如下,还有优化空间 MYHttpRequest.h(类定义, ...

随机推荐

  1. [ext4]磁盘布局 - inode bitmap & table

    在[磁盘布局 group部分]已经介绍过ext4的整体布局,其中存在两个与inode有关的名称:inode bitmap和inode table. Inode bitmap,用于表示inode tab ...

  2. smart beta

    本文来至人大经济论坛,http://bbs.pinggu.org/thread-3151691-1-1.html 众所周知,beta在CAPM模型中衡量了相对于持有整个市场所带来的风险溢价(risk ...

  3. nodejs版本管理工具NVM(Node Version Mene)

    最近打算用心学习nodejs,所以在学习中了解到NVM-nodejs的版本管理工具,下面我就记录下我学习并且安装的详细过程,请大神们放过~~第一步.你要先把你本机上安装的nodejs以及npm相关的东 ...

  4. 浅析SQL Server数据库中的伪列以及伪列的含义

    SQL Server中的伪列 下午看QQ群有人在讨论(非聚集)索引的存储,说,对于聚集索引表,非聚集索引存储的是索引键值+聚集索引键值:对于非聚集索引表,索引存储的是索引键值+RowId,这应该是一个 ...

  5. 基于三层交换机和基于路由子接口的vlan间路由

    1:通过三层交换机实现vlan间的通信:为三层交换机创建vlan,设置交换机的两个SVI,并配置IP地址. (在二层交换机上只能配置一个SVI端口,用来实现交换机交换机远程管理,在三层交换机上可以配置 ...

  6. JavaScript面向对象的理解

    JavaScript面向对象的理解  笔记链接: http://pan.baidu.com/s/1c0hivuS 1:JavaScript 中分两种对象,函数对象和普通对象new Function() ...

  7. Oracle 12C 新特性之非分区表转分区表online clause(不停业务+索引有效)

    12c以前非分区表需要转换为分区, 如果不停业务的话可以使用在线重定义,只有在表进行切换的时候会有短暂的锁表. 12c 中alter table online clause 实现了表上现有的索引有效, ...

  8. JS执行效率与性能提升方案

    如果是追加字符串,最好使用s+=anotherStr操作,而不是要使用s=s+anotherStr.如果要连接多个字符串,应该少使用+=,如 s+=a;s+=b;s+=c;应该写成s+=a + b + ...

  9. 一步步学习EF Core(2.事务与日志)

    前言 上节我们留了一个问题,为什么EF Core中,我们加载班级,数据并不会出来 其实答案很简单,~ 因为在EF Core1.1.2 中我们在EF6.0+中用到的的延迟加载功能并没有被加入,不过在EF ...

  10. js:不是空字符串的空字符串引起的bug

    今天在用js的时候,使用了两段完全相同的代码,可是一个报错,一个好好的 代码如下: <script type="text/javascript">    console ...