http://blog.csdn.net/wxwzy738/article/details/17265577
cobar client是出自阿里的产品,cobar client只需要引入jar包即可,不需要建立服务。下面的地址是cobar client的帮助文档
http://code.alibabatech.com/docs/cobarclient/zh/
http://www.kuqin.com/system-analysis/20120212/318089.html
分库分表都是在Cobar产品里面的,Cobar分为两类,分别是Cobar Client和Cobar Server,根据业务的需要进行选择,Cobar Server是一组独立的(Stand Alone)的Server集群,Cobar Client就是第三方的Java包,他就直接嵌入到应用上面去。然后他的拆分规则都是直接写到应用的配置文件里面的。这是阿里自主开发的,没有用到外面的一些开源的工具
用到的数据库创建语句:
- create database dbtest1;
- create database dbtest2;
- create database dbtest3;
-
- //分别在这三个数据库中创建下面的表:
- CREATE TABLE `cont` (
- `id` bigint(20) NOT NULL AUTO_INCREMENT,
- `taobaoId` bigint(20) DEFAULT '0',
- `name` varchar(20) DEFAULT '',
- `upd_time` datetime DEFAULT NULL,
- PRIMARY KEY (`id`)
- ) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8;
cobar是扩展ibatis的
SqlMapClientTemplate的功能,对分布在多个数据库的表进行路由读写的开源软件。但是不支持单库的多表操作。
以下贴出一些关键的代码,详细的可以下载功能进行运行查看:
工程截图:

