MyBatis-Plus深入 —— 条件构造器与插件管理

2023-11-05

前言

        在前面的文章中,荔枝梳理了一个MyBatis-Plus的基本使用、配置和通用Service接口,我们发现在MyBatis-Plus的辅助增强下我们不再需要通过配置xml文件中的sql语句来实现基本的sql操作了,不愧是最佳搭档!在这篇文章中,荔枝会着重梳理有关MyBatis-Plus的两个知识点:条件构造器、分页插件和乐观锁插件,希望对有需要的小伙伴有帮助~~~


文章目录

前言

一、条件构造器

1.1 组装查询条件

1.2 组装排序条件

1.3 组装删除条件

1.4 使用QueryWrapper实现修改功能 

1.5 条件优先级

1.6 子查询

1.7 使用UpdateWrapper实现修改功能

1.8 使用Condition组装条件

1.9 LambdaQueryWrapper

1.10 LambdaUpdateWrapper 

二、分页插件

2.1 基本使用 

2.2 自定义分页插件 

三、乐观锁插件

3.1 乐观锁和悲观锁

3.2 乐观锁插件

总结


一、条件构造器

        条件构造器,顾名思义就是用来封装当前我们用来查询的条件的,条件构造器的最顶层的接口是Mapper,被AbstractWrapper继承,其下由三个子类分别是:AbstractLambdaWrapper、UpdateWrapper和QueryWrapper。

1.1 组装查询条件

//条件构造器组装查询条件
    @Test
    public void testWrapper(){
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.like("user_name","crj")
                .between("age",20,30)
                .isNotNull("email");
        List<User> list = userMapper.selectList(queryWrapper);
        list.forEach(System.out::println);
    }

1.2 组装排序条件

//组装排序条件
    @Test
    public void test1(){
        //查询用户信息按照年龄的降序排序,若年龄相同则按照id升序排序
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.orderByDesc("age")
                .orderByAsc("uid");
        List<User> list = userMapper.selectList(queryWrapper);
        list.forEach(System.out::println);
    }

1.3 组装删除条件

//组装删除条件
    @Test
    public void test2(){
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.isNull("email");
        int result = userMapper.delete(queryWrapper);
        System.out.println("受影响函数"+result);
    }

1.4 使用QueryWrapper实现修改功能 

//实现修改功能
    @Test
    public void  test3(){
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        //把年龄大于20且姓名为crj或者是邮箱为null的用户信息进行修改
        queryWrapper.gt("age",20)
                .like("user_name","crj")
                .or()
                .isNull("email");
        User user = new User();
        user.setName("CRJ");
        user.setEmail("123456@123.com");
        int result = userMapper.update(user,queryWrapper);
        System.out.println(result);
    }

1.5 条件优先级

在and()和or()中通过Lambda表达式实现优先级操作,其中Lambda表达式中的条件优先执行。

 //条件优先级
    @Test
    public  void test4(){
        //将用户名中含有crj并且(年龄大于20或邮箱为null)的用户信息修改
        //lambda中的条件优先执行
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.like("user_name","crj")
                .and(i->i.gt("age",20).or().isNull("email"));
        User user = new User();
        user.setName("CRJ");
        user.setEmail("123456@123.com");
        int result = userMapper.update(user,queryWrapper);
        System.out.println(result);
    }

1.6 子查询

//子查询
    @Test
    public void test5(){
        //查询id小于等于100的用户信息
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.inSql("uid","select uid from t_user where uid<=100");
        List<User> list = userMapper.selectList(queryWrapper);
    }

1.7 使用UpdateWrapper实现修改功能

//使用UpdateWrapper实现修改功能
//将用户名中含有crj并且(年龄大于20或邮箱为null)的用户信息修改
    @Test
    public  void  test6(){
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
        updateWrapper.like("user_name","crj")
                .and(i->i.gt("age",20).or().isNull("email"));
        updateWrapper.set("user_name","CRJ");
        userMapper.update(null,updateWrapper);
    }

