1、特性

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响;

  • 损耗小:启动即会自动注入基本CRUD,性能基本无损耗,直接面向对象操作;

  • 强大的CRUD操作:内置通用Mapper、通用Service,仅仅通过少量配置即可实现表单大部分CRUD操作,更有强大的条件构造器,满足各类使用需求;

  • 支持Lambda形式调用:通过Lambda表达式,方便的编写各类查询条件,无需再担心字段写错;

  • 支持主键自动生成:支持多达4种主键策略(内含分布式唯一ID生成器-Sequence),可自由配置,完美解决主键问题;

  • 支持ActiveRecord模式:支持ActiveRecord形式调用,实体类只需继承Model类即可进行强大的CRUD操作;

  • 支持自定义全局通用操作:支持全局通用方法注入(Write once,use anywhere);

  • 内置代码生成器:采用代码或者Maven插件可快速生成Mapper、Model、Service、Controller层代码,支持模板引擎,更有超多自定义配置;

  • 内置分页插件:基于MyBatis物理分页,写分页等同于普通List查询;

  • 分页插件支持多种数据库:支持MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postre、SQLServer等多种数据库;

  • 内置性能分析插件:可输出SQL语句以及其执行时间;

  • 内置全局性能拦截插件:提供全表delete、update操作智能分析阻断,也可自定义拦截规则,预防误操作;

2、支持数据库

任何能使用MyBatis进行CRUD,并且支持标准SQL的数据库。

  • MySQL,Oracle,DB2,H2,HSQL,SQLite,PostgreSQL,SQLServer,Phoenix,Gauss ,ClickHouse,Sybase,OceanBase,Firebird,Cubrid,Goldilocks,csiidb;

  • 达梦数据库、虚谷数据库、人大金仓数据库、南大通用(华库)数据库、南大通用数据库、神通数据库、瀚高数据库。

3、安装

Spring Boot:(Maven)

<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.1</version>
</dependency>

Spring:(Maven)

<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus</artifactId><version>3.5.1</version>
</dependency>

Snapshot:

<repository><id>snapshots</id><url>https://oss.sonatype.org/content/repositories/snapshots/</url>
</repository>

4、配置

Spring Boot工程:配置MapperScan注解。

Spring工程:

(1)配置MapperScan

<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"><property name="basePackage" value="com.baomidou.mybatisplus.samples.quickstart.mapper"/>
</bean>

(2)调整SqlSessionFactory为MyBatis-Plus的SqlSessionFactory

<bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean"><property name="dataSource" ref="dataSource"/>
</bean>

5、注解

(1)@TableName

  • 描述:表名注解,标识实体类对应的表;

  • 使用位置:实体类。

属性 类型 必须指定 默认值 描述
value String "" 表名
schema String "" schema
keepGlobalPrefix boolean false 是否保持使用全局的 tablePrefix 的值(当全局 tablePrefix 生效时)
resultMap String "" xml 中 resultMap 的 id(用于满足特定类型的实体类对象绑定)
autoResultMap boolean false 是否自动构建 resultMap 并使用(如果设置 resultMap 则不会进行 resultMap 的自动构建与注入)
excludeProperty String[] {} 需要排除的属性名 @since 3.3.1

autoResultMap:MP会自动构建一个resultMap并注入到MyBatis里(一般用不上),注意:因为MP底层是MyBatis,所以MP只是注入了常用的CRUD到Mybatis里,注入之前是动态的(根据Entity字段以及注解变化而变化),但是注入之后是静态的(等于XML配置中的内容)。

typeHandler属性支持写的地方:

①、定义在resultMap里,作用于查询结果的封装;

②、定义在insert和update语句的#{property}中的property后面(例:#{property,typehandler=xxx.xxx.xxx}),并且只作用于当前设置值。

MyBatis有一个全局扫描自定义typeHandler包的配置,原理是根据property类型去找其对应的typeHandler并使用。

(2)@TableId

  • 描述:主键注解;

  • 使用位置:实体类主键字段。

属性 类型 必须指定 默认值 描述
value String "" 主键字段名
type Enum IdType.NONE 指定主键类型

IdType

描述
AUTO 数据库 ID 自增
NONE 无状态,该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT)
INPUT insert 前自行 set 主键值
ASSIGN_ID 分配 ID(主键类型为 Number(Long 和 Integer)或 String)(since 3.3.0),使用接口IdentifierGenerator的方法nextId(默认实现类为DefaultIdentifierGenerator雪花算法)
ASSIGN_UUID 分配 UUID,主键类型为 String(since 3.3.0),使用接口IdentifierGenerator的方法nextUUID(默认 default 方法)

(3)TableField

  • 描述:字段注解(非主键)

