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;
    }
}
相关推荐
九皇叔叔9 天前
【06】SpringBoot3 MybatisPlus 修改(Mapper)
java·spring boot·mybatis·mybatisplus
九皇叔叔12 天前
【02】SpringBoot3 MybatisPlus 加入日志功能
java·mysql·mybatis·日志·mybatisplus
子非鱼92118 天前
MyBatisPlus快速上手
数据库·spring boot·mybatisplus
DCTANT24 天前
【原创】使用更优雅的方式改造MyBatisPlus逻辑删除插件
spring boot·后端·mysql·kotlin·mybatis·mybatisplus
回忆是昨天里的海1 个月前
Spring boot接入视图时的问题
mysql·mybatisplus·视图
咘噜biu2 个月前
多租户动态数据源插件dynamic-datasource简介
java·mybatisplus·动态数据源·多租户
阿拉斯攀登2 个月前
MyBatis-Plus 全面介绍 & Spring Boot 集成实战
java·spring boot·mybatisplus·mp
LSL666_2 个月前
mybatisplus入门案例
数据库·mysql·mybatisplus
fanruitian2 个月前
springboot-mybatisplus-demo
spring boot·后端·mybatis·mybatisplus
草原印象2 个月前
Spring Boot Spring MVC MyBatis MyBatis Plus框架编写项目实战案例
spring boot·spring·mybatis·springmvc·mybatisplus