1.8 使用Condition组装条件

1.9 LambdaQueryWrapper

    @Test
    public void test8(){
        String username = "a";
        Integer ageBegin = null;
        Integer ageEnd = 30;
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(StringUtils.isNotBlank(username),User::getName,username)
                .ge(ageBegin!=null,User::getAge,ageBegin)
                .le(ageEnd!=null,User::getAge,ageEnd);
        List<User> list = userMapper.selectList(queryWrapper);
        list.forEach(System.out::println);
    }

1.10 LambdaUpdateWrapper 

    @Test
    public  void  test9(){
        LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.like(User::getName,"crj")
                .and(i->i.gt(User::getAge,20).or().isNull(User::getEmail));
        updateWrapper.set(User::getName,"CRJ");
        userMapper.update(null,updateWrapper);
    }

二、分页插件

2.1 基本使用 

 分页插件的配置类

package com.crj.mybatisplus_test.config;

import com.baomidou.mybatisplus.annotation.DbType;
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;

//配置类,配置MyBatisPlus的插件功能
@Configuration
@MapperScan("com.crj.mybatisplus_test.mapper")
public class MyBatisPlusConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}

测试类

package com.crj.mybatisplus_test;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.crj.mybatisplus_test.mapper.UserMapper;
import com.crj.mybatisplus_test.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class MyBatisPlusPluginsTest {
    @Autowired
    private UserMapper userMapper;

    @Test
    public void test1(){
        Page<User> page = new Page<>(1,3);
        userMapper.selectPage(page,null);
        System.out.println(page);
    }
}

page对象的几个方法:

  • page.getRecords(): 获取当前页数据
  • page.getCurrent():获取当前页的页码
  • page.getSize():获取每页显示的条数
  • page.getPages(): 获取总页数
  • page.getTotal(): 获取总记录数
  • page.hasNext(): 查看有没有下一页
  • page.hasPrevious():查看有没有上一页

配置类型别名:

mybatis-plus:

        type-aliases-package:全路径 

2.2 自定义分页插件 

        之前借助条件构造器来实现分页的操作,通过查看源码知晓,selectPage要求两个参数,返回值和第一个参数都是IPage类型的,而IPage类型的接口是被Page类对象实现的,因此第一个参数一定是page对象。我们需要在userMapper接口中手写一个方法替代原来的selectPage,同时分页插件的配置文件保持不变,配置好MyBatisPlus的插件功能

UserMapper.java 

package com.crj.mybatisplus_test.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.crj.mybatisplus_test.pojo.User;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;


@Repository
//继承MyBatis-Plus的BaseMapper接口
public interface UserMapper extends BaseMapper<User> {

    /**
     * 根据年龄查询用户信息并分页
     * @param page mybatis-plus提供的分页对象,必须放在第一个参数中
     * @param age
     * @return
     */
    Page<User> selectPageVo(@Param("page") Page<User> page,@Param("age") Integer age);
}

UserMapper.xml 

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.crj.mybatisplus_test.mapper.UserMapper">

<!--    Page<User> selectPageVo(@Param("page") Page<User> page,@Param("age") Integer age);-->
    <select id="selectPageVo" resultType="User">
        select uid,name,age from t_user where age > #{age}
    </select>
</mapper>

测试类

    @Test
    public void testPageVo(){
        Page<User> page = new Page<>(1,3);
        userMapper.selectPageVo(page,20);
    }

三、乐观锁插件

3.1 乐观锁和悲观锁

        说到乐观锁和悲观锁,我们经常通过一个场景来理解:我们需要对一个值为100的数进行+10操作再进行-30操作,这两步使用多线程执行。A和B线程同时取一个值为100的数C,A对C进行+10操作,B对取出来的值进行-30的操作,如果没有加锁控制,那么A处理的值D不能被B拿到且会被B覆盖。对于加锁这里简单归纳两种:乐观锁和悲观锁,悲观锁会格外注重线程安全,只有等A操作完后才能由B取值;而乐观锁则是通过版本控制的方式来检测是否C被修改了。

