中國加油,武漢加油!
篇幅較長,配合目錄觀看
1. 分庫分表的邏輯
1.1 爲什麼要使用分庫分表
- 考慮到高性能,單庫中一個表的數據過多會影響到查詢的效率
1.2 如何分庫分表
- 按照收貨地址分庫分表,會有跨庫查詢的情況
- 按照用戶id來分
- 按照用戶id後四位來分
3.1. 庫:用戶id%庫的數量
3.2. 表:用戶id/表的數量%表的數量
1.3 Test
@Test
void contextLoads() {
Integer userId = 4000;
Integer dbNum = 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)
- Lombok
- 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;
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;
}
@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);
}