springBoot 整合 sharding-jdbc Jpa 分庫分表
阿新 • • 發佈:2021-01-08
專案結構:
application.properties 檔案配置:
##Jpa配置 spring.jpa.database=mysql spring.jpa.show-sql=true spring.jpa.hibernate.ddl-auto=none ##資料庫配置 ##資料庫acnew地址 acnew.url=jdbc:mysql://localhost:3306/acnew?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai ##資料庫acnew使用者名稱 acnew.username=root ##資料庫acnew密碼 acnew.password=root ##資料庫acnew驅動 acnew.driverClassName=com.mysql.cj.jdbc.Driver ##資料庫acnew名稱 acnew.databaseName=acnew ##資料庫acold地址 acold.url=jdbc:mysql://localhost:3306/acold?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai ##資料庫acold使用者名稱 acold.username=root ##資料庫acold密碼 acold.password=root ##資料庫acold驅動 acold.driverClassName=com.mysql.cj.jdbc.Driver ##資料庫acold名稱 acold.databaseName=acold
1.Controller層 :
package com..web; import com.dangdang.ddframe.rdb.sharding.keygen.KeyGenerator;import com..dao.Save; import com..service.SaveInfoMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.repository.query.Param; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; importjava.util.ArrayList; import java.util.List; @RestController public class SaveController { @Autowired private SaveInfoMapper saveInfoMapper; //http://localhost:8080/save @GetMapping("save") public String save(){ long time = System.currentTimeMillis(); for(int i= 1 ; i <= 40 ; i ++){ Save save = new Save(); save.setId((long) i); save.setUsername( "shangpin" + i); save.setApplyno(i+1+""); save.setType((long) (i+1)); Save save1= saveInfoMapper.save(save); System.out.println(save1); } return "success"; } //http://localhost:8080/selectAll @GetMapping("selectAll") public List<Save> select(){ return saveInfoMapper.findAll(); } //http://localhost:8080/select @GetMapping("select") public List<Save> select(String id){ return saveInfoMapper.findAllByIdBetween(21L,39L); } //http://localhost:8080/find?id=1 @GetMapping("find") public Object find(@Param("id") Long id){ System.out.println(id); List<Long> list = new ArrayList<>(); list.add(id); return saveInfoMapper.findAllByIdIn(list); } //http://localhost:8080/delete @GetMapping("delete") public void delete(String id){ saveInfoMapper.deleteAll(); } }
2.資料表實體類:
package com..dao; import lombok.Data; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Table; import java.sql.Date; @Entity @Table(name="save") @Data public class Save { @Id private Long id; private String applyno; private String username; private String usernumber; private String address; private Long type; private String count; }
3. 資料表介面類:
package com.wondersgroup.service; import com.wondersgroup.dao.Save; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Component; import java.util.List; public interface SaveInfoMapper extends JpaRepository<Save,String> { List<Save> findAllByIdBetween(Long id1,Long id2); List<Save> findAllByIdIn(List<Long> id); }
4.兩個資料庫配置類:
acnew: package com..database; import com.alibaba.druid.pool.DruidDataSource; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; import javax.sql.DataSource; @Component @ConfigurationProperties(prefix = "acnew") public class Ac_newConfig { private String url; private String username; private String password; private String databaseName; private String driverClassName; public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getDriverClassName() { return driverClassName; } public void setDriverClassName(String driverClassName) { this.driverClassName = driverClassName; } public String getDatabaseName() { return databaseName; } public void setDatabaseName(String databaseName) { this.databaseName = databaseName; } public DataSource createDataSource() { DruidDataSource result = new DruidDataSource(); result.setDriverClassName(getDriverClassName()); result.setUrl(getUrl()); result.setUsername(getUsername()); result.setPassword(getPassword()); return result; } }
acold: package com..database; import com.alibaba.druid.pool.DruidDataSource; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; import javax.sql.DataSource; @Component @ConfigurationProperties(prefix = "acold") public class Ac_oldConfig { private String url; private String username; private String password; private String databaseName; private String driverClassName; public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getDriverClassName() { return driverClassName; } public void setDriverClassName(String driverClassName) { this.driverClassName = driverClassName; } public String getDatabaseName() { return databaseName; } public void setDatabaseName(String databaseName) { this.databaseName = databaseName; } public DataSource createDataSource() { DruidDataSource result = new DruidDataSource(); result.setDriverClassName(getDriverClassName()); result.setUrl(getUrl()); result.setUsername(getUsername()); result.setPassword(getPassword()); return result; } }
5.分庫分表策略類:
分庫: /** * 這裡使用的都是單鍵分片策略 * 示例分庫策略是: * id<=20使用acnew庫 * 其餘使用acold庫 */ package com..config; import com.dangdang.ddframe.rdb.sharding.api.ShardingValue; import com.dangdang.ddframe.rdb.sharding.api.strategy.database.SingleKeyDatabaseShardingAlgorithm; import com.google.common.collect.Range; import com..database.Ac_newConfig; import com..database.Ac_oldConfig; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.Collection; import java.util.LinkedHashSet; @Component public class FkShardingAlgorithm implements SingleKeyDatabaseShardingAlgorithm<Long> { @Autowired private Ac_newConfig ac_newConfig; @Autowired private Ac_oldConfig ac_OldConfig; @Override public String doEqualSharding(final Collection<String> availableTargetNames,final ShardingValue<Long> shardingValue) { Long value = shardingValue.getValue(); if (value <= 20L) { return ac_newConfig.getDatabaseName(); } else { return ac_OldConfig.getDatabaseName(); } } @Override public Collection<String> doInSharding(final Collection<String> availableTargetNames,final ShardingValue<Long> shardingValue) { Collection<String> result = new LinkedHashSet<>(availableTargetNames.size()); for (Long value : shardingValue.getValues()) { if (value <= 20L) { result.add(ac_newConfig.getDatabaseName()); } else { result.add(ac_OldConfig.getDatabaseName()); } } return result; } @Override public Collection<String> doBetweenSharding(final Collection<String> availableTargetNames, final ShardingValue<Long> shardingValue) { Collection<String> result = new LinkedHashSet<>(availableTargetNames.size()); Range<Long> range = shardingValue.getValueRange(); for (Long value = range.lowerEndpoint(); value <= range.upperEndpoint(); value++) { if (value <= 20L) { result.add(ac_newConfig.getDatabaseName()); } else { result.add(ac_OldConfig.getDatabaseName()); } } return result; } } 分表: /** * 這裡使用的都是單鍵分片策略 * 示例分表策略是: * type為奇數使用one表 * type為偶數使用two表 */ package com..config; import com.dangdang.ddframe.rdb.sharding.api.ShardingValue; import com.dangdang.ddframe.rdb.sharding.api.strategy.database.SingleKeyDatabaseShardingAlgorithm; import com.dangdang.ddframe.rdb.sharding.api.strategy.table.SingleKeyTableShardingAlgorithm; import com.google.common.collect.Range; import org.springframework.stereotype.Component; import java.util.Collection; import java.util.LinkedHashSet; @Component public class FbShardingAlgorithm implements SingleKeyTableShardingAlgorithm<Long> { @Override public String doEqualSharding(final Collection<String> tableNames,final ShardingValue<Long> shardingValue) { for(String table : tableNames){ System.out.println(table+"---"+shardingValue); System.out.println(shardingValue.getValue()%2+""); if("0".endsWith(shardingValue.getValue()%2+"")){ return "one"; }else{ return "two"; } } throw new IllegalArgumentException("無分表引數 無法定位具體資料表"); } @Override public Collection<String> doInSharding(final Collection<String> tableNames,final ShardingValue<Long> shardingValue) { Collection<String> result = new LinkedHashSet<>(tableNames.size()); for (Long value : shardingValue.getValues()) { for (String tableName : tableNames) { if (tableName.endsWith(String.valueOf(value))) { result.add(tableName); } } } return result; } @Override public Collection<String> doBetweenSharding(final Collection<String> tableNames,final ShardingValue<Long> shardingValue) { Collection<String> result = new LinkedHashSet<>(tableNames.size()); Range<Long> range = shardingValue.getValueRange(); for (Long i = range.lowerEndpoint(); i <= range.upperEndpoint(); i++) { for (String each : tableNames) { if (each.endsWith(i % 2 + "")) { result.add(each); } } } return result; } } 實現類: package com..config; import com.dangdang.ddframe.rdb.sharding.api.ShardingDataSourceFactory; import com.dangdang.ddframe.rdb.sharding.api.rule.DataSourceRule; import com.dangdang.ddframe.rdb.sharding.api.rule.ShardingRule; import com.dangdang.ddframe.rdb.sharding.api.rule.TableRule; import com.dangdang.ddframe.rdb.sharding.api.strategy.database.DatabaseShardingStrategy; import com.dangdang.ddframe.rdb.sharding.api.strategy.table.TableShardingStrategy; import com.dangdang.ddframe.rdb.sharding.keygen.DefaultKeyGenerator; import com.dangdang.ddframe.rdb.sharding.keygen.KeyGenerator; import com..database.Ac_newConfig; import com..database.Ac_oldConfig; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import javax.sql.DataSource; import java.sql.SQLException; import java.util.Arrays; import java.util.HashMap; import java.util.Map; @Configuration public class FkFbShardingAlgorithm { @Autowired private Ac_newConfig ac_newConfig; @Autowired private Ac_oldConfig ac_OldConfig; @Autowired private FbShardingAlgorithm fbShardingAlgorithm; @Autowired private FkShardingAlgorithm fkShardingAlgorithm; @Bean public DataSource getDataSource() throws SQLException { return buildDataSource(); } private DataSource buildDataSource() throws SQLException { //分庫設定 Map<String,DataSource> dataSourcemap = new HashMap<>(2); //新增兩個資料庫 Ac_new 和 Ac_old dataSourcemap.put(ac_newConfig.getDatabaseName(),ac_newConfig.createDataSource()); dataSourcemap.put(ac_OldConfig.getDatabaseName(),ac_OldConfig.createDataSource()); //設定預設資料庫(Ac_new) DataSourceRule dataSourceRule = new DataSourceRule(dataSourcemap,ac_newConfig.getDatabaseName()); //分表設定,大致思想就是將查詢虛擬表Save根據一定規則對映到真實表中去 TableRule orderTableRule = TableRule.builder("save") .actualTables(Arrays.asList("one", "two")) .dataSourceRule(dataSourceRule) .build(); //分庫分表策略 ShardingRule shardingRule = ShardingRule.builder() .dataSourceRule(dataSourceRule) .tableRules(Arrays.asList(orderTableRule)) .databaseShardingStrategy(new DatabaseShardingStrategy("id", fkShardingAlgorithm)) .tableShardingStrategy(new TableShardingStrategy("type",fbShardingAlgorithm)).build(); DataSource dataSource = ShardingDataSourceFactory.createDataSource(shardingRule); return dataSource; } @Bean public KeyGenerator keyGenerator() { return new DefaultKeyGenerator(); } }
最後,pom檔案配置:
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.4.0</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.wondersgroup</groupId> <artifactId>ac-fkfb</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <name>ac-fkfb</name> <description>Spring Boot fkfb</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!--匯入配置檔案處理器,配置檔案進行繫結就會有提示 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency> <!-- mysql:MyBatis相關依賴 <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.0.0</version> </dependency> <dependency> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-maven-plugin</artifactId> <version>1.4.0</version> <type>maven-plugin</type> </dependency> --> <!-- lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <!-- mysql:mysql驅動 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <!-- mysql:阿里巴巴資料庫連線池 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.9</version> </dependency> <!-- sharding-jdbc --> <dependency> <groupId>com.dangdang</groupId> <artifactId>sharding-jdbc-core</artifactId> <version>1.5.4</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>