springboot篇】二十一. 基於springboot電商項目 十三 分庫分表介紹和案例

中國加油,武漢加油!

篇幅較長,配合目錄觀看

1. 分庫分表的邏輯

1.1 爲什麼要使用分庫分表

  1. 考慮到高性能,單庫中一個表的數據過多會影響到查詢的效率

1.2 如何分庫分表

  1. 按照收貨地址分庫分表,會有跨庫查詢的情況
  2. 按照用戶id來分
  3. 按照用戶id後四位來分
    3.1. 庫:用戶id%庫的數量
    3.2. 表:用戶id/表的數量%表的數量

1.3 Test

@Test
void contextLoads() {

    Integer userId = 4000;

    Integer dbNum = 2; // *2
    Integer tabNum = 2;

    for (int i = userId; i < 4100; i++) {
        // 數據庫規則
        Integer dbIndex = (i % dbNum) + 1;
        Integer tableIndex = (i / tabNum % tabNum) + 1;
        System.out.println("用戶Id:" + i + ",數據庫:" + dbIndex + ",表:" + tableIndex);
    }
	// 擴容模擬
    int x = 2;
    for (int i = 0; i < 3; i++) {
        Integer dbIndex = (userId % dbNum) + 1;
        Integer tableIndex = (userId / tabNum % tabNum) + 1;
        System.out.println("第【" + i + "】次用戶Id:" + userId + ",數據庫:" + dbIndex + ",表:" + tableIndex);
        dbNum *= x;
        tabNum *= x;
    }
}

2. Mybatis實現動態數據源

2.1 腳本準備

在這裏插入圖片描述

2.2 shop-temp新建datasource-demo(module-springboot)

  1. Lombok
  2. MySQL Driver

2.2.1 datasource-demo導包

<dependency>
	<groupId>com.baomidou</groupId>
	<artifactId>mybatis-plus-boot-starter</artifactId>
	<version>2.3</version>
</dependency>

2.2.2 定義Temp實體類

package com.wpj.entity;

import com.baomidou.mybatisplus.annotations.TableId;
import com.baomidou.mybatisplus.annotations.TableName;
import com.baomidou.mybatisplus.enums.IdType;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("t_temp")
public class Temp {
    @TableId(type = IdType.AUTO)
    private Integer id;
    private String name;
}

2.2.3 定義Mapper接口

package com.wpj.mapper;

import com.baomidou.mybatisplus.mapper.BaseMapper;
import com.wpj.entity.Temp;

public interface ITempMapper extends BaseMapper<Temp> {
}

2.2.4 定義一個ServiceImpl實現類(偷懶)

package com.wpj.service.impl;

import com.wpj.entity.Temp;
import com.wpj.mapper.ITempMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class TempServiceImpl {
    @Autowired
    private ITempMapper tempMapper;

    public List<Temp> getList(){
        return tempMapper.selectList(null);
    }
}

2.2.5 配置yml

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/nz1904-springboot-shop
    username: root
    password: 123456
    driver-class-name: com.mysql.jdbc.Driver
mybatis-plus:
  type-aliases-package: com.wpj.entity
  mapper-locations: classpath:/mapper/*.xml

2.2.6 程序入口開啓包掃描

package com.wpj;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication(scanBasePackages = "com.wpj")
@MapperScan(basePackages = "com.wpj.mapper")
public class DatasourceDemoApplication {

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

2.2.7 Test

在這裏插入圖片描述

2.3 關閉自動創建數據源

package com.wpj;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;

@SpringBootApplication(scanBasePackages = "com.wpj", exclude = DataSourceAutoConfiguration.class)
@MapperScan(basePackages = "com.wpj.mapper")
public class DatasourceDemoApplication {

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

2.4 配置yml

spring:
  datasource1:
    url: jdbc:mysql://localhost:3306/nz1904-springboot-shop
    username: root
    password: 123456
    driver-class-name: com.mysql.jdbc.Driver
  datasource2:
    url: jdbc:mysql://localhost:3306/nz1904-springboot-shop-02
    username: root
    password: 123456
    driver-class-name: com.mysql.jdbc.Driver
mybatis-plus:
  type-aliases-package: com.wpj.entity
  mapper-locations: classpath:/mapper/*.xml

2.5 定義ThreadLocalDBName動態指定數據源

package com.wpj.config;

public class ThreadLocalDBName {

    private static ThreadLocal<String> threadLocal = new ThreadLocal<String>();

    public static void set(String dbName) {
        threadLocal.set(dbName);
    }

    public static String get() {
        return threadLocal.get();
    }
}

2.6 定義DynamicDataSource動態傳教數據源

package com.wpj.config;

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import org.springframework.lang.Nullable;

// MyBatis創建動態數據源
public class DynamicDataSource extends AbstractRoutingDataSource {

    @Override
    @Nullable
    protected Object determineCurrentLookupKey() {
        return ThreadLocalDBName.get();
    }
}

2.7 定義MyBatisConfig手動配置數據源

package com.wpj.config;

import com.zaxxer.hikari.HikariDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyBatisConfig {

    @Value("${spring.datasource1.username}")
    private String username;
    @Value("${spring.datasource1.password}")
    private String password;
    @Value("${spring.datasource1.driver-class-name}")
    private String driverClass;
    @Value("${spring.datasource1.url}")
    private String url1;
    @Value("${spring.datasource2.url}")
    private String url2;
    
    @Bean
    public HikariDataSource dataSource1(){
        HikariDataSource dataSource = new HikariDataSource();
        dataSource.setJdbcUrl(url1);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        dataSource.setDriverClassName(driverClass);
        return dataSource;
    }
    @Bean
    public HikariDataSource dataSource2(){
        HikariDataSource dataSource = new HikariDataSource();
        dataSource.setJdbcUrl(url2);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        dataSource.setDriverClassName(driverClass);
        return dataSource;
    }
     @Bean
    public DynamicDataSource dynamicDataSource(){
        Map<Object, Object> map = new HashMap<>();
        map.put("db1", dataSource1());
        map.put("db2", dataSource2());
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        dynamicDataSource.setTargetDataSources(map);
        dynamicDataSource.setDefaultTargetDataSource(dataSource1());
        return dynamicDataSource;
    }
    /**
     * 因爲我們要使用Mybatis-Plus,所以這裏要創建MybatisSqlSessionFactoryBean
     * @return
     */
    @Bean
    public MybatisSqlSessionFactoryBean mybatisSqlSessionFactoryBean(){
        MybatisSqlSessionFactoryBean sqlSessionFactoryBean = new MybatisSqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dynamicDataSource());
        sqlSessionFactoryBean.setTypeAliasesPackage("com.wpj.entity");
        return sqlSessionFactoryBean;
    }
}

2.8 Test

public List<Temp> getList(){
	ThreadLocalDBName.set("db2");
	return tempMapper.selectList(null);
}

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章