16. 从零开始学springboot-整合mybatisPlus-多数据源-代码生成器

前言

前几个案例一直只有一个固定的数据源,但是实际开发中我们常常会有多个数据库(分库分表存放业务场景&主从场景),所以本次来做个这样的尝试。
另外,我们此次使用mybatis-plus插件来更方便的进行数据操作。

几个概念

多模块(maven聚合):
我们之前的demo都是一个项目一个文件,但是实际生产场景中,这种方式还是比较少见的,正常一个项目都或或多或少的关联另一个项目,比如开发了一套api项目,这套api肯定会有对应的web项目,app项目等等,那么如何在创建项目时就能体现这种依赖关系呢?maven聚合应运而生。你可以简单的理解为有这么一个父项目,能管理所以依赖它的子项目,当父项目改动编译时,对应的所有子项目都会编译重新打包

mybatis-plus:
MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis -plus则是在MyBatis 上的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。

多数据源:
简而言之,同时连接多个数据库

项目构建

博主使用的是IDEA开发,所以建议大家都使用IDEA。

创建父项目

1.png
2.png

删除src目录,因为父项目不写代码

创建子项目

右键选择父项目


3.png
4.png
5.png
6.png

至此基本的项目结构已经建立,但是实际上demo和web-api的"父子关系"还没有建立,我们需要简单的修改下pom.xml
SpringBootDemo/pom.xml:

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.3.RELEASE</version>
    </parent>
    <packaging>pom</packaging>
    <modules>
        <module>sbmp-multidb</module>
    </modules>
7.png

sbmp-multidb/pom.xml更改parent:

    <parent>
        <groupId>com.mrcoder</groupId>
        <artifactId>SpringBootDemo</artifactId>
        <version>1.0.0</version>
        <relativePath>../pom.xml</relativePath>
    </parent>
8.png

Tips

那么问题来了,既然所谓的依赖是加载包,那么若我们在父pom.xml中加入一个依赖包,那么子模块会自动继承这个依赖么?
这就引出了maven 关于pom依赖管理的知识。请查看

9.1.从零开始学springboot-maven聚合下的pom依赖关系

添加依赖

以上完成了多模块的配置,下面我们添加子模块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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>


    <parent>
        <groupId>com.mrcoder</groupId>
        <artifactId>SpringBootDemo</artifactId>
        <version>1.0.0</version>
        <relativePath>../pom.xml</relativePath>
    </parent>


    <groupId>com.mrcoder</groupId>
    <artifactId>sbmp-multidb</artifactId>
    <version>0.0.1</version>
    <name>sbmp-multidb</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <spring.boot.version>2.1.0.RELEASE</spring.boot.version>
        <mysql.version>8.0.12</mysql.version>
        <mybatisplus.version>3.0.7.1</mybatisplus.version>
        <dynamic-datasource.version>2.5.0</dynamic-datasource.version>
        <lombok.version>1.18.2</lombok.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </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-starter-web</artifactId>
        </dependency>
        <!-- mysql驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>
        <!-- lombok简化类 -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
            <version>${lombok.version}</version>
        </dependency>
        <!-- 多数据源 -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
            <version>${dynamic-datasource.version}</version>
        </dependency>
        <!-- mybatis-plus -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>${mybatisplus.version}</version>
        </dependency>
        <!-- mybatis-plus代码生成器 -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>${mybatisplus.version}</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus</artifactId>
            <version>${mybatisplus.version}</version>
        </dependency>


    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

9.png
10.png

添加配置

application.yml:

spring:
  datasource:
    dynamic:
      primary: db1   #设置默认的数据源
      datasource:
        db1:
          username: root
          password: 123456
          url: jdbc:mysql://192.168.145.131:3306/test?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=GMT%2B8
          driver-class-name: com.mysql.cj.jdbc.Driver
        db2:
          username: root
          password: 123456
          url: jdbc:mysql://192.168.145.131:3306/test2?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=GMT%2B8
          driver-class-name: com.mysql.cj.jdbc.Driver
      mp-enabled: true
logging:
  level:
    com.xkcoding.multi.datasource.mybatis: debug

建库

