MybatisPlus学习总结(下)

一、条件构造器

在MP中,Wrapper接口的实现类关系如下:
在这里插入图片描述

## mybatis plus基本操作

查询方式	说明
setSqlSelect	设置 SELECT 查询字段
where	WHERE 语句,拼接 + WHERE 条件
and	AND 语句,拼接 + AND 字段=值
andNew	AND 语句,拼接 + AND (字段=)
or	OR 语句,拼接 + OR 字段=值
orNew	OR 语句,拼接 + OR (字段=)
eq	等于=
allEq	基于 map 内容等于=
ne	不等于<>
gt	大于>
ge	大于等于>=
lt	小于<
le	小于等于<=
like	模糊查询 LIKE
notLike	模糊查询 NOT LIKE
in	IN 查询
notIn	NOT IN 查询
isNull	NULL 值查询
isNotNull	IS NOT NULL
groupBy	分组 GROUP BY
having	HAVING 关键词
orderBy	排序 ORDER BY
orderAsc	ASC 排序 ORDER BY
orderDesc	DESC 排序 ORDER BY
exists	EXISTS 条件语句
notExists	NOT EXISTS 条件语句
between	BETWEEN 条件语句
notBetween	NOT BETWEEN 条件语句
addFilter	自由拼接 SQL
last	拼接在最后,例如:last("LIMIT 1")
注意! xxNew 都是另起 ( ... ) 括号包裹。

1.1 allEq

allEq(Map<R, V> params)
allEq(Map<R, V> params, boolean null2IsNull)
allEq(boolean condition, Map<R, V> params, boolean null2IsNull)

个别参数说明: params : 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 : 过滤函数,是否允许字段传入比对条件中 ,params 与 null2IsNull : 同上

  • 例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 =
    ‘老王’

代码示例:

@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<>();

    //SELECT id,user_name,name,age,email FROM tb_user WHERE (password IS NULL AND name = ? AND age = ?)
//        wrapper.allEq(params);

    //SELECT id,user_name,name,age,email FROM tb_user WHERE (name = ? AND age = ?)
//        wrapper.allEq(params,false);

    //过滤函数表示是否允许字段传入比对条件中 params
    //SELECT id,user_name,name,age,email FROM tb_user WHERE (password IS NULL AND age = ?)
    wrapper.allEq((k, v) -> (k.equals("age") || k.equals("id") || k.equals("password")) , params);

    List<User> users = userMapper.selectList(wrapper);
    for (User user : users) {
        System.out.println(user);
    }
}

1.2 基本比较操作

在这里插入图片描述

@Test
public void testEq() {
    QueryWrapper<User> wrapper = new QueryWrapper<>();

    //SELECT id,user_name,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);
    }
}

结果:
在这里插入图片描述

1.3 模糊查询

在这里插入图片描述

代码示例:

@Test
public void testLike(){
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    //SELECT id,user_name,name,age,email 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);
    }
}

结果:
在这里插入图片描述

1.4 排序

在这里插入图片描述
代码示例:

@Test
public void testOrderByAgeDesc(){
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    //按照年龄倒序排序
    // SELECT id,user_name,name,age,email 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);
    }
}

结果:
在这里插入图片描述

1.5 逻辑查询

在这里插入图片描述

代码示例:

@Test
public void testOr(){
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    // SELECT id,user_name,name,age,email FROM tb_user WHERE (name = ? OR age = ?)
    wrapper.eq("name", "王五").or().eq("age", 21);

    List<User> users = this.userMapper.selectList(wrapper);
    for (User user : users) {
        System.out.println(user);
    }
}

结果:
在这里插入图片描述

1.6 select

在MP查询中,默认查询所有的字段,如果有需要也可以通过select方法进行指定字段。

代码示例:

@Test
public void testSelect(){
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    //SELECT id,name,age FROM tb_user WHERE (name = ? OR age = ?)
    wrapper.eq("name", "王五")
            .or()
            .eq("age", 21)
            .select("id","name","age"); //指定查询的字段

    List<User> users = this.userMapper.selectList(wrapper);
    for (User user : users) {
        System.out.println(user);
    }
}

