1. 程式人生 > 實用技巧 >Sharding-JDBC 實戰

Sharding-JDBC 實戰

Sharding-JDBC簡單使用


1.Sharding-JDBC之環境搭建


1.1 建立一個Maven專案 mysql-example,父工程專案pom.xml如下

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>mysql-example</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>sharding-jdbc-example</module>
    </modules>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.compile.sourceEncoding>UTF-8</project.compile.sourceEncoding>
        <shardingsphere.version>4.1.0</shardingsphere.version>
        <springboot.version>2.2.5.RELEASE</springboot.version>
    </properties>

  <dependencyManagement>
      <dependencies>
          <dependency>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-starter-jdbc</artifactId>
              <version>${springboot.version}</version>
          </dependency>

          <dependency>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-starter-data-jpa</artifactId>
              <version>${springboot.version}</version>
          </dependency>

          <dependency>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-starter-test</artifactId>
              <version>${springboot.version}</version>
              <scope>test</scope>
          </dependency>

          <dependency>
              <groupId>mysql</groupId>
              <artifactId>mysql-connector-java</artifactId>
              <version>5.1.48</version>
          </dependency>
          <dependency>
              <groupId>org.apache.shardingsphere</groupId>
              <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
              <version>${shardingsphere.version}</version>
          </dependency>
      </dependencies>
  </dependencyManagement>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <testSource>1.8</testSource>
                    <testTarget>1.8</testTarget>
                </configuration>
                <version>3.8.1</version>
            </plugin>
        </plugins>
    </build>
</project>


1.2 建立子模組sharding-jdbc-example,子模組專案pom.xml如下

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>mysql-example</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>sharding-jdbc-example</artifactId>
  <dependencies>
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-jdbc</artifactId>
      </dependency>

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

      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-test</artifactId>
          <scope>test</scope>
      </dependency>

      <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
      </dependency>
      <dependency>
          <groupId>org.apache.shardingsphere</groupId>
          <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
      </dependency>

  </dependencies>

</project>


2.Sharding-JDBC之職位分庫業務


2.1資料庫準備

  • 使用的mysql 5.5.54
  • 由於資源限制,我就在一個服務裡建兩個資料庫lagou1,lagou2,建立相同的職位表,職位詳情表

  • 建表語句如下
#position表
CREATE TABLE `position` (
	`id` BIGINT ( 20 ) NOT NULL AUTO_INCREMENT,
	`name` VARCHAR ( 255 ) DEFAULT NULL,
	`salary` VARCHAR ( 50 ) DEFAULT NULL,
	`city` VARCHAR ( 255 ) DEFAULT NULL,
PRIMARY KEY ( `id` ) 
) ENGINE = INNODB AUTO_INCREMENT = 490171537622564865 DEFAULT CHARSET = utf8;

#position_detail表
CREATE TABLE `position_detail` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `pid` bigint(11) DEFAULT NULL,
  `description` text,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=490171537891000321 DEFAULT CHARSET=utf8;

2.2.2 建立實體類與Repository


# Position
package com.lagou.entity;

import javax.persistence.*;
import java.io.Serializable;

@Entity
@Table(name = "position")
public class Position implements Serializable{
    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @Column(name = "name")
    private  String name;
    @Column(name = "salary")
    private  String salary;
    @Column(name = "city")
    private  String city;


    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSalary() {
        return salary;
    }

    public void setSalary(String salary) {
        this.salary = salary;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    @Override
    public String toString() {
        return "Position{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", salary='" + salary + '\'' +
                ", city='" + city + '\'' +
                '}';
    }
}

#PositionDetail

package com.lagou.entity;

import javax.persistence.*;
import java.io.Serializable;
@Entity
@Table(name = "position_detail")
public class PositionDetail implements Serializable {
    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @Column(name = "pid")
    private Long pid;
    @Column(name = "description")
    private String description;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Long getPid() {
        return pid;
    }

    public void setPid(Long pid) {
        this.pid = pid;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }
}

## PositionRepository
package com.lagou.repository;

import com.lagou.entity.Position;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

public interface PositionRepository extends JpaRepository<Position,Long> {
    @Query(nativeQuery = true,value = "select p.id,p.name,p.salary,p.city,pd.description from position p join position_detail pd on(p.id =pd.pid) where p.id=:id")
    public Object findPositionsById(@Param("id") long id);
}

## PositionDetailRepository

package com.lagou.repository;

import com.lagou.entity.PositionDetail;
import org.springframework.data.jpa.repository.JpaRepository;

public interface PositionDetailRepository extends JpaRepository<PositionDetail,Long> {
}

## 啟動類

package com.lagou;

import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class RunBoot {
}


2.2.3 配置檔案

