前言
前几个案例一直只有一个固定的数据源,但是实际开发中我们常常会有多个数据库(分库分表存放业务场景&主从场景),所以本次来做个这样的尝试。
另外,我们此次使用mybatis-plus插件来更方便的进行数据操作。
几个概念
多模块(maven聚合):
我们之前的demo都是一个项目一个文件,但是实际生产场景中,这种方式还是比较少见的,正常一个项目都或或多或少的关联另一个项目,比如开发了一套api项目,这套api肯定会有对应的web项目,app项目等等,那么如何在创建项目时就能体现这种依赖关系呢?maven聚合应运而生。你可以简单的理解为有这么一个父项目,能管理所以依赖它的子项目,当父项目改动编译时,对应的所有子项目都会编译重新打包
mybatis-plus:
MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis -plus则是在MyBatis 上的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
多数据源:
简而言之,同时连接多个数据库
项目构建
博主使用的是IDEA开发,所以建议大家都使用IDEA。
创建父项目
删除src目录,因为父项目不写代码
创建子项目
右键选择父项目
至此基本的项目结构已经建立,但是实际上demo和web-api的"父子关系"还没有建立,我们需要简单的修改下pom.xml
SpringBootDemo/pom.xml:
org.springframework.boot
spring-boot-starter-parent
2.1.3.RELEASE
pom
sbmp-multidb
sbmp-multidb/pom.xml更改parent:
com.mrcoder
SpringBootDemo
1.0.0
../pom.xml
Tips
那么问题来了,既然所谓的依赖是加载包,那么若我们在父pom.xml中加入一个依赖包,那么子模块会自动继承这个依赖么?
这就引出了maven 关于pom依赖管理的知识。请查看
9.1.从零开始学springboot-maven聚合下的pom依赖关系
添加依赖
以上完成了多模块的配置,下面我们添加子模块pom.xml依赖
完整依赖:
4.0.0
com.mrcoder
SpringBootDemo
1.0.0
../pom.xml
com.mrcoder
sbmp-multidb
0.0.1
sbmp-multidb
Demo project for Spring Boot
2.1.0.RELEASE
8.0.12
3.0.7.1
2.5.0
1.18.2
org.springframework.boot
spring-boot-starter
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-starter-web
mysql
mysql-connector-java
${mysql.version}
org.projectlombok
lombok
true
${lombok.version}
com.baomidou
dynamic-datasource-spring-boot-starter
${dynamic-datasource.version}
com.baomidou
mybatis-plus-boot-starter
${mybatisplus.version}
com.baomidou
mybatis-plus-generator
${mybatisplus.version}
com.baomidou
mybatis-plus
${mybatisplus.version}
org.springframework.boot
spring-boot-maven-plugin
添加配置
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的类文件,
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;
/**
*
* mysql 代码生成器演示例子
*
*/
public class MysqlGenerator {
/**
*
* 读取控制台内容
*
*/
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 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();
}
}
相关的注释已经加上了,自行阅读,或者直接去看官方文档~,根据实际情况酌情修改。
这边我们直接运行代码生成器,点击绿色的小箭头
运行时会让你填写模块名和数据表名,
模块名写子模块的名称即可,这边不写子模块名填写其它名字的话则会自动创建一个子模块并将文件生成进去。
数据表名如实填写即可
目录结构
如图,标红部分为代码生成器自动生成的代码,只需小小的完善即可使用。
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;
/**
*
* 前端控制器
*
*
* @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 list() {
List 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;
/**
*
* Mapper 接口
*
*
* @author mrcoder
* @since 2019-03-07
*/
public interface MultiUserMapper extends BaseMapper {
}
service/IMultiUserService:
package com.mrcoder.sbmpmultidb.service;
import com.mrcoder.sbmpmultidb.entity.MultiUser;
import com.baomidou.mybatisplus.extension.service.IService;
/**
*
* 服务类
*
*
* @author mrcoder
* @since 2019-03-07
*/
public interface IMultiUserService extends IService {
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;
/**
*
* 服务实现类
*
*
* @author mrcoder
* @since 2019-03-07
*/
@Service
@DS("db1")
public class MultiUserServiceImpl extends ServiceImpl 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);
}
}
运行
项目地址
https://github.com/MrCoderStack/SpringBootDemo/tree/master/sbmp-multidb
https://gitee.com/MrCoderStack/SpringBootDemo/tree/master/sbmp-multidb