结果:
在这里插入图片描述

二、ActiveRecord

在Mybatis-Plus中提供了ActiveRecord的模式,支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可实现基本 CRUD 操作,简单来说就是一个实体类继承Model类,并通过注解与数据库的表名进行关联,这样就可以通过实体类直接进行表的简单增删改查操作

实现步骤:

  1. Mapper对象要先继承BaseMapper对象

    public interface UserMapper extends BaseMapper<User> {
    }
    
  2. 实体对象要继承Model对象

    @Data
    @TableName("tb_user")
    public class User extends Model<User> {
    
        @TableId(value = "id",type = IdType.AUTO)
        private Long id;
        private String userName;
        @TableField(select = false)//查询的时候不查询该字段
        private String password;
        private String name;
        private Integer age;
        private String email;
    
        @TableField(exist = false)
        private String address; //在数据库表中是不存在的
    }
    
  3. 代码测试

    @Test
    public void testSelectById(){
        User user = new User();
        user.setId(16L);
        //SELECT id,user_name,name,age,email FROM tb_user WHERE id=?
        User user1 = user.selectById();
        System.out.println(user1);
    }
    
    @Test
    public void testInsert(){
        User user = new User();
        user.setUserName("diaochan");
        user.setPassword("123456");
        user.setAge(20);
        user.setName("貂蝉");
        user.setEmail("diaochan@itcast.cn");
    
        //INSERT INTO tb_user ( user_name, password, name, age, email ) VALUES ( ?, ?, ?, ?, ? )
        // 调用AR的insert方法进行插入数据
        boolean insert = user.insert();
        System.out.println("result => " + insert);
    }
    

三、插件

3.1 mybatis的插件机制

参考博客:https://blog.csdn.net/oneby1314/article/details/116289510

3.2 常用插件配置

1、 防止全表更新与删除插件

  • 针对 update 和 delete 语句 作用: 阻止恶意的全表更新删除
  • SpringBoot配置:
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 防止全表更新与删除
        // 针对 update 和 delete 语句
        interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
        return interceptor;
    }
    
    如果进行全表的更新和删除操作则会抛出:MybatisPlusException: Prohibition of table update operation

2、分页插件

  1. 插件配置:(SpringBoot)

    @Configuration
    public class MybatisPlusConfig {
        // 配置分页插件,最新版
        @Bean
        public MybatisPlusInterceptor mybatisPlusInterceptor() {
            MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
            interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
            return interceptor;
        }
    
    }
    
  2. 测试:

    // 测试分页查询,前提:配置分页插件
    @Test
    public void testSelectPage(){
    
        Page<User> page = new Page<>(3,2); //查询
    
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        //设置查询条件
    //        wrapper.like("email", "itcast");//like表示模糊查询
        IPage<User> iPage = userMapper.selectPage(page, wrapper);
    
        System.out.println("数据总条数: " + iPage.getTotal());
        System.out.println("数据总页数: " + iPage.getPages());
        System.out.println("当前页数: " + iPage.getCurrent());
    
        List<User> records = iPage.getRecords();
        for (User record : records) {
            System.out.println(record);
        }
    
    }
    

    执行结果:
    在这里插入图片描述

3、乐观锁插件

  1. 插件配置:(SpringBoot)

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 添加乐观锁插件
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return interceptor;
    }
    
  2. 为表添加version字段,并且设置初始值为1

    ALTER TABLE `tb_user`
    ADD COLUMN `version` int(10) NULL AFTER `email`;
    UPDATE `tb_user` SET `version`='1';
    
  3. 为User实体对象添加version字段,并且添加@Version注解

    @Version
    private Integer version;
    
  4. 测试

    @Test
    public void testUpdateVersion(){
        User user = new User();
        user.setId(2L);// 查询条件
        User userVersion = user.selectById();
    
        user.setAge(23); // 更新的数据
        user.setVersion(userVersion.getVersion()); // 当前的版本信息
    
        boolean result = user.updateById();
        System.out.println("result => " + result);
    }
    

    执行结果:
    在这里插入图片描述

  5. 注意:

    支持的数据类型只有:int,Integer,long,Long,Date,Timestamp,LocalDateTime
    整数类型下 newVersion = oldVersion + 1
    newVersion 会回写到 entity 中