建立test、test2数据库
test库建表:

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for multi_user
-- ----------------------------
DROP TABLE IF EXISTS `multi_user`;
CREATE TABLE `multi_user` (
  `id` bigint(64) NOT NULL,
  `name` varchar(50) DEFAULT NULL,
  `age` int(30) DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of multi_user
-- ----------------------------
INSERT INTO `multi_user` VALUES ('1', '主库添加222', '20');

test2库建表:

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for multi_user
-- ----------------------------
DROP TABLE IF EXISTS `multi_user`;
CREATE TABLE `multi_user` (
  `id` bigint(64) NOT NULL,
  `name` varchar(50) DEFAULT NULL,
  `age` int(30) DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of multi_user
-- ----------------------------
INSERT INTO `multi_user` VALUES ('1103566261448732674', '主库添加', '20');
INSERT INTO `multi_user` VALUES ('1103566303475658753', '主库添加', '20');
INSERT INTO `multi_user` VALUES ('1103566435235524610', '主库添加', '20');

mybatis-plus代码生成器的使用

以上我们成功创建了一个多模块的项目,父项目为SpringBootDemo,子项目为sbmp-multidb
接下来,我们完善各"层"代码,考虑到手动一个个创建类文件和包太麻烦,这边我们使用一个偷懒工具,mybatis-plus-generator来自动生成相关的包和类文件(和mubatis-generator类似的功能)。

我们先右键新增一个名叫generator的package,里面新增一个MysqlGenerator的类文件,


11.png
12.png

generator/MysqlGenerator:

package com.mrcoder.sbmpmultidb.generator;

import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

/**
 * <p>
 * mysql 代码生成器演示例子
 * </p>
 */
public class MysqlGenerator {

    /**
     * <p>
     * 读取控制台内容
     * </p>
     */
    public static String scanner(String tip) {
        Scanner scanner = new Scanner(System.in);
        StringBuilder help = new StringBuilder();
        help.append("请输入" + tip + ":");
        System.out.println(help.toString());
        if (scanner.hasNext()) {
            String ipt = scanner.next();
            if (StringUtils.isNotEmpty(ipt)) {
                return ipt;
            }
        }
        throw new MybatisPlusException("请输入正确的" + tip + "!");
    }

    /**
     * RUN THIS
     */
    public static void main(String[] args) {
        // 代码生成器
        AutoGenerator mpg = new AutoGenerator();

        // 全局配置
        GlobalConfig gc = new GlobalConfig();
        String projectPath = System.getProperty("user.dir");
        gc.setOutputDir(projectPath + "/sbmp-multidb/src/main/java");
        gc.setAuthor("mrcoder");
        gc.setOpen(false);
        mpg.setGlobalConfig(gc);

        // 数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://192.168.145.131:3306/test?useUnicode=true&useSSL=false&characterEncoding=utf8");
        // dsc.setSchemaName("public");
        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("123456");
        mpg.setDataSource(dsc);

        // 包配置
        PackageConfig pc = new PackageConfig();
        pc.setModuleName(scanner("模块名"));
        pc.setParent("com.mrcoder");
        mpg.setPackageInfo(pc);

        // 自定义配置
        InjectionConfig cfg = new InjectionConfig() {
            @Override
            public void initMap() {
                // to do nothing
            }
        };
        List<FileOutConfig> focList = new ArrayList<>();
        focList.add(new FileOutConfig("/templates/mapper.xml.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义输入文件名称
                return projectPath + "/sbmp-multidb/src/main/resources/mapper/" + pc.getModuleName()
                        + "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
            }
        });
        cfg.setFileOutConfigList(focList);
        mpg.setCfg(cfg);
        mpg.setTemplate(new TemplateConfig().setXml(null));

        // 策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        //strategy.setSuperEntityClass("com.mrcoder.sbmpmultidb.BaseEntity");
        strategy.setEntityLombokModel(true);
        //strategy.setSuperControllerClass("com.mrcoder.sbmpmultidb.BaseController");
        strategy.setInclude(scanner("表名"));
        strategy.setSuperEntityColumns("id");
        strategy.setControllerMappingHyphenStyle(true);
        strategy.setTablePrefix(pc.getModuleName() + "_");
        mpg.setStrategy(strategy);
        // 选择 freemarker 引擎需要指定如下加,注意 pom 依赖必须有!
        mpg.setTemplateEngine(new FreemarkerTemplateEngine());
        mpg.execute();
    }

}

相关的注释已经加上了,自行阅读,或者直接去看官方文档~,根据实际情况酌情修改。

这边我们直接运行代码生成器,点击绿色的小箭头


13.png

运行时会让你填写模块名和数据表名,


14.png

模块名写子模块的名称即可,这边不写子模块名填写其它名字的话则会自动创建一个子模块并将文件生成进去。
数据表名如实填写即可

目录结构

15.png

如图,标红部分为代码生成器自动生成的代码,只需小小的完善即可使用。

controller和service/impl还是需要手动创建的。

完善

我们创建controller和service/impl的package,补充代码

controller/MultiUserController:

package com.mrcoder.sbmpmultidb.controller;


import com.mrcoder.sbmpmultidb.entity.MultiUser;
import com.mrcoder.sbmpmultidb.service.IMultiUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**
 * <p>
 *  前端控制器
 * </p>
 *
 * @author mrcoder
 * @since 2019-03-07
 */
@Controller
@RestController
@RequestMapping("/sbmpmultidb/multi-user")
public class MultiUserController {
    @Autowired
    private IMultiUserService userService;

    @RequestMapping("/id")
    public MultiUser id(){
        MultiUser user = userService.getById(1);
        return user;
    }

    @RequestMapping("/list")
    public List<MultiUser> list() {
        List<MultiUser> userList = userService.list();
        return userList;
    }

    @RequestMapping("add")
    public String add(){
        MultiUser userMaster = MultiUser.builder().name("主库添加").age(20).build();
        userService.addUser(userMaster);
        return "add success";
    }

    @RequestMapping("update")
    public String update(){

        MultiUser userMaster = MultiUser.builder().id(1L).name("主库添加222").age(20).build();
        userService.updateById(userMaster);
        return "update success";
    }
}

entity/MultiUser:

package com.mrcoder.sbmpmultidb.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

/**
 * @author mrcoder
 * @since 2019-02-26
 */
@Data
@TableName("multi_user")
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class MultiUser implements Serializable {
    private static final long serialVersionUID = -1923859222295750467L;
    //private static final long serialVersionUID = 1L;

    @TableId(type = IdType.ID_WORKER)
    private Long id;

    private String name;

    private Integer age;

}

mapper/MultiUserMapper:

package com.mrcoder.sbmpmultidb.mapper;

import com.mrcoder.sbmpmultidb.entity.MultiUser;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;

/**
 * <p>
 *  Mapper 接口
 * </p>
 *
 * @author mrcoder
 * @since 2019-03-07
 */
public interface MultiUserMapper extends BaseMapper<MultiUser> {

}

service/IMultiUserService:

package com.mrcoder.sbmpmultidb.service;

import com.mrcoder.sbmpmultidb.entity.MultiUser;
import com.baomidou.mybatisplus.extension.service.IService;

/**
 * <p>
 *  服务类
 * </p>
 *
 * @author mrcoder
 * @since 2019-03-07
 */
public interface IMultiUserService extends IService<MultiUser> {
    void addUser(MultiUser user);
}

service/impl/MultiUserServiceImpl:

package com.mrcoder.sbmpmultidb.service.impl;

import com.baomidou.dynamic.datasource.annotation.DS;
import com.mrcoder.sbmpmultidb.entity.MultiUser;
import com.mrcoder.sbmpmultidb.mapper.MultiUserMapper;
import com.mrcoder.sbmpmultidb.service.IMultiUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author mrcoder
 * @since 2019-03-07
 */
@Service
@DS("db1")
public class MultiUserServiceImpl extends ServiceImpl<MultiUserMapper, MultiUser> implements IMultiUserService {
    @DS("db2")
    @Override
    public void addUser(MultiUser user) {
        baseMapper.insert(user);
    }
}

最后我们在入口文件中加入扫描操作:

SbmpMultidbApplication:

package com.mrcoder.sbmpmultidb;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@MapperScan("com.mrcoder.sbmpmultidb.mapper")
public class SbmpMultidbApplication {

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

}

运行

16.png

项目地址

https://github.com/MrCoderStack/SpringBootDemo/tree/master/sbmp-multidb

https://gitee.com/MrCoderStack/SpringBootDemo/tree/master/sbmp-multidb

请关注我的订阅号

订阅号.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容

  • 1.父工程的pom.xml中导入依赖和插件,当前完整的文件如下: <?xml version="1.0"encod...
    瑜Z酱阅读 4,559评论 0 5
  • 1. 简介 1.1 什么是 MyBatis ? MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的...
    笨鸟慢飞阅读 5,423评论 0 4
  • “代码自动生成”,第一次知道这个词语是从大学的Java web课上,一位外聘老师口中得知。 从他的闲聊中了解到,许...
    娶个好听的昵称阅读 7,140评论 7 106
  • 焦点网络11期分享第2天,一件事情坚持下去就会有收获,在坚持过程中需要静下心来,所以趁着儿子这会自己玩,没有缠...
    尘_9075阅读 194评论 0 0
  • 只是依稀还记得,风吹过的日子。梦醒了,希望的正是现在。就好像还会回来一样,终究待过的地方。 不经意之间,踏下几步时...
    花言巧语只为逢场做戏阅读 209评论 0 1