sharding-jdbc之——分库分表实例

转载请注明出处:http://blog.csdn.net/l1028386804/article/details/79368021

一、概述

之前,我们介绍了利用Mycat进行分库分表操作,Mycat分表操作是利用分库来进行的,单个库中的分表操作可结合MySQL的分区进行,这也是Mycat官方提倡的方式。那么,如何利用Mycat真正实现数据库的分库分表,可以私信我。今天,我们来看看sharding-jdbc,sharding-jdbc也是一款分库分表的“中间件”,不过,它并不向Mycat那样作为一个真正的中间件,它是一款以jar包的形式整合到业务中的插件,这就决定了它是轻量级的,用法也是十分简单的。

二、分库分表实战

1、创建数据库

首先我们创建相应的数据库

create database sharding_0;
create database sharding_1;

这样我们就创建了两个数据库sharding_0和sharding_1;

接下来我们在两个库中创建相应的数据表,在两个库中分别进行如下SQL:

SET FOREIGN_KEY_CHECKS=0;
 
-- ----------------------------
-- Table structure for t_student_00
-- ----------------------------
DROP TABLE IF EXISTS `t_student_00`;
CREATE TABLE `t_student_00` (
  `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;
 
-- ----------------------------
-- Table structure for t_student_01
-- ----------------------------
DROP TABLE IF EXISTS `t_student_01`;
CREATE TABLE `t_student_01` (
  `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 AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;
 
-- ----------------------------
-- Table structure for t_user_00
-- ----------------------------
DROP TABLE IF EXISTS `t_user_00`;
CREATE TABLE `t_user_00` (
  `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;
 
-- ----------------------------
-- Table structure for t_user_01
-- ----------------------------
DROP TABLE IF EXISTS `t_user_01`;
CREATE TABLE `t_user_01` (
  `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 AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
 
-- ----------------------------
-- Table structure for t_user_02
-- ----------------------------
DROP TABLE IF EXISTS `t_user_02`;
CREATE TABLE `t_user_02` (
  `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 AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

这样,我们的数据库就准备好了。

2、创建项目

接下来,我们就创建一个Maven项目,项目结构如下:

sharding-jdbc之——分库分表实例_第1张图片

3、配置pom.xml


	4.0.0
	
		dubbo-tcc
		tcc-parent
		0.0.1-SNAPSHOT
	

	tcc-order
	war

	

		
			dubbo-tcc
			tcc-service-api
			0.0.1-SNAPSHOT
		

		
			org.mengyun
			tcc-transaction-spring
			1.2.4.23
		

		
			org.mengyun
			tcc-transaction-dubbo
			1.2.4.23
		

		
		
			org.springframework
			spring-context
		
		
			org.springframework
			spring-beans
		
		
			org.springframework
			spring-webmvc
		
		
			org.springframework
			spring-jdbc
		
		
			org.springframework
			spring-aspects
		
		
			org.springframework
			spring-context-support
		
		
			org.springframework
			spring-tx
		
		
			org.springframework
			spring-aop
		

		
		
			com.alibaba
			dubbo
			
				
					spring
					org.springframework
				
				
					netty
					org.jboss.netty
				
			
		
		
			org.apache.zookeeper
			zookeeper
		
		
			com.github.sgroschupf
			zkclient
		

		
			org.mybatis
			mybatis
			${mybatis.version}
		
		
			org.mybatis
			mybatis-spring
			${mybatis.spring.version}
		
		
		
			mysql
			mysql-connector-java
			${mysql.version}
		
		
		
			com.alibaba
			druid
			${druid.version}
		

		
		
			jstl
			jstl
			${jstl.version}
		
		
			javax.servlet
			servlet-api
			${servlet-api.version}
			provided
		
		
			javax.servlet
			jsp-api
			${jsp-api.version}
			provided
		

		
			junit
			junit
			test
		

	

4、创建数据库映射类

这里,我们创建两个数据库映射类:User类和Student类。

4-1、User类

package com.th.sharding.entity;

import java.io.Serializable;

public class User implements Serializable {

	private static final long serialVersionUID = 215524951712753197L;

	private Integer id;

	private Integer userId;

	private String name;

	private Integer age;

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public Integer getUserId() {
		return userId;
	}

	public void setUserId(Integer userId) {
		this.userId = userId;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		this.age = age;
	}

	@Override
	public String toString() {
		return "User [id=" + id + ", userId=" + userId + ", name=" + name + ", age=" + age + "]";
	}

}

4-2、Student类

package com.th.sharding.entity;

import java.io.Serializable;

public class Student implements Serializable {

	private static final long serialVersionUID = 4461939595448576648L;

	private Integer id;

	private Integer studentId;

	private String name;

	private Integer age;

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public Integer getStudentId() {
		return studentId;
	}

	public void setStudentId(Integer studentId) {
		this.studentId = studentId;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		this.age = age;
	}

	@Override
	public String toString() {
		return "Student [id=" + id + ", studentId=" + studentId + ", name=" + name + ", age=" + age + "]";
	}

}

5、创建Mapper类

5-1、UserMapper类

package com.th.sharding.mapper;

import java.util.List;

import com.th.sharding.entity.User;

public interface UserMapper {
	Integer insert(User u);

	List findAll();

	List findByUserIds(List userIds);
}

5-2、StudentMapper类

package com.th.sharding.mapper;

import java.util.List;

import com.th.sharding.entity.Student;

public interface StudentMapper {
	Integer insert(Student s);

	List findAll();

	List findByStudentIds(List studentIds);
}

6、创建service类

6-1、UserService类

package com.th.sharding.service;

import java.util.List;

import com.th.sharding.entity.User;

public interface UserService {
	public boolean insert(User u);

	public List findAll();

	public List findByUserIds(List ids);

	public void transactionTestSucess();

	public void transactionTestFailure() throws IllegalAccessException;

}

6-2、StudentService类

package com.th.sharding.service;

import com.th.sharding.entity.Student;

public interface StudentService {
	boolean insert(Student student);
}

7、创建service的实现类

7-1、UserServiceImpl类

package com.th.sharding.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.th.sharding.entity.Student;
import com.th.sharding.entity.User;
import com.th.sharding.mapper.StudentMapper;
import com.th.sharding.mapper.UserMapper;
import com.th.sharding.service.UserService;

@Service
public class UserServiceImpl implements UserService {
	@Resource
	public UserMapper userMapper;

	@Resource
	public StudentMapper studentMapper;

	public boolean insert(User u) {
		return userMapper.insert(u) > 0;
	}

	public List findAll() {
		return userMapper.findAll();
	}

	public List findByUserIds(List ids) {
		return userMapper.findByUserIds(ids);
	}

	@Transactional(propagation = Propagation.REQUIRED)
	public void transactionTestSucess() {
		User u = new User();
		u.setUserId(13);
		u.setAge(25);
		u.setName("war3 1.27");
		userMapper.insert(u);

		Student student = new Student();
		student.setStudentId(21);
		student.setAge(21);
		student.setName("hehe");
		studentMapper.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");
		userMapper.insert(u);

		Student student = new Student();
		student.setStudentId(21);
		student.setAge(21);
		student.setName("hehe1");
		studentMapper.insert(student);
		throw new IllegalAccessException();
	}
}

7-2、StudentServiceImpl类

package com.th.sharding.service.impl;

import javax.annotation.Resource;

import org.springframework.stereotype.Service;

import com.th.sharding.entity.Student;
import com.th.sharding.mapper.StudentMapper;
import com.th.sharding.service.StudentService;

@Service
public class StudentServiceImpl implements StudentService {

	@Resource
	public StudentMapper studentMapper;

	public boolean insert(Student student) {
		return studentMapper.insert(student) > 0;
	}

}

8、创建分库逻辑

8-1、User分库逻辑UserSingleKeyDatabaseShardingAlgorithm类

package com.th.sharding.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;

public class UserSingleKeyDatabaseShardingAlgorithm implements SingleKeyDatabaseShardingAlgorithm {

	/**
	 * sql 中关键字 匹配符为 =的时候,表的路由函数
	 */
	public String doEqualSharding(Collection availableTargetNames, ShardingValue shardingValue) {
		for (String each : availableTargetNames) {
			if (each.endsWith(shardingValue.getValue() % 2 + "")) {
				return each;
			}
		}
		throw new IllegalArgumentException();
	}

	/**
	 * sql 中关键字 匹配符为 in 的时候,表的路由函数
	 */
	public Collection doInSharding(Collection availableTargetNames, ShardingValue shardingValue) {
		Collection result = new LinkedHashSet(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 doBetweenSharding(Collection availableTargetNames, ShardingValue shardingValue) {
		Collection result = new LinkedHashSet(availableTargetNames.size());
		Range range = (Range) 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;
	}

}

8-2、Student分库逻辑StudentSingleKeyDatabaseShardingAlgorithm

package com.th.sharding.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;

public class StudentSingleKeyDatabaseShardingAlgorithm implements SingleKeyDatabaseShardingAlgorithm {
	/**
	 * sql 中关键字 匹配符为 =的时候,表的路由函数
	 */
	@Override
	public String doEqualSharding(Collection availableTargetNames, ShardingValue shardingValue) {
		for (String each : availableTargetNames) {
			if (each.endsWith(shardingValue.getValue() % 2 + "")) {
				return each;
			}
		}
		throw new IllegalArgumentException();
	}

	/**
	 * sql 中关键字 匹配符为 in 的时候,表的路由函数
	 */
	@Override
	public Collection doInSharding(Collection availableTargetNames, ShardingValue shardingValue) {
		Collection result = new LinkedHashSet(availableTargetNames.size());
		for (Integer value : shardingValue.getValues()) {
			for (String tableName : availableTargetNames) {
				if (tableName.endsWith(value % 2 + "")) {
					result.add(tableName);
				}
			}
		}
		return result;
	}

	/**
	 * sql 中关键字 匹配符为 between的时候,表的路由函数
	 */
	@Override
	public Collection doBetweenSharding(Collection availableTargetNames, ShardingValue shardingValue) {
		Collection result = new LinkedHashSet(availableTargetNames.size());
		Range range = (Range) 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;
	}

}

9、创建分表逻辑

9-1、User分表逻辑UserSingleKeyTableShardingAlgorithm

package com.th.sharding.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 {
	/**
	 * sql 中 = 操作时,table的映射
	 */
	public String doEqualSharding(Collection tableNames, ShardingValue shardingValue) {
		for (String each : tableNames) {
			if (each.endsWith(("0".concat(String.valueOf(shardingValue.getValue() % 3))))) {
				return each;
			}
		}
		throw new IllegalArgumentException();
	}

	/**
	 * sql 中 in 操作时,table的映射
	 */
	public Collection doInSharding(Collection tableNames, ShardingValue shardingValue) {
		Collection result = new LinkedHashSet(tableNames.size());
		for (Integer value : shardingValue.getValues()) {
			for (String tableName : tableNames) {
				if (tableName.endsWith(("0".concat(String.valueOf(value % 3))))) {
					result.add(tableName);
				}
			}
		}
		return result;
	}

	/**
	 * sql 中 between 操作时,table的映射
	 */
	public Collection doBetweenSharding(Collection tableNames, ShardingValue shardingValue) {
		Collection result = new LinkedHashSet(tableNames.size());
		Range range = (Range) shardingValue.getValueRange();
		for (Integer i = range.lowerEndpoint(); i <= range.upperEndpoint(); i++) {
			for (String each : tableNames) {
				if (each.endsWith(("0".concat(String.valueOf(i % 3))))) {
					result.add(each);
				}
			}
		}
		return result;
	}

}

9-2、创建Student分表逻辑StudentSingleKeyTableShardingAlgorithm

package com.th.sharding.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 StudentSingleKeyTableShardingAlgorithm implements SingleKeyTableShardingAlgorithm {
	/**
	 * sql 中 = 操作时,table的映射
	 */
	public String doEqualSharding(Collection tableNames, ShardingValue shardingValue) {
		for (String each : tableNames) {
			if (each.endsWith("0".concat(String.valueOf(shardingValue.getValue() % 2)))) {
				return each;
			}
		}
		throw new IllegalArgumentException();
	}

	/**
	 * sql 中 in 操作时,table的映射
	 */
	public Collection doInSharding(Collection tableNames, ShardingValue shardingValue) {
		Collection result = new LinkedHashSet(tableNames.size());
		for (Integer value : shardingValue.getValues()) {
			for (String tableName : tableNames) {
				if (tableName.endsWith("0".concat(String.valueOf(value % 2)))) {
					result.add(tableName);
				}
			}
		}
		return result;
	}

	/**
	 * sql 中 between 操作时,table的映射
	 */
	public Collection doBetweenSharding(Collection tableNames, ShardingValue shardingValue) {
		Collection result = new LinkedHashSet(tableNames.size());
		Range range = (Range) shardingValue.getValueRange();
		for (Integer i = range.lowerEndpoint(); i <= range.upperEndpoint(); i++) {
			for (String each : tableNames) {
				if (each.endsWith("0".concat(String.valueOf(i % 2)))) {
					result.add(each);
				}
			}
		}
		return result;
	}

}

10、创建Mapper.xml

10-1、创建UserMapper.xml

  
  
  
    
      
      
      
      
    
    
    
    insert into t_user (user_id,name,age) values (#{userId},#{name},#{age})  
    
    
    
    
    
    
    
     id,user_id,name,age  
        
  

10-2、创建StudentMapper.xml

  
  
  
    
      
      
      
      
    
    
    
    insert into t_student (student_id,name,age) values (#{studentId},#{name},#{age})  
    
    
    
    
    
    
    
     id,student_id,name,age  
        
  

11、创建jdbc_dev.properties

jdbc_driver0=com.mysql.cj.jdbc.Driver
jdbc_url0=jdbc:mysql://localhost:3306/sharding_0?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT
jdbc_username0=root
jdbc_password0=123456

jdbc_driver1=com.mysql.cj.jdbc.Driver
jdbc_url1=jdbc:mysql://localhost:3306/sharding_1?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT
jdbc_username1=root
jdbc_password1=123456

validationQuery=SELECT 1

12、创建spring配置文件

12-1、spring-database.xml

  
  
          
      
          
              
                classpath:config/resource/jdbc_dev.properties  
              
          
      
          
      
          
          
          
  
          
          
          
          
          
          
          
          
          
          
          
          
          
          
          
          
          
          
          
          
          
          
          
      
      
      
          
          
          
  
          
          
          
          
          
          
          
          
          
          
          
          
          
          
          
          
          
          
          
          
          
          
          
      
      
  
  

12-2、spring-sharding.xml

  
  
          
     
     
      
          
          
      
      
      
       
          
          
      
      
      
      
      
          
              
                  
                  
              
          
      
      
      
      
          
          
              
                t_user_00  
                t_user_01  
                t_user_02  
              
          
          
          
          
      
      
      
      
          
          
              
          
      
      
      
      
          
          
              
          
      
      
      
      
        
      
          
          
              
                t_student_00  
                t_student_01  
              
          
          
          
          
      
      
       
      
          
          
              
          
      
      
      
      
          
          
              
          
      
      
      
      
      
          
          
              
                  
                  
              
          
      
      
      
      
          
      
  
      
      
          
      
  
      
          
  

13、创建log4j.xml

      
    
    
      
      
         
         
         
           
         
      
    
      
      
         
         
         
         
         
        
         
       
    
       
       
         
         
         
         
         
         
            
         
       
    
       
       
         
         
         
         
         
        
         
       
    
       
       
          
          
          
       
    
       
       
           
           
           
          
          
       
    

14、创建测试类ShardingJdbcMybatisTest

package com.th.test;

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.th.sharding.entity.Student;
import com.th.sharding.entity.User;
import com.th.sharding.service.StudentService;
import com.th.sharding.service.UserService;

/**
 * 测试分库分表规则
 * 
 * @author
 *
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath*:config/spring/spring-database.xml", "classpath*:config/spring/spring-sharding.xml" })
public class ShardingJdbcMybatisTest {

	@Resource
	public UserService userService;

	@Resource
	public StudentService studentService;

	@Test
	public void testUserInsert() {
		User u = new User();
		u.setUserId(11);
		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 users = userService.findAll();
		if (null != users && !users.isEmpty()) {
			for (User u : users) {
				System.out.println(u);
			}
		}
	}

	@Test
	public void testSQLIN() {
		List users = userService.findByUserIds(Arrays.asList(1,13));
		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();
	}
}

三、测试

我们进行ShardingJdbcMybatisTest类,查看数据表数据,即可看到我们的程序利用sharding-jdbc实现了分库分表操作。

四、温馨提示

大家可以到链接http://download.csdn.net/download/l1028386804/10258290下载完整的sharding-jdbc分库分表实例源代码

你可能感兴趣的:(系统架构)