四、MybatisPlus 扩展

4.1 Sql注入器

SQL注入器主要用于扩充BaseMapper中的方法。以扩展findAll方法为例。

  1. 编写MyBaseMapper

    public interface MyBaseMapper<T> extends BaseMapper<T> {
        List<T> findAll();
    }
    
    

    其他的Mapper都可以继承该Mapper,这样实现了统一的扩展

    public interface UserMapper extends MyBaseMapper<User> {
    }
    
  2. 编写MySqlInjector

    如果直接继承AbstractSqlInjector的话,原有的BaseMapper中的方法将失效,所以我们选择继承DefaultSqlInjector进行扩展。

    public class MySqlInjector extends DefaultSqlInjector {
        @Override
        public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
            List<AbstractMethod> methodList = super.getMethodList(mapperClass);
    
            // 再扩充自定义的方法
            methodList.add(new FindAll());
    
            return methodList;
        }
    }
    
  3. 编写FindAll

    public class FindAll extends AbstractMethod {
        @Override
        public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?>
                modelClass, TableInfo tableInfo) {
            String sqlMethod = "findAll";
            String sql = "select * from " + tableInfo.getTableName();
            SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql,
                    modelClass);
            return this.addSelectMappedStatementForTable(mapperClass, sqlMethod, sqlSource, tableInfo);
        }
    }
    
  4. 注册到Spring容器

    /**
     * 自定义SQL注入器
     */
    @Bean
    public MySqlInjector mySqlInjector(){
        return new MySqlInjector();
    }
    
  5. 测试

    @Test
    public void testFindAll(){
        List<User> users = this.userMapper.findAll();
        for (User user : users) {
            System.out.println(user);
        }
    }
    

    结果:
    在这里插入图片描述

4.2 自动填充功能

有些时候我们可能会有这样的需求,插入或者更新数据时,希望有些字段可以自动填充数据,比如密码、时间等。在MP中提供了这样的功能,可以实现自动填充

  1. 添加@TableField注解

    @TableField(fill = FieldFill.INSERT) //插入数据时进行填充
    private String password;
    

    为password添加自动填充功能,在新增数据时有效。FieldFill提供了多种模式选择:
    在这里插入图片描述

  2. 自定义实现类 MyMetaObjectHandler
    注意:使用@Component注解标记

    @Component
    public class MyMetaObjectHandler implements MetaObjectHandler {
        /**
         * 插入数据时填充
         * @param metaObject
         */
        @Override
        public void insertFill(MetaObject metaObject) {
            // 先获取到password的值,再进行判断,如果为空,就进行填充,如果不为空,就不做处理
            Object password = getFieldValByName("password", metaObject);
            if(null == password){
    //            setFieldValByName("password", "888888", metaObject);
                //或者
                this.strictInsertFill(metaObject, "password",String.class,"888889" ); // 起始版本 3.3.0(推荐使用)
            }
    
        }
    
        /**
         * 更新数据时填充
         * @param metaObject
         */
        @Override
        public void updateFill(MetaObject metaObject) {
    
        }
    }
    
  3. 测试

    @Test
    public void testInsert() {
        User user = new User();
        user.setAge(29);
        user.setUserName("guanyu");
        user.setName("关于");
        //没有设置密码
    //        user.setPassword("123456");
        
        int result = userMapper.insert(user); //result数据库受影响的行数
        System.out.println("result => " + result);
        
    }
    

    结果:
    在这里插入图片描述

4.3 逻辑删除

