SpringBoot 整合 Sharding-JDBC 分库分表

导读

  分库分表的技术有:数据库中间件Mycat(点我直达),当当网开源的Sharding-JDBC;我们公司用的也是sharding-jdbc,自己也搭建一个完整的项目,直接可以拿来用。下面附源码(CRUD,分页,事务等都已测试过)

技术栈

  • SpringBoot 2.3.9
  • sharding-jdbc-core 2.0.3 (官网地址:点我直达
  • druid
  • mybatis-plus
  • lombok
  • mybatis | mybatisplus 分页功能
  • 统一异常处理器

项目结构

 

pom.xml

<?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.3.9.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.ybchen</groupId>
    <artifactId>springboot-sharding</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot-sharding</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
        <maven.compiler.target>1.8</maven.compiler.target>
        <maven.compiler.source>1.8</maven.compiler.source>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    </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>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!--sharding-->
        <dependency>
            <groupId>io.shardingjdbc</groupId>
            <artifactId>sharding-jdbc-core</artifactId>
            <version>2.0.3</version>
        </dependency>
        <!--mysql-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!--druid-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.5</version>
        </dependency>
        <!--mybatisplus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.1</version>
        </dependency>
        <!--mybatis pagehelper分页插件-->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper</artifactId>
            <version>5.2.0</version>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.20</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
            </resource>
        </resources>
    </build>
</project>

logback-spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出 -->
<!-- scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true -->
<!-- scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
<!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
<configuration  scan="true" scanPeriod="10 seconds">

    <contextName>logback</contextName>
    <!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义变量后,可以使“${}”来使用变量。 -->
    <property name="log.path" value="applog/" />
    <property name="log.name" value="springboot-sharding"/>
    <!--控制台打印格式-->
    <property name="CONSOLE_LOG_PATTERN_FILE" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %C:%M:%L [%thread] %-5level %msg%n"/>
    <!--debug文件打印格式-->
    <property name="DEBUG_LOG_PATTERN_FILE" value="%d{yyyy-MM-dd HH:mm:ss} [%c]-[%p] %m%n"/>

    <!-- 彩色日志 -->
    <!-- 彩色日志依赖的渲染类 -->
    <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
    <conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
    <conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
    <!-- 彩色日志格式 -->
    <property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>


    <!--输出到控制台-->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>debug</level>
        </filter>
        <encoder>
            <Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
            <!-- 设置字符集 -->
            <charset>UTF-8</charset>
        </encoder>
    </appender>


    <!--输出到文件-->
    <!-- 时间滚动输出 level为 INFO 日志 -->
    <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${log.path}/${log.name}/${log.name}_info.log</file>
        <!--日志文件输出格式-->
        <encoder>
            <pattern>${CONSOLE_LOG_PATTERN_FILE}</pattern>
            <charset>UTF-8</charset>
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 每天日志归档路径以及格式 -->
            <fileNamePattern>${log.path}/${log.name}/info/${log.name}-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文件保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日志文件只记录info级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>info</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!-- 时间滚动输出 level为 debug 日志 -->
    <appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${log.path}/${log.name}/${log.name}_debug.log</file>
        <!--日志文件输出格式-->
        <encoder>
            <pattern>${DEBUG_LOG_PATTERN_FILE}</pattern>
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log.path}/${log.name}/debug/${log.name}-debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文件保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日志文件只记录DEBUG级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>DEBUG</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!-- 时间滚动输出 level为 ERROR 日志 -->
    <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${log.path}/${log.name}/${log.name}_error.log</file>
        <!--日志文件输出格式-->
        <encoder>
            <pattern>${CONSOLE_LOG_PATTERN_FILE}</pattern>
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log.path}/${log.name}/error/${log.name}-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文件保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日志文件只记录ERROR级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <root level="info">
        <appender-ref ref="CONSOLE" />
        <appender-ref ref="INFO_FILE" />
        <appender-ref ref="DEBUG_FILE" />
        <appender-ref ref="ERROR_FILE" />
    </root>
    <logger name="com.ybchen.mapper" level="DEBUG"/>
    <logger name="com.ybchen" level="DEBUG"/>
</configuration>

application.properties

server.port=9999
# ds0
ds0.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
ds0.datasource.url=jdbc:mysql://localhost:3306/online_education?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
ds0.datasource.username=root
ds0.datasource.password=root
# ds1
ds1.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
ds1.datasource.url=jdbc:mysql://localhost:3306/online_education1?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
ds1.datasource.username=root
ds1.datasource.password=root

