1.MyBatis-Plus简介
1.1概念
- 简称MP,是一个MyBatis的增强工具,在MyBatis的基础上只做增强不做改变,为简化开发,提高效率而生。
1.1.1MP的特征
无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
损耗小:启动即会自动注入基本 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 操作智能分析阻断,也可自定义拦截规则,预防误操作
1.2MP架构
1.2整合MyBatis-Plus
对于Mybatis整合MP有常常有三种用法,分别是Mybatis+MP、Spring+Mybatis+MP、Spring Boot+Mybatis+MP。
创建数据库及表
创建工程
MP
创建子module
MyBatis实现查询User
MyBatis+MP实现查询User
第一步,将UserMapper继承BaseMapper,将拥有了BaseMapper中的所有方法
第二步,使用MP中的MybatisSqlSessionFactoryBuilder进程构建(是自己创建生成的)
Spring+MyBatis+MP
创建子module
实现查询User
SpringBoot+MyBatis+MP
使用SpringBoot将进一步的简化MP的整合,需要注意的是,由于使用SpringBoot需要继承parent,所以需要重新创 建工程,并不是创建子Module。
创建工程
导入坐标
创建编写application.properties
编写pojo
编写mapper接口 (加上注解@Runwith,@SpringBootTest:使用的是SpringBoot项目)
编写启动类
编写测试类
1.3通用CRUD
- 了解到通过继承BaseMapper就可以获取到各种各样的单表操作,接下来我们将详细讲解这些 操作。
1.3.1插入操作
- 方法定义:int insert(T entity);
- 测试用例
@RunWith(SpringRunner.class) @SpringBootTest public class TestUserMapper { @Autowired private UserMapper userMapper; @Test public void testInsert() { User user = new User(); user.setMail("zhugeliang@itcast.cn"); user.setAge(25); user.setUserName("zhugeliang"); user.setName("诸葛亮"); user.setPassword("123456"); user.setAddress("广州"); int result = this.userMapper.insert(user); //result数据库受影响的行数 System.out.println("result => " + result); //获取自增长后的id值, 自增长后的id值会回填到user对象中 System.out.println("id => " + user.getId()); }
修改User对象 ,使id自增长@TableId(type = IdType.AUTO) 不会出现其他的数字
@TableId(type = IdType.AUTO) //使id自增长 private Long id;
@TableField :在MP中通过@TableField注解可以指定字段的一些属性
- 对象中的属性名和字段名不一致的问题(非驼峰)
- 对象中的属性字段在表中不存在的问题
// 插入数据时进行填充 @TableField(select = false, fill = FieldFill.INSERT) //查询时不返回该字段的值 private String password; private String name; private Integer age; @TableField(value = "email") //指定数据表中字段名 private String mail; @TableField(exist = false) private String address; //在数据库表中是不存在的
1.3.2更新操作
- 一种是根据id更新,
- 一种是根据条件更新
根据id更新:(测试用例)
@Test public void testUpdateById() { User user = new User(); user.setId(1L); //条件,根据id更新 L是数据类型 此处就是id = 1 的信息会被全部修改 user.setAge(19); //更新的字段 user.setPassword("666666"); int result = this.userMapper.updateById(user); System.out.println("result => " + result); }
根据条件更新:
第一种方式: QueryWrapper
@Test public void testUpdate() { User user = new User(); user.setAge(20); //更新的字段 user.setPassword("8888888"); QueryWrapper<User> wrapper = new QueryWrapper<>(); //两个参数:column:字段,val:字段的值 wrapper.eq("user_name", "zhangsan"); //匹配user_name = zhangsan 的用户数据 //根据条件做更新 int result = this.userMapper.update(user, wrapper); System.out.println("result => " + result); }
第二种方式: UpdateWrapper
@Test public void testUpdate2() { //可以同时设置字段和条件 UpdateWrapper<User> wrapper = new UpdateWrapper<>(); wrapper.set("age", 21).set("password", "999999") //更新的字段 .eq("user_name", "zhangsan"); //更新的条件 //根据条件做更新 int result = this.userMapper.update(null, wrapper); System.out.println("result => " + result); }
1.3.3删除操作
- 根据id删除:deleteById()
@Test public void testDeleteById(){ // 根据id删除数据 int result = this.userMapper.deleteById(2L); System.out.println("result => " + result); }
根据columnMap 条件删除记录 deleteByMap()
@Test public void testDeleteByMap(){ Map<String,Object> map = new HashMap<>(); map.put("user_name", "zhangsan"); map.put("password", "999999"); // 根据map删除数据,多条件之间是and关系 int result = this.userMapper.deleteByMap(map); System.out.println("result => " + result); }
根据entity 条件删除记录 Wrapper< User> wrapper
@Test public void testDelete(){ //用法一: QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.eq("user_name", "caocao1") .eq("password", "123456"); //用法二:推荐 User user = new User(); user.setPassword("123456"); user.setUserName("caocao"); QueryWrapper<User> wrapper = new QueryWrapper<>(user); // 根据包装条件做删除 int result = this.userMapper.delete(wrapper); System.out.println("result => " + result); }
根据id 批量删除 id 不能为null 已经 empty deleteBatchIds()
@Test public void testDeleteBatchIds(){ // 根据id批量删除数据 传递集合 里面传递是就是id的值 则会删除掉对应的id的数据 int result = this.userMapper.deleteBatchIds(Arrays.asList(10L, 11L)); System.out.println("result => " + result); }
1.3.4查询操作
- 根据id查询、批量查询、查询单条数据、查询列表、分页查询等操作
- 根据id查询 selectById
@Test public void testSelectById() { User user = this.userMapper.selectById(2L); System.out.println(user); }
根据id批量查询 selectBatchIds
@Test public void testSelectBatchIds(){ // 根据id批量查询数据 通过集合接受数据 查询 id = 2,3,4,100的数据 没有的id值是查询不到的 List<User> users = this.userMapper.selectBatchIds(Arrays.asList(2L, 3L, 4L, 100L)); for (User user : users) { System.out.println(user); } }
查询一条数据:selectOne
@Test public void testSelectOne(){ //T selectOne(@Param("ew") Wrapper<T> queryWrapper); QueryWrapper<User> wrapper = new QueryWrapper<>(); //查询条件 wrapper.eq("password", "123456"); // 查询的数据超过一条时,会抛出异常 User user = this.userMapper.selectOne(wrapper); System.out.println(user); }
查询总记录数 selectCount()
@Test public void testSelectCount(){ // Integer selectCount(@Param("ew") Wrapper<T> queryWrapper); QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.gt("age", 20); // 条件:年龄大于20岁的用户 // 根据条件查询数据条数 Integer count = this.userMapper.selectCount(wrapper); System.out.println("count => " + count); }
查询数据的列表 selectList()
@Test public void testSelectList(){ // List<T> selectList(@Param("ew") Wrapper<T> queryWrapper); QueryWrapper<User> wrapper = new QueryWrapper<>(); //设置查询条件 val:模糊查询匹配 wrapper.like("email", "itcast"); List<User> users = this.userMapper.selectList(wrapper); for (User user : users) { System.out.println(user); } }
分页查询 selectPage()
- 配置分页插件:
@Conf@Configuration @MapperScan("cn.itcast.mp.mapper") //设置mapper接口的扫描包 public class MybatisPlusConfig { @Bean //配置分页插件 public PaginationInterceptor paginationInterceptor(){ return new PaginationInterceptor(); } }
测试用例
// 测试分页查询 要配置一个分页插件 @Test public void testSelectPage(){ //IPage<T> selectPage(IPage<T> page, @Param("ew") Wrapper<T> queryWrapper); Page<User> page = new Page<>(3,1); //查询第一页,查询1条数据 QueryWrapper<User> wrapper = new QueryWrapper<>(); //设置查询条件 wrapper.like("email", "itcast"); IPage<User> iPage = this.userMapper.selectPage(page, wrapper); System.out.println("数据总条数: " + iPage.getTotal()); System.out.println("数据总页数: " + iPage.getPages()); System.out.println("当前页数: " + iPage.getCurrent()); //getRecords获取数据 List<User> records = iPage.getRecords(); for (User record : records) { System.out.println(record); } }
1.3.5SQL注入原理
在MP中,ISqlInjector负责SQL的注入工作,它是一个接口,AbstractSqlInjector是它的实现类
在AbstractSqlInjector中,主要是由inspectInject()方法进行注入的
在实现方法中, methodList.forEach(m -> m.inject(builderAssistant, mapperClass, modelClass, tableInfo)); 是关键,循环遍历方法,进行注入。
1.4配置
1.4.1基本配置
configLocation
- 单独设置MyBatis配置文档,就讲配置路径配置到configLocation中。
- SpringBoot配置方式:
mybatis-plus.config-location = classpath:mybatis-config.xml
mapperLocations
在 Mapper 中有自定义方法(XML 中有自定义实现),需要进行该配置,指定Mapper 所对应的 XML 文件位置
SpringBoot配置方式:
mybatis-plus.mapper-locations = classpath*:mybatis/*.xml
typeAliasesoPackge
- MyBaits 别名包扫描路径,通过该属性可以给包中的类注册别名,注册后在 Mapper 对应的 XML 文件中可以直接使 用类名,而不用使用全限定的类名(即 XML 中调用的时候不用包含包名)。
mybatis-plus.type-aliases-package = cn.itcast.mp.pojo
1.4.2进阶配置
MyBatis的原生支持配置,通过MyBatis xml配置文件的形式进行配置
mapUnderscoreToCamelCase
类型:boolean
默认值:true
是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN(下划线命名) 到经典 Java 属 性名 aColumn(驼峰命名) 的类似映射。
#关闭自动驼峰映射,该参数不能和mybatis-plus.config-location同时存在 mybatis-plus.configuration.map-underscore-to-camel-case=false
cacheEnable
- 类型:booolean
- 默认值:true
- 全局地开启或关闭配置文件中的所有映射器已经配置的任何缓存,默认为 true。
mybatis-plus.configuration.cache-enabled=false
1.4.3 DB策略配置
- idType
- 类型: com.baomidou.mybatisplus.annotation.IdType
- 默认值:ID_WORKER
tablePrefix
- 类型:String
- 默认值:null
表示前缀,全局配置后可以省略@Tablename()配置
- SpringBoot:
mybatis-plus.global-config.db-config.id-type=auto
1.5条件构造器
在Mp中 wrapper 中重要的实现类有:AbstractWrapper AbstractChainWrapper是重点实现 ,前者重点学习
QueryWrapper(LambdaQueryWrapper) 和 UpdateWrapper(LambdaUpdateWrapper) 的父类 用于生成 sql 的 where 条件, entity 属性也用于生成 sql 的 where 条件 注意: entity 生成的 where 条件与 使用各个 api 生成 的 where 条件没有任何关联行为
allEq
- 说明:
- allEq(Map params)
- allEq(Map params, boolean null2IsNull)
- allEq(boolean condition,
- Map params, boolean null2IsNull)
测试用例:
@Test public void testAllEq(){ Map<String,Object> params = new HashMap<>(); params.put("name", "李四"); params.put("age", "20"); params.put("password", null); QueryWrapper<User> wrapper = new QueryWrapper<>(); // 生成的sql语句:SELECT id,user_name,name,age,email AS mail FROM tb_user WHERE password IS NULL AND name = ? AND age = ? // wrapper.allEq(params); //生成的sql语句:SELECT id,user_name,name,age,email AS mail FROM tb_user WHERE name = ? AND age = ? // wrapper.allEq(params, false); //SELECT id,user_name,name,age,email AS mail FROM tb_user WHERE age = ? //过滤 满足条件才能进行过滤 // wrapper.allEq((k, v) -> (k.equals("age") || k.equals("id")) , params); //SELECT id,user_name,name,age,email AS mail FROM tb_user WHERE name = ? AND age = ? wrapper.allEq((k, v) -> (k.equals("age") || k.equals("id") || k.equals("name")) , params); List<User> users = this.userMapper.selectList(wrapper); for (User user : users) { System.out.println(user); } }
基本比较操作:
eq
等于 =
ne
不等于 <>
gt
大于 >
ge
大于等于 >=
lt
小于 <
le
小于等于 <=
between
BETWEEN 值1 AND 值2
notBetween
NOT BETWEEN 值1 AND 值2
in 字段
IN (value.get(0), value.get(1), …)
notIn 字段
NOT IN (v0, v1, …)测试用例:
@Test public void testEq() { QueryWrapper<User> wrapper = new QueryWrapper<>(); // 生成的sql语句:SELECT id,user_name,password,name,age,email FROM tb_user WHERE password = ? AND age >= ? AND name IN (?,?,?) wrapper.eq("password", "123456") .ge("age", 20) .in("name", "李四", "王五", "赵六"); List<User> users = this.userMapper.selectList(wrapper); for (User user : users) { System.out.println(user); } }
模糊查询
like 模糊前后的值
LIKE ‘%值%’
例: like(“name”, “王”) —> name like ‘%王%’
notLike 不模糊
NOT LIKE '%值%
例: notLike(“name”, “王”) —> name not like ‘%王%’
likeLeft 左模糊
LIKE ‘%值’
例: likeLeft(“name”, “王”) —> name like ‘%王’
likeRight 右模糊
LIKE ‘值%’
例: likeRight(“name”, “王”) —> name like ‘王%’
- 测试用例:
@Test public void testLike(){ QueryWrapper<User> wrapper = new QueryWrapper<>(); //生成的sql语句: SELECT id,user_name,name,age,email AS mail FROM tb_user WHERE name LIKE ? // 传入参数:%五(String) wrapper.likeLeft("name", "五");//就把五前面的 字 或者 其他内容 给忽略掉 就是查询以 五 结尾的 List<User> users = this.userMapper.selectList(wrapper); for (User user : users) { System.out.println(user); } }
排序
排序 ORDER BY 字段
orderByAsc 降序
排序:ORDER BY 字段, … ASC
例: orderByAsc(“id”, “name”) —> order by id ASC,name ASC
orderByDesc 升序
排序:ORDER BY 字段, … DESC
例: orderByDesc(“id”, “name”) —> order by id DESC,name DESC测试用例:
@Test public void testOrderByAgeDesc(){ QueryWrapper<User> wrapper = new QueryWrapper<>(); //按照年龄倒序排序 //生成的sql语句: SELECT id,user_name,name,age,email AS mail FROM tb_user ORDER BY age DESC wrapper.orderByDesc("age"); List<User> users = this.userMapper.selectList(wrapper); for (User user : users) { System.out.println(user); } }
逻辑查询
- or
- 拼接OR
- 主动调用OR表示紧接着下一个方法不是用and链接
- and
- AND嵌套
测试用例:
@Test public void testOr(){ QueryWrapper<User> wrapper = new QueryWrapper<>(); //生成的sql语句: SELECT id,user_name,name,age,email AS mail FROM tb_user WHERE name = ? OR age = ? //若是中间没有or()操作,则是用and链接 返回的结果就会不一样 //or不走索引 用 Union拼接 wrapper.eq("name", "王五").or().eq("age", 21); List<User> users = this.userMapper.selectList(wrapper); for (User user : users) { System.out.println(user); } }
select 操作
- 在MP中查询中,默认查询所有的字段,可以通过指定字段进行查询
测试用例:
@Test public void testSelect(){ QueryWrapper<User> wrapper = new QueryWrapper<>(); //生成的sql语句:SELECT id,name,age FROM tb_user WHERE name = ? OR age = ? wrapper.eq("name", "王五") .or() .eq("age", 21) .select("id","name","age"); //指定查询 id name age 的字段 List<User> users = this.userMapper.selectList(wrapper); for (User user : users) { System.out.println(user); } }
2.Active Record (AR)
动态语言(PHP 、Ruby等)
属于ORM(对象关系层), 表映射到记录,记录映射到对象,字段映射到对象属性。遵循的命名和配置惯例 ,可以快速实现模型的操作。
ActiveRecord的主要思想:
每一个数据表对应创建一个类,类的每一个对象实例对应于数据库中表的一行记录;表的每个字段在类中都有相应的Field
ActiveRecord同时负责把自己持久化,在ActiveRecore中封装了对应的数据库的访问,即CRUD;
ActiveRecord的一种领域模型,封装了部分业务逻辑
2.1开启AR
- 将实体对象继承Model即可
import cn.itcast.mp.enums.SexEnum; import com.baomidou.mybatisplus.annotation.*; import com.baomidou.mybatisplus.extension.activerecord.Model; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @NoArgsConstructor @AllArgsConstructor public class User extends Model<User> { //继承Model类 private Long id; private String userName; private String password; private String name; private Integer age; private String mail; }
2.2根据主键查询
@RunWith(SpringRunner.class) @SpringBootTest public class TestUserMapper2 { @Test public void testSelectById(){ User user = new User(); user.setId(16L); User user1 = user.selectById(); System.out.println(user1); } }
2.3插入(新增)数据
@Test public void testInsert(){ User user = new User(); user.setUserName("diaochan"); user.setPassword("123456"); user.setAge(20); user.setName("貂蝉"); user.setMail("diaochan@itcast.cn"); user.setVersion(1); user.setSex(SexEnum.WOMAN); //使用的是枚举 // 调用AR的insert方法进行插入数据 boolean insert = user.insert(); System.out.println("result => " + insert); }
2.4更新操作
@Test public void testUpdate(){ User user = new User(); user.setId(13L);// 查询条件 user.setAge(31); // 更新的数据 在13中设置年龄为31岁 boolean result = user.updateById(); System.out.println("result => " + result); }
2.5删除操作
@Test public void testDelete(){ User user = new User(); user.setId(13L);//删除id为13行的数据 boolean delete = user.deleteById(); System.out.println("result => " + delete); }
2.6根据条件查询
@Test public void testSelect(){ User user = new User(); QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.ge("age", 30); //大于等于30岁的用户查询出来 使用ge 这个比较运算符 比较运算符在上面有笔记 List<User> users = user.selectList(wrapper); for (User user1 : users) { System.out.println(user1); } }
3.Oracle主键Sequence
4.插件
4.1 MyBatis的插件机制
MyBatis 允许在已映射语句执行过程中的某一点进行拦截调用 (拦截器)
Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
ParameterHandler (getParameterObject, setParameters)
ResultSetHandler (handleResultSets, handleOutputParameters)
StatementHandler (prepare, parameterize, batch, update, query)
拦截了Executor接口部分方法(update、query、commit、rollback)
对上面的方法概述:
拦截执行器的方法
拦截参数的处理
拦截结果集的处理
拦截sql语法构建的处理插件的方法
import org.apache.ibatis.executor.Executor; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.plugin.*; import java.util.Properties; @Intercepts({@Signature( type= Executor.class,//指定拦截的类型 Executor method = "update",//拦截的是update方法 args = {MappedStatement.class,Object.class})}) public class MyInterceptor implements Interceptor { @Override public Object intercept(Invocation invocation) throws Throwable { //拦截方法,具体业务逻辑编写的位置 return invocation.proceed(); } @Override public Object plugin(Object target) { //这次方法会执行多次,因为要执行上面的四个点(Executor、ParameterHandler 、ResultSetHandler 、StatementHandler )总共执行四次 //创建target对象的代理对象,目的是将当前拦截器加入到该对象中 return Plugin.wrap(target, this); } @Override public void setProperties(Properties properties) { //属性设置 } }
4.2执行分析插件
- 在MP中提供了对SQL执行的分析的插件,可用作阻断全表更新、删除的操作,
- 注意:该插件仅适用于开发环境,不 适用于生产环境。 主要是由于性能不行
SpringBoot配置:
@Bean //SQL分析插件 public SqlExplainInterceptor sqlExplainInterceptor(){ SqlExplainInterceptor sqlExplainInterceptor = new SqlExplainInterceptor(); List<ISqlParser> list = new ArrayList<>(); list.add(new BlockAttackSqlParser()); //全表更新、删除的阻断器 sqlExplainInterceptor.setSqlParserList(list); return sqlExplainInterceptor; }
测试用例 : 查询结构是错误的 被拦截了才会出错 ,说明拦截器生效了
/** * 测试全表更新,SQL分析器阻断效果 */ @Test public void testUpdateAll(){ User user = new User(); user.setAge(110); // 更新的数据 boolean result = user.update(null); // 条件为null 则是全表更新 System.out.println("result => " + result); }
当执行全表更新时,会抛出异常,这样有效防止了一些误操作
4.3性能分析插件
- 性能分析拦截器,用于输出每条 SQL 语句及其执行时间,可以设置最大执行时间,超过时间会抛出异常。
- 注意:该插件只用于开发环境,不建议生产环境使用。(性能问题)
mybatis-config.xml配置文件
<!-- 性能分析插件 --> <plugin interceptor="com.baomidou.mybatisplus.extension.plugins.PerformanceInterceptor"> <!--最大的执行时间,单位为毫秒--> <property name="maxTime" value="100"/> <!--对输出的SQL做格式化,默认为false--> <property name="format" value="true"/> </plugin>
4.4乐观锁插件
4.4.1主要适用的场景
目的: 当要更新一条记录的时候,希望这条记录没有被别人更新
并发操作
实现方式:
取出记录时,获取当前的版本(version)
更新时,带上这个版本(version)
执行更新时,set version = newVersion where version = oldVersion
如果版本(version)不对,则更新失败
乐观锁防止多个事务对同一个数据同时修改
4.4.2配置方式:
- Spring .xml
<bean class="com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor"/>
Spring boot
@Bean public OptimisticLockerInterceptor optimisticLockerInterceptor() { return new OptimisticLockerInterceptor(); }
- MyBatis 全局配置
- 注解实体字段为实体添加@Version注解
- 添加@version注解,设置初始值为1
ALTER TABLE `tb_user` ADD COLUMN `version` int(10) NULL AFTER `email`; UPDATE `tb_user` SET `version`='1';
为User实体对象添加version字段,并且添加@version注解
@Version //乐观锁的版本字段 private Integer version;
测试:
@Test public void testUpdateVersion(){ User user = new User(); user.setId(2L);// 查询条件 //先拿到版本 再设置id User userVersion = user.selectById(); user.setAge(23); // 更新的数据 user.setVersion(userVersion.getVersion()); // 当前的版本信息 boolean result = user.updateById(); System.out.println("result => " + result); }
特别说明:
支持的数据类型:int 、Integer、long、Long、Date、Timestamp、LocalDateTime
整数类型下 newVersion = oldVersion + 1
newVersioni 会回写到entity中
仅支持两种操作
updateById(id)
update(entity wrapper)
在update(entity ,warpper) 方法下,wrapper不能复用!!
5.Sql注入器
5.1编写MyBaseMapper 泛型里面传入的类不知道是哪一个 T 代表全部 类
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import java.util.List; public interface MyBaseMapper<T> extends BaseMapper<T> { List<T> findAll(); // 扩展其他的方法 }
然后其他的Mapper类就继承这个MyBaseMapper接口 相当于嵌套
import cn.itcast.mp.pojo.User; public interface UserMapper extends MyBaseMapper<User> { User findById(Long id); }
5.2编写MySallnjector
继承DefaultSqlInjector 进行扩展 ,不能直接继承 AbstractSqlInjector 因为继承了这个 导致BaseMapper中的方法失效
import com.baomidou.mybatisplus.core.injector.AbstractMethod; import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector; import java.util.ArrayList; import java.util.List; public class MySqlInjector extends DefaultSqlInjector { @Override public List<AbstractMethod> getMethodList() { List<AbstractMethod> list = new ArrayList<>(); // 获取父类中的集合 list.addAll(super.getMethodList()); // 再扩充自定义的方法 list.add(new FindAll()); return list; } }
5.3编写FindAll
import com.baomidou.mybatisplus.core.injector.AbstractMethod; import com.baomidou.mybatisplus.core.metadata.TableInfo; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.mapping.SqlSource; public class FindAll extends AbstractMethod { @Override public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) { String sql = "select * from " + tableInfo.getTableName(); SqlSource sqlSource = languageDriver.createSqlSource(configuration,sql, modelClass); return this.addSelectMappedStatement(mapperClass, "findAll", sqlSource, modelClass, tableInfo); } }
5.4注册到Spring容器中
在MyBatisPlusConfig中
@Bean public MySqlInjector mySqlInjector(){ return new MySqlInjector(); }
测试:
@Test public void testFindAll(){ List<User> userlist = this.userMapper.findAll(); for (User user : users) { System.out.println(user); } }
6.自动填充功能
6.4添加注解@TableFiled注解
为password添加自动填充功能,在新增数据时有效
FieldFill提供了多种模式选择
6.5编写MyMetaObjectHandler
测试:
7.逻辑删除
删除操作需要实现逻辑删除 ,所谓逻辑删除就是将数据标记为删除,而并非真正 的物理删除(非DELETE操作),查询时需要携带状态条件,确保被标记的数据不被查询到。这样做的目的就是避免 数据被真正的删除。
7.1修改表结构
- 为tb_user表增加deleted字段,用于表示数据是否被删除,1代表删除,0代表未删除。
7.2配置
application.properties
7.3测试
8.通用的枚举
解决繁琐的配置 ,通常表示一些固定的属性 比如:性别(男、女),学历:(小、初、高、大)
8.1修改表结构
ALTER TABLE `tb_user` ADD COLUMN `sex` int(1) NULL DEFAULT 1 COMMENT '1-男,2-女' AFTER `deleted`;
8.2定义枚举
package cn.itcast.mp.enums; import com.baomidou.mybatisplus.core.enums.IEnum; import com.fasterxml.jackson.annotation.JsonValue; public enum SexEnum implements IEnum<Integer> { MAN(1,"男"), WOMAN(2,"女"); private int value; private String desc; SexEnum(int value, String desc) { this.value = value; this.desc = desc; } @Override public Integer getValue() { return this.value; } @Override public String toString() { return this.desc; } }
8.3配置
application.properties文件
8.4修改实体
8.5测试
9.代码生成器
- AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。
9.1创建工程
9.2代码
10.MyBatisX快速开发插件
MyBatisX 是一款基于 IDEA 的快速开发插件,为效率而生。
9.2代码
10.MyBatisX快速开发插件
MyBatisX 是一款基于 IDEA 的快速开发插件,为效率而生。
7.1修改表结构
- 为tb_user表增加deleted字段,用于表示数据是否被删除,1代表删除,0代表未删除。
7.2配置
application.properties
7.3测试
8.通用的枚举
解决繁琐的配置 ,通常表示一些固定的属性 比如:性别(男、女),学历:(小、初、高、大)
8.1修改表结构
ALTER TABLE `tb_user` ADD COLUMN `sex` int(1) NULL DEFAULT 1 COMMENT '1-男,2-女' AFTER `deleted`;
8.2定义枚举
package cn.itcast.mp.enums; import com.baomidou.mybatisplus.core.enums.IEnum; import com.fasterxml.jackson.annotation.JsonValue; public enum SexEnum implements IEnum<Integer> { MAN(1,"男"), WOMAN(2,"女"); private int value; private String desc; SexEnum(int value, String desc) { this.value = value; this.desc = desc; } @Override public Integer getValue() { return this.value; } @Override public String toString() { return this.desc; } }
8.3配置
application.properties文件
8.4修改实体
8.5测试
9.代码生成器
AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。
9.1创建工程
9.2代码
10.MyBatisX快速开发插件
MyBatisX 是一款基于 IDEA 的快速开发插件,为效率而生。
- 功能:
- Java 与 XML 调回跳转
- Mapper 方法自动生成 XML