水平分库操作
1.创建两个数据库,分别具有相同的订单表
2.修改配置文件,配置分库策略
#sharding-jdbc分片规则配置
#数据源
spring.shardingsphere.datasource.names = m1,m2
spring.shardingsphere.datasource.m1.type = com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m1.driver-class-name = com.mysql.jdbc.Driver
spring.shardingsphere.datasource.m1.url = jdbc:mysql://172.16.14.128:3306/tt1?serverTimezone=Asia/Shanghai&characterEncoding=UTF-8&allowMultiQueries=true&zeroDateTimeBehavior=convertToNull&useSSL=false
spring.shardingsphere.datasource.m1.username = root
spring.shardingsphere.datasource.m1.password = Vv12345!
spring.shardingsphere.datasource.m2.type = com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m2.driver-class-name = com.mysql.jdbc.Driver
spring.shardingsphere.datasource.m2.url = jdbc:mysql://172.16.14.128:3306/tt2?serverTimezone=Asia/Shanghai&characterEncoding=UTF-8&allowMultiQueries=true&zeroDateTimeBehavior=convertToNull&useSSL=false
spring.shardingsphere.datasource.m2.username = root
spring.shardingsphere.datasource.m2.password = Vv12345!
# 分库策略,以user_id为分片键,分片策略为user_id % 2 + 1,user_id为偶数操作m1数据源,否则操作m2。
spring.shardingsphere.sharding.tables.t_order.database-strategy.inline.sharding-column = user_id
spring.shardingsphere.sharding.tables.t_order.database-strategy.inline.algorithm-expression = m$->{user_id % 2 + 1}
#分库策略,如何将一个逻辑表映射到多个数据源
spring.shardingsphere.sharding.tables.<逻辑表名称>.database‐strategy.<分片策略>.<分片策略属性名>= # 分片策略属性值
#分表策略,如何将一个逻辑表映射为多个实际表
spring.shardingsphere.sharding.tables.<逻辑表名称>.table‐strategy.<分片策略>.<分片策略属性名>= #分 片策略属性值
Sharding-JDBC支持以下几种分片策略: 不管理分库还是分表,策略基本一样。
standard:标准分片策略,对应StandardShardingStrategy。提供对SQL语句中的=, IN和BETWEEN AND的 分片操作支持。StandardShardingStrategy只支持单分片键,提供PreciseShardingAlgorithm和 RangeShardingAlgorithm两个分片算法。PreciseShardingAlgorithm是必选的,用于处理=和IN的分片。 RangeShardingAlgorithm是可选的,用于处理BETWEEN AND分片,如果不配置 RangeShardingAlgorithm,SQL中的BETWEEN AND将按照全库路由处理。
complex:符合分片策略,对应ComplexShardingStrategy。复合分片策略。提供对SQL语句中的=, IN和 BETWEEN AND的分片操作支持。ComplexShardingStrategy支持多分片键,由于多分片键之间的关系复 杂,因此并未进行过多的封装,而是直接将分片键值组合以及分片操作符透传至分片算法,完全由应用开发 者实现,提供最大的灵活度。
inline:行表达式分片策略,对应InlineShardingStrategy。使用Groovy的表达式,提供对SQL语句中的=和 IN的分片操作支持,只支持单分片键。对于简单的分片算法,可以通过简单的配置使用,从而避免繁琐的Java 代码开发,如: t_user_$->{u_id % 8} 表示t_user表根据u_id模8,而分成8张表,表名称为 t_user_0 到t_user_7 。
hint:Hint分片策略,对应HintShardingStrategy。通过Hint而非SQL解析的方式分片的策略。对于分片字段 非SQL决定,而由其他外置条件决定的场景,可使用SQL Hint灵活的注入分片字段。例:内部系统,按照员工 登录主键分库,而数据库中并无此字段。SQL Hint支持通过Java API和SQL注释(待实现)两种方式使用。 none:不分片策略,对应NoneShardingStrategy。不分片的策略。
目前例子中都使用inline分片策略,若对其他分片策略细节若感兴趣,请查阅官方文档: https://shardingsphere.apache.org
3.单元测试
3.1插入数据
package com.itheima.dbsharding.simple;
import com.itheima.dbsharding.simple.dao.OrderDao;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* @author jlm
* @version 1.0
**/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {ShardingJdbcSimpleBootstrap.class})
public class OrderDaoTest {
@Autowired
OrderDao orderDao;
@Test
public void testInsertOrder(){
long z = 1l;
for(int i=1;i<11;i++){
orderDao.insertOrder(new BigDecimal(i),z,"SUCCESS");
z++;
}
}
@Test
public void testSelectOrderbyIds(){
List<Long> ids = new ArrayList<>();
ids.add(462642714479951872L);
ids.add(462642714496729089L);
List<Map> maps = orderDao.selectOrderbyIds(ids);
System.out.println(maps);
}
}
根据打印的SQL我们可以明显的看到,user_id是奇数时对m2数据源操作,是偶数时对m1数据源进行操作
查看数据库数据符合预期结果
3.2查询数据
从数据库1和2中分别拿一个order_id,进行查询操作
运行后发现,它并没有去m2数据源进行查询,而是在m1数据源中查询了两次,此时我们需要修改一下配置文件
# 指定t_order表的数据分布情况,配置数据节点 m1.t_order_1,m1.t_order_2 m2.t_order_1,m2.t_order_2
spring.shardingsphere.sharding.tables.t_order.actual-data-nodes = m$->{1..2}.t_order_$->{1..2}
修改后,我们可以看到,这次获得我们想要的结果,sql执行了4条
此时我们可以修改一下dao层代码,指定user_id我们在看看
@Select("<script>" +
"select" +
" * " +
" from t_order t " +
" where t.order_id in " +
" <foreach collection='orderIds' open='(' separator=',' close=')' item='id'>" +
" #{id} " +
" </foreach>" +
" and user_id = 1" +
"</script>")
List<Map> selectOrderbyIds(@Param("orderIds") List<Long> orderIds);
此时只去查询了m2,因为user_id是奇数,那么奇数对应的数据源就是m2
为什么是两条sql呢,因为我们的order_id有一个是偶数,我们去掉偶数订单id,再看下结果
此时就仅仅执行了一条SQL