UserMapper.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.ybchen.mapper.UserMapper">
    <select id="all" resultType="com.ybchen.domain.UserDO">
        SELECT * FROM t_user
    </select>
    <insert id="add" parameterType="com.ybchen.domain.UserDO">
        INSERT INTO `t_user` (`id`, `user_name`, `age`, `create_time`, `tags`) VALUES (#{id}, #{userName}, #{age}, #{createTime}, #{tags})
    </insert>
    <update id="update" parameterType="com.ybchen.domain.UserDO">
        update t_user set user_name=#{userName} where id=#{id}
    </update>
    <delete id="delete">
        delete from t_user where id=#{id}
    </delete>
</mapper>

SpringBootShardingApplication.java

package com.ybchen;

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

//忽略自动装配DataSource
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
//扫描Mapper
@MapperScan("com.ybchen.mapper")
//开启事务
@EnableTransactionManagement
public class SpringbootShardingApplication {

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

}

DataSourceConfig.java

package com.ybchen;

import com.alibaba.druid.filter.Filter;
import com.alibaba.druid.filter.stat.StatFilter;
import com.alibaba.druid.pool.DruidDataSource;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import com.github.pagehelper.PageInterceptor;
import com.google.common.collect.Lists;
import groovy.util.logging.Slf4j;
import io.shardingjdbc.core.api.ShardingDataSourceFactory;
import io.shardingjdbc.core.api.config.ShardingRuleConfiguration;
import io.shardingjdbc.core.api.config.TableRuleConfiguration;
import io.shardingjdbc.core.api.config.strategy.InlineShardingStrategyConfiguration;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.*;

/**
 * @Description:配置参考链接:https://shardingsphere.apache.org/document/legacy/3.x/document/cn/manual/sharding-jdbc/configuration/config-java/
 * @Author:chenyanbin
 * @Date:2021/4/15 上午11:44
 * @Versiion:1.0
 */
@Configuration
@EnableTransactionManagement
@Slf4j
public class DataSourceConfig {
    @Autowired
    private Environment env;

    @Bean
    public Filter statFilter() {
        StatFilter filter = new StatFilter();
        filter.setSlowSqlMillis(5000);
        filter.setLogSlowSql(true);
        filter.setMergeSql(true);
        return filter;
    }

    @Bean("sqlSessionFactory")
    SqlSessionFactory sqlSessionFactory(
    ) throws Exception {
        final MybatisSqlSessionFactoryBean sessionFactory = new MybatisSqlSessionFactoryBean();
        //设置数据源
        sessionFactory.setDataSource(dataSource());
        //设置分页
        sessionFactory.setPlugins(new Interceptor[]{mybatisPlusInterceptor(), pageInterceptor()});
        //mapper扫描路径
        Resource[] r1 = new PathMatchingResourcePatternResolver()
                .getResources("classpath*:com/ybchen/mapper/xml/*.xml");
        Resource[] r2 = new PathMatchingResourcePatternResolver()
                .getResources("classpath*:mapper/*.xml");
        List<Resource> list = new ArrayList<>();
        list.addAll(Arrays.asList(r1));
        list.addAll(Arrays.asList(r2));
        sessionFactory.setMapperLocations(list.toArray(new Resource[list.size()]));
        return sessionFactory.getObject();
    }

    //事务管理
    @Bean
    public DataSourceTransactionManager transactitonManager(@Autowired DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    //mybatis 分页
    public PageInterceptor pageInterceptor() {
        PageInterceptor pi = new PageInterceptor();
        Properties p = new Properties();
        //当该参数设置为 true 时,pageNum<=0 时会查询第一页, pageNum>pages(超过总数时),会查询最后一页
        p.setProperty("reasonable", "true");
        pi.setProperties(p);
        return pi;
    }

    //mybatis plus分页
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
        mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return mybatisPlusInterceptor;
    }

    @Bean
    public DataSource dataSource() throws SQLException {
        ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();
        //添加表
        shardingRuleConfig.getTableRuleConfigs().add(tUserTableRuleConfiguration());
        Properties properties = new Properties();
        //是否开启SQL显示,默认值: false
//        properties.setProperty("sql.show", "true");
        return ShardingDataSourceFactory.createDataSource(createDataSourceMap(), shardingRuleConfig, new HashMap<>(), properties);
    }

    /**
     * 表分片规则配置对象,表:t_user
     * 参考链接:https://shardingsphere.apache.org/document/legacy/3.x/document/cn/manual/sharding-jdbc/configuration/config-java/
     *
     * @return
     */
    TableRuleConfiguration tUserTableRuleConfiguration() {
        TableRuleConfiguration result = new TableRuleConfiguration();
        //逻辑表名称
        result.setLogicTable("t_user");
        //由数据源名 + 表名组成,以小数点分隔。多个表以逗号分隔,支持inline表达式。缺省表示使用已知数据源与逻辑表名称生成数据节点。用于广播表(即每个库中都需要一个同样的表用于关联查询,多为字典表)或只分库不分表且所有库的表结构完全一致的情况
        result.setActualDataNodes("ds${0..1}.t_user");
        //分片列名称
        final String shardingColumn = "tags";
        //分片算法行表达式,需符合groovy语法,表达式参考:https://shardingsphere.apache.org/document/legacy/3.x/document/cn/features/sharding/other-features/inline-expression/
        final String algorithmExpression = "ds${tags%2}";
        //ShardingStrategyConfiguration的实现类,用于配置行表达式分片策略。
        result.setDatabaseShardingStrategyConfig(new InlineShardingStrategyConfiguration(shardingColumn, algorithmExpression));
        //自增列名称,缺省表示不适用自增主键生成器
//        result.setKeyGeneratorColumnName("id");
        return result;
    }

    Map<String, DataSource> createDataSourceMap() {
        Map<String, DataSource> result = new HashMap<>();
        result.put("ds0", dataSource_0());
        result.put("ds1", dataSource_1());
        return result;
    }

    /**
     * 数据源-0
     *
     * @return
     */
    public DataSource dataSource_0() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName(env.getProperty("ds0.datasource.driver-class-name"));
        dataSource.setUrl(env.getProperty("ds0.datasource.url"));
        dataSource.setUsername(env.getProperty("ds0.datasource.username"));
        dataSource.setPassword(env.getProperty("ds0.datasource.password"));
        dataSource.setProxyFilters(Lists.newArrayList(statFilter()));
        //每个分区最大的连接数
        dataSource.setMaxActive(20);
        //每个分区最小的连接数
        dataSource.setMinIdle(5);
        return dataSource;
    }

    /**
     * 数据源-1
     *
     * @return
     */
    public DataSource dataSource_1() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName(env.getProperty("ds1.datasource.driver-class-name"));
        dataSource.setUrl(env.getProperty("ds1.datasource.url"));
        dataSource.setUsername(env.getProperty("ds1.datasource.username"));
        dataSource.setPassword(env.getProperty("ds1.datasource.password"));
        dataSource.setProxyFilters(Lists.newArrayList(statFilter()));
        //每个分区最大的连接数
        dataSource.setMaxActive(20);
        //每个分区最小的连接数
        dataSource.setMinIdle(5);
        return dataSource;
    }
}

