MybatisPlus

MybatisPlus

  • 一、MyBatisPlus基础
    • [1.1 MyBatisPlus介绍](#1.1 MyBatisPlus介绍)
    • [1.2 MyBatisPlus入门](#1.2 MyBatisPlus入门)
    • [2. 继承BaseMapper<对应的想要返回类的类名>](#2. 继承BaseMapper<对应的想要返回类的类名>)
    • [1.3 常用注解](#1.3 常用注解)
      • [1.3.1 @TableName](#1.3.1 @TableName)
      • [1.3.2 @Tableid](#1.3.2 @Tableid)
      • [1.3.3 @TableField](#1.3.3 @TableField)
    • [1.4 常用配置](#1.4 常用配置)
  • 二、条件构造器
    • [2.2 自定义SQL](#2.2 自定义SQL)
    • [2.3 Service接口](#2.3 Service接口)
    • [2.4 基于Restful风格实现下列小练习](#2.4 基于Restful风格实现下列小练习)
    • [2.5 IService的Lambda查询](#2.5 IService的Lambda查询)
    • [2.6 批量删除](#2.6 批量删除)
  • 三、拓展业务
    • [3.1 静态工具](#3.1 静态工具)
    • [3.2 逻辑删除](#3.2 逻辑删除)
    • 3.3、枚举处理器
    • [3.4 JSON处理器](#3.4 JSON处理器)
    • [3.5 分页插件功能](#3.5 分页插件功能)
    • [3.6 通用分页实体](#3.6 通用分页实体)

一、MyBatisPlus基础

1.1 MyBatisPlus介绍

MyBatisPlus:就是相当于开发mybatis的应用小能手,能够简化我们的开发

1.2 MyBatisPlus入门

  1. 导入对应的start包,可以在这里找到对应想要的坐标信息
java 复制代码
<!-- https://mvnrepository.com/artifact/com.baomidou/mybatisplus-spring-boot-starter -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatisplus-spring-boot-starter</artifactId>
    <version>1.0.5</version>
</dependency> 

2. 继承BaseMapper<对应的想要返回类的类名>

java 复制代码
@Mapper
public interface BookDao extends BaseMapper<Book> { 
} 

测试:

java 复制代码
@SpringBootTest
class MyBatisPlusQuickstartApplicationTests {

    @Autowired
    private BookDao bookDao;
    @Test
    void contextLoads() {
        System.out.println(bookDao.selectById(14));
        List<Book> books = bookDao.selectList(null);
        System.out.println(books);
    } 
}

1.3 常用注解

MvBatisPlus通过扫描实体类,并基于反射获取实体类信息作为数据库表信息

当符合以下规定就不用进行配置,MybaitisPlus会自动识别:

  1. 类名驼峰转下划线作为表名
  2. 名为id的字段作为主键
  3. 变量名驼峰转下划线作为表的字段名
  • MybatisPlus中比较常用的几个注解如下
    • @TableName:用来指定表名
    • @Tableid:用来指定表中的主键字段信息
    • @TableField:用来指定表中的普通字段信息

1.3.1 @TableName

当表名和类的名字不相符合,那么就要添加这个注解来进行消除错误

1.3.2 @Tableid

如果主键不存在或者主键的名字不为id那么就要加上这个注解

  • ldType枚举:
    • AUTO : 数据库自增长
    • INPUT : 通过set方法自行输入
    • ASSIGN ID : 分配 ID,接口ldentifierGenerator的方法nextld来生成id默认实现类为DefaultldentifierGenerator雪花算法

1.3.3 @TableField

  • 常用的场景:
    • 成员变量名与数据库字段名不一致
    • 成员变量名以is开头,且是布尔值
    • 成员变量名与数据库关键字冲突
    • 成员变量不是数据库字段
java 复制代码
@TableName("tbl_book")
public class Book {
    @TableId(type = IdType.AUTO)
    private Integer id;
    @TableField("`type`")//进行转意
    private String type;
    @TableField(exist = false) //将其表面部位数据库当中的字段
    private String description;
    private String name; 
    public Book() {
    }

1.4 常用配置

java 复制代码
mybatis-plus:
            type-aliases-package: com.itheima.mp.domain.po # 别名扫描包
            mapper-locations: "classpath*:/mapper/**/*.xml" # Mapper.xml文件地址,默认值
            configuration:
              map-underscore-to-camel-case: true # 是否开启下划线和驼峰的映射
              cache-enabled: false # 是否开启二级缓存
            global-config:
              db-config:
                id-type: assign_id # id为雪花算法生成
                update-strategy: not_null # 更新笑略:只更新非空字段
                table-prefix: tbl_ #表面所有表面前面都加一个tbl_

这些配置不需要记下来,只需要我们需要配置的时候在官网上面进行查询

二、条件构造器

MyBatisPlus支持各种复杂的where条件,可以满足日常开发的所有需求

java 复制代码
@Test
    void testQueryWrapper(){
        //首先编写了查询的条件
       QueryWrapper<Book> wrapper = new QueryWrapper<Book>()
               .select("id","username","info","balance")
               .like("username","o")
               .ge("balance","1000");

       //进行查询操作
       List<Book> books = bookDao.selectList(wrapper);
       books.forEach(System.out::println);
   }

利用LambdaQueryWrapper书写:

java 复制代码
@Test
    void testQueryWrapper(){

        LambdaQueryWrapper<Book> wrapper = new LambdaQueryWrapper<Book>()
                .select(User::getId, User::getUsername, User::getInfo, User::getBalance)
                .like(User::getUsername, "o")
                .ge(User::getBalance, "1000");

        //进行查询操作
        List<Book> books = bookDao.selectList(wrapper);
        books.forEach(System.out::println);
    }
java 复制代码
@Test
    void testQueryWrapper2(){
       //首先编写条件
        QueryWrapper<Book> wrapper = new QueryWrapper<Book>()
               .eq("name", "jack");
       //然后创建需要修改的对象属性
       User user = new User;
       user.setBalance(2000);
       bookDao.update(user,wrapper);
   }
java 复制代码
  @Test
    void testUpdateWrapper(){
        //首先编写条件
        List<Long> ids=List.of(1L,4L,2L);
        UpdateWrapper<Book> wrapper = new UpdateWrapper<Book>()
                .setSql("balance = balance -200")
                .in("id", ids);
        //然后创建需要修改的对象属性
        User user = new User;
        user.setBalance(2000);
        bookDao.update(user,wrapper);
    }

2.2 自定义SQL

我们可以利用MyBatisPlus的Wrapper来构建复杂的Where条件,然后自己定义SQL语句中剩下的部分

基本步骤:

  1. 基于Wrapper构建where条件
java 复制代码
 @Test
    void testQueryWrappers(){
        List<Long> ids=List.of(1L,4L,2L);
        int mount = 200;
        //编写条件
        QueryWrapper<User> wrapper = new QueryWrapper<User>()
                .in("id", ids);

        bookDao.updateIds(wrapper,mount);
  1. 在mapper方法参数中用Param注解声明wrapper变量名称,必须是ew
java 复制代码
@Update("update tb_user set balance = balance - #{mount} ${ew.customSqlSegment}")
void updateIds(@Param("ew") QueryWrapper<User> wrapper,@Param("mount") int mount);

2.3 Service接口

利用的就是MybatisPlus创建好的IService<Book>ServiceImpl<BookDao, Book>两个父类,service和serviceImpl分别继承上述两个父类,就拥有了一系列MybaitisPlus封装好的方法

步骤:

  • 创建好BookService和 BookServiceImpl类,然后进行继承
java 复制代码
@Service
public class BookServiceImpl extends ServiceImpl<BookDao, Book> implements BookService {

}
java 复制代码
public interface BookService extends IService<Book> {
} 
  • 测试
java 复制代码
 /*
    * 用来测试service
    * */
    @Autowired
    private BookService service;
    @Test
    void testService(){
        Book book = new Book();
        book.setName("大学英语");
        book.setDescription("学习英语成就背时人生!!!!");
        book.setType("四级英语");
        service.save(book);
    }

    /*
    * 查询
    * */

    @Test
    void testServiceQuery(){
        List<Book> books = service.listByIds(List.of(15L, 16L, 22L));
        books.forEach(System.out::println);
    }

2.4 基于Restful风格实现下列小练习

  1. 新增用户
java 复制代码
@Autowired
    private AccountService accountService;

    /*增添用户*/
    @PostMapping
    public void InsertAccount(Account account){
        accountService.save(account);
    }
  1. 删除用户
java 复制代码
@DeleteMapping("/{id}")
    public void DeleteAccount(@PathVariable Long id){
        accountService.removeById(id);
    }
  1. 根据ID查询用户
java 复制代码
@GetMapping("/{id}")
    public Account QueryAccountById(@PathVariable Long id){
        return accountService.getById(id);
    }
  1. 根据IDS批量查询
java 复制代码
@GetMapping
    public List<Account> QueryAccountByIds(@RequestParam("ids") List<Long> ids){
        return accountService.listByIds(ids);
    }
  1. 根据Id扣减余额

Controller中的代码:

java 复制代码
 @PutMapping("/{id}/deduction/{money}")
    public void deductionMoneyById(@PathVariable Long id ,@PathVariable Long money){
        accountService.deductionMoney(id,money);
    }

AccountService中的代码:

java 复制代码
public interface AccountService extends IService<Account> {
    void deductionMoney(Long id, Long money);
}

AccountServiceImpl当中的代码:

java 复制代码
 public void deductionMoney(Long id, Long money) {
        //查询用户
        Account account = this.getById(id);
        //验证用户信息
        if (account == null || account.getStatus() == 0){
            //代表的是不能进行减去操作
            throw new RuntimeException("用户不存在或账户冻结");
        }
        //查询是否金额能够减去
        if(account.getMoney() < money ){
            throw new RuntimeException("用户的余额不足");
        }
        //进行金额消减
        baseMapper.deductionMoneyById(id,money);
    }

AccountDao当中的代码:

java 复制代码
@Mapper
public interface AccountDao extends BaseMapper<Account> { 
    @Update("update tbl_account set money = money - #{money} where id = #{id};")
    void deductionMoneyById(@Param("id") Long id,@Param("money") Long money); 
}

2.5 IService的Lambda查询

java 复制代码
/*lambda查询用户,Condition是利用一个类来接收传输过来的数据*/
    @GetMapping("/list")
    public List<Account> QueryAccountLambda(Condition condition){
        List<Account> accounts = accountService.lambdaQuerys(
                condition.getUsername(),
                condition.getStatus(),
                condition.getMaxBalance(),
                condition.getMinBalance()
        );
        return accounts;
    }
java 复制代码
@Override
    public List<Account> lambdaQuerys(
            @Param("username") String username,
            @Param("status") Integer status,
            @Param("maxBalance") Long maxBalance,
            @Param("minBalance") Long minBalance)
    {
        return lambdaQuery()
                .eq(username != null,Account::getUsername, username)
                .eq(status != null ,Account::getStatus, status)
                .le(maxBalance!= null,Account::getMoney, maxBalance)
                .ge(minBalance!= null,Account::getMoney, minBalance)
                .list();
    }


在Service当中实现的逻辑处理:

java 复制代码
 @Override
    public void deductionMoney(Long id, Long money) {
        //查询用户
        Account account = this.getById(id);
        //验证用户信息
        if (account == null || account.getStatus() == 0){
            //代表的是不能进行减去操作
            throw new RuntimeException("用户不存在或账户冻结");
        }
        //查询是否金额能够减去
        if(account.getMoney() < money ){
            throw new RuntimeException("用户的余额不足");
        }
        //进行金额消减
        long deMoney = account.getMoney() - money;
        System.out.println(deMoney);
        lambdaUpdate()
                .set(Account::getMoney,deMoney)
                .set(deMoney == 0,Account::getStatus,0)
                .eq(Account::getId,id)
                .eq(Account::getMoney,account.getMoney()) //乐观锁,防止多线程并发问题
                .update(); //必须要进行更新操作
    }

2.6 批量删除

java 复制代码
 @Autowired
    private AccountService service;

    /*首先创建一个自动增加的数据*/
    private Account buildAccount(int i){
        Account account = new Account();
        account.setMoney(2000+i);
        account.setStatus(1);
        account.setUsername("zhangsan" + i);
        return account;
    }


    @Test
    void InsertIds() {
        //首先创建一个容量为1000的list容器
        List<Account> list = new ArrayList<>(1000);

        //记录下当前时间
        long now = System.currentTimeMillis();

        for (int i = 0; i < 10000; i++) {
            list.add(buildAccount(i));
            //判断是否存满
            if (i%1000 == 0){
                //已经存满,加载数据
                service.saveBatch(list);
                //将list数据清空
                list.clear();
            }
        }
        long after = System.currentTimeMillis();
        System.out.println("总共用时:"+(after-now));
    }

在Datasource的url当中&这个参数:

三、拓展业务

下载插件IDEA当中的MybatisPlus


下载完后就点击这个进行Datasource的配置

点击这个进行配置文件的放置


3.1 静态工具


出现静态工具的原因是:
以为如果使用的是service进行创作,如果两张表相互嵌套相互使用,就会出现循环依赖,为了去除这个循环依赖,所以引入了静态工具

java 复制代码
 Db.lambdaQuery(Account.class)
                .eq(Account::getId, id)
                .list()

3.2 逻辑删除

  • 逻辑删除就是基于代码逻辑模拟删除效果,但并不会真正删除数据。思路如下
    • 在表中添加一个字段标记数据是否被删除
    • 当删除数据时把标记置为1
    • 查询时只查询标记为0的数据

MybatisPlus提供了逻辑删除功能,无需改变方法调用的方式,而是在底层帮我们自动修改CRUD的语句。我们要做的就是在application.yaml文件中配置逻辑删除的字段名称和值即可:

yml 复制代码
mybatis-plus:
  global-config:
    db-config: 
      logic-delete-field: deleted# 全局逻辑删除的实体字名,字段类型可以是boolean、integer
      logic-delete-value: 1 # 逻辑已删除值(默认为 1)
      logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)

就是说明我们在进行delete删除数据的时候不再是进行数据的删除,只是把deleted修改为1,在查询的时候加上where条件进行查询是否是1,如果为1,就不会在页面当中显示出来

逻辑删除的弊端:

  • 逻辑删除本身也有自己的问题,比如:会导致数据库表垃圾数据越来越多,影响查询效率
  • SQL中全都需要对逻辑删除字段做判断,影响查询效率因此,我不太推荐采用逻辑删除功能,
  • 如果数据不能删除,可以采用把数据迁移到其它表的办法

3.3、枚举处理器

步骤:

  1. 给枚举中的与数据库对应value值添加@EnumValue注解

  2. 在配置文件中配置统一的枚举处理器,实现类型转换

java 复制代码
public enum SexEnum {
 
    MAN(1, "男"),
    WOMAN(2, "女");
 
    @EnumValue
    private Integer key;
 
    @JsonValue
    private String display;
 
    SexEnum(Integer key, String display) {
        this.key = key;
        this.display = display;
    }
 
    public Integer getKey() {
        return key;
    }
 
    public String getDisplay() {
        return display;
    }
}

3.4 JSON处理器

将数据库当中的JSON类型的String进行转换:

  • 步骤:

3.5 分页插件功能

  1. 首先创建一个配置配去配置拦截器
java 复制代码
@Configuration
public class MyBatisConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        //1. 创建分页条件
        PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
        //2.将分页的条件放入到拦截器当中
        interceptor.addInnerInterceptor(paginationInnerInterceptor);
        return interceptor;
    }
}
  1. 调用方法,把条件插入
java 复制代码
 /*测试分页工具*/
    @Test
    void testPage(){
        //给与条件
        int pageNum = 1;
        int pageSize = 1;
        Page<Book> page = Page.of(pageNum, pageSize);

        //添加排序条件,可以添加多个,如果前一个相同,就按照后面的进行操作
        page.addOrder(new OrderItem("id", true));

        Page<Book> p =  service.page(page);  
		//可以查询表的其他信息 
        
        //获取到查询数据的总条数
        long total = p.getTotal();
        System.out.println("total"+total);
        //获取到当前分页的全部数据
        List<Book> records = p.getRecords();
        records.forEach(System.out::println);
        //获取到页码的数量
        long pages = p.getPages();
        System.out.println("pages:"+pages);
    }

3.6 通用分页实体

pojo.Book层:

java 复制代码
@Data
@TableName("tbl_book")
public class Book {
    private Integer id;
    private String type;
    private String name;
    private String description;
}

PageInfo(就是封装的分页信息类):

java 复制代码
@Data
public class PageInfo<T> {
    /*查询到的总条数*/
    private Long total;
    /*查询到的总页数*/
    private Long pages;
    /*查询到当前页的所有数据*/
    private List<T> info;
}

MybatisConfig(注解封装的拦截器,用来拦截信息添加分页功能):

java 复制代码
@Configuration
@MapperScan("com.itheima.dao")
public class MyBatisConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        //1. 创建分页条件
        PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
        //2.将分页的条件放入到拦截器当中
        interceptor.addInnerInterceptor(paginationInnerInterceptor);
        return interceptor;
    }
}

BookController:

java 复制代码
@RestController
@RequestMapping("/books")
public class BookController {
    @Autowired
    private BookService service;

   
    @GetMapping("/pages")
    PageInfo<Book> myQueryPages(BookQuery bookQuery){
        return service.QueryPages(bookQuery);
    } 
}

BookDao:

java 复制代码
@Mapper
public interface BookDao extends BaseMapper<Book>{
    @Select("select * from tbl_book where id > #{id}")
    Page<Book> selectPageVo(@Param("page") Page<User> page, @Param("id") Integer id);
}

TemplateQuery(查询条件类的模板《父类》):

java 复制代码
@Data
public class TemplateQuery {
    //页码
    private int queryPage;
    //size
    private int querySize;
    //排序条件
    private String ordered;
    //升序还是降序(true升序)
    private boolean desc;
}

BookQuery(创建放置查询条件的类):

java 复制代码
@Data
public class BookQuery extends TemplateQuery{
    /*查询的书名字*/
    private String name;
    /*查询的科目*/
    private String type;
}

Bookservice:

java 复制代码
public interface BookService extends IService<Book> {
    PageInfo<Book> QueryPages(BookQuery bookQuery);
} 

BookServiceImpl:

java 复制代码
@Service
public class BookServiceImpl extends ServiceImpl<BookDao, Book> implements BookService {
    @Override
    public PageInfo<Book> QueryPages(BookQuery bookQuery) {
        //获取到传输过来的数据
        int queryPage = bookQuery.getQueryPage();
        String name = bookQuery.getName();
        int querySize = bookQuery.getQuerySize();
        String ordered = bookQuery.getOrdered();
        String type = bookQuery.getType();

        //分页查询条件
        Page<Book> page = Page.of(queryPage, querySize);

        //排序条件
        //进行判断
        if(ordered != null){
            page.addOrder(new OrderItem(ordered,bookQuery.isDesc()));
        }else {
            //设置默认值
            page.addOrder(new OrderItem("id",true));
        }


        //分页条件
        lambdaQuery()
                .like(name !=null,Book::getName,name)
                .like(type != null,Book::getType,type)
                .page(page);

        //将数据进行封装
        PageInfo<Book> bookPageInfo = new PageInfo<>();

        bookPageInfo.setPages(page.getPages());
        bookPageInfo.setInfo(page.getRecords());
        bookPageInfo.setTotal(page.getTotal());

        return bookPageInfo;
    }
}
相关推荐
郭天宇 abfore15 天前
MybatisPlus
java·mybatis·mybatisplus·1024程序员节
我的程序快快跑啊1 个月前
MyBatisPlus:常见注解
java·mybatisplus
haloYml1 个月前
mybatisplus的查询,分页查询,自定义多表查询,修改的几种写法
mybatisplus
胡耀超1 个月前
1.分页查询(后端)—— Vue3 + SpringCloud 5 + MyBatisPlus + MySQL 项目系列(基于 Zulu 11)
mysql·spring·spring cloud·mybatis·mybatisplus·zulu11
u0100559603 个月前
IPage类与Page类区别和作用讲解
mybatis·mybatisplus
大飞哥~BigFei3 个月前
mybatisPlus的@TableLogic逻辑删除注解导致联合索引失效的坑
mysql·mybatisplus
装不满的克莱因瓶3 个月前
你真的懂Mybatis分页原理吗?
java·开发语言·架构·mybatis·mybatisplus·mybatis-plus·分页
是梦终空3 个月前
JAVA毕业设计153—基于Java+Springboot+小程序的校园维修管理系统小程序(源代码+数据库)
java·spring boot·小程序·毕业设计·layui·mybatisplus·校园维修管理系统
是梦终空4 个月前
JAVA毕业设计152—基于Java+Springboot+vue+小程序的个人健康管理系统小程序(源代码+数据库+15000字论文)
java·spring boot·vue·毕业设计·论文·mybatisplus·个人健康管理小程序
小言不爱说4 个月前
后端实现图片上传本地,可采用url查看图片
java·数据库·mybatisplus