目录
介绍
代码下载
效果
数据库
代码结构
上代码
pom.xml
yml配置
建表语句
mapper.xml
mybatisplus 配置.java
logback
application.java
BaseEntity
TUser
TUserMapper
TUserService
TUserServiceImpl
TUserController
测试
介绍
这套springboot + sharding sphere + mybatis plus 代码中有很多注释的,是可有可无类型,id放到了父类中,防止save 的时候,id变成0问题 实现id自动生成,全套一个shardingspere
代码下载
https://download.csdn.net/download/weixin_42749765/87759588
效果
数据库
代码结构
上代码
pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.2</version>
<relativePath/>
</parent>
<properties>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<start-class>com.superbase.fintech.Application</start-class>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.15</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.2</version>
</dependency>
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>4.0.1</version>
</dependency>
</dependencies>
yml配置
server:
port: 8080
spring:
main:
allow-bean-definition-overriding: true
shardingsphere:
props:
sql:
show: true # 开启sql日志输出
datasource:
names: t0,t1
t0:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/test_0?useUnicode=true&characterEncoding=utf8&tinyInt1isBit=false&useSSL=false&serverTimezone=GMT
username: root
password: admin
t1:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/test_1?useUnicode=true&characterEncoding=utf8&tinyInt1isBit=false&useSSL=false&serverTimezone=GMT
username: root
password: admin
sharding:
tables:
t_user:
actual-data-nodes: t0.t_user_$->{0..1}
table-strategy:
inline:
sharding-column: id
algorithm-expression: t_user_$->{id % 2}
key-generator:
column: id
type: SNOWFLAKE
binding-tables: t_user
pagehelper:
# 指定使用的数据库数据库
helperDialect: mysql
# reasonable:分页合理化参数,默认值为false。当该参数设置为 true 时,pageNum<=0 时会查询第一页,pageNum>pages(超过总数时),会查询最后一页。默认false 时,直接根据参数进行查询。
reasonable: true
supportMethodsArguments: true
params: count=countSql
mybatis-plus:
# 扫描 mapper.xml
mapper-locations: classpath*:mapper/**/**.xml
#实体扫描,多个package用逗号或者分号分隔
typeAliasesPackage: com.superbase.fintech
global-config:
db-config:
#主键类型 0:"数据库ID自增", 1:"用户输入ID",2:"全局唯一ID (数字类型唯一ID)", 3:"全局唯一ID UUID";
id-type: auto
#字段策略 0:"忽略判断",1:"非 NULL 判断"),2:"非空判断"
field-strategy: 0
#驼峰下划线转换
column-underline: false
#逻辑删除配置 使用mybatis plus内置方法默认过滤配置的逻辑删除字段,其他sql需手动过滤sql语句
logic-delete-field: deleteFlag
logic-delete-value: 1
logic-not-delete-value: 0
db-type: mysql
refresh: false
configuration:
jdbc-type-for-null: 'null'
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
map-underscore-to-camel-case: true
cache-enabled: false # 二级缓存是否开启
lazyLoadingEnabled: true #延时加载的开关
aggressiveLazyLoading: false #开启的话,延时加载一个属性时会加载该对象全部属性,否则按需加载属性
multipleResultSetsEnabled: true
建表语句
CREATE TABLE `t_user_0` (
`id` bigint NOT NULL,
`name` varchar(255) DEFAULT NULL,
`age` int DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
CREATE TABLE `t_user_1` (
`id` bigint NOT NULL,
`name` varchar(255) DEFAULT NULL,
`age` int DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
mapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.superbase.fintech.biz.mapper.TUserMapper">
</mapper>
mybatisplus 配置.java
package com.superbase.fintech.config;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MybatisPlusConfig {
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
}
logback
<?xml version="1.0" encoding="UTF-8"?>
<!-- 分级别异步文件日志输出配置 -->
<!-- 级别从高到低 OFF 、 FATAL 、 ERROR 、 WARN 、 INFO 、 DEBUG 、 TRACE 、 ALL -->
<!-- 日志输出规则 根据当前ROOT 级别,日志输出时,级别高于root默认的级别时 会输出 -->
<!-- 以下 每个配置的 filter 是过滤掉输出文件里面,会出现高级别文件,依然出现低级别的日志信息,通过filter 过滤只记录本级别的日志 -->
<!-- scan 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。 -->
<!-- scanPeriod 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
<!-- debug 当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<!-- logback项目名称 -->
<property name="appName" value="super-base"/>
<!-- 日志级别 DEBUG INFO WARN ERROR -->
<property name="logLevel" value="INFO"/>
<!-- 日志路径-->
<property name="logPath" value="/export/log"/>
<!-- 最大保存时间 30天-->
<property name="maxHistory" value="3"/>
<!-- 异步缓冲队列的深度,该值会影响性能.默认值为256 -->
<property name="queueSize" value="256"/>
<!-- lOGGER PATTERN 根据个人喜好选择匹配 -->
<property name="logPattern" value="%d{yy-MM-dd.HH:mm:ss.SSS} [%-16t] %-5p %-22c{0} %X{traceId} - %m%n"/>
<!-- 动态日志级别 -->
<jmxConfigurator/>
<!-- 控制台的标准输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<charset>UTF-8</charset>
<pattern>${logPattern}</pattern>
</encoder>
</appender>
<appender name="consoleDetail" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${logPath}/${appName}/${appName}_detail.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${logPath}/${appName}/detail/${appName}_detail.log.%d{yyyy-MM-dd}.zip</fileNamePattern>
<maxHistory>${maxHistory}</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${logPattern}</pattern>
</encoder>
</appender>
<!-- DUBUG 日志记录 -->
<appender name="FILE_DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>DEBUG</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<file>${logPath}/${appName}/${appName}_debug.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${logPath}/${appName}/debug/${appName}_debug.log.%d{yyyy-MM-dd}.zip
</fileNamePattern>
<maxHistory>${maxHistory}</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${logPattern}</pattern>
</encoder>
</appender>
<!-- INFO 级别的日志记录 -->
<appender name="FILE_INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<file>${logPath}/${appName}/${appName}_info.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${logPath}/${appName}/info/${appName}_info.log.%d{yyyy-MM-dd}.zip
</fileNamePattern>
<maxHistory>${maxHistory}</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${logPattern}</pattern>
</encoder>
</appender>
<!-- WARN 级别的日志记录 -->
<appender name="FILE_WARN" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>WARN</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<file>${logPath}/${appName}/${appName}_warn.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${logPath}/${appName}/warn/${appName}_warn.log.%d{yyyy-MM-dd}.zip
</fileNamePattern>
<maxHistory>${maxHistory}</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${logPattern}</pattern>
</encoder>
</appender>
<!-- Error 级别的日志记录 -->
<appender name="FILE_ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<file>${logPath}/${appName}/${appName}_error.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${logPath}/${appName}/error/${appName}_error.log.%d{yyyy-MM-dd}.zip
</fileNamePattern>
<maxHistory>${maxHistory}</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${logPattern}</pattern>
</encoder>
</appender>
<appender name="ASYNC_consoleDetail" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>${queueSize}</queueSize>
<appender-ref ref="consoleDetail"/>
</appender>
<!-- ASYNC_LOG_DEBUG -->
<appender name="ASYNC_LOG_DEBUG" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>${queueSize}</queueSize>
<appender-ref ref="FILE_DEBUG"/>
</appender>
<!-- ASYNC_LOG_INFO -->
<appender name="ASYNC_LOG_INFO" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>${queueSize}</queueSize>
<appender-ref ref="FILE_INFO"/>
</appender>
<!-- ASYNC_LOG_WARN -->
<appender name="ASYNC_LOG_WARN" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>${queueSize}</queueSize>
<appender-ref ref="FILE_WARN"/>
</appender>
<!--ASYNC_LOG_ERROR -->
<appender name="ASYNC_LOG_ERROR" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>${queueSize}</queueSize>
<appender-ref ref="FILE_ERROR"/>
</appender>
<logger name="org.springframework.web.servlet.DispatcherServlet" level="OFF"/>
<logger name="org.springframework.web.context.support.XmlWebApplicationContext" level="OFF"/>
<logger name="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping" level="OFF"/>
<!-- 日志的记录级别 -->
<!-- 在定义后引用APPENDER -->
<root level="${logLevel}">
<!-- 控制台 -->
<appender-ref ref="STDOUT"/>
<appender-ref ref="ASYNC_consoleDetail"/>
<!-- 具体的日志级别和文件的配置 -->
<appender-ref ref="ASYNC_LOG_DEBUG"/>
<appender-ref ref="ASYNC_LOG_INFO"/>
<appender-ref ref="ASYNC_LOG_WARN"/>
<appender-ref ref="ASYNC_LOG_ERROR"/>
</root>
</configuration>
appplication.properties 里边空的就不写了
application.java
package com.superbase.fintech;
import lombok.extern.slf4j.Slf4j;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure;
/**
* Application
*
* @author jianghaoyu
*/
//@SpringBootApplication
@Slf4j
@MapperScan("com.superbase.fintech.biz.mapper")
@SpringBootApplication(exclude={DruidDataSourceAutoConfigure.class})
public class Application {
public static void main(String[] args) {
log.info(" 服务端启动开始");
SpringApplication.run(Application.class, args);
log.info("服务端启动成功");
}
}
BaseEntity
package com.superbase.fintech.biz.entity;
import lombok.Data;
@Data
public class BaseEntity {
private long id;
}
TUser
package com.superbase.fintech.biz.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* @author jianghaoyu
* @since 2023-04-28
*/
@Data
//@EqualsAndHashCode(callSuper = true)
//@Accessors(chain = true)
//@TableName("t_user")
//public class TUser extends Model<TUser> {
public class TUser extends BaseEntity{
/**
* 主键Id 必须注释掉,才可自动生成
*/
// private long id;
/**
* 名称
*/
private String name;
/**
* 年龄
*/
private int age;
}
TUserMapper
package com.superbase.fintech.biz.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.superbase.fintech.biz.entity.TUser;
/**
* <p>
* 系统用户表 Mapper 接口
* </p>
*
* @author jianghaoyu
* @since 2023-04-28
*/
public interface TUserMapper extends BaseMapper<TUser> {
}
TUserService
package com.superbase.fintech.biz.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.superbase.fintech.biz.entity.TUser;
import java.util.List;
public interface TUserService extends IService<TUser> {
/**
* 保存用户信息
*
* @param entity
* @return
*/
@Override
boolean save(TUser entity);
/**
* 查询全部用户信息
*
* @return
*/
List<TUser> getUserList();
}
TUserServiceImpl
package com.superbase.fintech.biz.service.impl;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.superbase.fintech.biz.entity.TUser;
import com.superbase.fintech.biz.mapper.TUserMapper;
import com.superbase.fintech.biz.service.TUserService;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class TUserServiceImpl extends ServiceImpl<TUserMapper, TUser> implements TUserService {
@Override
public boolean save(TUser entity) {
return super.save(entity);
}
@Override
public List<TUser> getUserList() {
return baseMapper.selectList(Wrappers.lambdaQuery());
}
}
TUserController
package com.superbase.fintech.biz.ctr;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.superbase.fintech.biz.entity.TUser;
import com.superbase.fintech.biz.mapper.TUserMapper;
import com.superbase.fintech.biz.service.TUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* TUserController
* @author jianghaoyu
*
*/
@RestController
public class TUserController {
@Autowired
private TUserService userService;
@Autowired
private TUserMapper tUserMapper;
@GetMapping("/page")
public IPage<TUser> page() {
QueryWrapper<TUser> queryWrapper = new QueryWrapper<>();
queryWrapper.orderByDesc("age");
Page<TUser> page = new Page<>(2, 5);
IPage<TUser> pageList = userService.page(page, queryWrapper);
return pageList;
}
@GetMapping("/save")
public Boolean insert(TUser user) {
TUser t = new TUser();
t.setName("cccccccccccccccc");
return userService.save(t);
}
@RequestMapping("/dao/save")
public String save() {
TUser t = new TUser();
t.setName("SS");
tUserMapper.insert(t);
return "true";
}
}
测试
http://localhost:8080/save
http://localhost:8080/page
ok
持续更新