MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
官网:mybatis.plus 或 Redirect
愿景
我们的愿景是成为 MyBatis 最好的搭档,就像 魂斗罗 中的 1P、2P,基友搭配,效率翻倍。
文档地址:mybatis.plus
源码地址:https://github.com/baomidou/mybatis-plus
无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer2005、SQLServer 等多种数据库
支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
支持 XML 热加载:Mapper 对应的 XML 支持热加载,对于简单的 CRUD 操作,甚至可以无 XML 启动
支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
支持关键词自动转义:支持数据库关键词(order、key......)自动转义,还可自定义关键词
内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
内置性能分析插件:可输出 Sql 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作
内置 Sql 注入剥离器:支持 Sql 注入剥离,有效预防 Sql 注入攻击
Mybatis-Plus是由baomidou(苞米豆)组织开发并且开源的,目前该组织大概有30人左右。
码云地址:baomidou: 苞米豆,为提高生产率而生!
对于Mybatis整合MP有常常有三种用法,分别是Mybatis+MP、Spring+Mybatis+MP、Spring Boot+Mybatis+MP。
-- 创建测试表
CREATE TABLE `tb_user` (`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',`user_name` varchar(20) NOT NULL COMMENT '用户名',`password` varchar(20) NOT NULL COMMENT '密码',`name` varchar(30) DEFAULT NULL COMMENT '姓名',`age` int(11) DEFAULT NULL COMMENT '年龄',`email` varchar(50) DEFAULT NULL COMMENT '邮箱',PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;-- 插入测试数据
INSERT INTO `tb_user` (`id`, `user_name`, `password`, `name`, `age`, `email`) VALUES ('1', 'zhangsan', '123456', '张三', '18', 'test1@itcast.cn');
INSERT INTO `tb_user` (`id`, `user_name`, `password`, `name`, `age`, `email`) VALUES ('2', 'lisi', '123456', '李四', '20', 'test2@itcast.cn');
INSERT INTO `tb_user` (`id`, `user_name`, `password`, `name`, `age`, `email`) VALUES ('3', 'wangwu', '123456', '王五', '28', 'test3@itcast.cn');
INSERT INTO `tb_user` (`id`, `user_name`, `password`, `name`, `age`, `email`) VALUES ('4', 'zhaoliu', '123456', '赵六', '21', 'test4@itcast.cn');
INSERT INTO `tb_user` (`id`, `user_name`, `password`, `name`, `age`, `email`) VALUES ('5', 'sunqi', '123456', '孙七', '24', 'test5@itcast.cn');
导入依赖:
pom
jar
log4j.properties:
log4j.rootLogger=DEBUG,A1log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.COnversionPattern=[%t] [%c]-[%p] %m%n
1.编写mybatis-config.xml文件
2.User实体对象
package mytest.pojo;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {private Long id;private String user_Name;private String password;private String name;private Integer age;private String email;
}
3.UserMapper
package mytest.mapper;import mytest.pojo.User;import java.util.List;public interface UserMapper {List
4.UserMapper.xml
5.TestMybatis
package mytest;import mytest.mapper.UserMapper;
import mytest.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;import java.io.InputStream;public class TestMybatis {@Testpublic void testFindAll() throws Exception{String cOnfig="mybatis-config.xml";InputStream inputStream = Resources.getResourceAsStream(config);SqlSessionFactory sqlSessiOnFactory= new SqlSessionFactoryBuilder().build(inputStream);SqlSession sqlSession = sqlSessionFactory.openSession();UserMapper userMapper = sqlSession.getMapper(UserMapper.class);//测试查询for (User user : userMapper.findAll()) {System.out.println(user);}}
}
1.将UserMapper继承BaseMapper,将拥有BaseMapper的所有方法
package mytest.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import mytest.pojo.User;import java.util.List;public interface UserMapper extends BaseMapper
2.第二步,使用MP中的MybatisSqlSessionFactoryBuilder进程构建:
package mytest;import com.baomidou.mybatisplus.core.MybatisSqlSessionFactoryBuilder;
import mytest.mapper.UserMapper;
import mytest.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.junit.Test;import java.io.InputStream;
import java.util.List;public class TestMybatis {@Testpublic void testFindAll() throws Exception{String cOnfig="mybatis-config.xml";InputStream inputStream = Resources.getResourceAsStream(config);SqlSessionFactory sqlSessiOnFactory= new MybatisSqlSessionFactoryBuilder().build(inputStream);SqlSession sqlSession = sqlSessionFactory.openSession();UserMapper userMapper = sqlSession.getMapper(UserMapper.class);//测试查询
// List
}
简单说明:
由于使用了MybatisSqlSessionFactoryBuilder进行了构建,继承的BaseMapper中的方法就载入到了SqlSession中,所以就可以直接使用相关的方法;
引入了Spring框架,数据源、构建等工作就交给了Spring管理。
第一步,编写jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis_plus?useUnicode=true&characterEncoding=utf8&autoRecOnnect=true&allowMultiQueries=true&useSSL=false
jdbc.username=root
jdbc.password=123456789
第二步,编写applicationContext.xml
第三步,编写User对象以及UserMapper接口:
package mytest.pojo;import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName("tb_user")
public class User {private Long id;private String userName;private String password;private String name;private Integer age;private String email;
}
package mytest.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import mytest.pojo.User;import java.util.List;public interface UserMapper extends BaseMapper
}
第四步,编写测试用例:(在test目录下添加resources目录,加入jdbc.properties和applicationApplication.xml)
package mytest;import mytest.mapper.UserMapper;
import mytest.pojo.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;import java.util.List;@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locatiOns= "classpath:applicationContext.xml")
public class TestSpringMP {@Autowiredprivate UserMapper userMapper;@Testpublic void testSelectList(){List
使用SpringBoot将进一步的简化MP的整合,需要注意的是,由于使用SpringBoot需要继承parent,所以需要重新创建工程,并不是创建子Module。
log4j.properties:
log4j.rootLogger=DEBUG,A1log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.COnversionPattern=[%t] [%c]-[%p] %m%n
spring.application.name = itcast-mp-springbootspring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/mp?useUnicode=true&characterEncoding=utf8&autoRecOnnect=true&allowMultiQueries=true&useSSL=false
spring.datasource.username=root
spring.datasource.password=root
package cn.itcast.mp.pojo;import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName("tb_user")
public class User {private Long id;private String userName;private String password;private String name;private Integer age;private String email;
}
package cn.itcast.mp.mapper;import cn.itcast.mp.pojo.User;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;public interface UserMapper extends BaseMapper
}
package cn.itcast.mp;import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;@MapperScan("cn.itcast.mp.mapper") //设置mapper接口的扫描包
@SpringBootApplication
public class MyApplication {public static void main(String[] args) {SpringApplication.run(MyApplication.class, args);}}
package cn.itcast.mp;import cn.itcast.mp.mapper.UserMapper;
import cn.itcast.mp.pojo.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;import java.util.List;@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {@Autowiredprivate UserMapper userMapper;@Testpublic void testSelect() {List
/*** 插入一条记录** @param entity 实体对象*/int insert(T entity);
package cn.itcast.mp;import cn.itcast.mp.mapper.UserMapper;
import cn.itcast.mp.pojo.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;import java.util.List;@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {@Autowiredprivate UserMapper userMapper;@Testpublic void testInsert(){User user = new User();user.setAge(20);user.setEmail("test@itcast.cn");user.setName("曹操");user.setUserName("caocao");user.setPassword("123456");int result = this.userMapper.insert(user); //返回的result是受影响的行数,并不是自增后的idSystem.out.println("result = " + result); System.out.println(user.getId()); //自增后的id会回填到对象中}}
可以看到,数据已经写入到了数据库,但是,id的值不正确,我们期望的是数据库自增长,实际是MP生成了id的值写入到了数据库。
如何设置id的生成策略呢?
MP支持的id策略:
该类型可以通过自己注册自动填充插件进行填充package com.baomidou.mybatisplus.annotation;import lombok.Getter;/*** 生成ID类型枚举类** @author hubin* @since 2015-11-10*/
@Getter
public enum IdType {/*** 数据库ID自增*/AUTO(0),/*** 该类型为未设置主键类型*/NONE(1),/*** 用户输入ID*
}
修改User对象:
package cn.itcast.mp.pojo;import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName("tb_user")
public class User {@TableId(type = IdType.AUTO) //指定id类型为自增长private Long id;private String userName;private String password;private String name;private Integer age;private String email;
}
在MP中,更新操作有2种,一种是根据id更新,另一种是根据条件更新。
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {@Autowiredprivate UserMapper userMapper;@Testpublic void testUpdateById() {User user = new User();user.setId(6L); //主键user.setAge(21); //更新的字段//根据id更新,更新不为null的字段this.userMapper.updateById(user);}}
/*** 根据 whereEntity 条件,更新记录** @param entity 实体对象 (set 条件值,可以为 null)* @param updateWrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句)*/int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper
package cn.itcast.mp;import cn.itcast.mp.mapper.UserMapper;
import cn.itcast.mp.pojo.User;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import net.minidev.json.writer.UpdaterMapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;import java.util.List;@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {@Autowiredprivate UserMapper userMapper;@Testpublic void testUpdate() {User user = new User();user.setAge(22); //更新的字段//更新的条件QueryWrapper
或者,通过UpdateWrapper进行更新:
@Testpublic void testUpdate() {//更新的条件以及字段UpdateWrapper
/*** 根据 ID 删除** @param id 主键ID*/
int deleteById(Serializable id);
package cn.itcast.mp;import cn.itcast.mp.mapper.UserMapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {@Autowiredprivate UserMapper userMapper;@Testpublic void testDeleteById() {//执行删除操作int result = this.userMapper.deleteById(6L);System.out.println("result = " + result);}}
/*** 根据 columnMap 条件,删除记录** @param columnMap 表字段 map 对象*/int deleteByMap(@Param(Constants.COLUMN_MAP) Map
package cn.itcast.mp;import cn.itcast.mp.mapper.UserMapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;import java.util.HashMap;
import java.util.Map;@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {@Autowiredprivate UserMapper userMapper;@Testpublic void testDeleteByMap() {Map
/*** 根据 entity 条件,删除记录** @param wrapper 实体对象封装操作类(可以为 null)*/
int delete(@Param(Constants.WRAPPER) Wrapper
package cn.itcast.mp;import cn.itcast.mp.mapper.UserMapper;
import cn.itcast.mp.pojo.User;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;import java.util.HashMap;
import java.util.Map;@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {@Autowiredprivate UserMapper userMapper;@Testpublic void testDeleteByMap() {User user = new User();user.setAge(20);user.setName("张三");//将实体对象进行包装,包装为操作条件QueryWrapper
/*** 删除(根据ID 批量删除)** @param idList 主键ID列表(不能为 null 以及 empty)*/int deleteBatchIds(@Param(Constants.COLLECTION) Collection extends Serializable> idList);
package cn.itcast.mp;import cn.itcast.mp.mapper.UserMapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;import java.util.Arrays;@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {@Autowiredprivate UserMapper userMapper;@Testpublic void testDeleteByMap() {//根据id集合批量删除int result = this.userMapper.deleteBatchIds(Arrays.asList(1L,10L,20L));System.out.println("result = " + result);}}
MP提供了多种查询操作,包括根据id查询、批量查询、查询单条数据、查询列表、分页查询等操作。
/*** 根据 ID 查询** @param id 主键ID*/T selectById(Serializable id);
package cn.itcast.mp;import cn.itcast.mp.mapper.UserMapper;
import cn.itcast.mp.pojo.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {@Autowiredprivate UserMapper userMapper;@Testpublic void testSelectById() {//根据id查询数据User user = this.userMapper.selectById(2L);System.out.println("result = " + user);}}
/*** 查询(根据ID 批量查询)** @param idList 主键ID列表(不能为 null 以及 empty)*/
List
package cn.itcast.mp;import cn.itcast.mp.mapper.UserMapper;
import cn.itcast.mp.pojo.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;import java.util.Arrays;
import java.util.List;@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {@Autowiredprivate UserMapper userMapper;@Testpublic void testSelectBatchIds() {//根据id集合批量查询List
/*** 根据 entity 条件,查询一条记录** @param queryWrapper 实体对象封装操作类(可以为 null)*/
T selectOne(@Param(Constants.WRAPPER) Wrapper
package cn.itcast.mp;import cn.itcast.mp.mapper.UserMapper;
import cn.itcast.mp.pojo.User;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {@Autowiredprivate UserMapper userMapper;@Testpublic void testSelectOne() {QueryWrapper
/*** 根据 Wrapper 条件,查询总记录数** @param queryWrapper 实体对象封装操作类(可以为 null)*/
Integer selectCount(@Param(Constants.WRAPPER) Wrapper
package cn.itcast.mp;import cn.itcast.mp.mapper.UserMapper;
import cn.itcast.mp.pojo.User;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {@Autowiredprivate UserMapper userMapper;@Testpublic void testSelectCount() {QueryWrapper
/*** 根据 entity 条件,查询全部记录** @param queryWrapper 实体对象封装操作类(可以为 null)*/
List
package cn.itcast.mp;import cn.itcast.mp.mapper.UserMapper;
import cn.itcast.mp.pojo.User;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;import java.util.List;@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {@Autowiredprivate UserMapper userMapper;@Testpublic void testSelectList() {QueryWrapper
//根据大于小于条件查找符合条件的列表@Testpublic void testSelectList1() {QueryWrapper
/*** 根据 entity 条件,查询全部记录(并翻页)** @param page 分页查询条件(可以为 RowBounds.DEFAULT)* @param queryWrapper 实体对象封装操作类(可以为 null)*/
IPage
拦截器:
package mytest.Config;import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
@MapperScan("mytest.mapper") //设置mapper接口的扫描包
public class MybatisPlusConfig {/*** 分页插件*/@Beanpublic MybatisPlusInterceptor paginationInterceptor() {//定义mp拦截器MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();//添加具体的拦截器mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());return mybatisPlusInterceptor;}
}
配置分页插件:
package cn.itcast.mp;import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
@MapperScan("cn.itcast.mp.mapper") //设置mapper接口的扫描包
public class MybatisPlusConfig {/*** 分页插件*/@Beanpublic PaginationInterceptor paginationInterceptor() {return new PaginationInterceptor();}
}
测试用例:
package cn.itcast.mp;import cn.itcast.mp.mapper.UserMapper;
import cn.itcast.mp.pojo.User;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;import java.util.List;@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {@Autowiredprivate UserMapper userMapper;//分页查询@Testpublic void testSelectByPage(){//第几页 每页几条Page
//虚拟页面传过来null值,进行查询数据@Testpublic void selectByAgeUpAndDown(){UserQuery userQuery = new UserQuery();userQuery.setAge(20);userQuery.setAge2(25);
////null判定//方法一
// LambdaQueryWrapper
// if( null != userQuery.getAge()){
// lqw.gt(User::getAge,userQuery.getAge());//大于小的
// }
// if ( null != userQuery.getAge2()){
// lqw.lt(User::getAge,userQuery.getAge2());//小于大的
// }
// List
// System.out.println(userList);//方法二LambdaQueryWrapper
//查询投影@Testpublic void testAnyoneField(){//用QueryWrapper查询只有id,username,email的投影
// QueryWrapper
// qw.select("id","user_name","email");
// List
// System.out.println(users);//用LambdaQueryWrapper查询只有id,username,email的投影
// LambdaQueryWrapper
// lqw.select(User::getId,User::getUserName,User::getEmail);
// List
// System.out.println(users);}
//查询投影@Testpublic void testAnyoneField(){//查询计数
// QueryWrapper
// qw.select("count(*) as count");
// List
前面我们已经知道,MP在启动后会将BaseMapper中的一系列的方法注册到meppedStatements中,那么究竟是如何注入的呢?流程又是怎么样的?下面我们将一起来分析下。
在MP中,ISqlInjector负责SQL的注入工作,它是一个接口,AbstractSqlInjector是它的实现类,实现关系如下:
在AbstractSqlInjector中,主要是由inspectInject()方法进行注入的,如下:
@Override
public void inspectInject(MapperBuilderAssistant builderAssistant, Class> mapperClass) {Class> modelClass = extractModelClass(mapperClass);if (modelClass != null) {String className = mapperClass.toString();Set
}
在实现方法中,methodList.forEach(m -> m.inject(builderAssistant, mapperClass, modelClass, tableInfo));
是关键,循环遍历方法,进行注入。
最终调用抽象方法injectMappedStatement进行真正的注入:
/*** 注入自定义 MappedStatement** @param mapperClass mapper 接口* @param modelClass mapper 泛型* @param tableInfo 数据库表反射信息* @return MappedStatement*/public abstract MappedStatement injectMappedStatement(Class> mapperClass, Class> modelClass, TableInfo tableInfo);
以SelectById为例查看:
public class SelectById extends AbstractMethod {@Overridepublic MappedStatement injectMappedStatement(Class> mapperClass, Class> modelClass, TableInfo tableInfo) {SqlMethod sqlMethod = SqlMethod.LOGIC_SELECT_BY_ID;SqlSource sqlSource = new RawSqlSource(configuration, String.format(sqlMethod.getSql(),sqlSelectColumns(tableInfo, false),tableInfo.getTableName(), tableInfo.getKeyColumn(), tableInfo.getKeyProperty(),tableInfo.getLogicDeleteSql(true, false)), Object.class);return this.addSelectMappedStatement(mapperClass, sqlMethod.getMethod(), sqlSource, modelClass, tableInfo);}
}
可以看到,生成了SqlSource对象,再将SQL通过addSelectMappedStatement方法添加到meppedStatements中。
//条件查询@Testpublic void testIf(){//两个if条件测试
// LambdaQueryWrapper
// lqw.eq(User::getUserName,"lisi").eq(User::getPassword,"123456");
// User user = userMapper.selectOne(lqw);
// System.out.println(user);//范围查询LambdaQueryWrapper
// lqw.between(User::getAge,10,20);//10~20之间lqw.ge(User::getAge,10).le(User::getAge,20);//10~20之间带等号
// lqw.gt(User::getAge,10).lt(User::getAge,20);//10~20之间List
// LambdaQueryWrapper
// //模糊查询 likelqw.like(User::getUserName,"a");//是否含有a %a%
// lqw.likeRight(User::getUserName,"l");//左边匹配 l%lqw.likeLeft(User::getUserName,"l");//左边匹配 %l
// List
// System.out.println(userList);}
1.数据库字段名与类属性名不同
2.数据库中字段缺少类中的属性
3.密码属性查出效果删除
4.表名与类名不匹配
主键生成的策略有哪几种方式?
不同的表应用不同的id生成策略
日志:自增(1,2,3,4,……)
购物订单:特殊规则(FQ23948AK3843)
外卖单:关联地区日期等信息(10 04 20200314 34 91)
关系表:可省略id
……
省去每次都写表前缀和id的自增类型
mybatis-plus:
global-config:
db-config:
id-type: assign_id
table-prefix: tbl_
id生成策略全局配置
表名前缀全局配置
MyBatisPlus是否支持批量操作?
//删除指定多条数据
List
list.add(1402551342481838081L);
list.add(1402553134049501186L);
list.add(1402553619611430913L);userDao.deleteBatchIds(list);
//查询指定多条数据
List
list.add(1L);
list.add(3L);
list.add(4L);
userDao.selectBatchIds(list);
在实际环境中,如果想删除一条数据,是否会真的从数据库中删除该条数据?
删除操作业务问题:业务数据从数据库中丢弃
逻辑删除:为数据设置是否可用状态字段,删除时设置状态字段为不可用状态,数据保留在数据库中
①:数据库表中添加逻辑删除标记字段
②:实体类中添加对应字段,并设定当前字段为逻辑删除标记字段
package mytest.domain;import com.baomidou.mybatisplus.annotation.*;import lombok.Data;@Data
public class User {private Long id;//逻辑删除字段,标记当前记录是否被删除@TableLogic(value = "0",delval = "1")private Integer deleted;}
③:配置逻辑删除字面值
mybatis-plus:
global-config:
db-config:
table-prefix: tbl_
# 逻辑删除字段名
logic-delete-field: deleted
# 逻辑删除字面值:未删除为0
logic-not-delete-value: 0
# 逻辑删除字面值:删除为1
logic-delete-value: 1
逻辑删除本质:逻辑删除的本质其实是修改操作。如果加了逻辑删除字段,查询数据时也会自动带上逻辑删除字段。
乐观锁主张的思想是什么?
业务并发现象带来的问题:秒杀
①:数据库表中添加锁标记字段
②:实体类中添加对应字段,并设定当前字段为逻辑删除标记字段
package mytest.domain;import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.Version;
import lombok.Data;@Data
public class User {private Long id;@Versionprivate Integer version;
}
③:配置乐观锁拦截器实现锁机制对应的动态SQL语句拼装
package mytest.config;import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class MpConfig {@Beanpublic MybatisPlusInterceptor mpInterceptor() {//1.定义Mp拦截器MybatisPlusInterceptor mpInterceptor = new MybatisPlusInterceptor();//2.添加乐观锁拦截器mpInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());return mpInterceptor;}
}
④:使用乐观锁机制在修改前必须先获取到对应数据的verion方可正常进行
@Test
public void testUpdate() {/*User user = new User();user.setId(3L);user.setName("Jock666");user.setVersion(1);userDao.updateById(user);*///1.先通过要修改的数据id将当前数据查询出来//User user = userDao.selectById(3L);//2.将要修改的属性逐一设置进去//user.setName("Jock888");//userDao.updateById(user);//1.先通过要修改的数据id将当前数据查询出来User user = userDao.selectById(3L); //version=3User user2 = userDao.selectById(3L); //version=3user2.setName("Jock aaa");userDao.updateById(user2); //version=>4user.setName("Jock bbb");userDao.updateById(user); //verion=3?条件还成立吗?
}
---------------------------------------------------------------------------------------------------------------------------------
内容有部分存在书籍、课堂、网络记录,如有雷同纯属巧合