  • application.properties
spring.profiles.active=sharding-database
spring.shardingsphere.props.sql.show=true

  • application-sharding-database.properties
#datasource
spring.shardingsphere.datasource.names=ds0,ds1

spring.shardingsphere.datasource.ds0.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds0.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds0.jdbc-url=jdbc:mysql://127.0.0.1:3306/lagou1
spring.shardingsphere.datasource.ds0.username=root
spring.shardingsphere.datasource.ds0.password=root
#連線池型別jpa預設的是HikariDataSource
spring.shardingsphere.datasource.ds1.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds1.jdbc-url=jdbc:mysql://127.0.0.1:3306/lagou2
spring.shardingsphere.datasource.ds1.username=root
spring.shardingsphere.datasource.ds1.password=root



#sharding-database
#position表名, database-strategy :按庫切分 ,  inline:行表示式格式,  sharding-column:指明分片鍵
spring.shardingsphere.sharding.tables.position.database-strategy.inline.sharding-column=id

# algorithm-expression:指明表示式什麼時候定位到ds0ds1
spring.shardingsphere.sharding.tables.position.database-strategy.inline.algorithm-expression=ds$->{id % 2}

#position_detail的配置
spring.shardingsphere.sharding.tables.position_detail.database-strategy.inline.sharding-column=pid
spring.shardingsphere.sharding.tables.position_detail.database-strategy.inline.algorithm-expression=ds$->{pid % 2}

# 主鍵生成策略

#指定主鍵id的欄位名  #指定type型別如UUID ,SNOWFLAKE  注意使用jpa中entity的id主鍵生成需開啟
spring.shardingsphere.sharding.tables.position.key-generator.column=id

spring.shardingsphere.sharding.tables.position.key-generator.type=SNOWFLAKE

#spring.shardingsphere.sharding.tables.position.key-generator.type=LAGOUKEY


#position_detail的主鍵生成策略
spring.shardingsphere.sharding.tables.position_detail.key-generator.column=id
spring.shardingsphere.sharding.tables.position_detail.key-generator.type=SNOWFLAKE


2.2.4 測試類TestShardingDatabase

import javax.annotation.Resource;
import java.util.Date;
import java.util.Random;

@RunWith(SpringRunner.class)
@SpringBootTest(classes = RunBoot.class)
public class TestShardingDatabase {

    @Resource
    private PositionRepository positionRepository;
    @Resource
    private PositionDetailRepository positionDetailRepository;
   
    @Test
    public  void testAdd() {
        for (int i = 1; i <= 20; i++) {
            Position position = new Position();
            position.setName("lagou" + i);
            position.setSalary("10000");
            position.setCity("beijing");
            positionRepository.save(position);

            PositionDetail positionDetail = new PositionDetail();
            positionDetail.setPid(position.getId());
            positionDetail.setDescription("this is a pig" + i);
            positionDetailRepository.save(positionDetail);

        }
    }

}

2.2.5 執行效果





2.2.6 自定義主鍵生成策略實現 ShardingKeyGenerator介面即可

package com.lagou.id;

import org.apache.shardingsphere.core.strategy.keygen.SnowflakeShardingKeyGenerator;
import org.apache.shardingsphere.spi.keygen.ShardingKeyGenerator;

import java.util.Properties;

/**
 * 自定義主鍵生成器 
 */
public class MyLagouId implements ShardingKeyGenerator {

    /**
     * 用同一個主鍵生成器物件 就會分配均勻
     */
    private  SnowflakeShardingKeyGenerator snowflakeShardingKeyGenerator =  new SnowflakeShardingKeyGenerator();

    /**
     * 返回我們生成的主鍵值 由於這個演算法比較複雜,就還是使用SNOWFLAKE,也可以自己寫
     * @return
     */
    @Override
    public Comparable<?> generateKey() {
        System.out.println("---執行了自定義主鍵生成器MyLagouId");
        return snowflakeShardingKeyGenerator.generateKey();
    }

    /**
     * 返回配置檔案中那個的type
     * @return
     */
    @Override
    public String getType() {
        return "LAGOUKEY";
    }

    @Override
    public Properties getProperties() {
        return null;
    }

    @Override
    public void setProperties(Properties properties) {

    }
}

2.2.6.1 修改配置檔案並在resources下建一下檔案(檔名需一致)

  • org.apache.shardingsphere.spi.keygen.ShardingKeyGenerator內容如下
com.lagou.id.MyLagouId

  • 注意:resource檔案下的目錄分級為/

2.2.7修改application-sharding-database.properties的主鍵生成策略的type為自定義主鍵生成策略返回的type

spring.shardingsphere.sharding.tables.position.key-generator.type=LAGOUKEY


3.Sharding-JDBC之訂單分庫分表