未加锁的场景模拟

实体类

package com.crj.mybatisplus_test.pojo;

import lombok.Data;

@Data
public class Product {
    private Long id;
    private String name;
    private Integer price;
    private Integer version;

}

mapper接口

package com.crj.mybatisplus_test.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.crj.mybatisplus_test.pojo.Product;
import org.springframework.stereotype.Service;

@Service
public interface ProductMapper extends BaseMapper<Product> {

}

测试类

package com.crj.mybatisplus_test;

import com.crj.mybatisplus_test.mapper.ProductMapper;
import com.crj.mybatisplus_test.pojo.Product;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

//乐观锁插件使用
@SpringBootTest
public class MyBatisLockTest {
    @Autowired
    private ProductMapper productMapper;
    //模拟线程场景
    @Test
    public void test1(){
        Product productA = productMapper.selectById(1);
        System.out.println("A查询的商品价格"+productA.getPrice());
        Product productB = productMapper.selectById(1);
        System.out.println("B查询的商品价格"+productB.getPrice());

        productA.setPrice(productA.getPrice()+10);
        productMapper.updateById(productA);
        productB.setPrice(productB.getPrice()-30);
        productMapper.updateById(productB);
        //最后结果
        Product productC = productMapper.selectById(1);
        System.out.println("A查询的商品价格"+productC.getPrice());

    }
}

3.2 乐观锁插件

前面知道乐观锁实现需要加上版本号来控制,因此实体类需要进行通过@Version来设置版本号。

实体类

package com.crj.mybatisplus_test.pojo;

import com.baomidou.mybatisplus.annotation.Version;
import lombok.Data;

@Data
public class Product {
    private Long id;
    private String name;
    private Integer price;

    @Version //标识乐观锁版本号字段
    private Integer version;

}

MyBatis-Plus插件配置类

需要在配置类中配置好乐观锁插件方法OptimisticLockerInnerInterceptor()

package com.crj.mybatisplus_test.config;

import com.baomidou.mybatisplus.annotation.DbType;
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.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

//配置类,配置MyBatisPlus的插件功能
@Configuration
@MapperScan("com.crj.mybatisplus_test.mapper")
public class MyBatisPlusConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        //配置分页插件
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        //配置乐观锁插件
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return interceptor;
    }
}

测试类

需要注意的是B修改数据失败后需要重试即可完成任务需求。 

package com.crj.mybatisplus_test;

import com.crj.mybatisplus_test.mapper.ProductMapper;
import com.crj.mybatisplus_test.pojo.Product;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

//乐观锁插件使用
@SpringBootTest
public class MyBatisLockTest {
    @Autowired
    private ProductMapper productMapper;
    //模拟线程场景
    @Test
    public void test1(){
        Product productA = productMapper.selectById(1);
        System.out.println("A查询的商品价格"+productA.getPrice());
        Product productB = productMapper.selectById(1);
        System.out.println("B查询的商品价格"+productB.getPrice());

        productA.setPrice(productA.getPrice()+10);
        productMapper.updateById(productA);
        productB.setPrice(productB.getPrice()-30);
        int result = productMapper.updateById(productB);

        //由于加入了版本号控制,因此需要对修改失败的操作进行重试
        if(result==0){
            //失败重试
            Product productNew = productMapper.selectById(1);
            productNew.setPrice(productNew.getPrice()-30);
            productMapper.updateById(productNew);
        }
        //最后结果
        Product productC = productMapper.selectById(1);
        System.out.println("A查询的商品价格"+productC.getPrice());

    }
}

总结

        通过条件构造器的几种基本用法使用示例,荔枝对wrapper类的使用有了一个比较直观的理解,同时荔枝觉得更需要注意的是两种插件的使用。接下来的文章中荔枝会对MyBatis-Plus的相关基础知识收尾,同时尝试整合到学习的项目中,跟荔枝一起期待一波吧哈哈哈哈哈~~~

