登山则情满于山,观海则意溢于海。这篇文章主要讲述mybatis-plus详细使用教程相关的知识,希望能为你提供帮助。
mybatis-plus使用教程欢迎关注博主公众号「java大师」, 专注于分享Java领域干货文章http://www.javaman.cn/jszw/mybatis-plus
什么是Mybatis-PlusMyBatis-Plus (opens new window)(简称 MP)是一个 MyBatis (opens new window)的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
文章图片
- 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
- 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
- 强大的 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、Postgre、SQLServer 等多种数据库
- 内置性能分析插件:可输出 SQL 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
- 内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作
(来自官网的例子)
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)
);
2、插入表数据
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\');
3、新建springboot工程,引入mubatis-plus依赖
<
dependency>
<
groupId>
com.baomidou<
/groupId>
<
artifactId>
mybatis-plus-boot-starter<
/artifactId>
<
version>
3.1.0<
/version>
<
/dependency>
4、application.yml配置mysql数据源
# DataSource Config
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost/mp_plus?serverTimezone=GMT%2B8&
characterEncoding=UTF-8&
allowMultiQueries=true
username: root
password: 123456
5、使用mybatis-plus
- entity
@Data @AllArgsConstructor @NoArgsConstructor public class User { @TableId(type = IdType.AUTO) //采用数据库自增 private long id; private String name; private int age; private String email; }
- mapper接口
// 在对应的Mapper上面继承基本的类 BaseMapper
@Repository
public interface UserMapper extends BaseMapper<
User>
{
// 所有的CRUD操作都已经编写完成了
}
- springboot测试启动类增加@MapperScan扫描注解
@MapperScan("com.mpstudy.mp.mapper")
- 测试
@MapperScan("com.mpstudy.mp.mapper")
@SpringBootTest
class MpApplicationTests {// 继承了BaseMapper,所有的方法都来自己父类
// 我们也可以编写自己的扩展方法!
@Autowired
UserMapper userMapper;
@Test
void contextLoads() {
List<
User>
users = userMapper.selectList(null);
//条件构造器先不用
users.forEach(System.out::println);
}
}
- 测试结果
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@75023c53]
User(id=1, name=Jone, age=18, email=test1@baomidou.com, createTime=null, updateTime=null)
User(id=2, name=Jack, age=20, email=test2@baomidou.com, createTime=null, updateTime=null)
User(id=3, name=Tom, age=28, email=test3@baomidou.com, createTime=null, updateTime=null)
User(id=4, name=Sandy, age=21, email=test4@baomidou.com, createTime=null, updateTime=null)
User(id=5, name=Billie, age=24, email=test5@baomidou.com, createTime=null, updateTime=null)
日志配置1、在application.yml中新增配置
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl //标准输出
2、日志配置完成后,在控制台就会生成相应的日志
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@75023c53] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@688197093 wrapping com.mysql.jdbc.JDBC4Connection@3610f277] will not be managed by Spring
==>
Preparing: SELECT id,name,age,email,create_time,update_time FROM user
==>
Parameters:
<
==Columns: id, name, age, email, create_time, update_time
<
==Row: 1, Jone, 18, test1@baomidou.com, null, null
<
==Row: 2, Jack, 20, test2@baomidou.com, null, null
<
==Row: 3, Tom, 28, test3@baomidou.com, null, null
<
==Row: 4, Sandy, 21, test4@baomidou.com, null, null
<
==Row: 5, Billie, 24, test5@baomidou.com, null, null
CRUD详解 1、插入操作
@Test
void insert(){
User user = new User();
user.setName("java大师1");
user.setAge(11);
user.setEmail("111000@qq.com");
int insert = userMapper.insert(user);
}
上面的的例子中没有插入用户id,在User类中已经设置了自动,也就是跟着数据库的配置走(数据库中已经设置了自增)
?
2、更新操作
@Test
void update(){
User user = new User();
user.setId(6);
user.setAge(38);
int i = userMapper.updateById(user);
//传入的是个对象
System.out.println(i);
}
3、时间戳自动填充
实现方法有如下两种:
文章图片
- 编写时间戳自动填充注解
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.reflection.MetaObject; import org.springframework.stereotype.Component; import java.util.Date; @Slf4j @Component public class MyMetaObjectHandler implements MetaObjectHandler { @Override public void insertFill(MetaObject metaObject) { log.info("开始填充"); this.setFieldValByName("createTime",new Date(),metaObject); this.setFieldValByName("updateTime",new Date(),metaObject); }@Override public void updateFill(MetaObject metaObject) { log.info("更新填充"); this.setFieldValByName("updateTime",new Date(),metaObject); } }
- 在实体类的字段上增加TableField注解
@Data @AllArgsConstructor @NoArgsConstructor public class User {@TableId(type = IdType.AUTO) private long id; private String name; private int age; private String email; //创建时间注解 @TableField(fill = FieldFill.INSERT) private Date createTime; //修改时间注解 @TableField(fill = FieldFill.INSERT_UPDATE) private Date updateTime; }
- 测试
@Test void insert(){ User user = new User(); user.setName("公众号:java大师"); user.setAge(2); user.setEmail("javadashi@qq.com"); int insert = userMapper.insert(user); }
// 测试删除
@Test
public void testDeleteById(){
userMapper.deleteById(1);
} // 通过id批量删除
@Test
public void testDeleteBatchId(){
userMapper.deleteBatchIds(Arrays.asList(2,3,4));
} // 通过map删除
@Test
public void testDeleteMap(){
HashMap<
String, Object>
map = new HashMap<
>
();
map.put("name","java大师");
userMapper.deleteByMap(map);
5、逻辑删除
相对于物理删除来说,我们需要对数据进行留档,所以需要对删除的数据也要保留,这就要用到逻辑删除
- 在数据库表中增加sfyx(是否有效)字段
文章图片
- 实体类增加属性
@TableLogic //逻辑删除 private Integer sfyx;
- 配置逻辑删除组件并被springboot所管理
// 逻辑删除组件! @Bean public ISqlInjector sqlInjector() { return new LogicSqlInjector(); }
- 修改application.yml增加配置
mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config: db-config: logic-delete-value: 0//已删除 logic-not-delete-value: 1//未删除
- 【mybatis-plus详细使用教程】测试(看到虽然执行的的delete方法,但是实际的sql是update语句)
@Test void testDelete(){ int i = userMapper.deleteById(2); }
Creating a new SqlSession SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@456bcb74] was not registered for synchronization because synchronization is not active JDBC Connection [HikariProxyConnection@66747889 wrapping com.mysql.jdbc.JDBC4Connection@4dd90166] will not be managed by Spring ==> Preparing: UPDATE user SET sfyx=0 WHERE id=? AND sfyx=1 ==> Parameters: 2(Integer) < ==Updates: 1
- 配置分页拦截器
@Bean public PaginationInterceptor paginationInterceptor(){ return new PaginationInterceptor(); }
- 使用Page对象
@Test void testPage(){ Page< User> page = new Page< > (1,3); userMapper.selectPage(page, null); page.getRecords().forEach(System.out::println); System.out.println(page.getTotal()); }
- 创建VO对象
import com.mpstudy.mp.entity.User; import lombok.Data; @Data public class UserClassVo extends User { private String className; }
- UserMapper中增加getAllUsers方法,通过select注解编写sql
@Repository
public interface UserMapper extends BaseMapper<
User>
{
@Select("select a.*,b.name as class_name from user a,class b,user_class c where a.id=c.user_id and b.id=c.class_id ")
List<
UserClassVo>
getAllUsers();
}
- 测试
@Test void testGetAllUsers(){ List< UserClassVo> allUsers = userMapper.getAllUsers(); allUsers.forEach(System.out::println); }
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@47f04e4d] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@843410864 wrapping com.mysql.jdbc.JDBC4Connection@5f5827d0] will not be managed by Spring
==>
Preparing: select a.*,b.name as class_name from user a,class b,user_class c where a.id=c.user_id and b.id=c.class_id
==>
Parameters:
<
==Columns: id, name, age, email, create_time, update_time, sfyx, class_name
<
==Row: 2, Jack, 20, test2@baomidou.com, null, 2021-09-20 18:05:06.0, 0, 小二班
<
==Row: 3, Tom, 28, test3@baomidou.com, null, 2021-09-20 18:04:27.0, 1, 大一班
8、多表分页查询
- 创建VO对象
import com.mpstudy.mp.entity.User; import lombok.Data; @Data public class UserClassVo extends User { private String className; }
- UserMapper中增加getUsersByPage方法,通过select注解编写sql
@Repository public interface UserMapper extends BaseMapper< User> { //传入IPage对象和QueryWrapper条件构造器 //sql通过${ew.customSqlSegment}去解析构造器内容 @Select("select a.*,c.name as class_name from user a left join user_class b on a.id=b.user_id left join class c on b.class_id = c.id " + "${ew.customSqlSegment} ") IPage< UserClassVo> getUsersByPage(IPage< UserClassVo> page,@Param(Constants.WRAPPER) QueryWrapper wrapper); }
- 测试
@Test void testGetUsersByPage(){ Page< UserClassVo> page = new Page< > (2,2); QueryWrapper< UserClassVo> wrapper = new QueryWrapper< > (); wrapper.likeRight("a.name","java"); userMapper.getUsersByPage(page,wrapper); page.getRecords().forEach(System.out::println); }
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@f438904] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@766089249 wrapping com.mysql.jdbc.JDBC4Connection@62cba181] will not be managed by Spring
JsqlParserCountOptimize sql=select a.*,c.name as class_name from user a left join user_class b on a.id=b.user_id left join class c on b.class_id = c.id WHERE a.name LIKE ?
==>
Preparing: SELECT COUNT(1) FROM user a LEFT JOIN user_class b ON a.id = b.user_id LEFT JOIN class c ON b.class_id = c.id WHERE a.name LIKE ?
==>
Parameters: java%(String)
<
==Columns: COUNT(1)
<
==Row: 3
==>
Preparing: select a.*,c.name as class_name from user a left join user_class b on a.id=b.user_id left join class c on b.class_id = c.id WHERE a.name LIKE ? LIMIT ?,?
==>
Parameters: java%(String), 0(Long), 2(Long)
<
==Columns: id, name, age, email, create_time, update_time, sfyx, class_name
<
==Row: 6, java大师, 38, javadashi@qq.com, null, 2021-09-20 18:04:29.0, 1, 小二班
<
==Row: 7, java大师, 11, javadashi@qq.com, null, 2021-09-20 18:04:29.0, 1, 大一班
<
==Total: 2
10、条件构造器
支持:allEq,eq,isNull等等,具体见:条件构造器 | MyBatis-Plus (baomidou.com)
- 测试
@Test
void testWrapper01(){
// 查询name不为空的用户,并且邮箱不为空的用户,年龄大于等于12记录
QueryWrapper<
User>
wrapper = new QueryWrapper<
>
();
wrapper.isNotNull("name").isNotNull("create_time").gt("age",12);
List<
User>
users = userMapper.selectList(wrapper);
users.forEach(System.out::println);
}@Test
void testWrapper02(){
// 查询年龄18到24之间的记录
QueryWrapper<
User>
wrapper = new QueryWrapper<
>
();
wrapper.between("age",18,24);
List<
User>
users = userMapper.selectList(wrapper);
users.forEach(System.out::println);
}@Test
void testWrapper03(){
// 名字中带java的记录
QueryWrapper<
User>
wrapper = new QueryWrapper<
>
();
wrapper.likeRight("name","java");
List<
User>
users = userMapper.selectList(wrapper);
users.forEach(System.out::println);
}
11、性能分析插件
- 导入插件
@Bean @Profile({"dev"}) //开发环境运行 public PerformanceInterceptor performanceInterceptor(){ PerformanceInterceptor interceptor = new PerformanceInterceptor(); interceptor.setFormat(true); //格式化sql interceptor.setMaxTime(20); //设置超时时长,单位毫秒 return interceptor; }
- application.xml设置为dev开发模式
# DataSource Config spring: profiles: active: dev
- 测试(日志最后1行显示超时报错)
org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException: ### Error querying database.Cause: com.baomidou.mybatisplus.core.exceptions.MybatisPlusException:The SQL execution time is too large, please optimize ! ### The error may exist in com/mpstudy/mp/mapper/UserMapper.java (best guess) ### The error may involve com.mpstudy.mp.mapper.UserMapper.getUsersByPage ### The error occurred while handling results ### SQL: select a.*,c.name as class_name from user a left join user_class b on a.id=b.user_id left join class c on b.class_id = c.id WHERE a.name LIKE ? LIMIT ?,? ### Cause: com.baomidou.mybatisplus.core.exceptions.MybatisPlusException:The SQL execution time is too large, please optimize !
- 导入依赖
< dependency> < groupId> com.baomidou< /groupId> < artifactId> mybatis-plus-generator< /artifactId> < version> 3.1.0< /version> < /dependency>
- 代码生成
import com.baomidou.mybatisplus.annotation.DbType; import com.baomidou.mybatisplus.annotation.FieldFill; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.generator.AutoGenerator; import com.baomidou.mybatisplus.generator.InjectionConfig; import com.baomidou.mybatisplus.generator.config.DataSourceConfig; import com.baomidou.mybatisplus.generator.config.GlobalConfig; import com.baomidou.mybatisplus.generator.config.PackageConfig; import com.baomidou.mybatisplus.generator.config.StrategyConfig; import com.baomidou.mybatisplus.generator.config.po.TableFill; import com.baomidou.mybatisplus.generator.config.rules.DateType; import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; //代码自动生成器 public class CodeGenerator {public static void main(String[] args) { //构建一个 代码自动生成器 对象 AutoGenerator autoGenerator = new AutoGenerator(); //1、全局配置 GlobalConfig gc = new GlobalConfig(); String oPath = System.getProperty("user.dir"); //得到当前项目的路径 gc.setOutputDir(oPath + "/src/main/java"); //生成文件输出根目录 gc.setOpen(false); //生成完成后不弹出文件框 gc.setFileOverride(true); //文件覆盖 gc.setAuthor("ryan"); // 作者 gc.setServiceName("%sService"); //去除Service的I前綴 gc.setIdType(IdType.ID_WORKER); gc.setDateType(DateType.ONLY_DATE); gc.setSwagger2(true); autoGenerator.setGlobalConfig(gc); ///2、数据源配置 DataSourceConfig dsc = new DataSourceConfig(); dsc.setDbType(DbType.MYSQL); //设置数据库类型 dsc.setUrl("jdbc:mysql://localhost:3306/mp_plus?useSSL=false& useUnicode=true& characterEncoding=utf-8& serverTimezone=GMT%2B8"); //指定数据库 dsc.setDriverName("com.mysql.jdbc.Driver"); dsc.setUsername("root"); dsc.setPassword("root"); autoGenerator.setDataSource(dsc); //3、包的配置 PackageConfig pc = new PackageConfig(); pc.setModuleName("mp"); pc.setParent("com.mpstudy"); pc.setEntity("pojo"); pc.setMapper("mapper"); pc.setService("service"); pc.setController("controller"); autoGenerator.setPackageInfo(pc); // 4、策略配置 StrategyConfig strategy = new StrategyConfig(); strategy.setInclude("user","user_class","class"); // 设置要映射的表名 strategy.setNaming(NamingStrategy.underline_to_camel); strategy.setColumnNaming(NamingStrategy.underline_to_camel); strategy.setEntityLombokModel(true); // 自动lombok; strategy.setLogicDeleteFieldName("deleted"); strategy.setTablePrefix("tb_"); //去掉表的前缀 // 自动填充配置 TableFill gmtCreate = new TableFill("create_time", FieldFill.INSERT); TableFill gmtModified = new TableFill("update_time", FieldFill.INSERT_UPDATE); ArrayList< TableFill> tableFills = new ArrayList< > (); tableFills.add(gmtCreate); tableFills.add(gmtModified); strategy.setTableFillList(tableFills); // 乐观锁 strategy.setVersionFieldName("version"); strategy.setRestControllerStyle(true); strategy.setControllerMappingHyphenStyle(true); autoGenerator.setStrategy(strategy); //不加这个会报空指针异常 InjectionConfig injectionConfig = new InjectionConfig() { //自定义属性注入:abc //在.ftl(或者是.vm)模板中,通过${cfg.abc}获取属性 @Override public void initMap() { Map< String, Object> map = new HashMap< > (); map.put("abc", this.getConfig().getGlobalConfig().getAuthor() + "-mp"); this.setMap(map); } }; //自定义配置 autoGenerator.setCfg(injectionConfig); // 执行生成 autoGenerator.execute(); } }
推荐阅读
- CentOS7.9安装配置KickStart
- 查看MySQL冗余索引和未使用的索引
- MAC下安装WordPress网站开发框架XAMPP
- Redis 发布订阅
- windows环境下如何安装Oracle 11g(超级详细-保姆)
- 高可用延迟队列设计与实现
- k8s nginx-ingress部署
- tigervnc远程桌面连接教程-linux
- 如何为Android应用程序创建WordPress REST API