🤡 feat(新增): 读写分离完成

This commit is contained in:
bunny 2024-07-29 13:04:03 +08:00
parent 1fce2ee8ec
commit f744d564b4
21 changed files with 225 additions and 177 deletions

View File

@ -34,17 +34,5 @@
<artifactId>velocity-engine-core</artifactId>
<version>2.3</version>
</dependency>
<!-- 数据库代码生成器 - 旧版 -->
<!-- <dependency> -->
<!-- <groupId>com.baomidou</groupId> -->
<!-- <artifactId>mybatis-plus-generator</artifactId> -->
<!-- <version>3.4.1</version> -->
<!-- </dependency> -->
<!-- <dependency> -->
<!-- <groupId>org.apache.velocity</groupId> -->
<!-- <artifactId>velocity-engine-core</artifactId> -->
<!-- <version>2.0</version> -->
<!-- </dependency> -->
<!-- spring-web -->
</dependencies>
</project>

View File

@ -10,16 +10,17 @@ import java.util.Collections;
public class NewCodeGet {
// 数据连接
public static final String sqlHost = "jdbc:mysql://192.168.3.98:3306/db_user?serverTimezone=GMT%2B8&useSSL=false&characterEncoding=utf-8&allowPublicKeyRetrieval=true";
// public static final String sqlHost = "jdbc:mysql://192.168.3.98:3306/db_user?serverTimezone=GMT%2B8&useSSL=false&characterEncoding=utf-8&allowPublicKeyRetrieval=true";
public static final String sqlHost = "jdbc:mysql://192.168.3.21:3305/db_order?serverTimezone=GMT%2B8&useSSL=false&characterEncoding=utf-8&allowPublicKeyRetrieval=true";
// 作者名称
public static final String author = "Bunny";
public static final String author = "order";
// 公共路径
public static final String outputDir = "D:\\Project\\demo\\sharding-sphere5\\service";
public static final String outputDir = "D:\\MyFolder\\demo\\sharding-sphere5\\service";
// 实体类名称
public static final String entity = "Bunny";
public static final String entity = "order";
public static void main(String[] args) {
Generation("t_userinfo");
Generation("t_order");
}
/**
@ -40,7 +41,7 @@ public class NewCodeGet {
})
.packageConfig(builder -> {
builder.entity(entity)// 实体类包名
// TODO 父包名如果为空将下面子包名必须写全部 否则就只需写子包名
// 父包名如果为空将下面子包名必须写全部 否则就只需写子包名
.parent("cn.bunny.service")
.controller("controller")// 控制层包名
.mapper("mapper")// mapper层包名
@ -52,13 +53,13 @@ public class NewCodeGet {
.strategyConfig(builder -> {
// 设置要生成的表名
builder.addInclude(tableName)
.addTablePrefix("t_")// TODO 设置表前缀过滤
.addTablePrefix("t_")// 设置表前缀过滤
.entityBuilder()
.enableLombok()
.enableChainModel()
.naming(NamingStrategy.underline_to_camel)// 数据表映射实体命名策略默认下划线转驼峰underline_to_camel
.columnNaming(NamingStrategy.underline_to_camel)// 表字段映射实体属性命名规则默认null不指定按照naming执行
.idType(IdType.AUTO)// TODO 添加全局主键类型
.idType(IdType.AUTO)// 添加全局主键类型
.formatFileName("%s")// 格式化实体名称%s取消首字母I,
.mapperBuilder()
.mapperAnnotation(Mapper.class)// 开启mapper注解

View File

@ -1,57 +0,0 @@
package cn.bunny.common.generator;
public class OldCodeGet {
public static void main(String[] args) {
// // 1创建代码生成器
// AutoGenerator mpg = new AutoGenerator();
//
// // 2全局配置
// // 全局配置
// GlobalConfig gc = new GlobalConfig();
// // TODO 需要修改路径名称
// gc.setOutputDir("F:\\web项目\\Bunny-Cli\\Java\\java-template\\service" + "/src/main/java");
// gc.setServiceName("%sService"); // 去掉Service接口的首字母I
// gc.setAuthor("bunny");
// gc.setOpen(false);
// mpg.setGlobalConfig(gc);
//
// // 3数据源配置
// DataSourceConfig dsc = new DataSourceConfig();
// // TODO 需要修改数据库
// dsc.setUrl("jdbc:mysql://106.15.251.123:3305/guigu-oa?serverTimezone=GMT%2B8&useSSL=false&characterEncoding=utf-8&allowPublicKeyRetrieval=true");
// dsc.setDriverName("com.mysql.cj.jdbc.Driver");
// dsc.setUsername("root");
// dsc.setPassword("02120212");
// dsc.setDbType(DbType.MYSQL);
// mpg.setDataSource(dsc);
//
// // 4包配置
// PackageConfig pc = new PackageConfig();
// pc.setParent("cn.bunny");
// // TODO 需要修改模块名
// pc.setModuleName("service");
// pc.setController("controller");
// pc.setService("service");
// pc.setMapper("mapper");
// mpg.setPackageInfo(pc);
//
// // 5策略配置
// StrategyConfig strategy = getStrategyConfig();
// mpg.setStrategy(strategy);
//
// // 6执行
// mpg.execute();
// }
//
// private static StrategyConfig getStrategyConfig() {
// StrategyConfig strategy = new StrategyConfig();
// // TODO 要生成的表
// strategy.setInclude("sys_menu", "sys_role_menu");
// strategy.setNaming(NamingStrategy.underline_to_camel);// 数据库表映射到实体的命名策略
// strategy.setColumnNaming(NamingStrategy.underline_to_camel);// 数据库表字段映射到实体的命名策略
// strategy.setEntityLombokModel(true); // lombok 模型 @Accessors(chain = true) setter链式操作
// strategy.setRestControllerStyle(true); // restful api风格控制器
// strategy.setControllerMappingHyphenStyle(true); // url中驼峰转连字符
// return strategy;
}
}

View File

@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.bunny</groupId>
<artifactId>bunny-template</artifactId>
<artifactId>sharding-sphere5</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>

View File

@ -16,11 +16,11 @@ public class Knife4jConfig {
@Bean
public OpenAPI openAPI() {
// 作者等信息
Contact contact = new Contact().name("Bunny").email("1319900154@qq.com").url("http://z-bunny.com");
Contact contact = new Contact().name("order").email("1319900154@qq.com").url("http://z-bunny.com");
// 使用协议
License license = new License().name("MIT").url("http://MUT.com");
// 相关信息
Info info = new Info().title("Bunny-Java-Template").description("Bunny的Java模板").version("v1.0.0").contact(contact).license(license).termsOfService("记得给我start");
Info info = new Info().title("order-Java-Template").description("Bunny的Java模板").version("v1.0.0").contact(contact).license(license).termsOfService("记得给我start");
return new OpenAPI().info(info).externalDocs(new ExternalDocumentation());
}

View File

@ -13,9 +13,9 @@ public class JwtHelper {
// 时间 按天 计算
private static final long tokenExpiration = 24 * 60 * 60 * 1000;
// JWT 秘钥
private static final String tokenSignKey = "Bunny-Java-Template";
private static final String tokenSignKey = "order-Java-Template";
// 默认主题
private static final String subject = "Bunny";
private static final String subject = "order";
// 默认时间
private static final Date time = new Date(System.currentTimeMillis() + tokenExpiration * 7);

View File

@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.bunny</groupId>
<artifactId>bunny-template</artifactId>
<artifactId>sharding-sphere5</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>

View File

@ -16,7 +16,7 @@ import java.io.Serializable;
*
* </p>
*
* @author Bunny
* @author order
* @since 2024-07-28
*/
@Getter

View File

@ -9,7 +9,7 @@
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>cn.bunny</groupId>
<artifactId>bunny-template</artifactId>
<artifactId>sharding-sphere5</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<name>bunny-template</name>

View File

@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.bunny</groupId>
<artifactId>bunny-template</artifactId>
<artifactId>sharding-sphere5</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>

View File

@ -1,7 +1,13 @@
package cn.bunny.service.controller;
import cn.bunny.service.service.LoginService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@ -10,9 +16,22 @@ import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/")
public class IndexController {
@Autowired
private LoginService loginService;
@Operation(summary = "访问首页", description = "访问首页")
@GetMapping("")
public String index() {
return "欢迎访问 Bunny Java Template欢迎去Giteehttps://gitee.com/BunnyBoss/java_single.git";
return "欢迎访问 order Java Template欢迎去Giteehttps://gitee.com/BunnyBoss/java_single.git";
}
@Operation(summary = "生成验证码", description = "生成验证码")
@GetMapping("api/checkCode")
public ResponseEntity<byte[]> checkCode() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.IMAGE_JPEG);
byte[] image = loginService.checkCode();
return new ResponseEntity<>(image, headers, HttpStatus.OK);
}
}