GlobalExceptions.java

package com.ybchen.exception;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * @ClassName:GlobalExceptiions
 * @Description:全局异常
 * @Author:chenyb
 * @Date:2021/4/15 上午11:44
 * @Versiion:1.0
 */
@ControllerAdvice
public class GlobalExceptions {
    private final Logger logger = LoggerFactory.getLogger(getClass());

    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public Object handle(Exception ex) {
        logger.error("「 全局异常 」 ===============》{}", ex);
        return "「 全局异常 」错误信息:"+ex.getMessage();
    }
}

UserDO.java

package com.ybchen.domain;

import java.util.Date;

/**
 * @Description:mybatis方式实体类
 * @Author:chenyanbin
 * @Date:2021/4/16 上午9:47
 * @Versiion:1.0
 */
public class UserDO {
    private String id;
    private String userName;
    private Integer age;
    private Date createTime;
    private Integer tags;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    public Integer getTags() {
        return tags;
    }

    public void setTags(Integer tags) {
        this.tags = tags;
    }

    @Override
    public String toString() {
        return "UserDO{" +
                "id='" + id + '\'' +
                ", userName='" + userName + '\'' +
                ", age=" + age +
                ", createTime=" + createTime +
                ", tags=" + tags +
                '}';
    }
}

UserMybatisDO.java

package com.ybchen.domain;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;

import java.util.Date;

/**
 * @Description:mybatis plus方式实体类
 * @Author:chenyanbin
 * @Date:2021/4/16 上午9:47
 * @Versiion:1.0
 */
@TableName("t_user")
public class UserMybatisDO {
    @TableId(value = "id")
    private String id;
    @TableField("user_name")
    private String userName;
    @TableField("age")
    private Integer age;
    @TableField("create_time")
    private Date createTime;
    @TableField("tags")
    private Integer tags;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    public Integer getTags() {
        return tags;
    }

