ShardingSphere+JPA+Druid实现分表操作

要在SpringBoot项目中实现分表操作,本文使用的是ShardingSphere+JPA+Druid实现。过程中出现问题记录一下。

  1. 准备MySQL数据库表
    这里准备的是一张主表test_cost,两张从表test_cost_0和test_cost_1,结构需要相同,主表只是声明了表结构,供后端框架提供映射关系,不存储数据,从表是真正存储数据的表。
    在这里插入图片描述
  2. 引入依赖
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>2.6.0</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
    <version>2.6.0</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.26</version>
</dependency>
<!-- Spring Boot Starter Test -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <version>2.6.0</version>
    <scope>test</scope>
</dependency>
<!-- ShardingSphere -->
<dependency>
    <groupId>org.apache.shardingsphere</groupId>
    <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
    <version>5.2.0</version>
</dependency>
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-crypto</artifactId>
    <version>5.7.8</version> 
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.18</version>
</dependency>
<!-- Druid数据源 -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.2.8</version>
</dependency>
  1. 配置文件
server:
  port: 8080

spring:
  jpa:
    properties:
      hibernate:
        hbm2ddl:
          auto: update
        dialect: org.hibernate.dialect.MySQL5Dialect
        show_sql: true
        ddl-auto: create-drop
  shardingsphere:
    datasource:
      names: books # 数据库名称
      books:
        driver-class-name: com.mysql.cj.jdbc.Driver
        type: com.alibaba.druid.pool.DruidDataSource
        url: jdbc:mysql://localhost:3306/books?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
        username: root
        password: 980828
    rules:
      sharding:
        sharding-algorithms: #分片算法配置
          table-inline:
            type: INLINE
            props:
              algorithm-expression: test_cost_$->{ id % 2 }
        key-generators: #主键生成策略
          snowflake:
            type: SNOWFLAKE
            props:
              worker-id: 1
        tables: #分表策略
          test_cost: # 主表名称
            actual-data-nodes: books.test_cost_$->{0..1}
            table-strategy:
              standard:
                sharding-column: id
                sharding-algorithm-name: table-inline
    props:
      sql-show: true

这里的分片算法是根据id字段能否被2整除来分,分到两张从表中。

  1. Repository
@Repository
public interface TestRepository extends JpaRepository<TestEntity, Long> {
}
  1. 实体类
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Entity
@Table(name = "test_cost")
public class TestEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;
    private String name;
    private String gender;
    private String country;
    private BigDecimal cost;

}

在配置文件中配置了主键生成策略和分片算法,此处@GeneratedValue不能选IDENTITY,要选AUTO,由jpa自动选择。@Table的值为主表的表名。

  1. 遇见问题
    项目启动失败,出现了下图所示的异常:
    在这里插入图片描述
    从sharding官网的FAQ中发现如下解释:
    在这里插入图片描述

解决方案有两个:

  • 去掉druid-spring-boot-starter,直接使用druid-xxx.jar来替代,这就不会出现两个数据源冲突的问题
  • 仍然使用druid-spring-boot-starter,但是在springboot的启动类上exclude掉DruidDataSourceAutoConfigure这个类,忽略druid连接池的默认数据源配置(@SpringBootApplication(exclude = {DruidDataSourceAutoConfigure.class}))

这里采用的是第二种方式:

@SpringBootApplication(exclude = {DruidDataSourceAutoConfigure.class})
public class SpringbootRedisApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootRedisApplication.class, args);
    }

}
  1. 启动项目,报错:java.sql.SQLException: url not set
    在这里插入图片描述
    原因是配置文件的数据源处的数据库URL的键应为“url”而不是“jdbc-url”!!!(3中提供的是正确的配置)
    在这里插入图片描述
    改成url后,重新启动,运行正常。

  2. 运行结果
    在这里插入图片描述
    在这里插入图片描述
    成功按照分片算法插入到对应的分表中。