`

基于sharding-jdbc 之spring+mybatis+sharding-jdbc整合

 
阅读更多

基于sharding-jdbc 之spring+mybatis+sharding-jdbc整合

官方介绍文档: http://dangdangdotcom.github.io/sharding-jdbc/00-overview/

本文参考: http://blog.csdn.net/clypm/article/details/54378523

 

0.环境

ip :192.168.1.121

端口号:3306数据库1:sharding_0

数据库2:sharding_1

 

1.创建多个分库

create database sharding_0;
create database sharding_1;

 

2.在各个分库上,创建多张分表

 

SET FOREIGN_KEY_CHECKS=0; 
-- 逻辑表 t_user
-- 分表:t_user_0
DROP TABLE IF EXISTS `t_user_0`; 
CREATE TABLE `t_user_0` ( 
  `id` int(11) NOT NULL AUTO_INCREMENT, 
  `user_id` int(11) NOT NULL, 
  `name` varchar(255) NOT NULL, 
  `age` int(11) NOT NULL, 
  PRIMARY KEY (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 
-- 分表:t_user_1
DROP TABLE IF EXISTS `t_user_1`; 
CREATE TABLE `t_user_1` ( 
  `id` int(11) NOT NULL AUTO_INCREMENT, 
  `user_id` int(11) NOT NULL, 
  `name` varchar(255) NOT NULL, 
  `age` int(11) NOT NULL, 
  PRIMARY KEY (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

-- 分表: t_user_2 
DROP TABLE IF EXISTS `t_user_2`; 
CREATE TABLE `t_user_2` ( 
  `id` int(11) NOT NULL AUTO_INCREMENT, 
  `user_id` int(11) NOT NULL, 
  `name` varchar(255) NOT NULL, 
  `age` int(11) NOT NULL, 
  PRIMARY KEY (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

 
DROP TABLE IF EXISTS `t_student_0`; 
CREATE TABLE `t_student_0` ( 
  `id` int(11) NOT NULL AUTO_INCREMENT, 
  `student_id` int(11) NOT NULL, 
  `name` varchar(255) NOT NULL, 
  `age` int(11) NOT NULL, 
  PRIMARY KEY (`id`) 
) ENGINE=InnoDB  DEFAULT CHARSET=utf8; 
 
DROP TABLE IF EXISTS `t_student_1`; 
CREATE TABLE `t_student_1` ( 
  `id` int(11) NOT NULL AUTO_INCREMENT, 
  `student_id` int(11) NOT NULL, 
  `name` varchar(255) NOT NULL, 
  `age` int(11) NOT NULL, 
  PRIMARY KEY (`id`) 
) ENGINE=InnoDB  DEFAULT CHARSET=utf8; 

-- 学生表:测试事务时使用
DROP TABLE IF EXISTS `t_student_0`;
CREATE TABLE `t_student_0` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `student_id` int(11) NOT NULL,
  `name` varchar(255) NOT NULL,
  `age` int(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

DROP TABLE IF EXISTS `t_student_1`;
CREATE TABLE `t_student_1` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `student_id` int(11) NOT NULL,
  `name` varchar(255) NOT NULL,
  `age` int(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

 

3.案例:sharding-jdbc-mybatis-demo

3.1 组件

需要jar包:见 pom.xml ,加粗的标识

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.eshop</groupId>
    <artifactId>sharding-jdbc-mybatis-demo</artifactId> 
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

   <properties>  
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>  
        <spring.version>3.2.5.RELEASE</spring.version>  
        <mybatis.version>3.2.4</mybatis.version>  
    </properties>  
  
    <dependencies>  
        <dependency>  
            <groupId>junit</groupId>  
            <artifactId>junit</artifactId>  
            <version>4.10</version>  
        </dependency>  
        
        <dependency>  
            <groupId>org.springframework</groupId>  
            <artifactId>spring-orm</artifactId>  
            <version>${spring.version}</version>  
        </dependency>  
        <dependency>  
            <groupId>commons-dbcp</groupId>  
            <artifactId>commons-dbcp</artifactId>  
            <version>1.4</version>  
        </dependency>  
        <dependency>  
            <groupId>org.mybatis</groupId>  
            <artifactId>mybatis-spring</artifactId>  
            <version>1.2.2</version>  
        </dependency>  
        <dependency>  
            <groupId>org.mybatis</groupId>  
            <artifactId>mybatis</artifactId>  
            <version>${mybatis.version}</version>  
        </dependency>  
  
        <dependency>  
            <groupId>org.springframework</groupId>  
            <artifactId>spring-expression</artifactId>  
            <version>${spring.version}</version>  
        </dependency>  
        <dependency>  
            <groupId>org.springframework</groupId>  
            <artifactId>spring-aop</artifactId>  
            <version>${spring.version}</version>  
        </dependency>  
        <dependency>  
            <groupId>org.springframework</groupId>  
            <artifactId>spring-beans</artifactId>  
            <version>${spring.version}</version>  
        </dependency>  
        <dependency>  
            <groupId>org.springframework</groupId>  
            <artifactId>spring-context</artifactId>  
            <version>${spring.version}</version>  
        </dependency>  
        <dependency>  
            <groupId>org.springframework</groupId>  
            <artifactId>spring-context-support</artifactId>  
            <version>${spring.version}</version>  
        </dependency>  
        <dependency>  
            <groupId>org.springframework</groupId>  
            <artifactId>spring-test</artifactId>  
            <version>${spring.version}</version>  
        </dependency>  
        <dependency>  
            <groupId>org.springframework</groupId>  
            <artifactId>spring-tx</artifactId>  
            <version>${spring.version}</version>  
        </dependency>  
        <dependency>  
            <groupId>log4j</groupId>  
            <artifactId>log4j</artifactId>  
            <version>1.2.16</version>  
        </dependency>  
        <dependency>  
            <groupId>org.slf4j</groupId>  
            <artifactId>slf4j-log4j12</artifactId>  
            <version>1.7.5</version>  
        </dependency>  
        
        <dependency> 
        	<groupId>org.springframework</groupId> 
        	<artifactId>spring-webmvc</artifactId> 
        	<version>3.2.4.RELEASE</version> 
        </dependency>
        
        <!-- 分库分表使用的Dangdang Sharding-jdbc -->
        <dependency>  
            <groupId>com.dangdang</groupId>  
            <artifactId>sharding-jdbc-core</artifactId>  
            <version>1.4.2</version> 
        </dependency>  
        
   		<dependency>  
             <groupId>com.dangdang</groupId>  
             <artifactId>sharding-jdbc-config-spring</artifactId>  
             <version>1.4.2</version>  
        </dependency>
        
        <dependency>  
            <groupId>mysql</groupId>  
            <artifactId>mysql-connector-java</artifactId>  
            <version>5.1.28</version>  
        </dependency>    

	<dependency>
		<groupId>javax.servlet</groupId>
		<artifactId>servlet-api</artifactId>
		<version>2.5</version>
	</dependency>          
        
    </dependencies>   
</project>  

 错误分析:

 <!-- sharding-jdbc-core 现在用这个最新版本1.4.2会报错,暂时用1.0.0,待研究-->
Unsatisfied dependency expressed through constructor argument with index 1 of type [boolean]: Could not convert constructor argument value of type [java.util.ArrayList] to required type [boolean]
 问题解决:在rdb的配置方法里,就可以使用,而且分布式主键的包需要1.4.2版本

3.2 主配置文件applicationContext.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" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="
		http://www.springframework.org/schema/beans 
		http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context
		http://www.springframework.org/schema/context/spring-context.xsd">

	<context:annotation-config />
	<context:component-scan base-package="com.eshop.sharding.jdbc.*" />

	<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
		<property name="location" value="classpath:bp.properties" />
	</bean>

	<import resource="spring-database.xml" />
	<import resource="spring-sharding.xml" />

</beans>
 

3.3 配置文件spring-database.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" xmlns:context="http://www.springframework.org/schema/context"  
    xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring"  
    xmlns:tx="http://www.springframework.org/schema/tx"  
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd  
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd  
        http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring-1.2.xsd  
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">  
          
	<!-- 基础数据源 -->
	<bean id="abstractDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
	    <property name="driverClassName" value="${jdbc_driver_0}" /> 
        <!-- 初始化连接大小 -->  
        <property name="initialSize" value="0" />  
        <!-- 连接池最大使用连接数量 -->  
        <property name="maxActive" value="20" />  
        <!-- 连接池最小空闲 -->  
        <property name="minIdle" value="0" />  
        <!-- 获取连接最大等待时间 -->  
        <property name="maxWait" value="60000" />  
        <property name="validationQuery" value="${validationQuery}" />  
        <property name="testOnBorrow" value="false" />  
        <property name="testOnReturn" value="false" />  
        <property name="testWhileIdle" value="true" />  
        <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->  
        <property name="timeBetweenEvictionRunsMillis" value="60000" />  
        <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->  
        <property name="minEvictableIdleTimeMillis" value="25200000" />  
        <!-- 打开removeAbandoned功能 -->  
        <property name="removeAbandoned" value="true" />  
        <!-- 1800秒,也就是30分钟 -->  
        <property name="removeAbandonedTimeout" value="1800" />  
        <!-- 关闭abanded连接时输出错误日志 -->  
        <property name="logAbandoned" value="true" />  
        <property name="filters" value="stat" /> 
    </bean>    
      
          
    <bean id="sharding_0" class="com.alibaba.druid.pool.DruidDataSource" parent="abstractDataSource">
        <property name="url" value="${jdbc_url0}" />  
        <property name="username" value="${jdbc_username0}" />  
        <property name="password" value="${jdbc_password0}" />  
    </bean>
      
    <bean id="sharding_1" class="com.alibaba.druid.pool.DruidDataSource" parent="abstractDataSource">
        <property name="url" value="${jdbc_url1}" />  
        <property name="username" value="${jdbc_username1}" />  
        <property name="password" value="${jdbc_password1}" />  
    </bean>
  
</beans> 
 

3.4 配置文件spring-sharding.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" xmlns:context="http://www.springframework.org/schema/context"  
    xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring"  
    xmlns:tx="http://www.springframework.org/schema/tx"  
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd  
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd  
        http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring-1.2.xsd  
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">  
          
	<bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		<property name="basePackage" value="com.eshop.sharding.jdbc.dao" />
		<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
	</bean>
    
     <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">  
        <property name="dataSource" ref="shardingDataSource"/>  
        <property name="mapperLocations" value="classpath*:mappings/*Mapper.xml"/>
    </bean>
      
    <!-- 读写分离 
    <rdb:master-slave-data-source id="dataSource_0" master-data-source-ref="sharding_0" slave-data-sources-ref="sharding_2 "/>-->

    <bean id="shardingDataSource" class="com.dangdang.ddframe.rdb.sharding.api.ShardingDataSource">  
        <constructor-arg ref="shardingRule"/>  
    </bean>
    
    <!-- 构成分库分表的规则 传入数据源集合和每个表的分库分表的具体规则 -->  
    <bean id="shardingRule" class="com.dangdang.ddframe.rdb.sharding.api.rule.ShardingRule">  
        <constructor-arg index="0" ref="dataSourceRule"/>  
        <constructor-arg index="1">  
            <list>  
                <ref bean="userTableRule"/>  
                <ref bean="studentTableRule"/>  
            </list>  
        </constructor-arg>  
    </bean>   
    
    <!-- 配置好dataSourceRulue,即对数据源进行管理 -->  
    <bean id="dataSourceRule" class="com.dangdang.ddframe.rdb.sharding.api.rule.DataSourceRule">  
        <constructor-arg>  
            <map>  
                <entry key="sharding_0" value-ref="sharding_0"/>  
                <entry key="sharding_1" value-ref="sharding_1"/>          
            </map>  
        </constructor-arg>  
    </bean>        
      
    <!-- t_user表的分库分表配置 -->  
    <bean id="userTableRule" class="com.dangdang.ddframe.rdb.sharding.api.rule.TableRule">  
        <constructor-arg value="t_user" index="0"/>  <!-- 逻辑表名 -->
        <constructor-arg index="1">  <!-- 物理表列表 -->
            <list>  
                <value>t_user_0</value>  
                <value>t_user_1</value>  
                <value>t_user_2</value>  
            </list>  
        </constructor-arg>  
        <constructor-arg index="2" ref="dataSourceRule"/>  <!-- 数据源管理 -->
        <constructor-arg index="3" ref="userDatabaseShardingStrategy"/> <!-- 分库策略 --> 
        <constructor-arg index="4" ref="userTableShardingStrategy"/>  <!-- 分表策略 --> 
    </bean>  
      
    <!-- t_user分库策略 -->  
    <bean id="userDatabaseShardingStrategy" class="com.dangdang.ddframe.rdb.sharding.api.strategy.database.DatabaseShardingStrategy">  
        <constructor-arg index="0" value="user_id"/>  <!-- 分库字段 -->
        <constructor-arg index="1">  <!-- 分库策略 -->
            <bean class="com.eshop.sharding.jdbc.algorithm.UserSingleKeyDatabaseShardingAlgorithm" />  
        </constructor-arg>  
    </bean>  
      
    <!-- t_user 分表策略 -->  
    <bean id="userTableShardingStrategy" class="com.dangdang.ddframe.rdb.sharding.api.strategy.table.TableShardingStrategy">  
        <constructor-arg index="0" value="user_id"/><!-- 分表字段 -->
        <constructor-arg index="1"><!-- 分表策略 -->
            <bean class="com.eshop.sharding.jdbc.algorithm.UserSingleKeyTableShardingAlgorithm" />  
        </constructor-arg>  
    </bean>  
    
    <!-- 事务 -->  
    <bean id="transactionManager"  
          class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
        <property name="dataSource" ref="shardingDataSource" />  
    </bean>  
  
    <tx:annotation-driven transaction-manager="transactionManager" />  
          
</beans>  
 

3.5 log.xml

<?xml version="1.0" encoding="UTF-8"?>      
<!DOCTYPE log4j:configuration PUBLIC "-//APACHE//DTD LOG4J 1.2//EN" "log4j.dtd">    
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">    
  <!-- [控制台STDOUT] -->    
  <appender name="console" class="org.apache.log4j.ConsoleAppender">    
     <param name="encoding" value="GBK" />    
     <param name="target" value="System.out" />    
     <layout class="org.apache.log4j.PatternLayout">    
       <param name="ConversionPattern" value="%-5p %c{2} - %m%n" />    
     </layout>    
  </appender>    
    
  <!-- [公共Appender] -->    
  <appender name="DEFAULT-APPENDER" class="org.apache.log4j.DailyRollingFileAppender">    
     <param name="File" value="${webapp.root}/logs/common-default.log" />    
     <param name="Append" value="true" />    
     <param name="encoding" value="GBK" />    
     <param name="DatePattern" value="'.'yyyy-MM-dd'.log'" />    
     <layout class="org.apache.log4j.PatternLayout">    
    <param name="ConversionPattern" value="%d %-5p %c{2} - %m%n" />    
     </layout>    
   </appender>    
    
   <!-- [错误日志APPENDER] -->    
   <appender name="ERROR-APPENDER" class="org.apache.log4j.DailyRollingFileAppender">    
     <param name="File" value="${webapp.root}/logs/common-error.log" />    
     <param name="Append" value="true" />    
     <param name="encoding" value="GBK" />    
     <param name="threshold" value="error" />    
     <param name="DatePattern" value="'.'yyyy-MM-dd'.log'" />    
     <layout class="org.apache.log4j.PatternLayout">    
        <param name="ConversionPattern" value="%d %-5p %c{2} - %m%n" />    
     </layout>    
   </appender>    
    
   <!-- [组件日志APPENDER] -->    
   <appender name="COMPONENT-APPENDER"    
class="org.apache.log4j.DailyRollingFileAppender">    
     <param name="File" value="${webapp.root}/logs/logistics-component.log" />    
     <param name="Append" value="true" />    
     <param name="encoding" value="GBK" />    
     <param name="DatePattern" value="'.'yyyy-MM-dd'.log'" />    
     <layout class="org.apache.log4j.PatternLayout">    
    <param name="ConversionPattern" value="%d %-5p %c{2} - %m%n" />    
     </layout>    
   </appender>    
    
   <!-- [组件日志] -->    
   <logger name="LOGISTICS-COMPONENT">    
      <level value="${loggingLevel}" />    
      <appender-ref ref="COMPONENT-APPENDER" />    
      <appender-ref ref="ERROR-APPENDER" />    
   </logger>    
    
   <!-- Root Logger -->    
   <root>    
       <level value="${rootLevel}"></level>    
       <appender-ref ref="DEFAULT-APPENDER" />    
       <appender-ref ref="ERROR-APPENDER" />    
       <appender-ref ref="console" />   
       <appender-ref ref="COMPONENT-APPENDER" />   
   </root>    
</log4j:configuration>  

 

 

4.相关的类

 

4.1ShardingTmInterceptor

在跨库查询时,必须加这个类实现HandlerInterceptorAdapter,否则报错

package com.eshop.sharding.jdbc.aop;

import java.util.Date;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;

import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.AbstractPlatformTransactionManager;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

public class ShardingTmInterceptor extends HandlerInterceptorAdapter  {

	@Override
	public void afterCompletion(HttpServletRequest request,
			HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
		// TODO Auto-generated method stub
		super.afterCompletion(request, response, handler, ex);
	}

	@Override
	public void afterConcurrentHandlingStarted(HttpServletRequest request,
			HttpServletResponse response, Object handler) throws Exception {
		// TODO Auto-generated method stub
		super.afterConcurrentHandlingStarted(request, response, handler);
	}

	@Override
	public void postHandle(HttpServletRequest request,
			HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
		// TODO Auto-generated method stub
		super.postHandle(request, response, handler, modelAndView);
	}

	@Override
	public boolean preHandle(HttpServletRequest request,
			HttpServletResponse response, Object handler) throws Exception {
		
		AbstractApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
		//获取分库分表数据源
		DataSource shardingDataSource = (DataSource) ctx.getBean("shardingDataSource");
		//创建jdbcTemplate
		final JdbcTemplate jdbcTemplate = new JdbcTemplate(shardingDataSource);
		//获取事务管理器
		AbstractPlatformTransactionManager transactionManager = (AbstractPlatformTransactionManager) ctx.getBean("transactionManager");
		//创建事务模板
		TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
		//执行SQL(product是逻辑表名,id是分库分表键)
		transactionTemplate.execute(new TransactionCallbackWithoutResult() {
			
			@Override
			protected void doInTransactionWithoutResult(TransactionStatus arg0) {
				//HintManager hintManager = HintManager.getInstance();
				//hintManager.setMasterRouteOnly();
				
				String sql = "insert into product(id,title,last_modified) values(?,?,?)";
				jdbcTemplate.update(sql,1L,"title",new Date());
				
				//jdbcTemplate.queryForList("select id,title from product where id = ?",1L);
				
			}
		});
		
		
		return super.preHandle(request, response, handler);
	}
	
}

 

4.2  持久层接口类

UserDao

package com.eshop.sharding.jdbc.dao;  
  
import java.util.List;

import com.eshop.sharding.jdbc.domain.User;
  
public interface UserDao {
      
    Integer insert(User u);  
      
    List<User> findAll();  
      
    List<User> findByUserIds(List<Integer> userIds);  
      
  
} 

 对应的Mapper文件UserDao.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.eshop.sharding.jdbc.dao.UserDao" >
<!-- namespace必须写成对应的接口类 ->
  <resultMap id="resultMap" type="com.eshop.sharding.jdbc.domain.User" >  
	    <id column="id" property="id" jdbcType="INTEGER" />  
	    <result column="user_id" property="userId" jdbcType="INTEGER" />  
	    <result column="name" property="name" jdbcType="VARCHAR" />  
	    <result column="age" property="age" jdbcType="INTEGER" />  
  </resultMap> 
  
  <sql id="columnsName">  
     id,user_id,name,age  
  </sql>   
    
  <insert id="insert">  
    insert into t_user (user_id,name,age) values (#{userId},#{name},#{age})  
  </insert>  
    
  <select id="findAll" resultMap="resultMap">  
   select <include refid="columnsName"/> from t_user   
  </select>  
    
  <select id="findByUserIds" resultMap="resultMap">  
    select <include refid="columnsName"/> from t_user where user_id in (  
     <foreach collection="list" item="item" separator=",">  
        #{item}  
     </foreach>  
    )  
      
  </select>  
    
</mapper> 

 

4.3 分库/分表策略类

UserSingleKeyDatabaseShardingAlgorithm.java

package com.eshop.sharding.jdbc.algorithm;  
  
import java.util.Collection;  
import java.util.LinkedHashSet;
  
import com.dangdang.ddframe.rdb.sharding.api.ShardingValue;  
import com.dangdang.ddframe.rdb.sharding.api.strategy.database.SingleKeyDatabaseShardingAlgorithm;  
import com.google.common.collect.Range;  
  
/** 
 * USER表分库的逻辑函数 
 * @author lyncc 
 * 
 */  
public class UserSingleKeyDatabaseShardingAlgorithm implements SingleKeyDatabaseShardingAlgorithm<Integer>{  
  
    /** 
     * sql 中关键字 匹配符为 =的时候,表的路由函数
     */  
    public String doEqualSharding(Collection<String> availableTargetNames, ShardingValue<Integer> shardingValue) {  
        for (String each : availableTargetNames) {  
            if (each.endsWith(shardingValue.getValue() % 2 + "")) {  
                return each;  
            }  
        }  
        throw new IllegalArgumentException();  
    }  
  
    /** 
     * sql 中关键字 匹配符为 in 的时候,表的路由函数 
     */  
    public Collection<String> doInSharding(Collection<String> availableTargetNames, ShardingValue<Integer> shardingValue) {  
        Collection<String> result = new LinkedHashSet<String>(availableTargetNames.size());  
        for (Integer value : shardingValue.getValues()) {  
            for (String tableName : availableTargetNames) {  
                if (tableName.endsWith(value % 2 + "")) {  
                    result.add(tableName);  
                }  
            }  
        }  
        return result;  
    }  
  
    /** 
     * sql 中关键字 匹配符为 between的时候,表的路由函数 
     */  
    public Collection<String> doBetweenSharding(Collection<String> availableTargetNames,  
            ShardingValue<Integer> shardingValue) {  
        Collection<String> result = new LinkedHashSet<String>(availableTargetNames.size());  
        Range<Integer> range = (Range<Integer>) shardingValue.getValueRange();  
        for (Integer i = range.lowerEndpoint(); i <= range.upperEndpoint(); i++) {  
            for (String each : availableTargetNames) {  
                if (each.endsWith(i % 2 + "")) {  
                    result.add(each);  
                }  
            }  
        }  
        return result;  
    }  
  
}  

 

UserSingleKeyTableShardingAlgorithm.java

package com.eshop.sharding.jdbc.algorithm;  

import java.util.Collection;  
import java.util.LinkedHashSet;  
  
import com.dangdang.ddframe.rdb.sharding.api.ShardingValue;  
import com.dangdang.ddframe.rdb.sharding.api.strategy.table.SingleKeyTableShardingAlgorithm;  
import com.google.common.collect.Range;  
  
public class UserSingleKeyTableShardingAlgorithm implements SingleKeyTableShardingAlgorithm<Integer>{  
  
    /** 
     * sql 中 = 操作时,table的映射 
     */  
    public String doEqualSharding(Collection<String> tableNames, ShardingValue<Integer> shardingValue) {  
        for (String each : tableNames) {  
            if (each.endsWith(shardingValue.getValue() % 3 + "")) {  
                return each;  
            }  
        }  
        throw new IllegalArgumentException();  
    }  
  
    /** 
     * sql 中 in 操作时,table的映射 
     */  
    public Collection<String> doInSharding(Collection<String> tableNames, ShardingValue<Integer> shardingValue) {  
        Collection<String> result = new LinkedHashSet<String>(tableNames.size());  
        for (Integer value : shardingValue.getValues()) {  
            for (String tableName : tableNames) {  
                if (tableName.endsWith(value % 3 + "")) {  
                    result.add(tableName);  
                }  
            }  
        }  
        return result;  
    }  
  
    /** 
     * sql 中 between 操作时,table的映射 
     */  
    public Collection<String> doBetweenSharding(Collection<String> tableNames,  
            ShardingValue<Integer> shardingValue) {  
        Collection<String> result = new LinkedHashSet<String>(tableNames.size());  
        Range<Integer> range = (Range<Integer>) shardingValue.getValueRange();  
        for (Integer i = range.lowerEndpoint(); i <= range.upperEndpoint(); i++) {  
            for (String each : tableNames) {  
                if (each.endsWith(i % 3 + "")) {  
                    result.add(each);  
                }  
            }  
        }  
        return result;  
    }  
  
} 

 

5.事务管理:

新增Student的分库分表策略,具体见代码

 

事务接口实现类,UserServiceImpl

package com.eshop.sharding.jdbc.service.impl;  
  
import java.util.List;

import javax.annotation.Resource;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.eshop.sharding.jdbc.dao.StudentDao;
import com.eshop.sharding.jdbc.dao.UserDao;
import com.eshop.sharding.jdbc.domain.Student;
import com.eshop.sharding.jdbc.domain.User;
import com.eshop.sharding.jdbc.service.UserService;
  
@Service  
@Transactional  
public class UserServiceImpl implements UserService {  
  
    @Resource  
    public UserDao userDao;  
    
    @Resource  
    public StudentDao studentDao;  
      
    public boolean insert(User u) {  
        return userDao.insert(u) > 0 ? true :false;  
    }  
  
    public List<User> findAll() {  
        return userDao.findAll();  
    }  
  
    public List<User> findByUserIds(List<Integer> ids) {  
        return userDao.findByUserIds(ids);  
    }  
  
    @Transactional(propagation=Propagation.REQUIRED)  
    public void transactionTestSucess() {  
        User u = new User();  
        u.setUserId(13);  
        u.setAge(25);  
        u.setName("war3 1.27");  
        userDao.insert(u);  
          
        Student student = new Student();  
        student.setStudentId(21);  
        student.setAge(21);  
        student.setName("hehe");  
        studentDao.insert(student);  
    }  
  
    @Transactional(propagation=Propagation.REQUIRED)  
    public void transactionTestFailure() throws IllegalAccessException {  
        User u = new User();  
        u.setUserId(13);  
        u.setAge(25);  
        u.setName("war3 1.27 good");  
        userDao.insert(u);  
          
        Student student = new Student();  
        student.setStudentId(21);  
        student.setAge(21);  
        student.setName("hehe1");  
        studentDao.insert(student);  
        throw new IllegalAccessException();  
    }  
     
} 

 

 

 

 

 

测试类

package com.eshop.sharding.jdbc;  
  
import java.util.Arrays;
import java.util.List;

import javax.annotation.Resource;

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.eshop.sharding.jdbc.domain.User;
import com.eshop.sharding.jdbc.service.UserService;
  
@RunWith(SpringJUnit4ClassRunner.class)  
@ContextConfiguration(locations = "classpath*:applicationContext.xml")  
public class ShardingJdbcMybatisTest {  
  
    @Resource  
    public UserService userService;  
  
    @Test  
    public void testUserInsert() {  
        User u = new User();
        //为=号时,分库规则shardingValue.getValue() % 2 + "" ,分表规则 shardingValue.getValue() % 3 + ""
        //u.setUserId(11);  //11%2=1 11%3=2 sharding_1.t_user_2
        u.setUserId(12);	//12%2=0 12%3=0 sharding_0.t_user_0
        //u.setUserId(13);	//13%2=1 13%3=1 sharding_1.t_user_1    
        //u.setUserId(14);	//14%2=0 14%3=2 sharding_0.t_user_2
        u.setAge(25);  
        u.setName("github"); 
  
        Assert.assertEquals(userService.insert(u), true);  
    }  
      
//    @Test  
//    public void testStudentInsert() {  
//        Student student = new Student();  
//        student.setStudentId(21);  
//        student.setAge(21);  
//        student.setName("hehe");  
//        Assert.assertEquals(studentService.insert(student), true);  
//    }  
  
    @Test  
    public void testFindAll(){  
        List<User> users = userService.findAll();  
        if(null != users && !users.isEmpty()){  
            for(User u :users){  
                System.out.println(u);  
            }  
        }  
    }  
      
    @Test  
    public void testSQLIN(){  
        List<User> users = userService.findByUserIds(Arrays.asList(2,10,1));  
        if(null != users && !users.isEmpty()){  
            for(User u :users){  
                System.out.println(u);  
            }  
        }  
    }  
      
    @Test  
    public void testTransactionTestSucess(){  
        userService.transactionTestSucess();  
    }  
    
      
    @Test(expected = IllegalAccessException.class)  
    public void testTransactionTestFailure() throws IllegalAccessException{  
        userService.transactionTestFailure();  
    }  
      
      
}  

 

 

事务好像成问题

 

 6.最新的基于rdb的写法

参考配置:https://github.com/dangdangdotcom/sharding-jdbc/blob/master/sharding-jdbc-example/sharding-jdbc-example-mybatis/src/main/resources/META-INF/mybatis/mysql/shardingContext.xml

http://blog.csdn.net/farrell_zeng/article/details/52957274

http://www.cnblogs.com/zwt1990/p/6762135.html

 见工程:sharding-jdbc-mybatis-rdb-dxfl-demo

  <rdb:table-rule logic-table="t_user" actual-tables="t_order_${0..2}" database-strategy="userDatabaseShardingStrategy" table-strategy="userTableShardingStrategy">

报错:Invalid bean definition with name 'shardingDataSource' defined in null: Could not resolve placeholder '0..2' in string value "t_student_${0..2}"

 Cloud not resolve placeholder … in string value …异常的解决方法?

 

 在读取配置文件时, <context:property-placeholder location="classpath:bp.properties" ignore-unresolvable="true" />

7.主从配置

 

8.分布式主键

http://blog.csdn.net/u012768474/article/details/52767520

http://dangdangdotcom.github.io/sharding-jdbc/02-guide/key-generator/

http://blog.csdn.net/tianyaleixiaowu/article/details/70242971

 

先看官方的说法,http://dangdangdotcom.github.io/sharding-jdbc/02-guide/id-generator/ 
传统数据库软件开发中,主键自动生成技术是基本需求。而各大数据库对于该需求也提供了相应的支持,比如MySQL的自增键。 对于MySQL而言,分库分表之后,不同表生成全局唯一的Id是非常棘手的问题。因为同一个逻辑表内的不同实际表之间的自增键是无法互相感知的, 这样会造成重复Id的生成。我们当然可以通过约束表生成键的规则来达到数据的不重复,但是这需要引入额外的运维力量来解决重复性问题,并使框架缺乏扩展性。 
目前有许多第三方解决方案可以完美解决这个问题,比如UUID等依靠特定算法自生成不重复键,或者通过引入Id生成服务等。 但也正因为这种多样性导致了Sharding-JDBC如果强依赖于任何一种方案就会限制其自身的发展。 
基于以上的原因,最终采用了以JDBC接口来实现对于生成Id的访问,而将底层具体的Id生成实现分离出来 
其实最终要解决的问题就是各库各表中的数据,主键不能重复。官方提供的statement什么的没看懂,我就直接用它提供的通用主键生成器来生成主键了。

 

1.提供了一个类IdGenerator,这个类能生成一个保证不重复的Long型数字,我们就用它做主键

 

<dependency>
    <groupId>com.dangdang</groupId>
    <artifactId>sharding-jdbc-self-id-generator</artifactId>
    <version>${sharding-jdbc.version}</version>
</dependency>
 注:最新版本提供了该方法:1.4.2

 

 

2.在数据库中应该用大于等于64bit的数字类型的字段来保存该值,比如在MySQL中应该使用BIGINT。

其二进制表示形式包含四部分,从高位到低位分表为:1bit符号位(为0),41bit时间位,10bit工作进程位,12bit序列位。

用int转换会变成负数

 

可以新建类

 

package com.eshop.sharding.jdbc.idGenerator;

import org.springframework.stereotype.Service;

import com.dangdang.ddframe.rdb.sharding.id.generator.IdGenerator;
import com.dangdang.ddframe.rdb.sharding.id.generator.self.CommonSelfIdGenerator;

@Service
public class IdGeneratorTool {
	
    public IdGenerator getIdGenerator() {
        return new CommonSelfIdGenerator();
    }

}
    	long id = idGenerator.getIdGenerator().generateId().longValue();
    	u.setId(id);
 

 

 

一些最佳实践的说明

1. 在设计库和表时优先考虑使用0,可以配合取余来使用


2.做主键的字段一般设计成数字型


3.SingleKeyTableShardingAlgorithm的类型当然也可以定义为String,问题是使用between时,不好用;

SingleKeyTableShardingAlgorithm的类型设置成Integer类型

4.在写分库分表规则时:
(shardingValue.getValue()!=null && each.endsWith( String.valueOf(shardingValue.getValue()).substring(0, 6)))
这种方式可取:String.valueOf(shardingValue.getValue())
这种方式不可取:shardingValue.getValue().toString()
非维度查询也可以

当你需要使用某个维度进行操作,可以带条件,否则别带
做法:在batis配置文件里设置<if test="orderId != null" >AND order_id = #{orderId,jdbcType=INTEGER} </if>


至今总结:sharding-jdbc:可以维度和非维度查询;带维度条件则在维度条件下获取;否则在全库全表获取数据聚合。


可以尝试:分页,排序等等


统计时:
异构数据库:比如跨库join;
全局表:比如跨库join

 

 

 

分享到:
评论

相关推荐

    spring+mybatis+sharding-jdbc

    【标题】"spring+mybatis+sharding-jdbc"是一个基于Spring框架,结合MyBatis持久层框架和Sharding-JDBC分库分表组件的示例项目。该项目旨在展示如何在实际开发中处理大数据量场景下的数据库扩展问题,通过水平扩展...

    SpringBoot+Mybatis-Plus整合Sharding-JDBC5.1.1实现单库分表【全网最新】.doc

    ### SpringBoot+Mybatis-Plus 整合 Sharding-JDBC5.1.1 实现单库分表 #### 一、前言与背景 在现代软件开发中,随着业务量的增长,单一数据库往往难以满足高性能、高并发的需求,因此分库分表成为了一种常见的解决...

    spring+mybatis+sharding-jdbc 1.3.1实现分库分表案例(可直接运行)

    &lt;bean id="shardingDataSource" class="org.apache.shardingsphere.shardingjdbc.spring.boot.jta.datasource.SpringBootJtaShardingDataSource"&gt; &lt;property name="location" value="classpath:sharding-...

    spring+mybatis+sharding-jdbc 整合

    &lt;property name="url" value="jdbc:shardingjdbc:proxy:mysql://localhost:3306/sharding?serverTimezone=UTC"/&gt; ``` 5. **编写Mapper接口和XML**:如同普通的MyBatis项目,你需要创建Mapper接口和...

    springboot整合sharding-jdbc完整代码

    SpringBoot整合Sharding-JDBC是将Sharding-JDBC这一分布式数据库中间件与SpringBoot框架结合,以实现数据分片、读写分离等高级数据库管理功能。这个完整的代码示例覆盖了Sharding-JDBC的主要技术点,使开发者可以...

    当当开源sharding-jdbc-轻量级数据库分库分表中间件

    1. **高度兼容性**:Sharding-JDBC能够无缝集成到现有的基于Java的ORM框架中,如JPA、Hibernate、Mybatis、SpringJDBCTemplate等,或者直接使用JDBC进行操作,这极大地降低了代码迁移的成本。 2. **灵活性与扩展性...

    Springboot2+JPA|MyBatis+Sharding-JDBC示例

    在IT行业中,Spring Boot、JPA(Java Persistence API)、MyBatis和Sharding-JDBC都是极为重要的技术组件,尤其在构建高效、可扩展的微服务架构时。下面将详细阐述这些技术及其在"Springboot2+JPA|MyBatis+Sharding-...

    Spring Boot 集成 Sharding-JDBC + Mybatis-Plus 实现分库分表功能

    本篇文章将详细讲解如何使用Spring Boot结合Sharding-JDBC和Mybatis-Plus实现分库分表功能。 一、Sharding-JDBC简介 Sharding-JDBC是由Apache ShardingSphere项目提供的一个轻量级数据库中间件,它作为JDBC驱动...

    该项目主要采用springboot2.x+sharding -spring-boot-sharding-jdbc.zip

    在SpringBoot应用中,Sharding-JDBC的使用与常规JDBC操作类似,可以直接使用JdbcTemplate或者MyBatis等ORM框架。Sharding-JDBC会自动处理分片逻辑,用户无需关心底层细节。 五、注意事项 1. 分片键的选择:选择对...

    spring-boot+sharding-jdbc+mybatis+druid

    spring boot的配置文件配置无法具体配置druid连接池的各种属性(官网上我没找到),所以采用java类的方式配置,包括druid的wallFilter、statFilter、statViewServlet、webStatFilter等等

    sharding-jdbc.rar

    《基于Sharding-JDBC的SpringBoot+Mybatis整合实践》 在现代的互联网应用中,随着数据量的急剧增长,数据库的水平扩展成为了一个至关重要的问题。Sharding-JDBC作为一个轻量级的Java框架,提供了数据库分片的功能,...

    sharding-jdbc之——分库分表实例完整源码

    标题"sharding-jdbc之——分库分表实例完整源码"指出了本主题的核心,即`Sharding-JDBC`在实现数据库分库分表中的应用。Sharding-JDBC是阿里巴巴开源的轻量级Java框架,它可以在不修改现有数据库的情况下,对数据库...

    Sharding-JDBC教程:Spring Boot整合Sharding-JDBC实现读写分离.docx

    ### Sharding-JDBC 教程:Spring Boot 整合 Sharding-JDBC 实现读写分离 #### 一、Sharding-JDBC 和 Spring Boot 的简介 **Sharding-JDBC** 是阿里巴巴开源的一个轻量级 Java 框架,主要用于对数据库进行分片、...

    sharding-jdbc-master.zip 附完整代码可供参考

    【标题】"Sharding-JDBC-Master.zip" 提供了一个完整的示例,展示了如何在实际项目中使用Sharding-JDBC实现MyBatis的分库分表功能。这个压缩包包含了Sharding-JDBC的核心代码,方便开发者参考和学习。 【描述】中...

    sharding-jdbc-demo

    【标题】"sharding-jdbc-demo" 是一个基于Sharding-JDBC、SpringBoot、MyBatis和Druid的示例项目,旨在展示如何在Java环境中整合这些组件来实现数据库分片和微服务架构。 【描述】这个项目的核心是利用Sharding-...

    spring4.0.2+mybatis3.2.4+sharding-jdbc1.4.2实现分库分表、主从及事物支持

    本项目基于“spring4.0.2+mybatis3.2.4+sharding-jdbc1.4.2”搭建了一个实现分库分表、主从复制以及事务管理的解决方案。下面将详细讲解这个集成框架中的关键知识点。 首先,Spring 4.0.2 是一个广泛使用的Java应用...

    mybatis-plus-sharding-jdbc-spring-boot-starter:mybatis加上分片jdbc弹簧启动启动器

    因为原项目中提到的 sharding-jdbc-mybatis-plus-spring-boot-starter 没有再更新,所以产生了此项目 dependencies com.baomidou:mybatis-plus:2.2.0 sharding-jdbc-core-spring-boot-starter:2.0.3 spring-boot-...

    springBoot和sharding-jdbc、mybatis整合demo

    SpringBoot和Sharding-JDBC、MyBatis的整合是一个常见的数据分片与微服务架构中的实践,这使得大型应用能够有效地处理高并发和大数据量的情况。在这个名为"spring-boot-sharding-jdbc-master"的项目中,我们将探讨...

    sharding-jdbc-4.0.0-rc1 整合spring boot 2+mybatis plus 分库分表Demo

    在本项目中,我们主要探讨如何使用`sharding-jdbc-4.0.0-rc1`这个版本的ShardingSphere来整合`Spring Boot 2`框架和`MyBatis Plus`,实现数据库的分库分表功能。下面将详细阐述这一过程中的关键知识点。 1. **...

    Spring Mybatis Sharding-JDBC demo

    本文通过对一个基于 Spring、MyBatis 和 Sharding-JDBC 的项目进行分析,介绍了如何构建一个支持数据库分片的应用。通过遵循本文中的步骤,开发者不仅可以快速上手 Sharding-JDBC,还能够在实际项目中有效利用这项...

Global site tag (gtag.js) - Google Analytics