    public void setTags(Integer tags) {
        this.tags = tags;
    }

    @Override
    public String toString() {
        return "UserMybatisDO{" +
                "id='" + id + '\'' +
                ", userName='" + userName + '\'' +
                ", age=" + age +
                ", createTime=" + createTime +
                ", tags=" + tags +
                '}';
    }
}

UserMapper.java

package com.ybchen.mapper;

import com.ybchen.domain.UserDO;

import java.util.List;

public interface UserMapper {
    //查询
    List<UserDO> all();

    //添加
    Integer add(UserDO userDO);

    //更新
    Integer update(UserDO userDO);

    //删除
    Integer delete(String id);
}

UserMybatisPlusMapper.java

package com.ybchen.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ybchen.domain.UserMybatisDO;

public interface UserMybatisPlusMapper extends BaseMapper<UserMybatisDO> {
}

UserService.java

package com.ybchen.service;

import com.ybchen.domain.UserDO;
import com.ybchen.domain.UserMybatisDO;

import java.util.List;

/**
 * @Description:
 * @Author:chenyanbin
 * @Date:2021/4/15 下午4:52
 * @Versiion:1.0
 */
public interface UserService {
    //mybatis 查询
    List<UserDO> all();

    //mybatisplus 查询
    List<UserMybatisDO> allMybatisPlus();

    //添加
    Integer add(UserDO userDO);

    //更新
    Integer update(UserDO userDO);

    //删除
    Integer delete(String id);
}

UserServiceImpl.java

package com.ybchen.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.pagehelper.PageHelper;
import com.ybchen.domain.UserDO;
import com.ybchen.domain.UserMybatisDO;
import com.ybchen.mapper.UserMapper;
import com.ybchen.mapper.UserMybatisPlusMapper;
import com.ybchen.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;

/**
 * @Description:
 * @Author:chenyanbin
 * @Date:2021/4/15 下午4:53
 * @Versiion:1.0
 */
@Service
@Slf4j
public class UserServiceImpl implements UserService {
    @Autowired
    UserMapper userMapper;
    @Autowired
    UserMybatisPlusMapper userMybatisPlusMapper;

    @Override
    public List<UserDO> all() {
        log.info("---info----");
        log.debug("----debug----");
        log.error("----error----");
        //mybatis 分页
        PageHelper.startPage(4, 3);
        return userMapper.all();
    }

    @Override
    public List<UserMybatisDO> allMybatisPlus() {
        //mybatis plus 分页
        int start = 4;
        int end = 3;
        IPage<UserMybatisDO> page = new Page<>(start, end);
        return userMybatisPlusMapper.selectPage(page, null).getRecords();
    }

    @Override
    //开启事务
    @Transactional
    public Integer add(UserDO userDO) {
        userDO.setId(UUID.randomUUID().toString().replace("-", ""));
        userDO.setTags(LocalDateTime.now().getSecond());
        userMapper.add(userDO);
        //模拟事务失败
        int num = 1 / 0;
        userDO.setAge(99);
        userDO.setId(UUID.randomUUID().toString().replace("-", ""));
        return userMapper.add(userDO);
    }

    @Override
    public Integer update(UserDO userDO) {
        return userMapper.update(userDO);
    }

    @Override
    public Integer delete(String id) {
        return userMapper.delete(id);
    }
}

UserController.java

package com.ybchen.controller;

import com.ybchen.domain.UserDO;
import com.ybchen.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

/**
 * @Description:
 * @Author:chenyanbin
 * @Date:2021/4/15 下午4:52
 * @Versiion:1.0
 */
@RestController
public class UserController {
    @Autowired
    private UserService userService;

    @PostMapping("all")
    public Object all() {
        return userService.all();
    }

    @PostMapping("allMybatisPlus")
    public Object allMybatisPlus() {
        return userService.allMybatisPlus();
    }

    @PostMapping("add")
    public Object add(@RequestBody UserDO userDO) {
        return userService.add(userDO);
    }

    @PostMapping("update")
    public Object update(@RequestBody UserDO userDO) {
        return userService.update(userDO);
    }

    @GetMapping("delete")
    public Object delete(@RequestParam("id") String id) {
        return userService.delete(id);
    }
}

数据库

案例源码

链接: https://pan.baidu.com/s/1j8h4YJSShWKYjwCeX56O_w  密码: 8fpe
posted @ 2021-04-16 14:36  陈彦斌  阅读(969)  评论(0编辑  收藏  举报