本文主要讲解如何在springboot下整合mybatis-plus,并访问mysql数据库。
表结构
现有一张 User
表,其表结构如下:
id | name | age | |
---|---|---|---|
1 | Jone | 18 | test1@baomidou.com |
2 | Jack | 20 | test2@baomidou.com |
3 | Tom | 28 | test3@baomidou.com |
4 | Sandy | 21 | test4@baomidou.com |
5 | Billie | 24 | test5@baomidou.com |
其对应的数据库 Schema 脚本如下:
DROP TABLE IF EXISTS user;
CREATE TABLE user
(
id BIGINT(20) NOT NULL COMMENT '主键ID',
name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
age INT(11) NULL DEFAULT NULL COMMENT '年龄',
email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY (id)
);
其对应的数据库 Data 脚本如下:
DELETE FROM user;
INSERT INTO user (id, name, age, email) VALUES
(1, 'Jone', 18, 'test1@baomidou.com'),
(2, 'Jack', 20, 'test2@baomidou.com'),
(3, 'Tom', 28, 'test3@baomidou.com'),
(4, 'Sandy', 21, 'test4@baomidou.com'),
(5, 'Billie', 24, 'test5@baomidou.com');
如果执行 delete
提示 Error Code: 1175. You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column To disable safe mode, toggle the option in Preferences -> SQL Editor and reconnect.
就先执行下 SET SQL_SAFE_UPDATES =0;
命令,接着就可以了!
创建工程
创建一个 Spring Boot 工程
参考 SpringBoot 教程&笔记 |Demo01-构建一个简单的 Web 应用程来创建
添加依赖
引入 mybatis-plus-boot-starter
、lombok
、mysql-connector-java
、freemarker
、swagger2
依赖:
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.12</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.28</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
</dependencies>
配置
在 application.yml
配置文件中添加 mysql 数据库的相关配置:
# DataSource Config
spring:
datasource:
url: jdbc:mysql://localhost:3306/demo?useUnicode=yes&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
username: testuser
password:
driver-class-name: com.mysql.cj.jdbc.Driver
代码生成器
AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、Dao、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。
package com.heardfate.springboot.demo;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
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.TableFill;
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.Collections;
import java.util.List;
/**
* @program: springboot-demo04
* @since: 2018/10/23
* @author: Mr.HeardFate
*/
public class CodeGenerator {
/**
* 包名
*/
private static final String PACKAGE_NAME = "com.heardfate.springboot.demo";
/**
* 模块名称
*/
private static final String MODULE_NAME = "demo04";
private static final String NAME = "";
/**
* 输出文件的路径
*/
private static final String OUT_PATH = System.getProperty("user.dir") + NAME + "/src/main/java";
/**
* 输出文件的路径
*/ private static final String OUT_PATH_MAPPING = System.getProperty("user.dir") + NAME + "/src/main/resources/mapper";
/**
* 代码生成者
*/
private static final String AUTHOR = "Heardfate";
/**
* JDBC相关配置
*/
private static final String DRIVER = "com.mysql.cj.jdbc.Driver";
private static final String URL = "jdbc:mysql://127.0.0.1:3306/demo?useUnicode=true&useSSL=false" + "&characterEncoding=UTF-8";
private static final String USER_NAME = "testuser";
private static final String PASSWORD = "";
/**
* MySQL 生成演示
*/
public static void main(String[] args) {
// 自定义需要填充的字段
List tableFillList = new ArrayList();
//如 每张表都有一个创建时间、修改时间
//而且这基本上就是通用的了,新增时,创建时间和修改时间同时修改
//修改时,修改时间会修改,
//虽然像Mysql数据库有自动更新几只,但像ORACLE的数据库就没有了,
//使用公共字段填充功能,就可以实现,自动按场景更新了。
//如下是配置
//TableFill createField = new TableFill("gmt_create", FieldFill.INSERT);
//TableFill modifiedField = new TableFill("gmt_modified", FieldFill.UPDATE);
//tableFillList.add(createField);
//tableFillList.add(modifiedField);
// 代码生成器
AutoGenerator mpg = new AutoGenerator();
mpg.setGlobalConfig(// 全局配置
new GlobalConfig().setOutputDir(OUT_PATH)// 输出目录
.setFileOverride(true)// 是否覆盖文件
.setActiveRecord(true)// 开启 activeRecord 模式
.setEnableCache(false)// XML 二级缓存
.setBaseResultMap(false)// XML ResultMap
.setBaseColumnList(true)// XML columList
.setAuthor(AUTHOR)// 自定义文件命名,注意 %s 会自动填充表实体属性!
.setXmlName("%sMapper")
.setMapperName("%sDao")
.setSwagger2(true)
// .setServiceName("MP%sService")
// .setServiceImplName("%sServiceDiy")
// .setControllerName("%sAction") );
mpg.setDataSource(// 数据源配置
new DataSourceConfig().setDbType(DbType.MYSQL)// 数据库类型
.setDriverName(DRIVER).setUsername(USER_NAME).setPassword(PASSWORD).setUrl(URL));
mpg.setStrategy(// 策略配置
new StrategyConfig()
// .setCapitalMode(true)// 全局大写命名
//.setTablePrefix(new String[]{"table_", "test_"})// 此处可以修改为您的表前缀
.setNaming(NamingStrategy.underline_to_camel)// 表名生成策略
.setColumnNaming(NamingStrategy.underline_to_camel)
//.setLogicDeleteFieldName("is_delete") //逻辑删除字段
// .setInclude(new String[] {"user"}) // 需要生成的表
// .setExclude(new String[]{"test"}) // 排除生成的表
// 自定义实体,公共字段
//.setSuperEntityColumns(new String[]{"gmt_create", "gmt_modified", "create_user", "executor", "is_delete", "pass_key"})
//.setTableFillList(tableFillList)//和68行对应,设置公共填充字段
// 自定义实体父类
//.setSuperEntityClass("com.baomidou.demo.base.BsBaseEntity")
// 自定义 mapper 父类
// .setSuperMapperClass("com.baomidou.demo.base.BsBaseMapper")
// 自定义 service 父类
// .setSuperServiceClass("com.baomidou.demo.base.BsBaseService")
// 自定义 service 实现类父类
// .setSuperServiceImplClass("com.baomidou.demo.base.BsBaseServiceImpl")
// 自定义 controller 父类
// .setSuperControllerClass("com.baomidou.demo.TestController")
// 【实体】是否生成字段常量(默认 false)
// public static final String ID = "test_id";
.setEntityColumnConstant(true)
// 【实体】是否为构建者模型(默认 false)
// public User setName(String name) {this.name = name; return this;}
.setEntityBuilderModel(true)
// 【实体】是否为lombok模型(默认 false)document
.setEntityLombokModel(true)
// Boolean类型字段是否移除is前缀处理
.setEntityBooleanColumnRemoveIsPrefix(true)
//生成 @RestController 控制器
.setRestControllerStyle(true)
//驼峰转连字符
//.setControllerMappingHyphenStyle(true)
);
mpg.setPackageInfo(// 包配置
new PackageConfig().setModuleName(MODULE_NAME).setParent(PACKAGE_NAME)// 自定义包路径
.setController("controller")// 这里是控制器包名,默认 web
.setXml("mapper").setMapper("dao")
);
mpg.setCfg(
// 注入自定义配置,可以在 VM 中使用 cfg.abc 设置的值
new InjectionConfig() {
@Override
public void initMap() {}}
.setFileOutConfigList(
Collections.singletonList(new FileOutConfig("/templates/mapper.xml" + ".ftl") {
// 自定义输出文件目录
@Override
public String outputFile(TableInfo tableInfo) { return OUT_PATH_MAPPING + "/" + MODULE_NAME + "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML; }
})));
mpg.setTemplate(
// 关闭默认 xml 生成,调整生成 至 根目录
new TemplateConfig().setXml(null)
// 自定义模板配置,模板可以参考源码 /mybatis-plus/src/main/resources/template 使用 copy
// 至您项目 src/main/resources/template 目录下,模板名称也可自定义如下配置:
// .setController("...");
// .setEntity("...");
// .setMapper("...");
// .setXml("...");
// .setService("...");
// .setServiceImpl("..."); );
mpg.setTemplateEngine(new FreemarkerTemplateEngine());
// 执行生成
mpg.execute();
}
}
运行 Main 方法后,自动生成对应代码
MybatisPlus 配置
现在,我们添加 MybatisPlus 配置类
src/main/java/com/heardfate/springboot/demo/demo04/config/MybatisPlusConfig
package com.heardfate.springboot.demo.demo04.config;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Configuration;
/**
* @since: 2018/10/23
* @author: Mr.HeardFate
*/
@Configuration
@MapperScan("com.heardfate.springboot.demo.demo04.dao")
public class MybatisPlusConfig {
}
开始使用
添加测试类,进行功能测试:
package com.heardfate.springboot.demo;
import com.heardfate.springboot.demo.demo04.dao.UserDao;
import com.heardfate.springboot.demo.demo04.entity.User;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.List;
/**
* @since: 2018/10/23
* @author: Mr.HeardFate
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class SampleTest {
@Autowired
private UserDao userDao;
@Test
public void testSelect() {
System.out.println(("----- selectAll method test ------"));
List userList = userDao.selectList(null);
Assert.assertEquals(5, userList.size());
userList.forEach(System.out::println);
}
}
测试通过获取到数据库数据
2018-10-23 20:25:05.172 INFO 2483 --- [ main] c.heardfate.springboot.demo.SampleTest : Started SampleTest in 9.063 seconds (JVM running for 10.273)
----- selectAll method test ------
User(id=1, name=Jone, age=18, email=test1@baomidou.com)
User(id=2, name=Jack, age=20, email=test2@baomidou.com)
User(id=3, name=Tom, age=28, email=test3@baomidou.com)
User(id=4, name=Sandy, age=21, email=test4@baomidou.com)
User(id=5, name=Billie, age=24, email=test5@baomidou.com)
2018-10-23 20:25:05.838 INFO 2483 --- [ Thread-1] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor'
2018-10-23 20:25:05.839 INFO 2483 --- [ Thread-1] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated...
2018-10-23 20:25:05.852 INFO 2483 --- [ Thread-1] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed.
BIGINT UNSIGNED 映射为 BigIntger(2018-11-03 更新)
以上配置,如果数据库有字段类型为 BIGINT UNSIGNED,自动映射为 LONG 类型,,通过设置,映射为 BigIntger
BIGINT ,BIGINT UNSIGNED。
如果不是无符号类型,BIGINT(20)的取值范围为-9223372036854775808~9223372036854775807。
与 Java.lang.Long 的取值范围完全一致,可映射为 Long;
而 BIGINT(20) UNSIGNED 的取值范围是 0 ~ 18446744073709551615,其中一半的数据超出了 Long 的取值范围,需将其映射为 BigInteger。
更新后完整的代码生成器代码为:
package com.heardfate.springboot.demo;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
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.TableFill;
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.Collections;
import java.util.List;
/**
* @program: springboot-demo04
* @since: 2018/10/23
* @author: Mr.HeardFate
*/
public class CodeGenerator {
/**
* 包名
*/
private static final String PACKAGE_NAME = "com.heardfate.springboot.demo";
/**
* 模块名称
*/
private static final String MODULE_NAME = "demo04";
private static final String NAME = "";
/**
* 输出文件的路径
*/
private static final String OUT_PATH = System.getProperty("user.dir") + NAME + "/src/main/java";
/**
* 输出文件的路径
*/ private static final String OUT_PATH_MAPPING = System.getProperty("user.dir") + NAME + "/src/main/resources/mapper";
/**
* 代码生成者
*/
private static final String AUTHOR = "Heardfate";
/**
* JDBC相关配置
*/
private static final String DRIVER = "com.mysql.cj.jdbc.Driver";
private static final String URL = "jdbc:mysql://127.0.0.1:3306/demo?useUnicode=true&useSSL=false" + "&characterEncoding=UTF-8";
private static final String USER_NAME = "testuser";
private static final String PASSWORD = "";
/**
* MySQL 生成演示
*/
public static void main(String[] args) {
// 自定义需要填充的字段
List tableFillList = new ArrayList();
//如 每张表都有一个创建时间、修改时间
//而且这基本上就是通用的了,新增时,创建时间和修改时间同时修改
//修改时,修改时间会修改,
//虽然像Mysql数据库有自动更新几只,但像ORACLE的数据库就没有了,
//使用公共字段填充功能,就可以实现,自动按场景更新了。
//如下是配置
//TableFill createField = new TableFill("gmt_create", FieldFill.INSERT);
//TableFill modifiedField = new TableFill("gmt_modified", FieldFill.UPDATE);
//tableFillList.add(createField);
//tableFillList.add(modifiedField);
// 代码生成器
AutoGenerator mpg = new AutoGenerator();
mpg.setGlobalConfig(// 全局配置
new GlobalConfig().setOutputDir(OUT_PATH)// 输出目录
.setFileOverride(true)// 是否覆盖文件
.setActiveRecord(true)// 开启 activeRecord 模式
.setEnableCache(false)// XML 二级缓存
.setBaseResultMap(false)// XML ResultMap
.setBaseColumnList(true)// XML columList
.setAuthor(AUTHOR)// 自定义文件命名,注意 %s 会自动填充表实体属性!
.setXmlName("%sMapper")
.setMapperName("%sDao")
.setSwagger2(true)
// .setServiceName("MP%sService")
// .setServiceImplName("%sServiceDiy")
// .setControllerName("%sAction")
);
mpg.setDataSource(// 数据源配置
new DataSourceConfig().setDbType(DbType.MYSQL)// 数据库类型
.setDriverName(DRIVER).setUsername(USER_NAME).setPassword(PASSWORD).setUrl(URL)
.setTypeConvert(new MySqlTypeConvert() {
// 自定义数据库表字段类型转换【可选】
@Override
public IColumnType processTypeConvert(GlobalConfig globalConfig, String fieldType) {
System.out.println("待转换类型:" + fieldType);
// 注意!!!processTypeConvert存在默认类型转换,如果不是你要的效果请自定义返回。
String t = fieldType.toLowerCase();
if (t.contains("unsigned")) {
if (t.contains("bigint")) {
return DbColumnType.BIG_INTEGER;
}else{
System.err.println("I am not know!");
return super.processTypeConvert(globalConfig, fieldType);
}
}else{
return super.processTypeConvert(globalConfig, fieldType);
}
}
})
);
mpg.setStrategy(// 策略配置
new StrategyConfig()
// .setCapitalMode(true)// 全局大写命名
//.setTablePrefix(new String[]{"table_", "test_"})// 此处可以修改为您的表前缀
.setNaming(NamingStrategy.underline_to_camel)// 表名生成策略
.setColumnNaming(NamingStrategy.underline_to_camel)
//.setLogicDeleteFieldName("is_delete") //逻辑删除字段
// .setInclude(new String[] {"user"}) // 需要生成的表
// .setExclude(new String[]{"test"}) // 排除生成的表
// 自定义实体,公共字段
//.setSuperEntityColumns(new String[]{"gmt_create", "gmt_modified", "create_user", "executor", "is_delete", "pass_key"})
//.setTableFillList(tableFillList)//和68行对应,设置公共填充字段
// 自定义实体父类
//.setSuperEntityClass("com.baomidou.demo.base.BsBaseEntity")
// 自定义 mapper 父类
// .setSuperMapperClass("com.baomidou.demo.base.BsBaseMapper")
// 自定义 service 父类
// .setSuperServiceClass("com.baomidou.demo.base.BsBaseService")
// 自定义 service 实现类父类
// .setSuperServiceImplClass("com.baomidou.demo.base.BsBaseServiceImpl")
// 自定义 controller 父类
// .setSuperControllerClass("com.baomidou.demo.TestController")
// 【实体】是否生成字段常量(默认 false)
// public static final String ID = "test_id";
.setEntityColumnConstant(true)
// 【实体】是否为构建者模型(默认 false)
// public User setName(String name) {this.name = name; return this;}
.setEntityBuilderModel(true)
// 【实体】是否为lombok模型(默认 false)document
.setEntityLombokModel(true)
// Boolean类型字段是否移除is前缀处理
.setEntityBooleanColumnRemoveIsPrefix(true)
//生成 @RestController 控制器
.setRestControllerStyle(true)
//驼峰转连字符
//.setControllerMappingHyphenStyle(true)
);
mpg.setPackageInfo(// 包配置
new PackageConfig().setModuleName(MODULE_NAME).setParent(PACKAGE_NAME)// 自定义包路径
.setController("controller")// 这里是控制器包名,默认 web
.setXml("mapper").setMapper("dao")
);
mpg.setCfg(
// 注入自定义配置,可以在 VM 中使用 cfg.abc 设置的值
new InjectionConfig() {
@Override
public void initMap() {}}
.setFileOutConfigList(
Collections.singletonList(new FileOutConfig("/templates/mapper.xml" + ".ftl") {
// 自定义输出文件目录
@Override
public String outputFile(TableInfo tableInfo) { return OUT_PATH_MAPPING + "/" + MODULE_NAME + "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML; }
})));
mpg.setTemplate(
// 关闭默认 xml 生成,调整生成 至 根目录
new TemplateConfig().setXml(null)
// 自定义模板配置,模板可以参考源码 /mybatis-plus/src/main/resources/template 使用 copy
// 至您项目 src/main/resources/template 目录下,模板名称也可自定义如下配置:
// .setController("...");
// .setEntity("...");
// .setMapper("...");
// .setXml("...");
// .setService("...");
// .setServiceImpl("...");
);
mpg.setTemplateEngine(new FreemarkerTemplateEngine());
// 执行生成
mpg.execute();
}
}
BIGINT UNSIGNED 插入报错问题(2018-11-09 更新)
如果数据库字段类型为 BIGINT UNSIGNED,映射为 BigIntger。获取数据会正常,添加数据会报错
Could not set property 'id' of 'class XXX.entity.User' with value '1060015479998566402' Cause: java.lang.IllegalArgumentException: argument type mismatch
因为没有指定 ID 生成策略,mybatis-plus 默认为 ID_WORKER,是 Long 类型!
所以指定为 BigIntger,可以通过手动设置 ID,如bean.setId(new BigInteger(IdWorker.getIdStr()));
Issues:UNSIGNED BIGINT(20)映射问题
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于