属性 类型 必须指定 默认值 描述
value String "" 数据库字段名
exist boolean true 是否为数据库表字段
condition String "" 字段 where 实体查询比较条件,有值设置则按设置的值为准,没有则为默认全局的 %s=#{%s},参考(opens new window)
update String "" 字段 update set 部分注入,例如:当在version字段上注解update="%s+1" 表示更新时会 set version=version+1 (该属性优先级高于 el 属性)
insertStrategy Enum FieldStrategy.DEFAULT 举例:NOT_NULL insert into table_a(<if test="columnProperty != null">column</if>) values (<if test="columnProperty != null">#{columnProperty}</if>)
updateStrategy Enum FieldStrategy.DEFAULT 举例:IGNORED update table_a set column=#{columnProperty}
whereStrategy Enum FieldStrategy.DEFAULT 举例:NOT_EMPTY where <if test="columnProperty != null and columnProperty!=''">column=#{columnProperty}</if>
fill Enum FieldFill.DEFAULT 字段自动填充策略
select boolean true 是否进行 select 查询
keepGlobalFormat boolean false 是否保持使用全局的 format 进行处理
jdbcType JdbcType JdbcType.UNDEFINED JDBC 类型 (该默认值不代表会按照该值生效)
typeHandler Class<? extends TypeHandler> UnknownTypeHandler.class 类型处理器 (该默认值不代表会按照该值生效)
numericScale String "" 指定小数点后保留的位数

FieldStrategy

描述
IGNORED 忽略判断
NOT_NULL 非 NULL 判断
NOT_EMPTY 非空判断(只对字符串类型字段,其他类型字段依然为非 NULL 判断)
DEFAULT 追随全局配置

FieldFill

描述
DEFAULT 默认不处理
INSERT 插入时填充字段
UPDATE 更新时填充字段
INSERT_UPDATE 插入和更新时填充字段

(4)Version

  • 描述:乐观锁注解、标记@Version在字段上;

(5)@EnumValue

  • 描述:普通枚举类注解(注解在枚举字段上);

(6)TableLogic

  • 描述:表字段逻辑处理注解(逻辑删除)

属性 类型 必须指定 默认值 描述
value String "" 逻辑未删除值
delval String "" 逻辑删除值

(7)@SqlParser:see @InterceptorIgnore

(8)@KeySequence

  • 描述:序列主键策略oracle;

  • 属性:value、resultMap。

属性 类型 必须指定 默认值 描述
value String "" 序列名
clazz Class Long.class id 的类型, 可以指定 String.class,这样返回的 Sequence 值是字符串"1"

(9)InterceptorIgnore:see插件主体

(10)OrderBy

  • 描述:内置SQL默认指定排序,优先级低于wrapper条件查询。

属性 类型 必须指定 默认值 描述
isDesc boolean true 是否倒序查询
sort short Short.MAX_VALUE 数字越小越靠前

6、测试依赖

<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter-test</artifactId><version>3.5.1</version>
</dependency>

核心功能

1、代码生成器(旧)

AutoGenerator是MyBatis-Plus的代码生成器,通过AutoGenerator可以快速生成Entity、Mapper、MapperXML、Service、Controller等各个模块的代码。

添加依赖

<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-generator</artifactId><version>3.5.0</version>
</dependency>

添加模板引擎依赖

Velocity(默认):

<dependency><groupId>org.apache.velocity</groupId><artifactId>velocity-engine-core</artifactId><version>2.3</version>
</dependency>

Freemarker:

<dependency><groupId>org.freemarker</groupId><artifactId>freemarker</artifactId><version>2.3.31</version>
</dependency>

Beetl:

<dependency><groupId>com.ibeetl</groupId><artifactId>beetl</artifactId><version>3.10.0.RELEASE</version>
</dependency>

也可以自定义,需要在AutoGenerator中设置模板引擎:

AutoGenerator generator = new AutoGenerator();
generator.setTemplateEngine(new CustomTemplateEngine());

编写配置

  • 配置GlobalConfig

GlobalConfig globalConfig = new GlobalConfig();
globalConfig.setOutputDir(System.getProperty("user.dir") + "/src/main/java");
globalConfig.setAuthor("jobob");
globalConfig.setOpen(false);
  • 配置DataSourceConfig

    DataSourceConfig dataSourceConfig = new DataSourceConfig();
    dataSourceConfig.setUrl("jdbc:mysql://localhost:3306/ant?useUnicode=true&useSSL=false&characterEncoding=utf8");
    dataSourceConfig.setDriverName("com.mysql.jdbc.Driver");
    dataSourceConfig.setUsername("root");
    dataSourceConfig.setPassword("password");

自定义模板引擎:需继承com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine。

自定义代码模板

//指定自定义模板路径, 位置:/resources/templates/entity2.java.ftl(或者是.vm)
//注意不要带上.ftl(或者是.vm), 会根据使用的模板引擎自动识别
TemplateConfig templateConfig = new TemplateConfig().setEntity("templates/entity2.java");
AutoGenerator mpg = new AutoGenerator();
//配置自定义模板
mpg.setTemplate(templateConfig);

自定义属性注入

InjectionConfig injectionConfig = new InjectionConfig() {//自定义属性注入:abc//在.ftl(或者是.vm)模板中,通过${cfg.abc}获取属性@Overridepublic void initMap() {Map<String, Object> map = new HashMap<>();map.put("abc", this.getConfig().getGlobalConfig().getAuthor() + "-mp");this.setMap(map);}
};
AutoGenerator mpg = new AutoGenerator();
//配置自定义属性注入
mpg.setCfg(injectionConfig);
entity2.java.ftl
自定义属性注入abc=${cfg.abc}
entity2.java.vm
自定义属性注入abc=$!{cfg.abc}

字段其他信息查询注入

new DataSourceConfig().setDbQuery(new MySqlQuery() {/*** 重写父类预留查询自定义字段<br>* 这里查询的 SQL 对应父类 tableFieldsSql 的查询字段,默认不能满足你的需求请重写它<br>* 模板中调用:  table.fields 获取所有字段信息,* 然后循环字段获取 field.customMap 从 MAP 中获取注入字段如下  NULL 或者 PRIVILEGES*/@Overridepublic String[] fieldCustom() {return new String[]{"NULL", "PRIVILEGES"};}
})

2、代码生成器(新)

安装

<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-generator</artifactId><version>3.5.1</version>
</dependency>

快速生成

FastAutoGenerator.create("url", "username", "password").globalConfig(builder -> {builder.author("baomidou") // 设置作者.enableSwagger() // 开启 swagger 模式.fileOverride() // 覆盖已生成文件.outputDir("D://"); // 指定输出目录}).packageConfig(builder -> {builder.parent("com.baomidou.mybatisplus.samples.generator") // 设置父包名.moduleName("system") // 设置父包模块名.pathInfo(Collections.singletonMap(OutputFile.mapperXml, "D://")); // 设置mapperXml生成路径}).strategyConfig(builder -> {builder.addInclude("t_simple") // 设置需要生成的表名.addTablePrefix("t_", "c_"); // 设置过滤表前缀}).templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板.execute();

交互式生成

FastAutoGenerator.create(DATA_SOURCE_CONFIG)// 全局配置.globalConfig((scanner, builder) -> builder.author(scanner.apply("请输入作者名称?")).fileOverride())// 包配置.packageConfig((scanner, builder) -> builder.parent(scanner.apply("请输入包名?")))// 策略配置.strategyConfig((scanner, builder) -> builder.addInclude(getTables(scanner.apply("请输入表名,多个英文逗号分隔?所有输入 all"))).controllerBuilder().enableRestStyle().enableHyphenStyle().entityBuilder().enableLombok().addTableFills(new Column("create_time", FieldFill.INSERT)).build())/*模板引擎配置,默认 Velocity 可选模板引擎 Beetl 或 Freemarker.templateEngine(new BeetlTemplateEngine()).templateEngine(new FreemarkerTemplateEngine())*/.execute();
​
​
// 处理 all 情况
protected static List<String> getTables(String tables) {return "all".equals(tables) ? Collections.emptyList() : Arrays.asList(tables.split(","));
}

配置:代码生成器配置

(1)数据库配置(DataSourceConfig)

基础配置

属性 说明 示例
url jdbc 路径 jdbc:mysql://127.0.0.1:3306/mybatis-plus
username 数据库账号 root
password 数据库密码 123456
new DataSourceConfig.Builder("jdbc:mysql://127.0.0.1:3306/mybatis-plus","root","123456").build();

可选配置

方法 说明 示例
dbQuery(IDbQuery) 数据库查询 new MySqlQuery()
schema(String) 数据库 schema(部分数据库适用) mybatis-plus
typeConvert(ITypeConvert) 数据库类型转换器 new MySqlTypeConvert()
keyWordsHandler(IKeyWordsHandler) 数据库关键字处理器 new MySqlKeyWordsHandler()
new DataSourceConfig.Builder("jdbc:mysql://127.0.0.1:3306/mybatis-plus","root","123456").dbQuery(new MySqlQuery()).schema("mybatis-plus").typeConvert(new MySqlTypeConvert()).keyWordsHandler(new MySqlKeyWordsHandler()).build();

(2)全局配置(GlobalConfig)

方法 说明 示例
fileOverride 覆盖已生成文件 默认值:false
disableOpenDir 禁止打开输出目录 默认值:true
outputDir(String) 指定输出目录 /opt/baomidou/ 默认值: windows:D:// linux or mac : /tmp
author(String) 作者名 baomidou 默认值:作者
enableKotlin 开启 kotlin 模式 默认值:false
enableSwagger 开启 swagger 模式 默认值:false
dateType(DateType) 时间策略 DateType.ONLY_DATE 默认值: DateType.TIME_PACK
commentDate(String) 注释日期 默认值: yyyy-MM-dd
new GlobalConfig.Builder().fileOverride().outputDir("/opt/baomidou").author("baomidou").enableKotlin().enableSwagger().dateType(DateType.TIME_PACK).commentDate("yyyy-MM-dd").build();

(3)包配置(PackageConfig)

方法 说明 示例
parent(String) 父包名 默认值:com.baomidou
moduleName(String) 父包模块名 默认值:无
entity(String) Entity 包名 默认值:entity
service(String) Service 包名 默认值:service
serviceImpl(String) Service Impl 包名 默认值:service.impl
mapper(String) Mapper 包名 默认值:mapper
mapperXml(String) Mapper XML 包名 默认值:mapper.xml
controller(String) Controller 包名 默认值:controller
other(String) 自定义文件包名 输出自定义文件时所用到的包名
pathInfo(Map<OutputFile, String>) 路径配置信息 Collections.singletonMap(OutputFile.mapperXml, "D://")
new PackageConfig.Builder().parent("com.baomidou.mybatisplus.samples.generator").moduleName("sys").entity("po").service("service").serviceImpl("service.impl").mapper("mapper").mapperXml("mapper.xml").controller("controller").other("other") .pathInfo(Collections.singletonMap(OutputFile.mapperXml, "D://")).build();

(4)模板配置(TemplateConfig)

方法 说明 示例
disable 禁用所有模板
disable(TemplateType...) 禁用模板 TemplateType.ENTITY
entity(String) 设置实体模板路径(JAVA) /templates/entity.java
entityKt(String) 设置实体模板路径(kotlin) /templates/entity.java
service(String) 设置 service 模板路径 /templates/service.java
serviceImpl(String) 设置 serviceImpl 模板路径 /templates/serviceImpl.java
mapper(String) 设置 mapper 模板路径 /templates/mapper.java
mapperXml(String) 设置 mapperXml 模板路径 /templates/mapper.xml
controller(String) 设置 controller 模板路径 /templates/controller.java
new TemplateConfig.Builder().disable(TemplateType.ENTITY).entity("/templates/entity.java").service("/templates/service.java").serviceImpl("/templates/serviceImpl.java").mapper("/templates/mapper.java").mapperXml("/templates/mapper.xml").controller("/templates/controller.java").build();

(5)注入配置(InjectionConfig)

方法 说明 示例
beforeOutputFile(BiConsumer<TableInfo, Map<String, Object>>) 输出文件之前消费者
customMap(Map<String, Object>) 自定义配置 Map 对象 Collections.singletonMap("test", "baomidou")
customFile(Map<String, String>) 自定义配置模板文件 Collections.singletonMap("test.txt", "/templates/test.vm")
new InjectionConfig.Builder().beforeOutputFile((tableInfo, objectMap) -> {System.out.println("tableInfo: " + tableInfo.getEntityName() + " objectMap: " + objectMap.size());}).customMap(Collections.singletonMap("test", "baomidou")).customFile(Collections.singletonMap("test.txt", "/templates/test.vm")).build();

(6)策略配置(StrategyConfig)

方法 说明 示例
enableCapitalMode 开启大写命名 默认值:false
enableSkipView 开启跳过视图 默认值:false
disableSqlFilter 禁用 sql 过滤 默认值:true,语法不能支持使用 sql 过滤表的话,可以考虑关闭此开关
enableSchema 启用 schema 默认值:false,多 schema 场景的时候打开
likeTable(LikeTable) 模糊表匹配(sql 过滤) likeTable 与 notLikeTable 只能配置一项
notLikeTable(LikeTable) 模糊表排除(sql 过滤) likeTable 与 notLikeTable 只能配置一项
addInclude(String...) 增加表匹配(内存过滤) include 与 exclude 只能配置一项
addExclude(String...) 增加表排除匹配(内存过滤) include 与 exclude 只能配置一项
addTablePrefix(String...) 增加过滤表前缀
addTableSuffix(String...) 增加过滤表后缀
addFieldPrefix(String...) 增加过滤字段前缀
addFieldSuffix(String...) 增加过滤字段后缀
entityBuilder 实体策略配置
controllerBuilder controller 策略配置
mapperBuilder mapper 策略配置
serviceBuilder service 策略配置
new StrategyConfig.Builder().enableCapitalMode().enableSkipView().disableSqlFilter().likeTable(new LikeTable("USER")).addInclude("t_simple").addTablePrefix("t_", "c_").addFieldSuffix("_flag").build();

①、Entity策略配置

方法 说明 示例
nameConvert(INameConvert) 名称转换实现
superClass(Class<?>) 设置父类 BaseEntity.class
superClass(String) 设置父类 com.baomidou.global.BaseEntity
disableSerialVersionUID 禁用生成 serialVersionUID 默认值:true
enableColumnConstant 开启生成字段常量 默认值:false
enableChainModel 开启链式模型 默认值:false
enableLombok 开启 lombok 模型 默认值:false
enableRemoveIsPrefix 开启 Boolean 类型字段移除 is 前缀 默认值:false
enableTableFieldAnnotation 开启生成实体时生成字段注解 默认值:false
enableActiveRecord 开启 ActiveRecord 模型 默认值:false
versionColumnName(String) 乐观锁字段名(数据库)
versionPropertyName(String) 乐观锁属性名(实体)
logicDeleteColumnName(String) 逻辑删除字段名(数据库)
logicDeletePropertyName(String) 逻辑删除属性名(实体)
naming 数据库表映射到实体的命名策略 默认下划线转驼峰命名:NamingStrategy.underline_to_camel
columnNaming 数据库表字段映射到实体的命名策略 默认为 null,未指定按照 naming 执行
addSuperEntityColumns(String...) 添加父类公共字段
addIgnoreColumns(String...) 添加忽略字段
addTableFills(IFill...) 添加表字段填充
addTableFills(List<IFill>) 添加表字段填充
idType(IdType) 全局主键类型
convertFileName(ConverterFileName) 转换文件名称
formatFileName(String) 格式化文件名称
new StrategyConfig.Builder().entityBuilder().superClass(BaseEntity.class).disableSerialVersionUID().enableChainModel().enableLombok().enableRemoveIsPrefix().enableTableFieldAnnotation().enableActiveRecord().versionColumnName("version").versionPropertyName("version").logicDeleteColumnName("deleted").logicDeletePropertyName("deleteFlag").naming(NamingStrategy.no_change).columnNaming(NamingStrategy.underline_to_camel).addSuperEntityColumns("id", "created_by", "created_time", "updated_by", "updated_time").addIgnoreColumns("age").addTableFills(new Column("create_time", FieldFill.INSERT)).addTableFills(new Property("updateTime", FieldFill.INSERT_UPDATE)).idType(IdType.AUTO).formatFileName("%sEntity").build();

②、Controller策略配置

方法 说明 示例
superClass(Class<?>) 设置父类 BaseController.class
superClass(String) 设置父类 com.baomidou.global.BaseController
enableHyphenStyle 开启驼峰转连字符 默认值:false
enableRestStyle 开启生成@RestController 控制器 默认值:false
convertFileName(ConverterFileName) 转换文件名称
formatFileName(String) 格式化文件名称
new StrategyConfig.Builder().controllerBuilder().superClass(BaseController.class).enableHyphenStyle().enableRestStyle().formatFileName("%sAction").build();

③、Service策略配置

方法 说明 示例
superServiceClass(Class<?>) 设置 service 接口父类 BaseService.class
superServiceClass(String) 设置 service 接口父类 com.baomidou.global.BaseService
superServiceImplClass(Class<?>) 设置 service 实现类父类 BaseServiceImpl.class
superServiceImplClass(String) 设置 service 实现类父类 com.baomidou.global.BaseServiceImpl
convertServiceFileName(ConverterFileName) 转换 service 接口文件名称
convertServiceImplFileName(ConverterFileName) 转换 service 实现类文件名称
formatServiceFileName(String) 格式化 service 接口文件名称
formatServiceImplFileName(String) 格式化 service 实现类文件名称
new StrategyConfig.Builder().serviceBuilder().superServiceClass(BaseService.class).superServiceImplClass(BaseServiceImpl.class).formatServiceFileName("%sService").formatServiceImplFileName("%sServiceImp").build();

④、Mapper 策略配置

方法 说明 示例
superClass(Class<?>) 设置父类 BaseMapper.class
superClass(String) 设置父类 com.baomidou.global.BaseMapper
enableMapperAnnotation 开启 @Mapper 注解 默认值:false
enableBaseResultMap 启用 BaseResultMap 生成 默认值:false
enableBaseColumnList 启用 BaseColumnList 默认值:false
cache(Class<? extends Cache>) 设置缓存实现类 MyMapperCache.class
convertMapperFileName(ConverterFileName) 转换 mapper 类文件名称
convertXmlFileName(ConverterFileName) 转换 xml 文件名称
formatMapperFileName(String) 格式化 mapper 文件名称
formatXmlFileName(String) 格式化 xml 实现类文件名称
new StrategyConfig.Builder().mapperBuilder().superClass(BaseMapper.class).enableMapperAnnotation().enableBaseResultMap().enableBaseColumnList().cache(MyMapperCache.class).formatMapperFileName("%sDao").formatXmlFileName("%sXml").build();

3、CRUD接口

(1)Service CRUD接口

  • 通用Service CRUD封装IService接口,进一步封装CRUD采用get查询单行remove删除list查询集合page分页前缀命名方式区分Mapper层避免混淆;

  • 泛型T为任意实体对象;

  • 如果存在自定义通用Service方法的可能,创建自己的IBaseService继承Mybatis-Plus提供的基类;

  • 对象Wrapper为条件构造器。

①、Save

// 插入一条记录(选择字段,策略插入)
boolean save(T entity);
// 插入(批量)
boolean saveBatch(Collection<T> entityList);
// 插入(批量)
boolean saveBatch(Collection<T> entityList, int batchSize);
类型 参数名 描述
T entity 实体对象
Collection<T> entityList 实体对象集合
int batchSize 插入批次数量

②、SaveOrUpdate

// TableId 注解存在更新记录,否插入一条记录
boolean saveOrUpdate(T entity);
// 根据updateWrapper尝试更新,否继续执行saveOrUpdate(T)方法
boolean saveOrUpdate(T entity, Wrapper<T> updateWrapper);
// 批量修改插入
boolean saveOrUpdateBatch(Collection<T> entityList);
// 批量修改插入
boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize);
类型 参数名 描述
T entity 实体对象
Wrapper<T> updateWrapper 实体对象封装操作类 UpdateWrapper
Collection<T> entityList 实体对象集合
int batchSize 插入批次数量

③、Remove

// 根据 entity 条件,删除记录
boolean remove(Wrapper<T> queryWrapper);
// 根据 ID 删除
boolean removeById(Serializable id);
// 根据 columnMap 条件,删除记录
boolean removeByMap(Map<String, Object> columnMap);
// 删除(根据ID 批量删除)
boolean removeByIds(Collection<? extends Serializable> idList);
类型 参数名 描述
Wrapper<T> queryWrapper 实体包装类 QueryWrapper
Serializable id 主键 ID
Map<String, Object> columnMap 表字段 map 对象
Collection<? extends Serializable> idList 主键 ID 列表

④、Update

// 根据 UpdateWrapper 条件,更新记录 需要设置sqlset
boolean update(Wrapper<T> updateWrapper);
// 根据 whereWrapper 条件,更新记录
boolean update(T updateEntity, Wrapper<T> whereWrapper);
// 根据 ID 选择修改
boolean updateById(T entity);
// 根据ID 批量更新
boolean updateBatchById(Collection<T> entityList);
// 根据ID 批量更新
boolean updateBatchById(Collection<T> entityList, int batchSize);
类型 参数名 描述
Wrapper<T> updateWrapper 实体对象封装操作类 UpdateWrapper
T entity 实体对象
Collection<T> entityList 实体对象集合
int batchSize 更新批次数量

⑤、Get

// 根据 ID 查询
T getById(Serializable id);
// 根据 Wrapper,查询一条记录。结果集,如果是多个会抛出异常,随机取一条加上限制条件 wrapper.last("LIMIT 1")
T getOne(Wrapper<T> queryWrapper);
// 根据 Wrapper,查询一条记录
T getOne(Wrapper<T> queryWrapper, boolean throwEx);
// 根据 Wrapper,查询一条记录
Map<String, Object> getMap(Wrapper<T> queryWrapper);
// 根据 Wrapper,查询一条记录
<V> V getObj(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);
类型 参数名 描述
Serializable id 主键 ID
Wrapper<T> queryWrapper 实体对象封装操作类 QueryWrapper
boolean throwEx 有多个 result 是否抛出异常
T entity 实体对象
Function<? super Object, V> mapper 转换函数

⑥、List

// 查询所有
List<T> list();
// 查询列表
List<T> list(Wrapper<T> queryWrapper);
// 查询(根据ID 批量查询)
Collection<T> listByIds(Collection<? extends Serializable> idList);
// 查询(根据 columnMap 条件)
Collection<T> listByMap(Map<String, Object> columnMap);
// 查询所有列表
List<Map<String, Object>> listMaps();
// 查询列表
List<Map<String, Object>> listMaps(Wrapper<T> queryWrapper);
// 查询全部记录
List<Object> listObjs();
// 查询全部记录
<V> List<V> listObjs(Function<? super Object, V> mapper);
// 根据 Wrapper 条件,查询全部记录
List<Object> listObjs(Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询全部记录
<V> List<V> listObjs(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);
类型 参数名 描述
Wrapper<T> queryWrapper 实体对象封装操作类 QueryWrapper
Collection<? extends Serializable> idList 主键 ID 列表
Map<String, Object> columnMap 表字段 map 对象
Function<? super Object, V> mapper 转换函数

⑦、Page

// 无条件分页查询
IPage<T> page(IPage<T> page);
// 条件分页查询
IPage<T> page(IPage<T> page, Wrapper<T> queryWrapper);
// 无条件分页查询
IPage<Map<String, Object>> pageMaps(IPage<T> page);
// 条件分页查询
IPage<Map<String, Object>> pageMaps(IPage<T> page, Wrapper<T> queryWrapper);
类型 参数名 描述
IPage<T> page 翻页对象
Wrapper<T> queryWrapper 实体对象封装操作类 QueryWrapper

⑧、Count

// 查询总记录数
int count();
// 根据 Wrapper 条件,查询总记录数
int count(Wrapper<T> queryWrapper);
类型 参数名 描述
Wrapper<T> queryWrapper 实体对象封装操作类 QueryWrapper

⑨、Chain

query

// 链式查询 普通
QueryChainWrapper<T> query();
// 链式查询 lambda 式。注意:不支持 Kotlin
LambdaQueryChainWrapper<T> lambdaQuery();
​
// 示例:
query().eq("column", value).one();
lambdaQuery().eq(Entity::getId, value).list();

update

// 链式更改 普通
UpdateChainWrapper<T> update();
// 链式更改 lambda 式。注意:不支持 Kotlin
LambdaUpdateChainWrapper<T> lambdaUpdate();
​
// 示例:
update().eq("column", value).remove();
lambdaUpdate().eq(Entity::getId, value).update(entity);

(2)Mapper CRUD接口

  • 通用CRUD封装BaseMapper接口,为Mybatis-Plus启动时自动解析实体表关系映射转换为Mybatis内部对象注入容器;

  • 泛型T为任意实体对象;

  • 参数Serializable为任意类型主键Mybatis-Plus,不推荐使用复合主键约定每一张表都有自己的唯一id主键;

  • 对象Wrapper为条件构造器。

①、Insert

// 插入一条记录
int insert(T entity);
类型 参数名 描述
T entity 实体对象

②、Delete

// 根据 entity 条件,删除记录
int delete(@Param(Constants.WRAPPER) Wrapper<T> wrapper);
// 删除(根据ID 批量删除)
int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
// 根据 ID 删除
int deleteById(Serializable id);
// 根据 columnMap 条件,删除记录
int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
类型 参数名 描述
Wrapper<T> wrapper 实体对象封装操作类(可以为 null)
Collection<? extends Serializable> idList 主键 ID 列表(不能为 null 以及 empty)
Serializable id 主键 ID
Map<String, Object> columnMap 表字段 map 对象

③、Update

// 根据 whereWrapper 条件,更新记录
int update(@Param(Constants.ENTITY) T updateEntity, @Param(Constants.WRAPPER) Wrapper<T> whereWrapper);
// 根据 ID 修改
int updateById(@Param(Constants.ENTITY) T entity);
类型 参数名 描述
T entity 实体对象 (set 条件值,可为 null)
Wrapper<T> updateWrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句)

④、Select

// 根据 ID 查询
T selectById(Serializable id);
// 根据 entity 条件,查询一条记录
T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
​
// 查询(根据ID 批量查询)
List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
// 根据 entity 条件,查询全部记录
List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 查询(根据 columnMap 条件)
List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
// 根据 Wrapper 条件,查询全部记录
List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询全部记录。注意: 只返回第一个字段的值
List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
​
// 根据 entity 条件,查询全部记录(并翻页)
IPage<T> selectPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询全部记录(并翻页)
IPage<Map<String, Object>> selectMapsPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询总记录数
Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
类型 参数名 描述
Serializable id 主键 ID
Wrapper<T> queryWrapper 实体对象封装操作类(可以为 null)
Collection<? extends Serializable> idList 主键 ID 列表(不能为 null 以及 empty)
Map<String, Object> columnMap 表字段 map 对象
IPage<T> page 分页查询条件(可以为 RowBounds.DEFAULT)

(3)mapper层 选装件

com.baomidou.mybatisplus.extension.injector.methods包下,需配合Sql注入器使用。

①、AlwaysUpdateSomeColumnById

int alwaysUpdateSomeColumnById(T entity);

②、insertBatchSomeColumn

int insertBatchSomeColumn(List<T> entityList);

③、logicDeleteByIdWithFill

int logicDeleteByIdWithFill(T entity);

(4)ActiveRecord模式

  • 实体类只需继承Model类即可进行强大的CRUD操作;

  • 需要项目中已注入对应实体的BaseMapper

①、继承Model

class User extends Model<User>{// fields...
}

②、调用CRUD方法

User user = new User();
user.insert();
user.selectAll();
user.updateById();
user.deleteById();
// ...

(5)SimpleQuery工具类

  • 对selectList查询后的结果用Stream流进行了一些封装,可以返回指定结果,简洁了api的调用;

  • 需要项目中已注入对应实体的BaseMapper;

①、keyMap

// 查询表内记录,封装返回为Map<属性,实体>
Map<A, E> keyMap(LambdaQueryWrapper<E> wrapper, SFunction<E, A> sFunction, Consumer<E>... peeks);
// 查询表内记录,封装返回为Map<属性,实体>,考虑了并行流的情况
Map<A, E> keyMap(LambdaQueryWrapper<E> wrapper, SFunction<E, A> sFunction, boolean isParallel, Consumer<E>... peeks);
类型 参数名 描述
E entity 实体对象
A attribute 实体属性类型,也是map中key的类型
LambdaQueryWrapper<E> wrapper 支持lambda的条件构造器
SFunction<E, A> sFunction 实体中属性的getter,用于封装后map中作为key的条件
boolean isParallel 为true时底层使用并行流执行
Consumer<E>... peeks 可叠加的后续操作

②、map

// 查询表内记录,封装返回为Map<属性,属性>
Map<A, P> map(LambdaQueryWrapper<E> wrapper, SFunction<E, A> keyFunc, SFunction<E, P> valueFunc, Consumer<E>... peeks);
// 查询表内记录,封装返回为Map<属性,属性>,考虑了并行流的情况
Map<A, P> map(LambdaQueryWrapper<E> wrapper, SFunction<E, A> keyFunc, SFunction<E, P> valueFunc, boolean isParallel, Consumer<E>... peeks);
类型 参数名 描述
E entity 实体对象
A attribute 实体属性类型,也是map中key的类型
P attribute 实体属性类型,也是map中value的类型
LambdaQueryWrapper<E> wrapper 支持lambda的条件构造器
SFunction<E, A> keyFunc 封装后map中作为key的条件
SFunction<E, P> valueFunc 封装后map中作为value的条件
boolean isParallel 为true时底层使用并行流执行
Consumer<E>... peeks 可叠加的后续操作

③、group

// 查询表内记录,封装返回为Map<属性,List<实体>>
Map<K, List<T>> group(LambdaQueryWrapper<T> wrapper, SFunction<T, A> sFunction, Consumer<T>... peeks);
// 查询表内记录,封装返回为Map<属性,List<实体>>,考虑了并行流的情况
Map<K, List<T>> group(LambdaQueryWrapper<T> wrapper, SFunction<T, K> sFunction, boolean isParallel, Consumer<T>... peeks);
// 查询表内记录,封装返回为Map<属性,分组后对集合进行的下游收集器>
M group(LambdaQueryWrapper<T> wrapper, SFunction<T, K> sFunction, Collector<? super T, A, D> downstream, Consumer<T>... peeks);
// 查询表内记录,封装返回为Map<属性,分组后对集合进行的下游收集器>,考虑了并行流的情况
M group(LambdaQueryWrapper<T> wrapper, SFunction<T, K> sFunction, Collector<? super T, A, D> downstream, boolean isParallel, Consumer<T>... peeks);
类型 参数名 描述
T entity 实体对象
K attribute 实体属性类型,也是map中key的类型
D - 下游收集器返回类型,也是map中value的类型
A - 下游操作中间类型
M - 最终结束返回的Map<K, D>
LambdaQueryWrapper<E> wrapper 支持lambda的条件构造器
SFunction<E, A> sFunction 分组依据,封装后map中作为key的条件
Collector<T, A, D> downstream 下游收集器
boolean isParallel 为true时底层使用并行流执行
Consumer<T>... peeks 可叠加的后续操作

④、list

// 查询表内记录,封装返回为List<属性>
List<A> list(LambdaQueryWrapper<E> wrapper, SFunction<E, A> sFunction, Consumer<E>... peeks);
// 查询表内记录,封装返回为List<属性>,考虑了并行流的情况
List<A> list(LambdaQueryWrapper<E> wrapper, SFunction<E, A> sFunction, boolean isParallel, Consumer<E>... peeks);
类型 参数名 描述
E entity 实体对象
A attribute 实体属性类型,也是list中元素的类型
LambdaQueryWrapper<E> wrapper 支持lambda的条件构造器
SFunction<E, A> sFunction 封装后list中的元素
boolean isParallel 为true时底层使用并行流执行
Consumer<E>... peeks 可叠加的后续操作

4、条件构造器

  • 以下出现的第一个入参boolean condition表示该条件是否加入最后生成的sql中;

  • 以下代码块内的多个方法均为从上往下补全个别boolean类型的入参,默认为true;

  • 以下出现的泛型Param均为Wrapper的子类实例(均具有AbstractWrapper的所有方法);

  • 以下方法在入参中出现的R为泛型,在普通wrapper中是String,在LambdaWrapper中是函数(例:Entity::gentId,Entity是实体,getId为字段id的getMethod);

  • 以下方法在入参中的R column均表示为数据库字段,当R具体类型为String时则为数据库字段名(字段名是数据库关键字的自己用转义符包裹)而不是实体类数据字段名,当R具体类型为SFunction时项目runtime不支持eclipse自家的编译器;

  • 举例均使用普通wrapper,入参为Map和List的均以json形式表现;

  • 如果入参的Map或者List为空,则不会加入最后生成的sql中。

(1)AbstractWrapper

QueryWrapper(LambdaQueryWrapper)和UpdateWrapper(LambdaUpdateWrapper)的父类用于生成sql的where条件,entity属性也用于生成sql的where条件。

①、allEq

allEq(Map<R, V> params)
allEq(Map<R, V> params, boolean null2IsNull)
allEq(boolean condition, Map<R, V> params, boolean null2IsNull)
  • 全部eq(或个别isNull)

param:key为数据库字段名,value为字段值;
null2IsNull:为true则在map的value为null时调用isNull方法,为false时则忽略value为null的。
  • 例1: allEq({id:1,name:"老王",age:null})--->id = 1 and name = '老王' and age is null

  • 例2: allEq({id:1,name:"老王",age:null}, false)--->id = 1 and name = '老王'

allEq(BiPredicate<R, V> filter, Map<R, V> params)
allEq(BiPredicate<R, V> filter, Map<R, V> params, boolean null2IsNull)
allEq(boolean condition, BiPredicate<R, V> filter, Map<R, V> params, boolean null2IsNull) 
filter:过滤函数,是否允许字段传入比对条件中
  • 例1: allEq((k,v) -> k.indexOf("a") >= 0, {id:1,name:"老王",age:null})--->name = '老王' and age is null

  • 例2: allEq((k,v) -> k.indexOf("a") >= 0, {id:1,name:"老王",age:null}, false)--->name = '老王'

②、eq

eq(R column, Object val)
eq(boolean condition, R column, Object val)
  • 等于 =

  • eq("name", "老王")`--->`name = '老王'

③、ne

ne(R column, Object val)
ne(boolean condition, R column, Object val)
  • 不等于 <>

  • 例: ne("name", "老王")--->name <> '老王'

④、gt

gt(R column, Object val)
gt(boolean condition, R column, Object val)
  • 大于 >

  • 例: gt("age", 18)--->age > 18

⑤、ge

ge(R column, Object val)
ge(boolean condition, R column, Object val)
  • 大于等于 >=

  • 例: ge("age", 18)--->age >= 18

⑥、lt

lt(R column, Object val)
lt(boolean condition, R column, Object val)
  • 小于 <

  • 例: lt("age", 18)--->age < 18

⑦、le

le(R column, Object val)
le(boolean condition, R column, Object val)
  • 小于等于 <=

  • 例: le("age", 18)--->age <= 18

⑧、between

between(R column, Object val1, Object val2)
between(boolean condition, R column, Object val1, Object val2)
  • BETWEEN 值1 AND 值2

  • 例: between("age", 18, 30)--->age between 18 and 30

⑨、notBetween

notBetween(R column, Object val1, Object val2)
notBetween(boolean condition, R column, Object val1, Object val2)
  • NOT BETWEEN 值1 AND 值2

  • 例: notBetween("age", 18, 30)--->age not between 18 and 30

⑩、like

like(R column, Object val)
like(boolean condition, R column, Object val)
  • LIKE '%值%'

  • 例: like("name", "王")--->name like '%王%'

11、notLike

notLike(R column, Object val)
notLike(boolean condition, R column, Object val)
  • NOT LIKE '%值%'

  • 例: notLike("name", "王")--->name not like '%王%'

12、likeLeft

likeLeft(R column, Object val)
likeLeft(boolean condition, R column, Object val)
  • LIKE '%值'

  • 例: likeLeft("name", "王")--->name like '%王'

13、likeRight

likeRight(R column, Object val)
likeRight(boolean condition, R column, Object val)
  • LIKE '值%'

  • 例: likeRight("name", "王")--->name like '王%'

14、isNull

isNull(R column)
isNull(boolean condition, R column)
  • 字段 IS NULL

  • 例: isNull("name")--->name is null

15、isNotNull

isNotNull(R column)
isNotNull(boolean condition, R column)
  • 字段 IS NOT NULL

  • 例: isNotNull("name")--->name is not null

16、in

in(R column, Collection<?> value)
in(boolean condition, R column, Collection<?> value)
  • 字段 IN (value.get(0), value.get(1), ...)

  • 例: in("age",{1,2,3})--->age in (1,2,3)

in(R column, Object... values)
in(boolean condition, R column, Object... values)
  • 字段 IN (v0, v1, ...)

  • 例: in("age", 1, 2, 3)--->age in (1,2,3)

17、notIn

notIn(R column, Collection<?> value)
notIn(boolean condition, R column, Collection<?> value)
  • 字段 NOT IN (value.get(0), value.get(1), ...)

  • 例: notIn("age",{1,2,3})--->age not in (1,2,3)

notIn(R column, Object... values)
notIn(boolean condition, R column, Object... values)
  • 字段 NOT IN (v0, v1, ...)

  • 例: notIn("age", 1, 2, 3)--->age not in (1,2,3)

18、inSql

inSql(R column, String inValue)
inSql(boolean condition, R column, String inValue)
  • 字段 IN ( sql语句 )

  • 例: inSql("age", "1,2,3,4,5,6")--->age in (1,2,3,4,5,6)

  • 例: inSql("id", "select id from table where id < 3")--->id in (select id from table where id < 3)

19、notInSql

notInSql(R column, String inValue)
notInSql(boolean condition, R column, String inValue)
  • 字段 NOT IN ( sql语句 )

  • 例: notInSql("age", "1,2,3,4,5,6")--->age not in (1,2,3,4,5,6)

  • 例: notInSql("id", "select id from table where id < 3")--->id not in (select id from table where id < 3)

20、groupBy

groupBy(R... columns)
groupBy(boolean condition, R... columns)
  • 分组:GROUP BY 字段, ...

  • 例: groupBy("id", "name")--->group by id,name

21、orderByAsc

orderByAsc(R... columns)
orderByAsc(boolean condition, R... columns)
  • 排序:ORDER BY 字段, ... ASC

  • 例: orderByAsc("id", "name")--->order by id ASC,name ASC

22、orderByDesc

orderByDesc(R... columns)
orderByDesc(boolean condition, R... columns)
  • 排序:ORDER BY 字段, ... DESC

  • 例: orderByDesc("id", "name")--->order by id DESC,name DESC

23、orderBy

orderBy(boolean condition, boolean isAsc, R... columns)
  • 排序:ORDER BY 字段, ...

  • 例: orderBy(true, true, "id", "name")--->order by id ASC,name ASC

24、having

having(String sqlHaving, Object... params)
having(boolean condition, String sqlHaving, Object... params)
  • HAVING ( sql语句 )

  • 例: having("sum(age) > 10")--->having sum(age) > 10

  • 例: having("sum(age) > {0}", 11)--->having sum(age) > 11

25、func

func(Consumer<Children> consumer)
func(boolean condition, Consumer<Children> consumer)
  • func 方法(主要方便在出现if...else下调用不同方法能不断链)

  • 例: func(i -> if(true) {i.eq("id", 1)} else {i.ne("id", 1)})

26、or

or()
or(boolean condition)
  • 拼接OR

  • 主动调用or表示紧接着下一个方法不是用and连接(不调用or则默认为使用and连接);

  • 例: eq("id",1).or().eq("name","老王")--->id = 1 or name = '老王'

or(Consumer<Param> consumer)
or(boolean condition, Consumer<Param> consumer)
  • OR 嵌套

  • 例: or(i -> i.eq("name", "李白").ne("status", "活着"))--->or (name = '李白' and status <> '活着')

27、and

and(Consumer<Param> consumer)
and(boolean condition, Consumer<Param> consumer)
  • AND 嵌套

  • 例: and(i -> i.eq("name", "李白").ne("status", "活着"))--->and (name = '李白' and status <> '活着')

28、nested

nested(Consumer<Param> consumer)
nested(boolean condition, Consumer<Param> consumer)
  • 正常嵌套 不带 AND 或者 OR

  • 例: nested(i -> i.eq("name", "李白").ne("status", "活着"))--->(name = '李白' and status <> '活着')

29、apply

apply(String applySql, Object... params)
apply(boolean condition, String applySql, Object... params)
  • 拼接 sql:用于数据库函数动态入参的params对应前面applySql内部的{index}部分,这样不会有sql注入风险;

  • 例: apply("id = 1")--->id = 1

  • 例: apply("date_format(dateColumn,'%Y-%m-%d') = '2008-08-08'")--->date_format(dateColumn,'%Y-%m-%d') = '2008-08-08'")

  • 例: apply("date_format(dateColumn,'%Y-%m-%d') = {0}", "2008-08-08")--->date_format(dateColumn,'%Y-%m-%d') = '2008-08-08'")

30、last

last(String lastSql)
last(boolean condition, String lastSql)
  • 无视优化规则直接拼接到 sql 的最后

注意事项:

只能调用一次,多次调用以最后一次为准 有sql注入的风险,请谨慎使用

  • 例: last("limit 1")

31、exists

exists(String existsSql)
exists(boolean condition, String existsSql)
  • 拼接 EXISTS ( sql语句 )

  • 例: exists("select id from table where age = 1")--->exists (select id from table where age = 1)

32、notExists

notExists(String notExistsSql)
notExists(boolean condition, String notExistsSql)
  • 拼接 NOT EXISTS ( sql语句 )

  • 例: notExists("select id from table where age = 1")--->not exists (select id from table where age = 1)

(2)QueryWrapper

  • 继承自AbstractWrapper,自身的内部属性entity也用于生成where条件及LambdaQueryWrapper,也可以通过new QueryWrapper().lambda()方法获取;

select

select(String... sqlSelect)
select(Predicate<TableFieldInfo> predicate)
select(Class<T> entityClass, Predicate<TableFieldInfo> predicate)
  • 设置查询字段

说明:

以上方法分为两类. 第二类方法为:过滤查询字段(主键除外),入参不包含 class 的调用前需要wrapper内的entity属性有值! 这两类方法重复调用以最后一次为准

  • 例: select("id", "name", "age")

  • 例: select(i -> i.getProperty().startsWith("test"))

(3)UpdateWrapper

①、set

set(String column, Object val)
set(boolean condition, String column, Object val)
  • SQL SET 字段

  • 例: set("name", "老李头")

  • 例: set("name", "")--->数据库字段值变为空字符串

  • 例: set("name", null)--->数据库字段值变为null

②、setSql

setSql(String sql)
  • 设置 SET 部分 SQL

  • 例: setSql("name = '老李头'")

③、lambda

  • 获取 LambdaWrapperQueryWrapper中是获取LambdaQueryWrapperUpdateWrapper中是获取LambdaUpdateWrapper

(4)使用Wrapper自定义SQL

  • 需要mybatis-plus版本 >= 3.0.7,param参数名要么叫ew,要么加上注解@Param(Constants.WRAPPER)使用${ew.customSqlSegment}不支持Wrapper内的entity生成where语句。

kotlin持久化对象定义最佳实践

由于kotlin相比于java多了数据对象(data class),建议按照以下形式定义持久化对象:

@TableName("sys_user")
class User {@TableId(type = IdType.AUTO)var id: Int? = null
​@TableField("username")var name: String? = null
​var roleId: Int? = null
}

注意:这里的TableIdTableField并非必要,只是为了展示Mybatis-Plus中的annotation使用

这里所有成员都需要定义为可空类型(?),并赋予null的初始值,方便我们在以下场景中使用(类似java中的updateSelective

val wrapper = KtUpdateWrapper(User::class.java).eq(User::id, 2)
val newRecord = User()
newRecord.name = "newName"
userMapper!!.update(newRecord, wrapper)

不建议使用data class及全参数构造方法,这样我们会写很多不必要的null来构造一个空对象

用注解

@Select("select * from mysql_data ${ew.customSqlSegment}")
List<MysqlData> getAll(@Param(Constants.WRAPPER) Wrapper wrapper);

用XML

List<MysqlData> getAll(Wrapper ew);
<select id="getAll" resultType="MysqlData">SELECT * FROM mysql_data ${ew.customSqlSegment}
</select>

kotlin使用wrapper

kotlin 可以使用 QueryWrapperUpdateWrapper 但无法使用 LambdaQueryWrapperLambdaUpdateWrapper 如果想使用 lambda 方式的 wrapper 请使用 KtQueryWrapperKtUpdateWrapper

val queryWrapper = KtQueryWrapper(User()).eq(User::name, "sss").eq(User::roleId, "sss2")
userMapper!!.selectList(queryWrapper)
​
val updateConditionWrapper = KtUpdateWrapper(User()).eq(User::name, "sss").eq(User::roleId, "sss2")
val updateRecord = User()
updateRecord.name = "newName"
userMapper!!.update(updateRecord, updateConditionWrapper)
​
val updateRecord = User()
updateRecord.id = 2
updateRecord.name = "haha"
userMapper.updateById(updateRecord)

链式调用 lambda 式

// 区分:
// 链式调用 普通
UpdateChainWrapper<T> update();
// 链式调用 lambda 式。注意:不支持 Kotlin
LambdaUpdateChainWrapper<T> lambdaUpdate();
​
// 等价示例:
query().eq("id", value).one();
lambdaQuery().eq(Entity::getId, value).one();
​
// 等价示例:
update().eq("id", value).remove();
lambdaUpdate().eq(Entity::getId, value).remove();

5、主键策略

主键生成策略必须使用INPUT

支持父类定义@KeySequence子类继承使用

内置支持:

  • DB2KeyGenerator

  • H2KeyGenerator

  • KingbaseKeyGenerator

  • OracleKeyGenerator

  • PostgreKeyGenerator

如果内置支持不满足需求,可实现IkeyGenerator接口来扩展。

@KeySequence(value = "SEQ_ORACLE_STRING_KEY", clazz = String.class)
public class YourEntity {
​@TableId(value = "ID_STR", type = IdType.INPUT)private String idStr;
​
}

(1)Spring-Boot

①、通过配置类

@Bean
public IKeyGenerator keyGenerator() {return new H2KeyGenerator();
}

②、通过MybatisPlusPropertiesCustomizer自定义

@Bean
public MybatisPlusPropertiesCustomizer plusPropertiesCustomizer() {return plusProperties -> plusProperties.getGlobalConfig().getDbConfig().setKeyGenerator(new H2KeyGenerator());
}

(2)Spring

①、XML配置

<bean id="globalConfig" class="com.baomidou.mybatisplus.core.config.GlobalConfig"><property name="dbConfig" ref="dbConfig"/>
</bean>
​
<bean id="dbConfig" class="com.baomidou.mybatisplus.core.config.GlobalConfig.DbConfig"><property name="keyGenerator" ref="keyGenerator"/>
</bean>
​
<bean id="keyGenerator" class="com.baomidou.mybatisplus.extension.incrementer.H2KeyGenerator"/>

②、注解配置

@Bean
public GlobalConfig globalConfig() {GlobalConfig conf = new GlobalConfig();conf.setDbConfig(new GlobalConfig.DbConfig().setKeyGenerator(new H2KeyGenerator()));return conf;
}

6、自定义ID生成器

(1)Spring Boot

①、声明为Bean供Spring扫描注入

@Component
public class CustomIdGenerator implements IdentifierGenerator {@Overridepublic Long nextId(Object entity) {//可以将当前传入的class全类名来作为bizKey,或者提取参数来生成bizKey进行分布式Id调用生成.String bizKey = entity.getClass().getName();//根据bizKey调用分布式ID生成long id = ....;//返回生成的id值即可.return id;}
}

②、使用配置类

@Bean
public IdentifierGenerator idGenerator() {return new CustomIdGenerator();
}

③、通过MybatisPlusPropertiesCustomizer自定义

@Bean
public MybatisPlusPropertiesCustomizer plusPropertiesCustomizer() {return plusProperties -> plusProperties.getGlobalConfig().setIdentifierGenerator(new CustomIdGenerator());
}

(2)Spring

①、XML配置

<bean name="customIdGenerator" class="com.baomidou.samples.incrementer.CustomIdGenerator"/>
​
<bean id="globalConfig" class="com.baomidou.mybatisplus.core.config.GlobalConfig"><property name="identifierGenerator" ref="customIdGenerator"/>
</bean>

②、注解配置

@Bean
public GlobalConfig globalConfig() {GlobalConfig conf = new GlobalConfig();conf.setIdentifierGenerator(new CustomIdGenerator());return conf;
}

扩展部分

1、逻辑删除

只对自动注入的sql起效:

  • 插入:不作限制;

  • 查找:追加where条件过滤掉已删除数据,且使用wrapper.entity生成的where条件会忽略该字段;

  • 更新:追加where条件防止更新到已删除数据,且使用wrapper.entity生成的where条件会忽略该字段;

  • 删除:转变为更新;

例如:

  • 删除:update user set deleted=1 where id = 1 and deleted = 0

  • 查找:select id,name,deleted from user where deleted = 0

字段类型支持说明:

  • 支持所有的数据类型(推荐使用IntegerBooleanLocalDateTime

  • 如果数据库字段使用datetime,逻辑未删除值和已删除值支持配置为字符串null,另一个值支持配置为函数来获取值如now()

(1)使用方法

①、配置:com.baomidou.mybatisplus.core.config.GlobalConfig$DbConfig

  • application.yml

mybatis-plus:global-config:db-config:logic-delete-field: flag # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)logic-delete-value: 1 # 逻辑已删除值(默认为 1)logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)

②、实体类字段上加上@TableLogic注解

@TableLogic
private Integer deleted;

(2)常见问题

①、如何insert?

  • 字段在数据库定义默认值(推荐);

  • insert前自己set值;

  • 自动填充功能。

②、删除接口自动填充功能失效

  • 使用update方法并:UpdateWrapper.set(column, value)(推荐);

  • 使用update方法并:UpdateWrapper。setSql("column=value")

  • 使用Sql注入器注入:com.baomidou.mybatisplus.extension.methods.LogicDeleteByIdWithFill并使用(推荐)。

2、通用枚举

(1)声明通用枚举属性

  • 使用@EnumValue注解枚举属性

public enum GradeEnum {
​PRIMARY(1, "小学"),  SECONDORY(2, "中学"),  HIGH(3, "高中");
​GradeEnum(int code, String descp) {this.code = code;this.descp = descp;}
​@EnumValue//标记数据库存的值是codeprivate final int code;//。。。
}
  • 枚举属性,实现IEnum接口如下:

public enum AgeEnum implements IEnum<Integer> {ONE(1, "一岁"),TWO(2, "二岁"),THREE(3, "三岁");
​private int value;private String desc;
​@Overridepublic Integer getValue() {return this.value;}
}
  • 实体属性使用枚举类型

public class User {/*** 名字* 数据库字段: name varchar(20)*/private String name;
​/*** 年龄,IEnum接口的枚举处理* 数据库字段:age INT(3)*/private AgeEnum age;
​/*** 年级,原生枚举(带{@link com.baomidou.mybatisplus.annotation.EnumValue}):* 数据库字段:grade INT(2)*/private GradeEnum grade;
}

(2)配置扫描通用枚举

  • spring mvc配置参考,安装集成MybatisSqlSessionFactoryBean枚举包扫描;

  • 配置文件:resources/application.yml

mybatis-plus:# 支持统配符 * 或者 ; 分割typeEnumsPackage: com.baomidou.springboot.entity.enums....
  • 自定义配置类:MybatisPlusAutoConfiguration

​
@Configuration
public class MybatisPlusAutoConfiguration {
​@Beanpublic MybatisPlusPropertiesCustomizer mybatisPlusPropertiesCustomizer() {return properties -> {GlobalConfig globalConfig = properties.getGlobalConfig();globalConfig.setBanner(false);MybatisConfiguration configuration = new MybatisConfiguration();configuration.setDefaultEnumTypeHandler(MybatisEnumTypeHandler.class);properties.setConfiguration(configuration);};}
}

如何序列化枚举值为数据库存储值

(1)Jackson

①、重写toString方法

springboot

    @Beanpublic Jackson2ObjectMapperBuilderCustomizer customizer(){return builder -> builder.featuresToEnable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);}

jackson

    ObjectMapper objectMapper = new ObjectMapper();objectMapper.configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING, true);

②、注解处理

public enum GradeEnum {
​PRIMARY(1, "小学"),  SECONDORY(2, "中学"),  HIGH(3, "高中");
​GradeEnum(int code, String descp) {this.code = code;this.descp = descp;}
​@EnumValue@JsonValue  //标记响应json值private final int code;
}

(2)Fastjson

①、重写toString方法

全局处理方式:

    FastJsonConfig config = new FastJsonConfig();config.setSerializerFeatures(SerializerFeature.WriteEnumUsingToString);

局部处理方式:

    @JSONField(serialzeFeatures= SerializerFeature.WriteEnumUsingToString)private UserStatus status;

3、字段类型处理器

类型处理器,用于JavaType与JdbcType之间的转换,用于PreparedStatement设置参数值和从ResultSet或CallableStatement中取出一个值,讲解mybatis-plus内置常用类型处理器如何通过TableField注解快速注入到mybatis容器中。

  • JSON字段类型

@Data
@Accessors(chain = true)
@TableName(autoResultMap = true)
public class User {private Long id;
​...
​
​/*** 注意!! 必须开启映射注解** @TableName(autoResultMap = true)** 以下两种类型处理器,二选一 也可以同时存在** 注意!!选择对应的 JSON 处理器也必须存在对应 JSON 解析依赖包*/@TableField(typeHandler = JacksonTypeHandler.class)// @TableField(typeHandler = FastjsonTypeHandler.class)private OtherInfo otherInfo;
​
}
  • XML写法

<result column="other_info" jdbcType="VARCHAR" property="otherInfo" typeHandler="com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler" />

4、自动填充功能

原理:

  • 实现元对象处理器接口:com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;

  • 注解填充字段@TableField(.. fill = FieldFill.INSERT)生成器策略部分也可以配置

public class User {
​// 注意!这里需要标记为填充字段@TableField(.. fill = FieldFill.INSERT)private String fillField;
​....
}
  • 自定义实现类MyMetaObjectHandler

@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
​@Overridepublic void insertFill(MetaObject metaObject) {log.info("start insert fill ....");this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now()); // 起始版本 3.3.0(推荐使用)// 或者this.strictInsertFill(metaObject, "createTime", () -> LocalDateTime.now(), LocalDateTime.class); // 起始版本 3.3.3(推荐)// 或者this.fillStrategy(metaObject, "createTime", LocalDateTime.now()); // 也可以使用(3.3.0 该方法有bug)}
​@Overridepublic void updateFill(MetaObject metaObject) {log.info("start update fill ....");this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); // 起始版本 3.3.0(推荐)// 或者this.strictUpdateFill(metaObject, "updateTime", () -> LocalDateTime.now(), LocalDateTime.class); // 起始版本 3.3.3(推荐)// 或者this.fillStrategy(metaObject, "updateTime", LocalDateTime.now()); // 也可以使用(3.3.0 该方法有bug)}
}

注意事项

  • 填充原理是直接给entity的属性设置值;

  • 注解则是指定该属性在对应情况下必有值,如果无值则入库会是null;

  • MetaObjectHandler提供的默认方法的策略均为:如果属性有值则不覆盖,如果填充值为null则不填充;

  • 字段必须声明TableField注解,属性fill选择对应策略,该声明告知Mybatis-Plus需要预留注入SQL字段;

  • 填充处理器MyMetaObjectHandler字段名以及字段类型来区分必须使用父类的strictInsertFill或者strictUpdateFill方法;

  • 不需要根据任何来区分可以使用父类的fillStrategy方法;

  • update(T t, Wrapper updateWrapper)时t不能为空,否则自动填充失效;

public enum FieldFill {/*** 默认不处理*/DEFAULT,/*** 插入填充字段*/INSERT,/*** 更新填充字段*/UPDATE,/*** 插入和更新填充字段*/INSERT_UPDATE
}

5、SQL注入器

注入器配置

全局配置sqlInjector用于注入ISqlInjector接口的子类,实现自定义方法注入。

  • SQL自动注入器接口ISqlInjector

public interface ISqlInjector {
​/*** <p>* 检查SQL是否注入(已经注入过不再注入)* </p>** @param builderAssistant mapper 信息* @param mapperClass      mapper 接口的 class 对象*/void inspectInject(MapperBuilderAssistant builderAssistant, Class<?> mapperClass);
}

自定义自己的通用方法可以实现接口ISqlInjector也可以继承抽象类AbstractSqlInjector注入通用方法SQL语句,然后继承BaseMapper添加自定义方法,全局配置sqlInjector注入MP会自动将类所有方法注入到mybatis容器中。

6、执行SQL分析打印

该功能依赖p6spy组件,完美的输出打印SQL及执行时间。3.1.0以上版本。

  • p6spy依赖引入

Maven:

<dependency><groupId>p6spy</groupId><artifactId>p6spy</artifactId><version>最新版本</version>
</dependency>

Gradle:

compile group: 'p6spy', name: 'p6spy', version: '最新版本'
  • application.yml配置

spring:datasource:driver-class-name: com.p6spy.engine.spy.P6SpyDriverurl: jdbc:p6spy:h2:mem:test...
  • spy.properties配置

#3.2.1以上使用
modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory
#3.2.1以下使用或者不配置
#modulelist=com.p6spy.engine.logging.P6LogFactory,com.p6spy.engine.outage.P6OutageFactory
# 自定义日志打印
logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger
#日志输出到控制台
appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger
# 使用日志系统记录 sql
#appender=com.p6spy.engine.spy.appender.Slf4JLogger
# 设置 p6spy driver 代理
deregisterdrivers=true
# 取消JDBC URL前缀
useprefix=true
# 配置记录 Log 例外,可去掉的结果集有error,info,batch,debug,statement,commit,rollback,result,resultset.
excludecategories=info,debug,result,commit,resultset
# 日期格式
dateformat=yyyy-MM-dd HH:mm:ss
# 实际驱动可多个
#driverlist=org.h2.Driver
# 是否开启慢SQL记录
outagedetection=true
# 慢SQL记录标准 2 秒
outagedetectioninterval=2

注意

  • driver-class-name为p6spy提供的驱动类;

  • url前缀为jdbc:p6spy跟着冒号为对应数据库链接地址;

  • 打印出sql为null,在excludecategories增加commit;

  • 批量操作不打印sql,去除excludecategories中的batch;

  • 批量操作打印重复的问题请使用MybatisPlusLogFactory;

7、数据安全保护

  • 该功能为了保护数据库配置及数据安全,在一定的程度上控制开发人员流动导致敏感信息泄露。

  • 3.3.2开始支持;

  • 配置安全

YML配置:

// 加密配置 mpw: 开头紧接加密内容( 非数据库配置专用 YML 中其它配置也是可以使用的 )
spring:datasource:url: mpw:qRhvCwF4GOqjessEB3G+a5okP+uXXr96wcucn2Pev6Bf1oEMZ1gVpPPhdDmjQqoMpassword: mpw:Hzy5iliJbwDHhjLs1L0j6w==username: mpw:Xb+EgsyuYRXw7U7sBJjBpA==

密钥加密:

// 生成 16 位随机 AES 密钥
String randomKey = AES.generateRandomKey();
​
// 随机密钥加密
String result = AES.encrypt(data, randomKey);

使用:

// Jar 启动参数( idea 设置 Program arguments , 服务器可以设置为启动环境变量 )
--mpw.key=d1104d7c3b616f0b

加密配置必须以mpw:字符串开头。

8、多数据源

dynamic-datasource-spring-boot-starter是一个基于springboot的快速集成多数据源的启动器,是一个第三方mybatis扩展库,与mybatis-plus本身无关。

(1)特性

  • 支持数据源分组,适用于多种场景,纯粹多库、读写分离、一主多从 混合模式;

  • 支持数据库敏感配置信息加密ENC();

  • 支持每个数据库独立初始化表结构schema和数据库database;

  • 支持无数据源启动,支持懒加载数据源(需要的时候再创建连接);

  • 支持自定义注解,需继承DS;

  • 提供并简化对Druid、HikariCp、BeeCp、Dbcp2的快速集成;

  • 提供对Mybatis-Plus、Quartz、ShardingJdbc、p6sy、Jndi等组件的集成方案;

  • 提供自定义数据源来源方案(如全从数据库加载);

  • 提供项目启动后动态增加移除数据源方案;

  • 提供Mybatis环境下的纯读写分离方案;

  • 提供使用spel动态参数解析数据源方案,内置spel、session、header、支持自定义;

  • 支持多层数据源嵌套切换,(ServiceA >>> ServiceB >>> ServiceC);

  • 提供基于seata的分布式事务方案

  • 提供本地多数据源事务方案

(2)约定

  • 本框架只做 切换数据源 这件核心的事情,并不限制你的具体操作,切换了数据源可以做任何CRUD;

  • 配置文件所有以下划线 _ 分割的数据源 首部 即为组的名称,相同组名称的数据源会放在一个组下;

  • 切换数据源可以是组名,也可以是具体数据源名称。组名则切换时采用负载均衡算法切换;

  • 默认的数据源名称为 master ,你可以通过 spring.datasource.dynamic.primary 修改;

  • 方法上的注解优先于类上注解;

  • DS支持继承抽象类上的DS,暂不支持继承接口上的DS。

(3)使用方法

①、引入dynamic-datasource-spring-boot-starter;

<dependency><groupId>com.baomidou</groupId><artifactId>dynamic-datasource-spring-boot-starter</artifactId><version>${version}</version>
</dependency>

②、配置数据源;

spring:datasource:dynamic:primary: master #设置默认的数据源或者数据源组,默认值即为masterstrict: false #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源datasource:master:url: jdbc:mysql://xx.xx.xx.xx:3306/dynamicusername: rootpassword: 123456driver-class-name: com.mysql.jdbc.Driver # 3.2.0开始支持SPI可省略此配置slave_1:url: jdbc:mysql://xx.xx.xx.xx:3307/dynamicusername: rootpassword: 123456driver-class-name: com.mysql.jdbc.Driverslave_2:url: ENC(xxxxx) # 内置加密,使用请查看详细文档username: ENC(xxxxx)password: ENC(xxxxx)driver-class-name: com.mysql.jdbc.Driver#......省略#以上会配置一个默认库master,一个组slave下有两个子库slave_1,slave_2
# 多主多从                      纯粹多库(记得设置primary)                   混合配置
spring:                               spring:                               spring:datasource:                           datasource:                           datasource:dynamic:                              dynamic:                              dynamic:datasource:                           datasource:                           datasource:master_1:                             mysql:                                master:master_2:                             oracle:                               slave_1:slave_1:                              sqlserver:                            slave_2:slave_2:                              postgresql:                           oracle_1:slave_3:                              h2:                                   oracle_2:
​

③、使用@DS切换数据源;

@DS 可以注解在方法上或类上,同时存在就近原则 方法上注解 优先于 类上注解

注解 结果
没有@DS 默认数据源
@DS("dsName") dsName可以为组名也可以为具体某个库的名称
@Service
@DS("slave")
public class UserServiceImpl implements UserService {
​@Autowiredprivate JdbcTemplate jdbcTemplate;
​public List selectAll() {return  jdbcTemplate.queryForList("select * from user");}@Override@DS("slave_1")public List selectByCondition() {return  jdbcTemplate.queryForList("select * from user where age >10");}
}

9、MybatisX

相关问题的答案:

根据Mapper找到实体类的方式:

  • 继承mybatis-plus的BaseMapper;

  • Mapper.xml文件有resultMap标签;

  • 在Mapper类上增加注释指定实体类,例如:@Entity com.xx.xx.UserModel

JPA提示生成代码,根据以下规则找到表名:

  • 实体类有JPA注解,如:@Table(name="t_user")

  • 实体类有 mybatis-plus 注解,如:@Table("t_user")

  • 实体类有注释:@TableName com.xx.xx.UserModel

  • 如果不存在以上规则,将驼峰转下划线,如UserModel的表名为:user_model。

插件

1、Mybatis插件机制

四大对象

  • Executor:执行器对象

  • StatementHandler:编译器对象

  • ParameterHandler:参数处理器对象

  • ResultSetHandler:结果集处理器对象

插件编写

1、实现Interceptor接口;

执行目标方法:

放行执行:Invocation.proceed();

包装目标对象:为目标对象创建一个代理对象:

Plugin.wrap(target, this);使用当前拦截器来包装我们的目标对象。然后返回动态代理对象。

2、使用@Intercepts注解完成插件签名;

3、将写好的插件注册到全局配置文件中;

插件会产生目标对象的代理对象,多个插件就会产生多层代理。

创建动态代理的时候,是按照插件配置顺序创建层层代理对象,执行目标方法,按照逆向顺序执行。

分页插件

PaginationInterceptor

执行分析插件:

SqlExplainInterceptor

性能分析插件:

PerformanceInterceptor

乐观锁插件:

OptimisticLockerInterptor

Mybatis-Plus自定义全局操作

(1)AutoSqlInjector

注入SQL语句

注入的方法名

构造SqlSource对象

元数据处理器接口

MetaObjectHandler

insertFill(MetaObject metaObject);

updateFill(MetaObject metaObject);

Oracle主键序列

多个表使用同一个Sequence,可以让实体类继承同一个父类。

Mybatis Plus相关推荐

  1. mybatis查询报错:com.mysql.cj.exceptions.DataConversionException: Cannot determine value type from string

    mybatis查询报错: com.mysql.cj.exceptions.DataConversionException: Cannot determine value type from strin ...

  2. MyBatis的插入后获得主键的方式

    需求: 使用MyBatis往MySQL数据库中插入一条记录后,需要返回该条记录的自增主键值. 方法: 在mapper中指定keyProperty属性,示例如下: <insert id=" ...

  3. mybatis使用注解开发

    mybatis使用注解开发 面向接口编程 在之前我们是通过面向对象编程,但是在真正开发的时候我们会选择面向接口编程. 根本原因 : 解耦 , 可拓展 , 提高复用 , 分层开发中 , 上层不用管具体的 ...

  4. mybatis ResultMap

    ResultMap 解决属性名和字段的名称不一致的问题. 查询为null的问题 创建java实体类: public class User {private int id; //idprivate St ...

  5. mybatis配置文件解析

    mybatis配置文件解析 mybatis核心配置文件`mybatis-config.xml文件. mybatis的配置文件包含了会深深影响mybatis行为的设置和属性信息. 能配置的内容: con ...

  6. mybatis CRUD操作

    mybatis CRUD操作 select select标签是mybatis最常用的标签之一. select语句有很多属性可以详细的配置每一天sql语句. id 命名空间唯一的标识. 接口中的方法名与 ...

  7. java mybatis基础

    java mybatis基础 1.1 什么是mybatis? mybatis是一个优秀的持久层框架. 避免几乎所有的JDBC代码和手动设置参数以及获取结果集的过程. 可以使用简单的xml或者注解来配置 ...

  8. mybatis的资源过滤错误及xml文件编码错误

    mybatis 解决maven项目内资源过滤的问题 写的配置文件无法被导出或者生效的问题. 解决方案: <build><resources><resource>&l ...

  9. Mybatis传递多个参数的4种方式

    现在大多项目都是使用Mybatis了,但也有些公司使用Hibernate.使用Mybatis最大的特性就是sql需要自己写,而写sql就需要传递多个参数.面对各种复杂的业务场景,传递参数也是一种学问. ...

  10. SpringBoot (五) :SpringBoot整合mybatis

    说在前面 mybatis刚开始使用的时候比较麻烦,需要各种配置文件.实体类.dao层映射关联.还有一大推其它配置.初期开发了generator可以根据表结果自动生产实体类.配置文件和dao层代码,可以 ...

最新文章

  1. Go --- 设计模式(工厂模式)
  2. 跟风 Python 的人,后来都怎样了?
  3. 分享:根据svg节点对象类型和路径值转换坐标值
  4. 单表数据量过大处理策略
  5. 基于规则的应用程序开发实战(转载与MSDN)
  6. minheight能继承吗_民法典亮点盘点 | 侄子能继承叔叔的遗产吗?
  7. Win7下DB2 Express-C 9.7.2的卸载与安装(上)
  8. 17. 维基百科的高性能架构设计分析
  9. 【转】adns解析库——域名解析实例(C++、linux)
  10. Java-IO操作性能对比
  11. 2003服务器系统QQ安装不了,windows2003server
  12. Android BT种子文件解析
  13. php宝宝起名,宝宝在线起名取名大全
  14. qpython3.0.0_qpython3
  15. macOS 安卓模拟器 Nox夜神模拟器 共享目录
  16. php7.4 ffi,PHP7.4 全新扩展方式 FFI 详解
  17. 苹果账号打包发布APP流程详解
  18. 一直空中三角测量计算失败
  19. MathType 快捷键隐藏章节符
  20. 2021年Gartner数据防泄露市场指南发布,做为中国数据安全代表性厂商天空卫士连续三年入选

热门文章

  1. 【开发教程6】疯壳·ARM功能手机-中断实验教程
  2. 《马克思主义基本原理概论》复习笔记
  3. 计算机接口学平时作业,西电《计算机接口与通信技术》平时作业[教学作业]
  4. 运维(20) 制作启动U盘安装Win10
  5. 猴子--教你如何准备一份数据分析师简历的清单
  6. Android安全-应用沙盒简述
  7. 高级设计总监的设计方法论——5W1H需求分析法 KANO模型分析法
  8. kasp技术原理_Massarray技术——中高通量大样本的SNP检测利器!
  9. 2021-05-15 随机生成车架号
  10. 如何用卡诺图化简带有约束条件的逻辑函数?