View File

@ -15,7 +15,7 @@ import org.springframework.web.bind.annotation.*;
* 前端控制器
* </p>
*
* @author Bunny
* @author order
* @since 2024-07-28
*/
@Tag(name = "用户表")

View File

@ -1,31 +0,0 @@
package cn.bunny.service.controller;
import cn.bunny.service.service.LoginService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Tag(name = "web相关接口")
@RestController
@RequestMapping("/api")
public class WebController {
@Autowired
private LoginService loginService;
@Operation(summary = "生成验证码", description = "生成验证码")
@GetMapping("checkCode")
public ResponseEntity<byte[]> checkCode() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.IMAGE_JPEG);
byte[] image = loginService.checkCode();
return new ResponseEntity<byte[]>(image, headers, HttpStatus.OK);
}
}

View File

@ -9,7 +9,7 @@ import org.apache.ibatis.annotations.Mapper;
* Mapper 接口
* </p>
*
* @author Bunny
* @author order
* @since 2024-07-28
*/
@Mapper

View File

@ -10,7 +10,7 @@ import com.baomidou.mybatisplus.extension.service.IService;
* 服务类
* </p>
*
* @author Bunny
* @author order
* @since 2024-07-28
*/
public interface UserService extends IService<User> {

View File

@ -13,7 +13,7 @@ import org.springframework.stereotype.Service;
* 服务实现类
* </p>
*
* @author Bunny
* @author order
* @since 2024-07-28
*/
@Service

View File

@ -9,7 +9,8 @@ spring:
name: bunny-service
datasource:
driver-class-name: org.apache.shardingsphere.driver.ShardingSphereDriver
url: jdbc:shardingsphere:classpath:sharding.yaml
# url: jdbc:shardingsphere:classpath:sharding/sharding-default.yaml
url: jdbc:shardingsphere:classpath:sharding/sharding-sharding.yaml
jackson:
date-format: yyyy-MM-dd HH:mm:ss

View File

@ -1,54 +0,0 @@
mode:
type: Standalone
repository:
type: JDBC
dataSources:
master:
dataSourceClassName: com.zaxxer.hikari.HikariDataSource
driverClassName: com.mysql.cj.jdbc.Driver
jdbcUrl: jdbc:mysql://192.168.3.21:3306/db_user?serverTimezone=GMT%2B8&useSSL=false&characterEncoding=utf-8&allowPublicKeyRetrieval=true
username: root
password: "02120212"
slave1:
dataSourceClassName: com.zaxxer.hikari.HikariDataSource
driverClassName: com.mysql.cj.jdbc.Driver
jdbcUrl: jdbc:mysql://192.168.3.21:3307/db_user?serverTimezone=GMT%2B8&useSSL=false&characterEncoding=utf-8&allowPublicKeyRetrieval=true
username: root
password: "02120212"
slave2:
dataSourceClassName: com.zaxxer.hikari.HikariDataSource
driverClassName: com.mysql.cj.jdbc.Driver
jdbcUrl: jdbc:mysql://192.168.3.21:3308/db_user?serverTimezone=GMT%2B8&useSSL=false&characterEncoding=utf-8&allowPublicKeyRetrieval=true
username: root
password: "02120212"
rules:
- !SINGLE
tables:
- "*.*"
defaultDataSource: master
- !READWRITE_SPLITTING
dataSources:
readwrite_ds:
writeDataSourceName: master
readDataSourceNames:
- slave1
- slave2
transactionalReadQueryStrategy: PRIMARY
loadBalancerName: random
loadBalancers:
random:
type: RANDOM
props:
sql-show: true
sqlParser:
sqlStatementCache:
initialCapacity: 2000
maximumSize: 65535
parseTreeCache:
initialCapacity: 128
maximumSize: 1024
sqlTranslator:
type: Native
useOriginalSQLWhenTranslatingFailed: true

View File

@ -0,0 +1,130 @@
mode:
type: Standalone
repository:
type: JDBC
dataSources:
master:
dataSourceClassName: com.zaxxer.hikari.HikariDataSource
driverClassName: com.mysql.cj.jdbc.Driver
jdbcUrl: jdbc:mysql://192.168.3.21:3306/db_user?serverTimezone=GMT%2B8&useSSL=false&characterEncoding=utf-8&allowPublicKeyRetrieval=true
username: root
password: "02120212"
slave1:
dataSourceClassName: com.zaxxer.hikari.HikariDataSource
driverClassName: com.mysql.cj.jdbc.Driver
jdbcUrl: jdbc:mysql://192.168.3.21:3307/db_user?serverTimezone=GMT%2B8&useSSL=false&characterEncoding=utf-8&allowPublicKeyRetrieval=true
username: root
password: "02120212"
slave2:
dataSourceClassName: com.zaxxer.hikari.HikariDataSource
driverClassName: com.mysql.cj.jdbc.Driver
jdbcUrl: jdbc:mysql://192.168.3.21:3308/db_user?serverTimezone=GMT%2B8&useSSL=false&characterEncoding=utf-8&allowPublicKeyRetrieval=true
username: root
password: "02120212"
rules:
- !SINGLE
# 匹配所有表
tables:
- "*.*"
# 默认数据库
defaultDataSource: master
# 数据分片配置
- !SHARDING
tables:
t_order:
actualDataNodes: ds_${0..1}.t_order_${0..1}
tableStrategy:
standard:
shardingColumn: order_id
shardingAlgorithmName: t_order_inline
keyGenerateStrategy:
column: order_id
keyGeneratorName: snowflake
auditStrategy:
auditorNames:
- sharding_key_required_auditor
allowHintDisable: true
t_order_item:
actualDataNodes: ds_${0..1}.t_order_item_${0..1}
tableStrategy:
standard:
shardingColumn: order_id
shardingAlgorithmName: t_order_item_inline
keyGenerateStrategy:
column: order_item_id
keyGeneratorName: snowflake
t_account:
actualDataNodes: ds_${0..1}.t_account_${0..1}
tableStrategy:
standard:
shardingAlgorithmName: t_account_inline
keyGenerateStrategy:
column: account_id
keyGeneratorName: snowflake
defaultShardingColumn: account_id
bindingTables:
- t_order,t_order_item
defaultDatabaseStrategy:
standard:
shardingColumn: user_id
shardingAlgorithmName: database_inline
defaultTableStrategy:
none:
shardingAlgorithms:
database_inline:
type: INLINE
props:
algorithm-expression: ds_${user_id % 2}
t_order_inline:
type: INLINE
props:
algorithm-expression: t_order_${order_id % 2}
t_order_item_inline:
type: INLINE
props:
algorithm-expression: t_order_item_${order_id % 2}
t_account_inline:
type: INLINE
props:
algorithm-expression: t_account_${account_id % 2}
keyGenerators:
snowflake:
type: SNOWFLAKE
auditors:
sharding_key_required_auditor:
type: DML_SHARDING_CONDITIONS
# 广播表
- !BROADCAST
tables:
- t_address
# 读写分离配置
- !READWRITE_SPLITTING
dataSources:
readwrite_ds:
writeDataSourceName: master
readDataSourceNames:
- slave1
- slave2
transactionalReadQueryStrategy: PRIMARY
# 负载均衡名称对应下面loadBalancers中名称
loadBalancerName: ds_wight
loadBalancers:
# 随机负载均衡算法
ds_random:
type: RANDOM
# 轮询负载均衡算法
ds_round:
type: ROUND_ROBIN
# 权重负载均衡算法
ds_wight:
type: WEIGHT
# 配置数据库权重
props:
slave1: 1
slave2: 2
# 打印SQL
props:
sql-show: true

View File

@ -0,0 +1,36 @@
mode:
type: Standalone
repository:
type: JDBC
dataSources:
server_user:
dataSourceClassName: com.zaxxer.hikari.HikariDataSource
driverClassName: com.mysql.cj.jdbc.Driver
jdbcUrl: jdbc:mysql://192.168.3.21:3304/db_user?serverTimezone=GMT%2B8&useSSL=false&characterEncoding=utf-8&allowPublicKeyRetrieval=true
username: root
password: "02120212"
server_order:
dataSourceClassName: com.zaxxer.hikari.HikariDataSource
driverClassName: com.mysql.cj.jdbc.Driver
jdbcUrl: jdbc:mysql://192.168.3.21:3305/db_order?serverTimezone=GMT%2B8&useSSL=false&characterEncoding=utf-8&allowPublicKeyRetrieval=true
username: root
password: "02120212"
rules:
# - !SINGLE
# # 匹配所有表
# tables:
# - "*.*"
# # 默认数据库
# defaultDataSource: server_user
# 数据分片配置
- !SHARDING
tables:
server_user:
actualDataNodes: server_user.t_user
server_order:
actualDataNodes: server_order.t_order
# 打印SQL
props:
sql-show: true

View File

@ -26,14 +26,29 @@ class UserServiceImplTest {
@Test
@Transactional
void addTransactional() {
// 插入时会回滚在测试状态下加上事务都会回滚
User user = new User();
user.setUname("哈哈哈");
userMapper.insert(user);
}
// 查询测试
@Test
void selectUseList() {
List<User> users = userMapper.selectList(null);
users.forEach(System.out::println);
}
// 负载均衡测试
@Test
void selectUserAllLoadBalancers() {
List<User> userList1 = userMapper.selectList(null);
System.out.println(userList1);
List<User> userList2 = userMapper.selectList(null);
System.out.println(userList2);
List<User> userList3 = userMapper.selectList(null);
System.out.println(userList3);
List<User> userList4 = userMapper.selectList(null);
System.out.println(userList3);
}
}