springboot2+JPA集成 sharing-jdbc实现单库分表

Posted 零度anngle

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了springboot2+JPA集成 sharing-jdbc实现单库分表相关的知识,希望对你有一定的参考价值。

1、用户表增长到一定程度,我们假设对user表进行分库操作,user为表的逻辑名,实际表名为user_$0..3,即user_0,user_1,user_2,user_3,

    首先创建四张表:

CREATE TABLE `user_0` (
  `id` bigint(64) NOT NULL,
  `city` varchar(20) NOT NULL,
  `name` varchar(20) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

CREATE TABLE `user_1` (
  `id` bigint(64) NOT NULL,
  `city` varchar(20) NOT NULL,
  `name` varchar(20) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

CREATE TABLE `user_2` (
  `id` bigint(64) NOT NULL,
  `city` varchar(20) NOT NULL,
  `name` varchar(20) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

CREATE TABLE `user_3` (
  `id` bigint(64) NOT NULL,
  `city` varchar(20) NOT NULL,
  `name` varchar(20) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

2、引入依赖,我需要以下依赖,三个组件+一个mysql连接驱动

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

<dependency>
    <groupId>org.apache.shardingsphere</groupId>
    <artifactId>sharding-jdbc-core</artifactId>
    <version>4.1.1</version>
</dependency>

<dependency>
    <groupId>org.apache.shardingsphere</groupId>
    <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
    <version>4.1.1</version>
</dependency>

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>

3、基本代码

1、model类:User.java

@Data
@Entity
@Table(name="user")
public class User 
    @Id
    private Long id;

    @Column(updatable = false)
    private String city;

    private String name;

2、dao类:UserRepository.java

package com.zmx.demo.shardingJdbcTest.dao;
import com.zmx.demo.shardingJdbcTest.domain.User;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;
public interface UserRepository extends JpaRepository<User,Long> 

    List<User>  findUserByCity(String city);

    List<User> findUserByNameLike(String name);

3、测试类型

    @Test
    public void testUserRepository()

        User user1 = new User();
        user1.setId(1L);
        user1.setCity("常山");
        user1.setName("赵子龙");
        userRepository.save(user1);


        User user2 = new User();
        user2.setId(2L);
        user2.setCity("山东");
        user2.setName("诸葛亮");
        userRepository.save(user2);


        User user3 = new User();
        user3.setId(3L);
        user3.setCity("山西");
        user3.setName("黄忠");
        userRepository.save(user3);


        User user4 = new User();
        user4.setId(4L);
        user4.setCity("东北");
        user4.setName("马超");
        userRepository.save(user4);


        User user5 = new User();
        user5.setId(5L);
        user5.setCity("长德");
        user5.setName("关云长");
        userRepository.save(user5);


        User user6 = new User();
        user6.setId(6L);
        user6.setCity("长德");
        user6.setName("张翼德");
        userRepository.save(user6);

    


    @Test
    public void testUserDao()
        // String city = "长德";
        // List<User> userList = userRepository.findUserByCity(city);

        String keyword = "黄";
        List<User> userList = userDao.queryByName(keyword,1,10);
        userList.forEach(x -> System.out.println(x.getName()));

    

4、配置文件:(通过代码也可以看出我们使用city字段对用户进行分表的)

#jpa
logging.level.org.hibernate.SQL=DEBUG
spring.jpa.database=mysql
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=none

#sharing-jdbc-datasource

spring.shardingsphere.datasource.names=db
spring.shardingsphere.datasource.db.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.db.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.db.jdbc-url=jdbc:mysql://host:3306/db?serverTimezone=GMT%2b8&useUnicode=true&autoReconnect=true&characterEncoding=utf-8&generateSimpleParameterMetadata=true
spring.shardingsphere.datasource.db.username=root
spring.shardingsphere.datasource.db.password=XXXXXX

#分表策略
spring.shardingsphere.sharding.tables.user.actual-data-nodes=db.user_$0..3
spring.shardingsphere.sharding.tables.user.table-strategy.standard.sharding-column=city
spring.shardingsphere.sharding.tables.user.table-strategy.standard.precise-algorithm-class-name=com.zmx.demo.shardingJdbcTest.UserSharingAlgorithm
spring.shardingsphere.props.sql.show=true

上面配置之后,我们使用了新的sharing-jdbc-datasource替换了原来的jdbc-datasource,同时配置了User表的分表策略,还有上述配置还应用了一个分表算法:

UserSharingAlgorithm.java,这个是最正规代码,我们要实现sharing-jbdc给我提供的接口:PreciseShardingAlgorithm类,具体实现如下:
package com.zmx.demo.shardingJdbcTest;

import lombok.extern.slf4j.Slf4j;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingValue;

import java.util.Collection;

/**
 * 分表算法
 */
@Slf4j
public class UserSharingAlgorithm implements PreciseShardingAlgorithm<String> 

    @Override
    public String doSharding(Collection<String> collection, PreciseShardingValue<String> preciseShardingValue) 
        log.debug("分表算法参数 ,",collection,preciseShardingValue);
        int hash = HashUtils.rsHash(String.valueOf(preciseShardingValue.getValue()));
        return "user_" + (hash % 4);
    

其实很简单,就先对city进行rehash,然后取模,四张表就是除4,Hash算法大家可以自行google,我也提供一个,以免大家阅读不顺畅,如下:

    /**
     * RS算法hash
     * @param str 字符串
     * @return hash值
     */

    public static int rsHash(String str) 
        int b = 378551;
        int a = 63689;
        int hash = 0;
        for (int i = 0; i < str.length(); i++) 
            hash = hash * a + str.charAt(i);
            a = a * b;
        
        return hash & 0x7FFFFFFF;
    

一切进本完成,运行测试:

可以看到数据被分别插入到不同表中,相同city的数据被放到了同一张表中。

以上是关于springboot2+JPA集成 sharing-jdbc实现单库分表的主要内容,如果未能解决你的问题,请参考以下文章

SpringBoot2.0 基础案例(09):集成JPA持久层框架,简化数据库操作

SpringBoot 2.1.1.RELEASE 集成JPA

springspringboot使用jpa集成elasticsearch7.0

Springboot集成ES及JPA

Spring Boot 2.1 缺少多个 org.hibernate.jpa.event 类

在集成测试中每个方法不回滚后 Spring Data JPA 数据库更改