小编最近一直在研究关于分库分表的东西,前几天docker安装了mycat实现了分库分表,但是都在说mycat的bug很多。很多人还是倾向于shardingsphere
,其实他是一个全家桶,有JDBC、Proxy 和 Sidecar
组成,小编今天以最简单的JDBC
来简单整合一下!
现在最新版已经是5.1.1
,小编看了半天也没明白怎么配置,高版本的咱不会,咱只能搞低版本的试试,体验一下,后续在研究高版本的哈!
主要分享一下在搭建过程中需要的坑,帮助后来人铺路!!
如果想看mycat的可以看一下小编之前写的文章哈:Docker安装Mycat和Mysql进行水平分库分表实战
写在前面:小编本来用的是4.1.1
,但是运行就报错,后面再和大家说,所以本教学最终使用的版本是:4.0.0-RC1
,如果嫌弃版本太老可以走了,不要浪费时间!后续小编研究明白就会更新新版本的哈,点个关注,更新了来看哦!!
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
<exclusions>
<exclusion>
<groupId>org.junit.vintagegroupId>
<artifactId>junit-vintage-engineartifactId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>org.apache.shardingspheregroupId>
<artifactId>sharding-jdbc-spring-boot-starterartifactId>
<version>4.0.0-RC1version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.18.10version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druid-spring-boot-starterartifactId>
<version>1.1.21version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-jdbcartifactId>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
dependency>
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-boot-starterartifactId>
<version>3.5.1version>
dependency>
前面说了,4.1.1
这个版本有问题,现在来详细说一下哈!
Caused by: java.lang.IllegalArgumentException: Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required
at org.springframework.util.Assert.notNull(Assert.java:201) ~[spring-core-5.2.12.RELEASE.jar:5.2.12.RELEASE]
at org.mybatis.spring.support.SqlSessionDaoSupport.checkDaoConfig(SqlSessionDaoSupport.java:122) ~[mybatis-spring-2.0.6.jar:2.0.6]
at org.mybatis.spring.mapper.MapperFactoryBean.checkDaoConfig(MapperFactoryBean.java:73) ~[mybatis-spring-2.0.6.jar:2.0.6]
at org.springframework.dao.support.DaoSupport.afterPropertiesSet(DaoSupport.java:44) ~[spring-tx-5.2.12.RELEASE.jar:5.2.12.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1853) ~[spring-beans-5.2.12.RELEASE.jar:5.2.12.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1790) ~[spring-beans-5.2.12.RELEASE.jar:5.2.12.RELEASE]
... 30 common frames omitted
经过长达1小时的不断改进,最终解决为用低版本的!如果有大佬有其他解决方案,欢迎评论区交流哈!!
<dependency>
<groupId>org.apache.shardingspheregroupId>
<artifactId>sharding-jdbc-spring-boot-starterartifactId>
<version>4.0.0-RC1version>
dependency>
命名为:user_0
、user_1
CREATE TABLE `user_0` (
`cid` bigint(25) NOT NULL,
`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`gender` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`data` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`cid`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;
@Data
public class User implements Serializable {
private static final long serialVersionUID = 337361630075002456L;
private Long cid;
private String name;
private String gender;
private String data;
}
@RestController
@RequestMapping("/test")
public class UserController {
@Autowired
private UserMapper userMapper;
@GetMapping("/insertTest")
public void insertTest(){
for (int i = 1 ; i < 10; i++) {
User test = new User("王"+i,"男","数据" + i);
userMapper.insert(test);
}
}
}
我们直接省略了service,简单一下哈!!
public interface UserMapper extends BaseMapper<User> {
}
server:
port: 8089
spring:
main:
# 一个实体类对应三张表,覆盖,不然启动报错
allow-bean-definition-overriding: true
# Sharding-JDBC的配置
shardingsphere:
datasource:
# 数据源(逻辑名字)
names: m1
# 配置数据源
m1:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/test?characterEncoding=utf8&useSSL=true&createDatabaseIfNotExist=true&serverTimezone=GMT&nullNamePatternMatchesAll=true
username: root
password: root
# 分片的配置
sharding:
# 表的分片策略
tables:
# 逻辑表的名称
user:
# 数据节点配置,采用Groovy表达式
actual-data-nodes: m1.user_$->{0..1}
# 配置策略
table-strategy:
# 精确匹配
inline:
sharding-column: cid
algorithm-expression: user_$->{cid % 2}
# 主键生成策略
key-generator:
# 主键
column: cid
# 雪花算法
type: SNOWFLAKE
props:
sql:
# 日志显示具体的SQL
show: true
logging:
level:
com.wang.test.demo: DEBUG
mybatis-plus:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.example.demo.entity
configuration:
#在映射实体或者属性时,将数据库中表名和字段名中的下划线去掉,按照驼峰命名法映射 address_book ---> addressBook
map-underscore-to-camel-case: true
@MapperScan("com.example.demo.mapper")
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
本次测试策略是:行表达式分片策略:inline
输入 :localhost:8089/test/insertTest
分片成功
@GetMapping("/selectTest")
public void selectTest(){
User user = userMapper.selectOne(Wrappers.<User>lambdaQuery().eq(User::getCid,736866689420886017L));
System.out.println(user);
}
@GetMapping("/selectListTest")
public void selectListTest(){
List<User> list = userMapper.selectList(null);
System.out.println(list);
}
由于没有条件,他会去两个表中都进行查询然后汇总给我们
需要先配置mybatis-plus分页配置类:
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
@GetMapping("/selectListPage")
public void selectListPage(){
IPage<User> page = new Page(1,5);
IPage<User> userIPage = userMapper.selectPage(page,null);
List<User> records = userIPage.getRecords();
System.out.println(records);
}
我们user_0有4条数据,user_1有5条数据
我们发现它会向所有的表中去进行一遍分页查询,第一个表数据不够就会加上另一个表分页拿到的值
分页size为3时,一个user_0就可以满足分页条件,就会忽略user_1的分页数据。
我们先把user_0表
性别修改两个为女,然后进行查询!看看没有分片的字段是否能够只去user_0
去查询
@GetMapping("/selectListByGender")
public void selectListByGender(){
List<User> list = userMapper.selectList(Wrappers.<User>lambdaQuery().eq(User::getGender, "女"));
System.out.println(list);
}
有图可见:不是分片的字段查询,回去所有的表去查询一遍,效率和不分表一样了哈!!
这样就完成了一个简单的分表的测试,后面小编在研究一下其他的分片操作,后续在写博客进行更新。看到这里了,还不给小编一键三连走起来,谢谢大家了!!
点击访问!小编自己的网站,里面也是有很多好的文章哦!