一、简介
Mybatis-Plus是一款 MyBatis 动态 sql 自动注入 crud 简化 增 删 改 查 操作中间件。启动加载 XML 配置时注入 mybatis 单表 动态 SQL 操作 ,为简化开发工作、提高生产率而生。Mybatis-Plus 启动注入非拦截实现、性能更优。
1.1、原理
1.3、简化
MP简化了MyBatis的单表基本操作,提供了两种操作方式:
(1)、传统模式
Mybatis-Plus 通过 EntityWrapper(简称 EW,MP 封装的一个查询条件构造器)或者 Condition(与EW类似) 来让用户自由的构建查询条件,简单便捷,没有额外的负担,能够有效提高开发效率。
(2)、ActiveRecord模式
Active Record(简称AR)模式是软件里的一种架构性模式,主要概念是关系型数据库中的数据在内存中以对象的形式存储。由Martin Fowler在其2003年初版的书籍《Patterns of Enterprise Application Architecture》命名。遵循该模式的对象接口一般包括如Insert, Update, 和 Delete这样的函数,以及对应于底层数据库表字段的相关属性。
AR模式是一种访问数据库数据的方式。数据表或视图被映射成一个类。每个对象实例则对应于表的一条记录。对象被创建后,通过save就可以向表中新添一行记录。当对象被更新时,表中相应记录也被更新。这个包裹类通过属性或方法的形式实现访问表或视图中的每一个字段。
该模式主要被对象持久化工具采用,用于对象关系映射 (ORM). 典型的,外键关系会以合适的对象实例属性的形式暴露访问。
1.4、常用实体注解
1.表名注解@TableName
2.主键注解@TableId
3.字段注解@TableFieId
4.序列主键策略注解@KeySequence
二、搭建
环境:
IDEA
Spring Boot-2.0
MyBatis-Plus-2.2.0
MyBatisPlus-spring-boot-starter-1.0.5
druid-spring-boot-starter-1.1.9
首先创建SpringBoot Maven项目,然后加入以下依赖:
4.0.0
com.fendo.mybatis.plus
demo
0.0.1-SNAPSHOT
jar
mybatis-plus
mybatis-plus 示例
org.springframework.boot
spring-boot-starter-parent
2.0.0.RELEASE
UTF-8
UTF-8
1.8
1.8
1.8
1.0.5
2.2.0
1.2.39
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-jetty
org.springframework.boot
spring-boot-devtools
runtime
mysql
mysql-connector-java
runtime
org.springframework.boot
spring-boot-starter-test
test
com.baomidou
mybatisplus-spring-boot-starter
${mybatisplus-spring-boot-starter.version}
com.baomidou
mybatis-plus
${mybatisplus.version}
com.alibaba
fastjson
${fastjson.version}
com.alibaba
druid-spring-boot-starter
1.1.9
com.jayway.restassured
rest-assured
2.9.0
io.springfox
springfox-swagger2
2.2.2
io.springfox
springfox-swagger-ui
2.2.2
org.springframework.boot
spring-boot-maven-plugin
# Tomcat
server:
tomcat:
uri-encoding: UTF-8
max-threads: 1000
min-spare-threads: 30
port: 8080
connection-timeout: 5000
#datasource
spring:
datasource:
name: fendo
url: jdbc:mysql://localhost:3306/fendo_plus_boot?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC&useSSL=false
username: root
password: root
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
initialSize: 5
minIdle: 5
maxActive: 20
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
maxPoolPreparedStatementPerConnectionSize: 20
spring.datasource.filters: stat,wall,log4j
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
# jackson时间格式化
jackson:
time-zone: GMT+8
date-format: yyyy-MM-dd HH:mm:ss
thymeleaf:
cache: false
prefix: classpath:/templates/
suffix: .html
mode: LEGACYHTML5
encoding: UTF-8
check-template: false
enabled: false
resources: # 指定静态资源的路径
static-locations: classpath:/static/,classpath:/views/
mvc:
view:
prefix: /WEB-INF/
suffix: .jsp
# Mybatis-Plus 配置
mybatis-plus:
mapper-locations: classpath:/mapper/*Mapper.xml
typeAliasesPackage: com.fendo.mybatis.plus.entity
typeEnumsPackage: com.fendo.mybatis.plus.entity.enums
# global-config:
# id-type: 2
# field-strategy: 2
# db-column-underline: true
# refresh-mapper: true
# #capital-mode: true
# #key-generator: com.baomidou.springboot.xxx
# logic-delete-value: 0
# logic-not-delete-value: 1
# sql-injector: com.baomidou.mybatisplus.mapper.LogicSqlInjector
# #meta-object-handler: com.baomidou.springboot.xxx
# #sql-injector: com.baomidou.springboot.xxx
# configuration:
# map-underscore-to-camel-case: true
# cache-enabled: false
global-config:
id-type: 3 #0:数据库ID自增 1:用户输入id 2:全局唯一id(IdWorker) 3:全局唯一ID(uuid)
db-column-underline: false
refresh-mapper: true
configuration:
map-underscore-to-camel-case: true
cache-enabled: true #配置的缓存的全局开关
lazyLoadingEnabled: true #延时加载的开关
multipleResultSetsEnabled: true #开启的话,延时加载一个属性时会加载该对象全部属性,否则按需加载属性
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #打印sql语句,调试用
创建MyBatis-Plus配置类MybatisPlusConfig
/**
* projectName: fendo-plus-boot
* fileName: MybatisPlusConfig.java
* packageName: com.fendo.mybatis.plus.config
* date: 2018-01-12 23:13
* copyright(c) 2017-2020 xxx公司
*/
package com.fendo.mybatis.plus.config;
import com.baomidou.mybatisplus.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.plugins.PerformanceInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @version: V1.0
* @author: fendo
* @className: MybatisPlusConfig
* @packageName: com.fendo.mybatis.plus.config
* @description: Mybatis-plus配置类
* @data: 2018-01-12 23:13
**/
@Configuration
@MapperScan("com.fendo.mybatis.plus.mapper*")
public class MybatisPlusConfig {
/**
* mybatis-plus SQL执行效率插件【生产环境可以关闭】
*/
@Bean
public PerformanceInterceptor performanceInterceptor() {
return new PerformanceInterceptor();
}
/**
* 分页插件
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
}
首先创建User表
CREATE TABLE `user` (
`id` varchar(32) NOT NULL,
`name` varchar(255) DEFAULT NULL,
`age` int(2) DEFAULT NULL,
`sex` int(2) DEFAULT NULL,
`create_by` varchar(255) DEFAULT NULL,
`create_date` datetime DEFAULT NULL,
`update_by` varchar(255) DEFAULT NULL,
`update_date` datetime DEFAULT NULL,
`remarks` varchar(255) DEFAULT NULL,
`del_flag` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Controller测试类如下:
/**
* projectName: mybatis-plus
* fileName: UserController.java
* packageName: com.fendo.mybatis.plus.controller
* date: 2018-03-24 19:07
* copyright(c) 2017-2020 xxx公司
*/
package com.fendo.mybatis.plus.controller;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.plugins.pagination.PageHelper;
import com.fendo.mybatis.plus.common.utils.IdGen;
import com.fendo.mybatis.plus.entity.UserEntity;
import com.fendo.mybatis.plus.entity.enums.AgeEnum;
import com.fendo.mybatis.plus.entity.enums.SexEnum;
import com.fendo.mybatis.plus.service.UserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @version: V1.0
* @author: fendo
* @className: UserController
* @packageName: com.fendo.mybatis.plus.controller
* @description: 用户Controller
* @data: 2018-03-24 19:07
**/
@RestController
@RequestMapping("/user")
@Api("用户操作接口")
public class UserController {
@Autowired
private UserService userService;
/**
* 分页 PAGE
*/
@GetMapping("/page")
@ApiOperation(value = "用户分页数据", response = UserEntity.class)
@ApiResponse(code = 200, message = "success")
public Page test() {
return userService.selectPage(new Page(0,12));
}
/**
* AR 部分测试
*/
@GetMapping("/insert")
public Page insert() {
UserEntity user = new UserEntity(IdGen.getUUID(), "testAr", AgeEnum.ONE, SexEnum.FEMALE);
System.err.println("删除所有:" + user.delete(null));
user.insert();
System.err.println("查询插入结果:" + user.selectById().toString());
user.setName("mybatis-plus-ar");
System.err.println("更新:" + user.updateById());
return user.selectPage(new Page(0, 12), null);
}
/**
* 增删改查 CRUD
*/
@GetMapping("/crud")
public UserEntity crud() {
System.err.println("删除一条数据:" + userService.deleteById("85349feb19f04fa78a7a717f4dce031f"));
System.err.println("deleteAll:" + userService.deleteAll());
String IdGens = IdGen.getUUID();
System.err.println("插入一条数据:" + userService.insert(new UserEntity(IdGens, "张三", AgeEnum.TWO, SexEnum.FEMALE)));
UserEntity user = new UserEntity("张三", AgeEnum.TWO, SexEnum.MALE);
boolean result = userService.insert(user);
// 自动回写的ID
String id = user.getId();
System.err.println("插入一条数据:" + result + ", 插入信息:" + user.toString());
System.err.println("查询:" + userService.selectById(id).toString());
System.err.println("更新一条数据:" + userService.updateById(new UserEntity(IdGens, "三毛", AgeEnum.ONE, SexEnum.FEMALE)));
for (int i = 0; i < 5; ++i) {
userService.insert(new UserEntity( IdGen.getUUID(), "张三" + i, AgeEnum.ONE, SexEnum.FEMALE));
}
Page userListPage = userService.selectPage(new Page(1, 5), new EntityWrapper<>(new UserEntity()));
System.err.println("total=" + userListPage.getTotal() + ", current list size=" + userListPage.getRecords().size());
return userService.selectById(IdGens);
}
/**
* 插入 OR 修改
*/
@GetMapping("/save")
public UserEntity save() {
String IdGens = IdGen.getUUID();
UserEntity user = new UserEntity(IdGens, "王五", AgeEnum.ONE, SexEnum.FEMALE);
userService.insertOrUpdate(user);
return userService.selectById(IdGens);
}
@GetMapping("/add")
public Object addUser() {
UserEntity user = new UserEntity(IdGen.getUUID(), "张三'特殊`符号", AgeEnum.TWO, SexEnum.FEMALE);
JSONObject result = new JSONObject();
result.put("result", userService.insert(user));
return result;
}
@GetMapping("/selectsql")
public Object getUserBySql() {
JSONObject result = new JSONObject();
result.put("records", userService.selectListBySQL());
return result;
}
/**
* 7、分页 size 一页显示数量 current 当前页码
* 方式一:http://localhost:8080/user/page?size=1¤t=1
* 方式二:http://localhost:8080/user/pagehelper?size=1¤t=1
*/
// 参数模式分页
@GetMapping("/pages")
public Object page(Page page) {
return userService.selectPage(page);
}
// ThreadLocal 模式分页
@GetMapping("/pagehelper")
public Object pagehelper(Page page) {
PageHelper.setPagination(page);
page.setRecords(userService.selectList(null));
page.setTotal(PageHelper.freeTotal());//获取总数并释放资源 也可以 PageHelper.getTotal()
return page;
}
/**
* 测试事物
* http://localhost:8080/user/test_transactional
* 访问如下并未发现插入数据说明事物可靠!!
* http://localhost:8080/user/test
*
* 启动 Application 加上 @EnableTransactionManagement 注解其实可无默认貌似就开启了
* 需要事物的方法加上 @Transactional 必须的哦!!
*/
@Transactional
@GetMapping("/test_transactional")
public void testTransactional() {
String IdGens = IdGen.getUUID();
userService.insert(new UserEntity(IdGens, "测试事物", AgeEnum.ONE, SexEnum.FEMALE));
System.out.println(" 这里手动抛出异常,自动回滚数据 : " + IdGens);
throw new RuntimeException();
}
}
创建测试类GeneratorStart
/**
* projectName: fendo-plus-boot
* fileName: GeneratorStart.java
* packageName: com.fendo.shiro.generator
* date: 2018-01-15 19:59
* copyright(c) 2017-2020 xxx公司
*/
package com.gzsys.modules.gen;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.builder.ConfigBuilder;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.DbType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @version: V1.0
* @author: fendo
* @className: GeneratorStart
* @packageName: com.gzsys.modules.gen
* @description: 代码生成器
* @data: 2018-01-15 19:59
**/
public class GeneratorStart {
public static void main(String[] args) {
String packageName = "com.gzsys.modules.yun";
boolean serviceNameStartWithI = false;//user -> UserService, 设置成true: user -> IUserService
generateByTables(serviceNameStartWithI, packageName, "USER_LOGIN");
}
private static void generateByTables(boolean serviceNameStartWithI, String packageName, String... tableNames) {
// 全局配置
GlobalConfig config = new GlobalConfig();
AutoGenerator mpg = new AutoGenerator();
String dbUrl = "jdbc:oracle:thin:@//106.14.160.67:1521/test";
DataSourceConfig dataSourceConfig = new DataSourceConfig();
dataSourceConfig.setDbType(DbType.ORACLE)
.setUrl(dbUrl)
.setUsername("test")
.setPassword("Eru43wPo")
.setDriverName("oracle.jdbc.driver.OracleDriver");
// 策略配置
StrategyConfig strategyConfig = new StrategyConfig();
strategyConfig
.setCapitalMode(true) // 全局大写命名 ORACLE 注意
.setEntityLombokModel(false) //实体 是否为lombok模型(默认 false)
.setDbColumnUnderline(true) //表名、字段名、是否使用下划线命名
.setNaming(NamingStrategy.underline_to_camel) //表名生成策略
.setInclude(tableNames);//修改替换成你需要的表名,多个表名传数组
// strategyConfig.setExclude(new String[]{"test"}); // 排除生成的表
// 自定义实体父类
strategyConfig.setSuperEntityClass("com.gzsys.common.persistence.BaseEntity");
// 自定义实体,公共字段
strategyConfig.setSuperEntityColumns(new String[] { "ID", "CREATE_TIME", "CREATE_NAME" , "UPDATE_TIME", "UPDATE_NAME", "STATE"});
// 自定义 mapper 父类
// strategyConfig.setSuperMapperClass("com.baomidou.demo.TestMapper");
// 自定义 service 父类
//strategyConfig.setSuperServiceClass("com.baomidou.demo.TestService");
// 自定义 service 实现类父类
//strategyConfig.setSuperServiceImplClass("com.baomidou.demo.TestServiceImpl");
// 自定义 controller 父类
strategyConfig.setSuperControllerClass("com.gzsys.common.base.controller.BaseController");
// 【实体】是否生成字段常量(默认 false)
// public static final String ID = "test_id";
// strategyConfig.setEntityColumnConstant(true);
// 【实体】是否为构建者模型(默认 false)
// public User setName(String name) {this.name = name; return this;}
// strategyConfig.setEntityBuliderModel(true);
config.setActiveRecord(true) //是否 开启 ActiveRecord 模式
.setAuthor("fendo")
.setOutputDir("d:\\codeGen")
.setFileOverride(true)
.setActiveRecord(true)
.setEnableCache(false)// XML 二级缓存
.setBaseResultMap(true)// XML ResultMap
.setBaseColumnList(false);// XML columList
if (!serviceNameStartWithI) {
config.setServiceName("%sService"); //自定义Service后戳,注意 %s 会自动填充表实体属性!
}
// 注入自定义配置,可以在 VM 中使用 cfg.abc 【可无】
InjectionConfig cfg = new InjectionConfig() {
@Override
public void initMap() {
Map map = new HashMap();
map.put("abc", this.getConfig().getGlobalConfig().getAuthor() + "-mp");
this.setMap(map);
}
};
// 自定义 xxList.jsp 生成
List focList = new ArrayList();
//focList.add(new FileOutConfig("/template/list.jsp.vm") {
// @Override
// public String outputFile(TableInfo tableInfo) {
// // 自定义输入文件名称
// return "D://my_" + tableInfo.getEntityName() + ".jsp";
// }
//});
//cfg.setFileOutConfigList(focList);
//mpg.setCfg(cfg);
// 调整 xml 生成目录演示
focList.add(new FileOutConfig("/templates/mapper.xml.vm") {
@Override
public String outputFile(TableInfo tableInfo) {
return "d:\\codeGen/resources/mapping/modules/yun/" + tableInfo.getEntityName() + ".xml";
}
});
cfg.setFileOutConfigList(focList);
mpg.setCfg(cfg);
// 关闭默认 xml 生成,调整生成 至 根目录
TemplateConfig tc = new TemplateConfig();
tc.setXml(null);
mpg.setTemplate(tc);
// 自定义模板配置,可以 copy 源码 mybatis-plus/src/main/resources/templates 下面内容修改,
// 放置自己项目的 src/main/resources/templates 目录下, 默认名称一下可以不配置,也可以自定义模板名称
// TemplateConfig tc = new TemplateConfig();
// tc.setController("...");
// tc.setEntity("...");
// tc.setMapper("...");
// tc.setXml("...");
// tc.setService("...");
// tc.setServiceImpl("...");
// 如上任何一个模块如果设置 空 OR Null 将不生成该模块。
// mpg.setTemplate(tc);
//生成文件 配置
mpg.setGlobalConfig(config) //全局 相关配置
.setDataSource(dataSourceConfig) //数据源配置
.setStrategy(strategyConfig) //数据库表配置
.setPackageInfo( //包 相关配置
new PackageConfig() //跟包相关的配置项
.setParent(packageName) //父包名。如果为空,将下面子包名必须写全部, 否则就只需写子包名
.setController("controller") //Controller包名
.setEntity("entity") //entity包名
//.setXml("/")
)
.execute();
}
private void generateByTables(String packageName, String... tableNames) {
generateByTables(true, packageName, tableNames);
}
}