今朝已然成为过去,明日依然向往未来!我是小荔枝,在技术成长的路上与你相伴,码文不易,麻烦举起小爪爪点个赞吧哈哈哈~~~ 比心心♥~~~

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

MyBatis-Plus深入 —— 条件构造器与插件管理 的相关文章

  • 按下按钮并在java中的新窗口中打开文件

    我创建了一个 JFrame 并放置了一个文本字段和按钮 在文本字段中我放置了从文本文件读取的名称 我知道我想单击按钮并打开一个已知窗口 我想在其中放置名称 其他信息来自同一个文件 这是我的代码 这是我的主框架 package Fronten
  • 带路径压缩算法的加权 Quick-Union

    有一种 带路径压缩的加权快速联合 算法 代码 public class WeightedQU private int id private int iz public WeightedQU int N id new int N iz new
  • Java:扩展类并实现具有相同方法的接口

    可能无法完成以下操作 我收到编译错误 继承的方法 A doSomthing int 无法隐藏 B 中的公共抽象方法 public class A int doSomthing int x return x public interface
  • 如何在java中将数组值排序为循环格式?

    我的数组值如下 String value 1 2 3 4 5 6 7 8 9 10 假设如果我将值 5 传递给 tat 数组 它应该按如下顺序排序 5 6 7 8 9 10 1 2 3 4 怎么办 有人帮忙吗 感谢你 你需要的就是所谓的轮换
  • 垃圾收集器如何在幕后工作来收集死对象?

    我正在阅读有关垃圾收集的内容 众所周知 垃圾收集会收集死亡对象并回收内存 我的问题是 Collector 如何知道任何对象已死亡 它使用什么数据结构来跟踪活动对象 我正在研究这个问题 我发现GC实际上会跟踪活动对象 并标记它们 每个未标记的
  • 什么是抽象类? [复制]

    这个问题在这里已经有答案了 当我了解抽象类时 我说 WT H 问题 创建一个无法实例化的类有什么意义呢 为什么有人想要这样的课程 什么情况下需要抽象类 如果你明白我的意思 最常见的是用作基类或接口 某些语言有单独的interface构建 有
  • Android studio - 如何保存先前活动中选择的数据

    这是我的代码片段 这Textview充当按钮并具有Onclicklistner在他们 当cpu1000时Textview单击它会导致cpu g1000其代码如下所示的类 public class Game 1000 extends AppC
  • Runtime.exec 处理包含多个空格的参数

    我怎样才能进行以下运行 public class ExecTest public static void main String args try Notice the multiple spaces in the argument Str
  • 提供节点名或服务名,或未知 Java

    最近我尝试运行我的 Java 项目 每当我运行它并将其打开到我得到的服务器地址时 Unable to determine host name java net UnknownHostException Caused by java net
  • 将人类日期(当地时间 GMT)转​​换为日期

    我正在服务器上工作 服务器正在向我发送 GMT 本地日期的日期 例如Fri Jun 22 09 29 29 NPT 2018在字符串格式上 我将其转换为日期 如下所示 SimpleDateFormat simpleDateFormat ne
  • 如何在 ant 中为 junit 测试设置 file.encoding?

    我还没有完全完成file encoding 和 ant https stackoverflow com questions 1339352 how do i set dfile encoding within ants build xml
  • 从jar中获取资源

    我有包含文件的 jar myJar res endingRule txt myJar wordcalculator merger Marge class 在 Marge java 中我有代码 private static final Str
  • Akka 与现有 java 项目集成的示例

    如果我已经有现有的javaWeb 应用程序使用spring and servlet容器 将 Akka 集成到其中的正确方法是什么 就像我将会有Actor1 and Actor2互相沟通的 开始使用这些演员的切入点是什么 例如 1 把它放在那
  • 在Java中运行bat文件并等待

    您可能会认为从 Java 启动 bat 文件是一项简单的任务 但事实并非如此 我有一个 bat 文件 它对从文本文件读取的值循环执行一些 sql 命令 它或多或少是这样的 FOR F x in CD listOfThings txt do
  • 如何将 HTML 链接放入电子邮件正文中?

    我有一个可以发送邮件的应用程序 用 Java 实现 我想在邮件中放置一个 HTML 链接 但该链接显示为普通字母 而不是 HTML 链接 我怎样才能将 HTML 链接放入字符串中 我需要特殊字符吗 太感谢了 Update 大家好你们好 感谢
  • 轻松的反应

    我有一个与这里描述的类似的案例 动态更改RESTEasy服务返回类型 https stackoverflow com questions 3786781 dynamically change resteasy service return
  • partitioningBy 必须生成一个包含 true 和 false 条目的映射吗?

    The 分区依据 https docs oracle com javase 8 docs api java util stream Collectors html partitioningBy java util function Pred
  • 子类构造函数(JAVA)中的重写函数[重复]

    这个问题在这里已经有答案了 为什么在派生类构造函数中调用超类构造函数时 id 0 当创建子对象时 什么时候在堆中为该对象分配内存 在基类构造函数运行之后还是之前 class Parent int id 10 Parent meth void
  • Java RMI - 客户端超时

    我正在使用 Java RMI 构建分布式系统 它必须支持服务器丢失 如果我的客户端使用 RMI 连接到服务器 如果该服务器出现故障 例如电缆问题 我的客户端应该会收到异常 以便它可以连接到其他服务器 但是当服务器出现故障时 我的客户端什么也
  • Spring RESTful控制器方法改进建议

    我是 Spring REST 和 Hibernate 的新手 也就是说 我尝试组合一个企业级控制器方法 我计划将其用作未来开发的模式 您认为可以通过哪些方法来改进 我确信有很多 RequestMapping value user metho

