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的数据被放到了同一张表中。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值