下面列举一个简单的功能,就spring与ibatis进行整合,在mysql数据库上面进行操作,对cont表进行添加和查询的功能操作:
简单看下service,dao的文件代码
Service:
- public interface ContService {
-
-
-
-
-
- public Long addCont(Cont cont);
-
-
-
-
- public Cont getContByKey(Long id);
-
-
-
-
-
-
-
-
- public List<Cont> getContList(ContQuery contQuery);
- }
ServiceImpl:
- @Service("contService")
- public class ContServiceImpl implements ContService {
-
- private static final Log log = LogFactory.getLog(ContServiceImpl.class);
-
- @Resource
- ContDAO contDAO;
-
-
-
-
-
-
- public Long addCont(Cont cont) {
- try {
- return contDAO.addCont(cont);
- } catch (SQLException e) {
- log.error("dao addCont error.:" + e.getMessage(), e);
- }
- return 0L;
- }
-
-
-
-
- public Cont getContByKey(Long id) {
- try {
- return contDAO.getContByKey(id);
- } catch (SQLException e) {
- log.error("dao getContbyKey error.:" + e.getMessage(), e);
- }
- return null;
- }
-
-
- public List<Cont> getContList(ContQuery contQuery) {
- try {
- return contDAO.getContList(contQuery);
- } catch (SQLException e) {
- log.error("get Cont list error." + e.getMessage(), e);
- }
- return Collections.emptyList();
- }
-
- }
Dao:
- @Repository
- public class ContDAO {
-
- @Resource
- SqlMapClientTemplate sqlMapClientTemplate;
-
- public Long addCont(Cont cont) throws SQLException {
- return (Long) this.sqlMapClientTemplate.insert("Cont.insertCont", cont);
- }
-
-
-
-
-
-
- public Cont getContByKey(Long id) throws SQLException {
- Map<String, Object> params = new HashMap<String, Object>();
- params.put("id", id);
- Cont result = (Cont) this.sqlMapClientTemplate.queryForObject(
- "Cont.getContByKey", params);
- return result;
- }
-
- @SuppressWarnings("unchecked")
- public List<Cont> getContList(ContQuery contQuery) throws SQLException {
- if (contQuery.getFields() != null && contQuery.getFields() != "") {
- return (List<Cont>) this.sqlMapClientTemplate.queryForList(
- "Cont.getContListFields", contQuery);
- }
- return (List<Cont>) this.sqlMapClientTemplate.queryForList(
- "Cont.getContList", contQuery);
- }
-
- }
1、下面applicationContext.xmlspring配置文件是针对没有在cobar的情况下进行的常规配置:
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:aop="http://www.springframework.org/schema/aop"
- xmlns:context="http://www.springframework.org/schema/context"
- xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mybatis="http://mybatis.org/schema/mybatis-spring"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
- http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
- http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
- http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring.xsd"
- default-lazy-init="false">
-
- <description>Spring公共配置</description>
- <context:component-scan base-package="com.hj.cobar"></context:component-scan>
-
- <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
- <property name="location">
- <value>application.development.properties</value>
- </property>
- </bean>
-
- <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
-
- <property name="url" value="${jdbc_url}"/>
- <property name="username" value="${jdbc_user}"/>
- <property name="password" value="${jdbc_password}"/>
-
-
- <property name="initialSize" value="1"/>
- <property name="minIdle" value="1"/>
- <property name="maxActive" value="20"/>
-
-
- <property name="maxWait" value="60000"/>
-
-
- <property name="timeBetweenEvictionRunsMillis" value="60000"/>
-
-
- <property name="minEvictableIdleTimeMillis" value="300000"/>
-
- <property name="validationQuery" value="SELECT 'x'"/>
- <property name="testWhileIdle" value="true"/>
- <property name="testOnBorrow" value="false"/>
- <property name="testOnReturn" value="false"/>
-
-
- <property name="poolPreparedStatements" value="false"/>
- <property name="maxPoolPreparedStatementPerConnectionSize" value="20"/>
-
-
- <property name="filters" value="stat"/>
- </bean>
-
- <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
- <property name="dataSource" ref="dataSource"/>
- </bean>
-
-
- <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
-
-
- <bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
- <property name="dataSource" ref="dataSource" />
- <property name="configLocation">
- <value>classpath:/sqlmap-config.xml</value>
- </property>
- </bean>
-
- <bean id="sqlMapClientTemplate" class="org.springframework.orm.ibatis.SqlMapClientTemplate">
- <property name="sqlMapClient" ref="sqlMapClient" />
- </bean>
-
- </beans>
2、下面是在applicationContext.xml使用cobar的配置,一些细节可参考阿里的cobar的帮助文档:
3、在sharding-rules-on-namespace.xml配置cobar的路由规则,因为此路由规则是使用自定义的路由规则,所以还要写一个自定义的规则函数类
- <rules>
-
- <rule>
- <namespace>Cont</namespace>
- <!--
- 表达式如果不使用自定义路由规则函数,而是直接使用 taobaoId%2==0这种的话就不用在文件
- 中配置<property name="functionsMap">中了
- -->
- <shardingExpression>hash.apply(taobaoId) == 0</shardingExpression>
- <shards>partition0</shards>
- </rule>
- <rule>
- <namespace>Cont</namespace>
- <shardingExpression>hash.apply(taobaoId) == 1</shardingExpression>
- <shards>partition1</shards>
- </rule>
- <rule>
- <namespace>Cont</namespace>
- <shardingExpression>hash.apply(taobaoId) == 2</shardingExpression>
- <shards>partition2</shards>
- </rule>
-
- </rules>
4、自定义的路由规则函数类
hash的一种做法是对taobaoId进行md5加密,然后取前几位(我们这里取前两位),然后就可以将不同的taobaoId哈希到不同的用户表(cont_xx)中了。
通过这个技巧,我们可以将不同的taobaoId分散到256中用户表中,分别是cont_00,user_01 ...... cont_ff。因为taobaoId是数字且递增,根据md5的算法,可以将用户数据几乎很均匀的分别到不同的cont表中。
但是这里有个问题是,如果我们的系统的数据越来越多,势必单张表的数据量越来越大,而且根据这种算法无法扩展表,这又会回到单表量大的问题。
下面只是简单的用求余的方法来返回值
-
-
-
-
-
-
-
-
-
- public class HashFunction{
-
-
-
-
-
-
-
-
-
- public int apply(Long taobaoId) {
-
-
- System.out.println("taobaoId:"+taobaoId);
- int result = (int)(taobaoId % 3);
- System.out.println("在第"+(result + 1)+"个数据库中");
- return result;
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- }
5、下面是对service的单元测试
-
-
-
- public class AppTest extends TestCase{
- ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
- ContService contService = (ContService) context.getBean("contService");
-
-
-
-
- public void test1(){
- Cont cont = contService.getContByKey(2L);
- System.out.println(cont);
-
- }
-
-
-
-
- public void test2(){
- Cont cont = new Cont();
- cont.setName("gd");
- Long taobaoId = new Long(new Random().nextInt(10000));
- System.out.println("#"+taobaoId);
- cont.setTaobaoId(taobaoId);
- contService.addCont(cont);
- }
-
-
-
-
-
- public void test3(){
- ContQuery contQuery = new ContQuery();
- contQuery.setTaobaoId(2809L);
- List<Cont> list = contService.getContList(contQuery);
- if(list != null){
- System.out.println(list.get(0));
- }
- }
- }
工程下载地址: http://download.csdn.net/detail/wxwzy738/6698067