逻辑删除就是将数据标记为删除,而并非真正的物理删除(非DELETE操作),查询时需要携带状态条件,确保被标记的数据不被查询到。这样做的目的就是避免数据被真正的删除。

MP就提供了这样的功能,下面看一下怎么使用

  1. 修改表结构
    为tb_user表增加deleted字段,用于表示数据是否被删除,1代表删除,0代表未删除。

    ALTER TABLE `tb_user`
    ADD COLUMN `deleted` int(1) NULL DEFAULT 0 COMMENT '1代表删除,0代表未删除' AFTER `version`;
    
  2. 配置(如果和默认值相同也可以不配置)
    application.properties:

    # 逻辑已删除值(默认为 1)
    mybatis-plus.global-config.db-config.logic-delete-value=1
    # 逻辑未删除值(默认为 0)
    mybatis-plus.global-config.db-config.logic-not-delete-value=0
    
  3. 同时,修改User实体,增加deleted属性并且添加@TableLogic注解:

    @TableLogic // 逻辑删除字段 ,1-删除,0-未删除
    private Integer deleted;
    

    如果删除状态和配置的不一样可以使用 valuehedelval 属性指定

    @TableLogic(value = "1", delval = "0")
    
  4. 测试

    删除测试:

    @Test
    public void testDeleteById(){
        // 根据id删除数据
        int result = userMapper.deleteById(2L);
        System.out.println("result => " + result);
    }
    

    结果:
    在这里插入图片描述
    查询测试:

    @Test
    public void testSelectById() {
        User user = userMapper.selectById(3L);
        System.out.println(user);
    }
    

    结果:
    在这里插入图片描述

4.4 通用枚举

解决了繁琐的配置,让 mybatis 优雅的使用枚举属性

  1. 修改表结构和User实体

    ALTER TABLE `tb_user`
    ADD COLUMN `sex` int(1) NULL DEFAULT 1 COMMENT '1-男,2-女' AFTER `deleted`;
    

    User类中添加sex字段

    private SexEnum sex;//性别
    
  2. 定义枚举

    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;
        }
    }
    
  3. 配置

    # 枚举包扫描
    mybatis-plus.type-enums-package=com.zb.enums
    
  4. 测试

    新增测试:

    @Test
    public void testInsert(){
        User user = new User();
        user.setUserName("zhangfei");
        user.setPassword("123456");
        user.setAge(20);
        user.setName("张飞");
        user.setEmail("zhangfei@itcast.cn");
        user.setVersion(1);
        user.setSex(SexEnum.WOMAN); //使用的是枚举
    
        // 调用AR的insert方法进行插入数据
        boolean insert = user.insert();
        System.out.println("result => " + insert);
    }
    

    结果:
    在这里插入图片描述

查询测试:

4.5 执行 SQL 分析打印(待补)

五、代码生成器

AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper、XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。

  1. 导入依赖

    <!--mybatis-plus的springboot支持-->
    <dependency>
      <groupId>com.baomidou</groupId>
      <artifactId>mybatis-plus-boot-starter</artifactId>
      <version>3.4.3</version>
    </dependency>
    
    <dependency>
      <groupId>com.baomidou</groupId>
      <artifactId>mybatis-plus-generator</artifactId>
      <version>3.4.1</version>
    </dependency>
    <!--使用Freemarker模板引擎-->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-freemarker</artifactId>
    </dependency>
    
  2. 执行下面代码

    //mysql 代码生成器演示例子
    public class MysqlGenerator {
    
        /**
         * <p>
         * 读取控制台内容
         * </p>
         */
        public static String scanner(String tip) {
            Scanner scanner = new Scanner(System.in);
            StringBuilder help = new StringBuilder();
            help.append("请输入" + tip + ":");
            System.out.println(help.toString());
            if (scanner.hasNext()) {
                String ipt = scanner.next();
                if (StringUtils.isNotBlank(ipt)) {
                    return ipt;
                }
            }
            throw new MybatisPlusException("请输入正确的" + tip + "!");
        }
    
        /**
         * RUN THIS
         */
        public static void main(String[] args) {
            // 代码生成器
            AutoGenerator mpg = new AutoGenerator();
    
            // 全局配置
            GlobalConfig gc = new GlobalConfig();
            String projectPath = System.getProperty("user.dir");
            gc.setOutputDir(projectPath + "/src/main/java");
            gc.setAuthor("zhaobin"); //设置作者
            gc.setOpen(false);
            mpg.setGlobalConfig(gc);
    
            // 数据源配置
            DataSourceConfig dsc = new DataSourceConfig();
            dsc.setUrl("jdbc:mysql://127.0.0.1:3306/mp?useUnicode=true&useSSL=false&characterEncoding=utf8");
            // dsc.setSchemaName("public");
            dsc.setDriverName("com.mysql.jdbc.Driver");
            dsc.setUsername("root");
            dsc.setPassword("root");
            mpg.setDataSource(dsc);
    
            // 包配置
            PackageConfig pc = new PackageConfig();
            pc.setModuleName(scanner("模块名"));
            pc.setParent("com.zb");
            mpg.setPackageInfo(pc);
    
            // 自定义配置
            InjectionConfig cfg = new InjectionConfig() {
                @Override
                public void initMap() {
                    // to do nothing
                }
            };
            List<FileOutConfig> focList = new ArrayList<>();
            focList.add(new FileOutConfig("/templates/mapper.xml.ftl") {
                @Override
                public String outputFile(TableInfo tableInfo) {
                    // 自定义输入文件名称
                    return projectPath + "/itcast-mp-generator/src/main/resources/mapper/" + pc.getModuleName()
                            + "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
                }
            });
            cfg.setFileOutConfigList(focList);
            mpg.setCfg(cfg);
            mpg.setTemplate(new TemplateConfig().setXml(null));
    
            // 策略配置
            StrategyConfig strategy = new StrategyConfig();
            strategy.setNaming(NamingStrategy.underline_to_camel);
            strategy.setColumnNaming(NamingStrategy.underline_to_camel);
    //        strategy.setSuperEntityClass("com.baomidou.mybatisplus.samples.generator.common.BaseEntity");
            strategy.setEntityLombokModel(true);
    //        strategy.setSuperControllerClass("com.baomidou.mybatisplus.samples.generator.common.BaseController");
            strategy.setInclude(scanner("表名"));
            strategy.setSuperEntityColumns("id");
            strategy.setControllerMappingHyphenStyle(true);
            strategy.setTablePrefix(pc.getModuleName() + "_");
            mpg.setStrategy(strategy);
            // 选择 freemarker 引擎需要指定如下加,注意 pom 依赖必须有!
            mpg.setTemplateEngine(new FreemarkerTemplateEngine());
            mpg.execute();
        }
    
    }
    
  3. 执行结果
    在这里插入图片描述
    MP会生成mapper、service、controller三层,其中service层接口还继承了IService,service层实现类继承了ServiceImpl。下面看一下这两个怎么使用。

5.1 IService使用

mp框架同样提供了service层的封装支持,让我们能够简化service层的开发;

  • IService的方法:
    在这里插入图片描述
    具体使用:
  1. service接口继承IService

    public interface UserService extends IService<User> {
    }
    
  2. service实现类继承ServiceImpl

    @Service
    public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    }
    
  3. 测试

    @Test //测试分页
    void testPage() {
        //分页查询数据
        Page<User> page = userService.page(new Page<User>(1, 2));
        System.out.println("数据总条数: " + page.getTotal());
        System.out.println("数据总页数: " + page.getPages());
        System.out.println("当前页数: " + page.getCurrent());
    
        List<User> records = page.getRecords();
        for (User record : records) {
            System.out.println(record);
        }
    }
    
    @Test //测试删除
    void testRemove() {
        boolean result = userService.removeById(1);
    }
    

好的博客:https://blog.csdn.net/oneby1314/category_11026446.html

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值