一. Mybatis-Plus的實(shí)體類(lèi)注解
1. @TableName注解
@TableName(value = …)
當(dāng)數(shù)據(jù)庫(kù)名與實(shí)體類(lèi)名不一致或不符合駝峰命名時(shí)墨状,需要在此注解指定表名
@TableId(type = …)
指定實(shí)體類(lèi)的屬性為對(duì)應(yīng)的主鍵杯瞻,主要有以下幾種:
// 數(shù)據(jù)庫(kù)ID自增
IdType.AUTO
// 該類(lèi)型為未設(shè)置主鍵類(lèi)型(默認(rèn))
IdType.NONE
/**
* 用戶(hù)輸入ID
* <p>該類(lèi)型可以通過(guò)自己注冊(cè)自動(dòng)填充插件進(jìn)行填充</p>
*/
IdType.INPUT
/* 以下3種類(lèi)型胁赢、只有當(dāng)插入對(duì)象ID 為空,才自動(dòng)填充亦渗。 */
//1.全局唯一ID (idWorker)
IdType.ID_WORKER
//2.全局唯一ID (UUID)
IdType.UUID
//3.字符串全局唯一ID (idWorker 的字符串表示)
IdType.ID_WORKER_STR
2. @TableField注解
- 主要用來(lái)解決實(shí)體類(lèi)的字段名與數(shù)據(jù)庫(kù)中的字段名不匹配的問(wèn)題(數(shù)據(jù)庫(kù)user_addr,字段useraddr未駝峰)
- 實(shí)體類(lèi)中的屬性字段在表中不存在的問(wèn)題
// 用來(lái)解決數(shù)據(jù)庫(kù)中的字段和實(shí)體類(lèi)的字段不匹配問(wèn)題
@TableField(value = "age")
// 用來(lái)解決實(shí)體類(lèi)中有的屬性但是數(shù)據(jù)表中沒(méi)有的字段
@TableField(exist = false) // 默認(rèn)為true
二. Navicat v15激活步驟
navicat15安裝完后別著急打開(kāi)
1. 運(yùn)行Navicat Keygen Patch v5.6.0 DFoX.exe
2. 點(diǎn)擊Generate按鈕就會(huì)生成一個(gè)許可證秘鑰汁尺,將許可證秘鑰復(fù)制后就打開(kāi)Navicat Premium 15
3. 打開(kāi)Navicat Premium 15法精,點(diǎn)擊注冊(cè)
4. 粘貼秘鑰,然后點(diǎn)擊激活按鈕
5. 在彈出的界面選擇手動(dòng)激活
6. 將請(qǐng)求碼粘貼到注冊(cè)機(jī)Request Code框中
7. 點(diǎn)擊激活頁(yè)面的激活彈出(說(shuō)明激活成功)
三. 服務(wù)部署到docker后痴突,查看信息
1. 查看日志信息
docker logs -tf --tail 10 容器ID
2. 查看服務(wù)的配置文件
2.1 列出在運(yùn)行的容器
docker ps
2.2 進(jìn)入該容器
docker exec -it 容器ID /bin/bash
2.3 找到配置文件后進(jìn)行修改查看
四. Mybatis-plus多數(shù)據(jù)源配置
1. 環(huán)境準(zhǔn)備
1.1 數(shù)據(jù)庫(kù)相關(guān)
以 mysql 為例進(jìn)行演示說(shuō)明搂蜓,因?yàn)樾枰鄶?shù)據(jù)源,一個(gè)最簡(jiǎn)單的 case 就是一個(gè)物理庫(kù)上多個(gè)邏輯庫(kù)辽装,本文是基于本機(jī)的 mysql 進(jìn)行操作
創(chuàng)建數(shù)據(jù)庫(kù)test
與 story
帮碰,兩個(gè)庫(kù)下都存在一個(gè)表money
(同名同結(jié)構(gòu)表,但是數(shù)據(jù)不同哦)
CREATE TABLE `money` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(20) NOT NULL DEFAULT '' COMMENT '用戶(hù)名',
`money` int(26) NOT NULL DEFAULT '0' COMMENT '錢(qián)',
`is_deleted` tinyint(1) NOT NULL DEFAULT '0',
`create_at` date NOT NULL COMMENT '創(chuàng)建時(shí)間',
`update_at` date NOT NULL COMMENT '更新時(shí)間',
PRIMARY KEY (`id`),
KEY `name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
1.2 項(xiàng)目環(huán)境
本項(xiàng)目借助SpringBoot 2.2.1.RELEASE
+ maven 3.5.3
+ IDEA
進(jìn)行開(kāi)發(fā)
下面是核心的pom.xml
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.1</version>
</dependency>
</dependencies>
配置文件信息application.yml
拾积,請(qǐng)注意下面的寫(xiě)法格式殉挽,如有疑問(wèn)可以參考官方教程
spring:
datasource:
dynamic:
primary: story #設(shè)置默認(rèn)的數(shù)據(jù)源或者數(shù)據(jù)源組,默認(rèn)值即為master
strict: false #設(shè)置嚴(yán)格模式,默認(rèn)false不啟動(dòng). 啟動(dòng)后在未匹配到指定數(shù)據(jù)源時(shí)候會(huì)拋出異常,不啟動(dòng)則使用默認(rèn)數(shù)據(jù)源.
datasource:
story:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/story?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
username: root
password:
test:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
username: root
password:
2. 項(xiàng)目演示
2.1 實(shí)體類(lèi)
mybatis-plus 可以借助插件實(shí)現(xiàn)自動(dòng)生成相應(yīng)的代碼,我們這里簡(jiǎn)單自主實(shí)現(xiàn)測(cè)試 demo拓巧,因?yàn)閮蓚€(gè)數(shù)據(jù)庫(kù)中表結(jié)構(gòu)完全一致斯碌,所以只需要一個(gè) Entity
@Data
@Accessors(chain = true)
@TableName(value = "money")
public class MoneyPo {
/**
* 指定自增策略
*/
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
private String name;
private Long money;
@TableField("is_deleted")
private Integer isDeleted;
@TableField(value = "create_at")
private Date createAt;
@TableField(value = "update_at")
private Date updateAt;
}
2.2 Mapper 接口
數(shù)據(jù)庫(kù)操作定義接口MoneyMapper
public interface MoneyMapper extends BaseMapper<MoneyPo> {
}
對(duì)應(yīng)的 xml 文件resources/mapper/money-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.ruangh.mybatisplus.datasouce.mybatisplusdatasouce.mapper.MoneyMapper">
</mapper>
2.3 Service 接口與實(shí)現(xiàn)
因?yàn)閮蓮埍恚晕覀兛梢远x一個(gè)接口肛度,兩個(gè)不同的實(shí)現(xiàn)
public interface MoneyService extends IService<MoneyPo> {
}
@Service
@DS("story")
public class StoryMoneyServiceImpl extends ServiceImpl<MoneyMapper, MoneyPo> implements MoneyService {
}
@Service
@DS("test")
public class TestMoneyServiceImpl extends ServiceImpl<MoneyMapper, MoneyPo> implements MoneyService {
}
請(qǐng)注意上面 Service 的注解@DS
傻唾,value 為前面數(shù)據(jù)源配置文件中的 key(spring.datasource.dynamic.datasource
下面的story
+ test
)
這個(gè)注解可以放在類(lèi)上也可以放在方法上,方法上的優(yōu)先級(jí) > 類(lèi)承耿,所以上面的兩個(gè) Service 實(shí)現(xiàn)可以改成一個(gè)
@Service
public class MoneyServiceImpl extends ServiceImpl<MoneyMapper, MoneyPo> implements MoneyService {
@DS("story")
public List<MoneyPo> findByStoryIds(Collection<Long> ids) {
return baseMapper.selectBatchIds(ids);
}
@DS("test")
public List<MoneyPo> findByTestIds(Collection<Long> ids) {
return baseMapper.selectBatchIds(ids);
}
}
2.4 測(cè)試
為簡(jiǎn)單起見(jiàn)冠骄,直接在啟動(dòng)類(lèi)中添加寫(xiě)上測(cè)試代碼
![010](E:\ruanghDoc\LearningClip\學(xué)習(xí)筆記\新能康-復(fù)盤(pán)\210904-mybatis-plus注解\010.png)@SpringBootApplication
@MapperScan("com.ruangh.mybatisplus.datasouce.mybatisplusdatasouce.mapper")
public class MybatisplusDatasouceApplication {
public MybatisplusDatasouceApplication(TestMoneyServiceImpl testMoneyService, StoryMoneyServiceImpl storyMoneyService) {
List<MoneyPo> moneyPoList = testMoneyService.listByIds(Arrays.asList(1, 1000));
System.out.println(moneyPoList);
System.out.println("--------------");
moneyPoList = storyMoneyService.listByIds(Arrays.asList(1, 1000));
System.out.println(moneyPoList);
}
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
}
3. 遇到的坑
可以看到啟動(dòng)過(guò)程中我們配置的多數(shù)據(jù)庫(kù)源Start completed.之后遇到異常之后又被shutdown了。
因?yàn)橐肓硕鄠€(gè)Mybatis 的jar包引起的加袋,檢查bom.xml文件是否引入了mybatis和mybatis-plus兩個(gè)依賴(lài)凛辣,如果是去掉mybatis即可。
五. MyBatis-Plus Wrapper條件構(gòu)造器篩選不必要的字段
1. 需求
這個(gè)MP的Wrapper默認(rèn)查詢(xún)是查詢(xún)?nèi)康牧兄吧眨俏业男枨笫切枰樵?xún)某幾個(gè)列即可蟀给。
2. 解決辦法
/**
* 名字包含雨并且年齡小于40
* <p>
* 只顯示id蝙砌、name 兩列
*/
@Test
public void selectByWrapper1() {
QueryWrapper<User> wrapper = new QueryWrapper();
wrapper.like("name", "雨").lt("age", 40)
.select("id","name");
List<User> users = userMapper.selectList(wrapper);
users.forEach(System.out::println);
}
/**
* 名字包含雨并且年齡小于40
* <p>
* 除了create_time、manager_id 其他列都顯示
*/
@Test
public void selectByWrapper2() {
QueryWrapper<User> wrapper = new QueryWrapper();
wrapper.like("name", "雨").lt("age", 40)
.select(User.class,i -> !i.getColumn().equals("create_time")
&& !i.getColumn().equals("manager_id"));
List<User> users = userMapper.selectList(wrapper);
users.forEach(System.out::println);
}
六. Mybatis-Plus代碼自動(dòng)生成
1. 準(zhǔn)備
準(zhǔn)備兩張表跋理,用于測(cè)試
CREATE TABLE `userT0` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(20) NOT NULL DEFAULT '' COMMENT '用戶(hù)名',
`pwd` varchar(26) NOT NULL DEFAULT '' COMMENT '密碼',
`isDeleted` tinyint(1) NOT NULL DEFAULT '0',
`created` varchar(13) NOT NULL DEFAULT '0',
`updated` varchar(13) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `story_t0` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`userId` int(20) unsigned NOT NULL DEFAULT '0' COMMENT '作者的userID',
`name` varchar(20) NOT NULL DEFAULT '' COMMENT '作者名',
`title` varchar(26) NOT NULL DEFAULT '' COMMENT '密碼',
`story` text COMMENT '故事內(nèi)容',
`is_deleted` tinyint(1) NOT NULL DEFAULT '0',
`create_at` varchar(13) NOT NULL DEFAULT '0',
`update_at` varchar(13) NOT NULL DEFAULT '0',
`tag` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `userId` (`userId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
請(qǐng)注意择克,上面兩張表的命名格式并不一樣,有的是駝峰前普,有的是下劃線(主要為了演示不同表名肚邢,對(duì)于生成代碼的影響)
2. 配置依賴(lài)
首先需要在我們的xml文件中,添加相關(guān)的依賴(lài)
<dependencies>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.3.1.tmp</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- 下面兩個(gè)拭卿,用于測(cè)試生成后的代碼骡湖,在生成代碼時(shí),可以不需要-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.2.0</version>
</dependency>
</dependencies>
3. 代碼生成類(lèi)
寫(xiě)一個(gè)代碼生成類(lèi)方法峻厚,主要邏輯如下
public class CodeGenerator {
public static void main(String[] args) {
// 代碼生成器
AutoGenerator mpg = new AutoGenerator();
// 全局配置
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir") + "/spring-boot/106-mybatis-plus-generator";
gc.setOutputDir(projectPath + "/src/main/java");
gc.setAuthor("ruangh");
gc.setOpen(false);
// 覆蓋寫(xiě)
gc.setFileOverride(false);
mpg.setGlobalConfig(gc);
// 數(shù)據(jù)源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://127.0.0.1:3306/story?useSSL=false&serverTimezone=UTC");
// dsc.setSchemaName("public");
dsc.setDriverName("com.mysql.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("123456");
mpg.setDataSource(dsc);
// 包配置
PackageConfig pc = new PackageConfig();
// 不額外指定模塊响蕴,如果指定為 test,則生成的xml會(huì)在 mapper/test/ 目錄下
pc.setModuleName("");
pc.setParent("com.ruangh.mybatisplus.generator");
mpg.setPackageInfo(pc);
// 自定義配置
InjectionConfig cfg = new InjectionConfig() {
@Override
public void initMap() {
// to do nothing
}
};
// 如果模板引擎是 freemarker
String templatePath = "/templates/mapper.xml.ftl";
// 自定義輸出配置
List<FileOutConfig> focList = new ArrayList<>();
// 自定義配置會(huì)被優(yōu)先輸出
focList.add(new FileOutConfig(templatePath) {
@Override
public String outputFile(TableInfo tableInfo) {
// 自定義輸出文件名 惠桃, 如果你 Entity 設(shè)置了前后綴浦夷、此處注意 xml 的名稱(chēng)會(huì)跟著發(fā)生變化!辜王!
return projectPath + "/src/main/resources/mapper/" + pc.getModuleName() + "/" +
tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
}
});
cfg.setFileOutConfigList(focList);
mpg.setCfg(cfg);
// 配置模板
TemplateConfig templateConfig = new TemplateConfig();
templateConfig.setXml(null);
// 不自動(dòng)生成controller類(lèi)
templateConfig.setController(null);
mpg.setTemplate(templateConfig);
// 策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setNaming(NamingStrategy.underline_to_camel);
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
// strategy.setSuperEntityClass("你自己的父類(lèi)實(shí)體,沒(méi)有就不用設(shè)置!");
strategy.setEntityLombokModel(true);
strategy.setRestControllerStyle(true);
// 公共父類(lèi)
// strategy.setSuperControllerClass("你自己的父類(lèi)控制器,沒(méi)有就不用設(shè)置!");
// 寫(xiě)于父類(lèi)中的公共字段
// strategy.setSuperEntityColumns("id");
// 設(shè)置需要生成的表名
strategy.setInclude("userT0", "story_t0");
strategy.setControllerMappingHyphenStyle(true);
// strategy.setTablePrefix(pc.getModuleName() + "_");
mpg.setStrategy(strategy);
mpg.setTemplateEngine(new FreemarkerTemplateEngine());
mpg.execute();
}
}
上面的代碼劈狐,絕大部分都是通用的,下面著重說(shuō)明需要注意的點(diǎn)
GlobalConfig#setOutputDir
: 設(shè)置代碼輸出的項(xiàng)目根路徑呐馆,請(qǐng)根據(jù)具體的項(xiàng)目要求進(jìn)行指定肥缔,不包含包名哦-
GlobalConfig#setFileOverride(true)
: 設(shè)置為true,則每次生成都會(huì)覆蓋之前生成的代碼汹来,適用于表結(jié)構(gòu)發(fā)生變化的場(chǎng)景
- 注意:會(huì)導(dǎo)致之前添加的業(yè)務(wù)代碼被覆蓋掉续膳,需要額外注意
- 通常希望設(shè)置為false,當(dāng)表結(jié)構(gòu)發(fā)生變化時(shí)收班,手動(dòng)介入
DataSourceConfig
: 數(shù)據(jù)源的設(shè)置姑宽,上面設(shè)置的是mysql的相關(guān)配置-
PackageConfig
: 包信息
-
setParent
: java包路徑 -
setModuleName
: 設(shè)置模塊名,如設(shè)置為test闺阱,則xml在mapper/test/
目錄下; parent包自動(dòng)加上.test
-
FileOutConfig
: xml文件名-
TemplateConfig
: 模板配置
- 可用默認(rèn)的代碼生成模板炮车,也可以使用自定義的模板
- 不想生成某個(gè)模板類(lèi)時(shí),設(shè)置為null即可(如上面的不生成controller)
-
StrategyConfig
: 策略配置
- 可以指定db->pojo字段名的映射規(guī)則
- 可以指定POJO/Controller繼承自定義的基類(lèi)
在IDEA中酣溃,直接右鍵執(zhí)行上面的代碼瘦穆,就會(huì)生成目標(biāo)類(lèi),如下截圖
4. 輸出測(cè)試
測(cè)試我們生成的類(lèi)赊豌,是否可以對(duì)db進(jìn)行操作扛或,則有必要寫(xiě)一個(gè)啟動(dòng)類(lèi)
@RestController
@SpringBootApplication
@MapperScan("com.ruangh.mybatisplus.generator.mapper")
public class Application {
@Autowired
private IUserT0Service userT0Service;
@GetMapping
public UserT0 hello(int id) {
return userT0Service.getById(id);
}
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
}
請(qǐng)注意上面的@MapperScan
注解,其次對(duì)應(yīng)的application.yml
配置文件內(nèi)容如下
spring:
datasource:
# 注意指定時(shí)區(qū)
url: jdbc:mysql://127.0.0.1:3306/story?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
username: root
password:
mybatis-plus:
configuration:
# 執(zhí)行的sql語(yǔ)句日志輸出
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
在db中插入一條數(shù)據(jù)
INSERT INTO `userT0` (`id`, `name`, `pwd`, `isDeleted`, `created`, `updated`)
VALUES
true(1, '一灰灰', 'yihuihuiblog', 0, '2020-04-06 15', '2020-04-06 15');
訪問(wèn)url: http://localhost:8080/?id=1
控制臺(tái)輸出如下:
5. 特殊場(chǎng)景說(shuō)明
上面的代碼生成碘饼,針對(duì)首次執(zhí)行生成打碼時(shí)熙兔,問(wèn)題不大悲伶;但是后續(xù)的業(yè)務(wù)開(kāi)發(fā)中,總會(huì)有一些其他的情況住涉,下面分別說(shuō)明
5.1 表結(jié)構(gòu)修改
當(dāng)表的結(jié)構(gòu)發(fā)生變化時(shí)麸锉,我們需要一般需要重新生成對(duì)應(yīng)的Entity,這個(gè)時(shí)候舆声,需要GlobalConfig#setFileOverride(true)
5.2 繼承公用POJO
我們可以定義一個(gè)通用的PO類(lèi)花沉,希望所有的表生成的POJO繼承它
@Data
public class BasePo implements Serializable {
private static final long serialVersionUID = -1136173266983480386L;
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
}
在代碼自動(dòng)生成類(lèi)的策略配置中,添加下面的兩行設(shè)置即可
// 所有實(shí)體類(lèi)繼承自 BasePo, 且id在父類(lèi)中
StrategyConfig strategy = new StrategyConfig();
strategy.setSuperEntityClass(BasePo.class);
strategy.setSuperEntityColumns("id");
5.3 生成部分代碼
有些時(shí)候媳握,我并不希望生成service
,xml
碱屁,可能就只需要實(shí)體類(lèi) + mapper接口
,這個(gè)時(shí)候可以設(shè)置TemplateConfig
TemplateConfig templateConfig = new TemplateConfig();
templateConfig.setController(null);
templateConfig.setEntityKt(null);
templateConfig.setService(null);
templateConfig.setServiceImpl(null);