转载请注明出处:http://blog.csdn.net/l1028386804/article/details/79368021
之前,我们介绍了利用Mycat进行分库分表操作,Mycat分表操作是利用分库来进行的,单个库中的分表操作可结合MySQL的分区进行,这也是Mycat官方提倡的方式。那么,如何利用Mycat真正实现数据库的分库分表,可以私信我。今天,我们来看看sharding-jdbc,sharding-jdbc也是一款分库分表的“中间件”,不过,它并不向Mycat那样作为一个真正的中间件,它是一款以jar包的形式整合到业务中的插件,这就决定了它是轻量级的,用法也是十分简单的。
首先我们创建相应的数据库
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;
这样,我们的数据库就准备好了。
接下来,我们就创建一个Maven项目,项目结构如下:
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
这里,我们创建两个数据库映射类: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-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-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-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-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-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-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
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-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
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分库分表实例源代码