随机推荐

  • 关闭、开启 hype-v

    情景 在使用docker之后 需要使用虚拟机 直接开启虚拟机会报错 VMware Workstation 不支持在此主机上使用虚拟化性能计数器 有关更多详细信息 请参阅 VMware 知识库文章 81623 模块 VPMC 启动失败 未能启
  • JS 使用DES加密解密

    1 安装插件 npm install crypto js 2 使用 import CryptoJS from crypto js const key abcdefg const keyHex CryptoJS enc Utf8 parse
  • shardingsphere的sharding jdbc报类型转换异常问题

    shardingsphere的sharding jdbc报类型转换异常问题 根据官网的解释 在4 1 1的版本中是不支持数据库的原生native sql的 所有的sql都会被转换校验一次之后才会进入mybatis进行解析 如果你的sql中使
  • get 和 post 俩种提交表单的方式

    get 和 post 俩种提交表单的方式 自动提交表单的数据 启用表单的自动提交方式时 我们需要添加上这一句 eg action Main GetData method post action Main GetData 这是所对应的路径 m
  • 【华为OD机试python】阿里巴巴找黄金宝箱(IV)【2023 B卷

    题目描述 一贫如洗的樵夫阿里巴巴在去砍柴的路上 无意中发现了强盗集团的藏宝地 藏宝地有编号从0 N的箱子 每个箱子上面有一个数字 箱子排列成一个环 编号最大的箱子的下一个是编号为0的箱子 请输出每个箱子贴的数字之后的第一个比它大的数 如果不
  • JetBrains软件(Idea、Pycharm等)模板设置

    以Idea为例 一 打开File中的Settings 二 打开Editor中的File and Code Templates 找到对应的文件修改即可 三 修改后的状态
  • CCF/CSP 201409-3 字符串匹配(满分题解Java版)

    此题虽然放在了第三题 但是如果对Java的API了解的比较好的同学 解这道题一点都不难 比前几题都要简单一些 题目描述 官方题目地址 读题请点击 Java满分题解 import java util Scanner next 与 nextLi
  • Java 图形用户界面 复习题

    题目 编写一个包含主方法main的公共类 访问权限为public的类 该类继承自窗体类JFrame 并且 该类实现了接口ActionListener 实现接口ActionListener的方法actionPerformed 需要实现的界面
  • 工程师如何提高写作修养

    昨天非常有幸参加了电子工业出版社博文视点专业出版高峰论坛 在 写作精进 分论坛上 我受邀做了主题为 工程师如何提高写作修养 的分享 昨天现场的同学的不多 而这个主题估计很多都会有兴趣 发布在这里 供大家参考 在此 再次感谢电子工业出版社博文
  • 字符串前面补零的简单写法

    include
  • 代理模式--静态代理

    明确AOP之前首先要对代理模式进行深刻的学习 代理模式分为静态代理 和动态代理 动态代理又包括JDK代理和Cglib 本文主要学习静态代理 代理模式 从生活出发 我是一个要租房子的人 我要租房子 要找房屋中介 房源多 我不会去找房东 因为很
  • 2022亚太E题——How Many Nuclear Bombs can Destroy the Earth?(思路)

    欢迎来到本博客 博主优势 博客内容尽量做到思维缜密 逻辑清晰 为了方便读者 座右铭 行百里者 半于九十 本文目录如下 目录 1 概述 2 2022亚太E题 How Many Nuclear Bombs can Destroy the Ear
  • 使用Flutter开发俄罗斯方块小游戏

    一 本篇文章主要是来讲解下俄罗斯方块游戏的开发思路 当然可能不是最好的思路 博客文章顶部有代码 仅供参考 二 效果图 视频效果图地址 三 UI页面思路拆解 游戏的主界面两部分组成 上面为15 10的格子用来放置方块 下面为操作按钮和显示当前
  • MP2481DH背光IC过压保护设置问题

    现象 夏普的屏可以点亮 但是君创的屏点不亮 分析 过压保护了 具体还没分析 以后再看数据手册 解决 如下电阻改为300K 可同时兼容两款屏
  • 基于FPGA的频率计

    1 简介 频率计又称为频率计数器 是一种专门对被测信号频率进行测量的电子测量仪器 2 传统测量法 传统测量法有两种 周期测量法 和 频率测量法 2 1 周期测量法 原理 先测出被测信号的周期 T T T 然后根据频率 f
  • 宏包algorithm与algorithmic引发的Undefined control sequence问题

    背景 自己是在texlive vs code环境下写小论文 在写算法的时候 一直出现输入控制语句全部都是没有定义的 如下 Undefined control sequence REQUIRE Undefined control sequen
  • Typora--图片上传方案Typora+PicGo+Gitee

    目录 一 简介 二 步骤 1 Gitee的部署 2 PicGo的设置 3 Typora的设置 三 其他 一 简介 当使用Typora的MarkDown编辑软件来做学习记录 上传图片时 都要创建一个文件夹来存放图片 这样子一来很不方便 有没有
  • 使用JDBC数据迁移把Mysql数据到另一个库中

    数据迁移 简介 整体思路链接2个需要迁移的数据库 根据sql 进行查询 判断什么样的数据需要迁移 什么样的数据需要过滤掉 数据重复或者出错的情况输出到某个文件中 如果数据可以整体迁移而且不出格式差异的情况也可以直接导出sql文件进行迁移 此
  • Binder 连接池的学习

    利用AIDL方式能很方便地进行客户端和服务端的跨进程通信 但是 我们想一下 如果按照我们之前的使用方法 必须满足一个AIDL接口对应一个service 那么问题来了 假如我们的应用 有很多业务场景 而每一个业务场景都需要和服务端通讯 那么我
  • MyBatis-Plus深入 —— 条件构造器与插件管理

    前言 在前面的文章中 荔枝梳理了一个MyBatis Plus的基本使用 配置和通用Service接口 我们发现在MyBatis Plus的辅助增强下我们不再需要通过配置xml文件中的sql语句来实现基本的sql操作了 不愧是最佳搭档 在这篇