我们在前面的文章中已经学习了目前开发所需的主流框架
类似于我们所学习的SpringBoot框架用于简化Spring开发,我们的国人大大也开发了一款MyBatisPlus框架用来简化MyBatis开发
下面让我们来逐步掌握MyBatisPlus的内容吧~
首先我们来简单介绍一下MyBatisPlus:
MyBatisPlus开发具有三种开发方式:
我们以基于SpringBoot使用MyBatisPlus为案例来展示MyBatisPlus开发的便捷性
首先我们回忆一下SpringBoot使用MyBatis开发的相关步骤:
其中最为繁琐的就是数据层接口的配置,需要书写大量的@注解来进行数据库的查询
package com.itheima.dao;
import com.itheima.domain.Book;
import org.apache.ibatis.annotations.*;
import java.util.List;
@Mapper
public interface BookDao {
@Insert("insert into tbl_book (type,name,description) values(#{type},#{name},#{description})")
public int save(Book book);
@Update("update tbl_book set type = #{type}, name = #{name}, description = #{description} where id = #{id}")
public int update(Book book);
@Delete("delete from tbl_book where id = #{id}")
public int delete(Integer id);
@Select("select * from tbl_book where id = #{id}")
public Book getById(Integer id);
@Select("select * from tbl_book")
public List<Book> getAll();
}
我们的SpringBoot使用MyBatisPlus大量简化了数据层代码书写
我们下面依次介绍整体步骤:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.itheima</groupId>
<artifactId>mybatisplus_01_quickstart</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--由于SpringBoot中未整合MyBatisPlus,所以我们需要手动添加MyBatisPlus依赖坐标-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!--德鲁伊坐标-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/mybatisplus_db?serverTimezone=UTC
username: root
password: root
package com.itheima.domain;
import lombok.*;
@Data
public class User {
private Long id;
private String name;
private String password;
private Integer age;
private String tel;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getTel() {
return tel;
}
public void setTel(String tel) {
this.tel = tel;
}
@java.lang.Override
public java.lang.String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", password='" + password + '\'' +
", age=" + age +
", tel='" + tel + '\'' +
'}';
}
}
package com.itheima.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.itheima.domain.User;
import org.apache.ibatis.annotations.Mapper;
// @Mapper为了使扫描到该数据层包(SpringBoot中提及)
@Mapper
// 注意:MyBatisPlus不需要书写方法,我们直接继承BaseMapper类,并表明我们所使用的实体类即可
public interface UserDao extends BaseMapper<User> {
// 不需要书写方法,在BaseMapper类中为我们配置了大量的数据库方法来查询,新增,修改,删除
}
package com.itheima;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itheima.dao.UserDao;
import com.itheima.domain.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest
class Mybatisplus01QuickstartApplicationTests {
@Autowired
private UserDao userDao;
// 我们只需要得到UserDao类,并调用其方法即可(MyBatisPlus提供方法)
// 在这里我们仅调用selectById方法,当作测试
@Test
void testGetById(){
User user = userDao.selectById(2L);
System.out.println(user);
}
}
至此,我们的第一个MyBatisPlus案例就结束了
在使用过MyBatisPlus后,我们就可以重新介绍一下MyBatisPlus了:
MyBatisPlus特征:
最后提及一句:MyBatisPlus是由国人开发,官网也是以中文书写,具有中国风范~
我们在前面已经大致掌握了MyBatisPlus的具体操作流程,下面让我们更加细腻的分析数据层开发
在正式开始讲解数据层开发前,为大家提供一个简单可靠的依赖:
那么这个坐标具有什么作用呢
我们采用一个简单的案例来展示:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
</dependency>
package com.itheima.domain;
import lombok.*;
//lombok
@Data
public class User {
private Long id;
private String name;
private String password;
private Integer age;
private String tel;
}
/*
lombok为我们提供了多个注解:
@Setter:提供所有set方法
@Getter:提供所有Get方法
@ToString:提供ToString重构方法
@NoArgsConstructor:无参构造
@AllArgsConstructor:有参构造
其中我们最常用的注解是:
@Data:包括了除构造函数外的所有方法(Set,Get,ToString,hashCode,equals)
*/
首先我们来列出一些我们通常开发中会使用的数据层语句:
| 功能 | MP接口 |
|---|---|
| 新增 | int insert(T t) |
| 删除 | int deleteById(Serializable id) |
| 修改 | int updateById(T t) |
| 根据id查询 | T selectById(Serializable id) |
| 查询全部 | List |
上述方法我们无需在数据层定义,直接测试即可:
package com.itheima;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itheima.dao.UserDao;
import com.itheima.domain.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest
class Mybatisplus01QuickstartApplicationTests {
// 自动装配数据层
@Autowired
private UserDao userDao;
// 注意:id的数据类型为LONG,数值后需要加L
// 注意:下述部分方法需要返回id,实体类,null
// 新增
@Test
void testSave(){
User user = new User();
user.setName("黑马程序员");
user.setPassword("itheima");
user.setAge(12);
user.setTel("4006184000");
userDao.insert(user);
}
// 删除
@Test
void testDelete(){
userDao.deleteById(1L);
}
// 更新(注意:根据id进行更新,更新与原数据不同的数值,null值不进行更新)
@Test
void testUpdate(){
User user = new User();
user.setId(1L);
user.setName("Tom888");
user.setPassword("tom888");
userDao.updateById(user);
}
// 根据id查询
@Test
void testGetById(){
User user = userDao.selectById(2L);
System.out.println(user);
}
// 查询全部
@Test
void testGetAll() {
List<User> userList = userDao.selectList(null);
System.out.println(userList);
}
}
我们将分页查询单独列为一个小节进行讲解:
| 功能 | MP接口 |
|---|---|
| 分页查询 | IPage<T> selectPage(IPage<T> page) |
MyBatisPlus的分页查询需要一些前置条件,我们下面一一讲述:
// MyBatisPlus的分页操作需要添加拦截器
// 我们在Java文件夹下创建Config文件夹,创建MPConfig的Java类作为配置类
package com.itheima.config;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
// 作为配置类,让spring可以直接扫描
@Configuration
public class MpConfig {
// 需要设置为Bean
@Bean
public MybatisPlusInterceptor mpInterceptor(){
//1.定义Mp拦截器MybatisPlusInterceptor(相当于外层拦截器)
MybatisPlusInterceptor mpInterceptor = new MybatisPlusInterceptor();
//2.添加具体的拦截器PaginationInnerInterceptor(相当于在大拦截器中添加小拦截器)
mpInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return mpInterceptor;
}
}
package com.itheima;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itheima.dao.UserDao;
import com.itheima.domain.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest
class Mybatisplus01QuickstartApplicationTests {
@Autowired
private UserDao userDao;
@Test
void testGetByPage(){
// selectPage需要两个参数IPage和Wrapper,IPage具有Page的实现类,Wrapper我们会在后续讲到,这里暂设为null
//IPage对象封装了分页操作相关的数据,第一个参数为开始数,第二个数为本页可展示数据数
IPage page = new Page(2,3);
userDao.selectPage(page,null);
// 下述为page本身携带的一些方法,用于查看相关数据
System.out.println("当前页码值:"+page.getCurrent());
System.out.println("每页显示数:"+page.getSize());
System.out.println("一共多少页:"+page.getPages());
System.out.println("一共多少条数据:"+page.getTotal());
System.out.println("数据:"+page.getRecords());
}
}
# 如果我们想要查看实际开发的数据库语句,我们可以选择开启日志进行查看
# 查看日志方法设置在yaml配置文件中
# 开启mp的日志(输出到控制台)
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
我们在前面已经讲解了简单的数据层开发,下面我们将会进一步讲解DQL的编程内容
在正式开始前,我们讲一些简单轻松的知识点:

那么我们该如何清除呢
<!--我们在sources中新创一个spring config 文件-->
<!--设置一个configuration双标签,不用填写内容即可-->
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
</configuration>
# 我们只需要将spring和MyBatisPlus的banner设置为false即可关闭版本图
# dataSource
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/mybatisplus_db?serverTimezone=UTC
username: root
password: root
main:
banner-mode: off
# mp日志
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
banner: false
在介绍条件查询前,我们需要先来介绍Wrapper:
接下来我们就来介绍三种基本条件查询:
package com.itheima;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.itheima.dao.UserDao;
import com.itheima.domain.User;
import com.itheima.domain.query.UserQuery;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
import java.util.Map;
@SpringBootTest
class Mybatisplus02DqlApplicationTests {
@Autowired
private UserDao userDao;
@Test
void testGetAll() {
//方式一:按条件查询
// 我们的条件查询一般采用QueryWrapper类型的类来创造Wrapper条件判断参数
QueryWrapper qw = new QueryWrapper();
// 我们采用QueryWrapper的一些方法来进行给予判断条件,后续我们会进行介绍
// 这里采用lt小于方法,后面跟String类型字符串代表数据库列名,在跟数值表示值
qw.lt("age",18);
// 我们采用userDao的selectList方法根据qw条件判断机制来进行获取数据
// 获取了User数值的List,并打印即可
List<User> userList = userDao.selectList(qw);
System.out.println(userList);
}
}
package com.itheima;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.itheima.dao.UserDao;
import com.itheima.domain.User;
import com.itheima.domain.query.UserQuery;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
import java.util.Map;
@SpringBootTest
class Mybatisplus02DqlApplicationTests {
@Autowired
private UserDao userDao;
@Test
void testGetAll() {
//方式二:lambda格式按条件查询
QueryWrapper<User> qw = new QueryWrapper<User>();
// MyBatisPlus可支持Lambda表达式,我们使用lambda方法使后续操作均变为Lambda表达式形式
// 我们的String数据库列名可以采用Lambda表达式形式书写
qw.lambda().lt(User::getAge, 10);
List<User> userList = userDao.selectList(qw);
System.out.println(userList);
}
}
package com.itheima;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.itheima.dao.UserDao;
import com.itheima.domain.User;
import com.itheima.domain.query.UserQuery;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
import java.util.Map;
@SpringBootTest
class Mybatisplus02DqlApplicationTests {
@Autowired
private UserDao userDao;
@Test
void testGetAll() {
//方式三:lambda格式按条件查询
// 这里直接继承LambdaQueryWrapper,后续操作可以直接采用Lambda表达式,不用携带方法lambda
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
lqw.lt(User::getAge, 10);
List<User> userList = userDao.selectList(lqw);
System.out.println(userList);
}
}
除了上面三种基本条件查询外,我们可以发现条件查询是可以叠加使用的,主要分为两种叠加方式:
package com.itheima;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.itheima.dao.UserDao;
import com.itheima.domain.User;
import com.itheima.domain.query.UserQuery;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
import java.util.Map;
@SpringBootTest
class Mybatisplus02DqlApplicationTests {
@Autowired
private UserDao userDao;
@Test
void testGetAll() {
// 10到30岁之间
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
// 依次分开书写
lqw.lt(User::getAge, 30);
lqw.gt(User::getAge, 10);
List<User> userList = userDao.selectList(lqw);
System.out.println(userList);
}
}
package com.itheima;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.itheima.dao.UserDao;
import com.itheima.domain.User;
import com.itheima.domain.query.UserQuery;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
import java.util.Map;
@SpringBootTest
class Mybatisplus02DqlApplicationTests {
@Autowired
private UserDao userDao;
@Test
void testGetAll() {
// 10到30岁之间
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
// 链式叠加书写
lqw.lt(User::getAge, 30).gt(User::getAge, 10);
List<User> userList = userDao.selectList(lqw);
System.out.println(userList);
}
}
最后我们还要介绍两种组合查询条件形式:
package com.itheima;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.itheima.dao.UserDao;
import com.itheima.domain.User;
import com.itheima.domain.query.UserQuery;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
import java.util.Map;
@SpringBootTest
class Mybatisplus02DqlApplicationTests {
@Autowired
private UserDao userDao;
@Test
void testGetAll() {
//并且关系
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
//并且关系:10到30岁之间(直接链式书写即可)
lqw.lt(User::getAge, 30).gt(User::getAge, 10);
List<User> userList = userDao.selectList(lqw);
System.out.println(userList);
}
}
package com.itheima;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.itheima.dao.UserDao;
import com.itheima.domain.User;
import com.itheima.domain.query.UserQuery;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
import java.util.Map;
@SpringBootTest
class Mybatisplus02DqlApplicationTests {
@Autowired
private UserDao userDao;
@Test
void testGetAll() {
//或者关系
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
//或者关系:小于10岁或者大于30岁(在条件之间采用or方法来隔离)
lqw.lt(User::getAge, 10).or().gt(User::getAge, 30);
List<User> userList = userDao.selectList(lqw);
System.out.println(userList);
}
}
我们在做实际项目处理时,会出现各种查询框架
例如价格查询搜索产品,但我们可能不会同时给出最低价限制和最高价限制
我们以代码来做一个简单示例:
package com.itheima;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.itheima.dao.UserDao;
import com.itheima.domain.User;
import com.itheima.domain.query.UserQuery;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
import java.util.Map;
@SpringBootTest
class Mybatisplus02DqlApplicationTests {
@Autowired
private UserDao userDao;
@Test
void testGetAll() {
// 模拟页面传递过来的查询数据
UserQuery uq = new UserQuery();
// 如果我们下面的数据有一个没有设置,就会导致查询语句中的?没有填充,导致搜索失败
uq.setAge(10);
uq.setAge2(null);
// null判定
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
lqw.lt(User::getAge, uq.getAge2());
lqw.gt(User::getAge, uq.getAge());
List<User> userList = userDao.selectList(lqw);
System.out.println(userList)
}
}
在之前我们的null值处理大部分都是采用if语句来进行判断:
package com.itheima;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.itheima.dao.UserDao;
import com.itheima.domain.User;
import com.itheima.domain.query.UserQuery;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
import java.util.Map;
@SpringBootTest
class Mybatisplus02DqlApplicationTests {
@Autowired
private UserDao userDao;
@Test
void testGetAll() {
// 模拟页面传递过来的查询数据
UserQuery uq = new UserQuery();
// 可能出现有任意一个数没有赋值
uq.setAge(10);
uq.setAge2(null);
// null判定
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
lqw.lt(User::getAge, uq.getAge2());
// 正常我们采用if来进行判断是否有值,若有值则加入操作
// 但当if语句过多,导致代码冗杂
if( null != uq.getAge()) {
lqw.gt(User::getAge, uq.getAge());
}
List<User> userList = userDao.selectList(lqw);
System.out.println(userList);
}
}
MyBatisPlus给出了一种新的判定方法来决定是否加载该语句:
package com.itheima;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.itheima.dao.UserDao;
import com.itheima.domain.User;
import com.itheima.domain.query.UserQuery;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
import java.util.Map;
@SpringBootTest
class Mybatisplus02DqlApplicationTests {
@Autowired
private UserDao userDao;
@Test
void testGetAll() {
// 模拟页面传递过来的查询数据
UserQuery uq = new UserQuery();
uq.setAge(10);
uq.setAge2(30);
// LambdaQueryWrapper的各种方法中均携带了一个判定条件在最前面的参数中,当成立执行后续操作,不成立直接跳过
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
// 先判定第一个参数是否为true,如果为true连接当前条件
lqw.lt(null != uq.getAge2(),User::getAge, uq.getAge2());
lqw.gt(null != uq.getAge(),User::getAge, uq.getAge());
List<User> userList = userDao.selectList(lqw);
System.out.println(userList);
}
}
我们选择性的查询数据库列称为查询投影,接下来让我们来介绍查询投影的实现方法
查询投影的实现我们大致分为两种类型:
package com.itheima;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.itheima.dao.UserDao;
import com.itheima.domain.User;
import com.itheima.domain.query.UserQuery;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
import java.util.Map;
@SpringBootTest
class Mybatisplus02DqlApplicationTests {
@Autowired
private UserDao userDao;
@Test
void testGetAll() {
// 查询投影
// 当我们所查询的内容属于实体类中包含的属性,我们可以采用QW或LambdaQW来实现
// 我们大部分采用LambdaQW来实现,因为带有自动识别,不易出错
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
// 我们采用select方法来添加查询种类,LambdaQueryWrapper采用Lambda表达式添加
lqw.select(User::getId,User::getName,User::getAge);
QueryWrapper<User> lqw = new QueryWrapper<User>();
// 我们采用select方法来添加查询种类,QueryWrapper采用String添加
lqw.select("id","name","age","tel");
List<User> userList = userDao.selectList(lqw);
System.out.println(userList);
}
}
package com.itheima;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.itheima.dao.UserDao;
import com.itheima.domain.User;
import com.itheima.domain.query.UserQuery;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
import java.util.Map;
@SpringBootTest
class Mybatisplus02DqlApplicationTests {
@Autowired
private UserDao userDao;
@Test
void testGetAll() {
// 查询投影
// 未定义的属性我们只能采用QueryWrapper的String字符串来书写,例如count(*)和分组条件
QueryWrapper<User> lqw = new QueryWrapper<User>();
lqw.select("count(*) as count, tel");
// QueryWrapper提供了分组方法groupBy,参数为String类型的数据库列名
lqw.groupBy("tel");
List<Map<String, Object>> userList = userDao.selectMaps(lqw);
System.out.println(userList);
}
}
首先我们给出所有查询条件官网链接:条件构造器 | MyBatis-Plus (baomidou.com)

如果有需要可以上网查询相关构造方法
下面我们仅对一些常用查询条件进行展示:
package com.itheima;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.itheima.dao.UserDao;
import com.itheima.domain.User;
import com.itheima.domain.query.UserQuery;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
import java.util.Map;
@SpringBootTest
class Mybatisplus02DqlApplicationTests {
@Autowired
private UserDao userDao;
@Test
void testGetAll() {
//条件查询
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
// eq等同于=
lqw.eq(User::getName,"Jerry").eq(User::getPassword,"jerry");
User loginUser = userDao.selectOne(lqw);
System.out.println(loginUser);
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
//范围查询 lt le gt ge eq between
lqw.between(User::getAge,10,30);
List<User> userList = userDao.selectList(lqw);
System.out.println(userList);
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
//模糊匹配 like
lqw.likeLeft(User::getName,"J");
List<User> userList = userDao.selectList(lqw);
System.out.println(userList);
// 查询全部
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
List<User> userList = userDao.selectList(lqw);
System.out.println(userList);
}
}
最后介绍的依旧是我们在MyBatis中也出现的老问题:
我们在下面分为几种情况来讲解:
// 假设我们的数据库表名为tbl_user,但我们的实体类设计为User
package com.itheima.domain;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
// 采用注解@TableName,后面跟对应的数据库表名
@TableName("tbl_user")
public class User {
private Long id;
private String name;
private String password;
private Integer age;
private String tel;
}
// 假设我们的数据库密码设计为pwd,但是我们的实体类密码属性设计为password
package com.itheima.domain;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
//lombok
@Data
@TableName("tbl_user")
public class User {
private Long id;
private String name;
// 采用@TableField注解,后面采用属性value=数据库列名
@TableField(value = "pwd")
private String password;
private Integer age;
private String tel;
}
// 例如我们的pwd密码,在查询时不应当被查询,但是我们采用select * from tbl_user来查询,如何屏蔽
package com.itheima.domain;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
//lombok
@Data
@TableName("tbl_user")
public class User {
private Long id;
private String name;
// 采用@TableField注解,后面采用属性select设置为false,即为不可查询
@TableField(value = "pwd",select = false)
private String password;
private Integer age;
private String tel;
}
// 例如我们设计了一个属性online判断是否在线,不用放于数据库中,我们该如何在select * 中去除该属性
package com.itheima.domain;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
//lombok
@Data
@TableName("tbl_user")
public class User {
private Long id;
private String name;
@TableField(value = "pwd",select = false)
private String password;
private Integer age;
private String tel;
// 采用@TableField注解,后面跟属性exist设置为false,则判断该属性不存在于数据库中
@TableField(exist = false)
private Integer online;
}
我们将上述内容分离出来主要解释两个注解:
这一章节我们来讲一些MyBatisPlus中经常用到的操作,下面我们一一介绍
我们在实际开发中会有需要ID生成需求,对于不同的情况需要采取不同的ID生成方法:
因此MyBatisPlus提供了一种新的注解来实现这类需求:
ID生成策略枚举值:
我们给出示例演示:
package com.itheima.domain;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.Version;
import lombok.Data;
@Data
//设置表名映射关系
@TableName("tbl_user")
public class User {
//设置主键生成策略(这里设置为自增)
@TableId(type = IdType.AUTO)
private Long id;
private String name;
@TableField(value = "pwd",select = false)
private String password;
private Integer age;
private String tel;
@TableField(exist = false)
private Integer online;
private Integer deleted;
private Integer version;
}
我们也可以同一设置@TableId的type属性,使整个项目的@TableId都以一种形态执行:
# dataSource
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/mybatisplus_db?serverTimezone=UTC
username: root
password: root
main:
banner-mode: off
# mp日志
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
banner: false
db-config:
id-type: assign_id # 设置为雪花算法设置ID
我们在实际开发中常常会进行多条记录操作:
MyBatisPlus也为我们提供了相对应的方法:
package com.itheima;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itheima.dao.UserDao;
import com.itheima.domain.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.ArrayList;
import java.util.List;
@SpringBootTest
class Mybatisplus03DqlApplicationTests {
@Autowired
private UserDao userDao;
@Test
void testDelete(){
//删除指定多条数据
//deleteBatchIds参数为数组形式,我们提供id的数组即可
List<Long> list = new ArrayList<>();
list.add(1402551342481838081L);
list.add(1402553134049501186L);
list.add(1402553619611430913L);
userDao.deleteBatchIds(list);
}
@Test
void testSelect()}{
//查询指定多条数据
//selectBatchIds参数为数组形式,我们提供id的数组即可
List<Long> list = new ArrayList<>();
list.add(1L);
list.add(3L);
list.add(4L);
userDao.selectBatchIds(list);
}
}
我们在实际开发中面对项目的删除操作有时并非是真正的删除操作:
因而我们提出了逻辑删除的概念:
下面我们来讲解如何在MyBatisPlus中实现这种思想:
ALTER TABLE tb_user ADD deleted int(1) DEFAULT 0;
package com.itheima.domain;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.Version;
import lombok.Data;
@Data
//设置表名映射关系
@TableName("tbl_user")
public class User {
//设置主键生成策略
@TableId(type = IdType.ASSIGN_ID)
private Long id;
private String name;
@TableField(value = "pwd",select = false)
private String password;
private Integer age;
private String tel;
@TableField(exist = false)
private Integer online;
//逻辑删除字段,标记当前记录是否被删除(value原值,delval修改值)
@TableLogic(value = "0" ,delval = "1")
private Integer deleted;
}
/*
@TableLogic
在设置之后,我们采用delete方法时,不会直接删除数据,而是将该数据值从value变为delval
类似于:UPDATE tbl_user SET deleted = 1 WHERE id = ? AND deleted = 0;
*/
同样,我们的逻辑删除值也可以进行统一设置:
# dataSource
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/mybatisplus_db?serverTimezone=UTC
username: root
password: root
main:
banner-mode: off
# mp日志
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
banner: false
db-config:
id-type: assign_id
table-prefix: tbl_
# 逻辑删除字段名
logic-delete-field: deleted
# 逻辑删除字面值:未删除为0
logic-not-delete-value: 0
# 逻辑删除字面值:删除为1
logic-delete-value: 1
我们在业务开发中也会遇到多线程的问题:
首先我们来讲解一下乐观锁的基本概念:
在MyBatisPlus中我们采用乐观锁的概念来解决:
ALTER TABLE tb_user ADD version int(11) DEFAULT 1;
package com.itheima.domain;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.Version;
import lombok.Data;
@Data
//设置表名映射关系
@TableName("tbl_user")
public class User {
@TableId(type = IdType.ASSIGN_ID)
private Long id;
private String name;
@TableField(value = "pwd",select = false)
private String password;
private Integer age;
private String tel;
@TableField(exist = false)
private Integer online;
@TableLogic(value = "0" ,delval = "1")
private Integer deleted;
// version版本注解(乐观锁)
@Version
private Integer version;
}
/*
我们来讲解一下为什么需要使用拦截器
我们将前面我们介绍的乐观锁概念转化为语句:
SELETE version FROM tbl_user
UPDATE tbl_user SET ...(用户修改) version=version+1 WHERE id = ? AND version = version(我们之前读取的version)
倘若用户操作前有其他用户操作,那么version就会发生变化,导致用户无法找到对应的数据,无法操作
因为我们需要对前面的version进行修改,我们需要将语句拦截下来进行一定修改,所以这里采用拦截器
*/
package com.itheima.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 {
@Bean
public MybatisPlusInterceptor mpInterceptor() {
//1.定义Mp拦截器
MybatisPlusInterceptor mpInterceptor = new MybatisPlusInterceptor();
//2.添加具体的拦截器
mpInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
//3.添加乐观锁拦截器
mpInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return mpInterceptor;
}
}
package com.itheima;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itheima.dao.UserDao;
import com.itheima.domain.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.ArrayList;
import java.util.List;
@SpringBootTest
class Mybatisplus03DqlApplicationTests {
@Autowired
private UserDao userDao;
@Test
void testUpdate(){
// 我们设置一个实例User,id为1,version为1
User user = new User();
user.setId(1L);
user.setName("Jock666");
user.setVersion(1);
userDao.updateById(user);
// 我们用user,user2来当作两个用户
// 假设两个用户同时读取数据
User user = userDao.selectById(3L); //version=1
User user2 = userDao.selectById(3L); //version=1
// user用户首先进行操作(这时 实例version为1 操作成立 ,操作结束后version变为2)
// UPDATE tbl_user SET ...(用户修改) version=2 WHERE id = 1 AND version = 1
user.setName("Jock aaa");
userDao.updateById(user2);
// user2用户开始操作(这时 实例version为2 但前面读取的version为1,读取不到数据,无法操作)
// UPDATE tbl_user SET ...(用户修改) version=2 WHERE id = 1 AND version = 1(已读取不到数据)
user2.setName("Jock bbb");
userDao.updateById(user);
}
}
好的,关于MyBatisPlus的内容就介绍到这里,希望能为你带来帮助!
该文章属于学习内容,具体参考B站黑马程序员李老师的SSM框架课程
Transformers开始在视频识别领域的“猪突猛进”,各种改进和魔改层出不穷。由此作者将开启VideoTransformer系列的讲解,本篇主要介绍了FBAI团队的TimeSformer,这也是第一篇使用纯Transformer结构在视频识别上的文章。如果觉得有用,就请点赞、收藏、关注!paper:https://arxiv.org/abs/2102.05095code(offical):https://github.com/facebookresearch/TimeSformeraccept:ICML2021author:FacebookAI一、前言Transformers(VIT)在图
我想开始使用“Sinatra”框架进行编码,但我找不到该框架的“MVC”模式。是“MVC-Sinatra”模式或框架吗? 最佳答案 您可能想查看Padrino这是一个围绕Sinatra构建的框架,可为您的项目提供更“类似Rails”的感觉,但没有那么多隐藏的魔法。这是使用Sinatra可以做什么的一个很好的例子。虽然如果您需要开始使用这很好,但我个人建议您将它用作学习工具,以对您来说最有意义的方式使用Sinatra构建您自己的应用程序。写一些测试/期望,写一些代码,通过测试-重复:)至于ORM,你还应该结帐Sequel其中(imho
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭10年前。我一直在Rails上做两个项目,它们运行良好,但在这个过程中重新发明了轮子,自来水(和热水)和止痛药,正如我随后了解到的那样,这些已经存在于框架中。那么基本上,正确了解框架中所有智能部分的最佳方法是什么,这将节省时间而不是自己构建已经实现的功能?从第1页开始阅读文档?是否有公开所有内容的特定示例应用程序?一个特定的开源项目?所有的rails交通?还是完全
关闭。这个问题不符合StackOverflowguidelines.它目前不接受答案。我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。关闭4年前。Improvethisquestion我希望能够将模板化的YARD文档样式注释插入到我现有的Rails遗留应用程序中。目前它的评论很少。我想要具有指定参数的类header和方法header(通过从我假定的方法签名中提取)和返回值的占位符。在PHP代码中,我有一些工具可以检查代码并在适当的位置创建插入到代码中的文档header注释。在带有Ducktyping等的Ruby中,我确信诸如@params等类型之类
我尝试用Ruby设计一个基于Web的应用程序。我开发了一个简单的核心应用程序,在没有框架和数据库的情况下在六边形架构中实现DCI范例。核心六边形中有小六边形和网络,数据库,日志等适配器。每个六边形都在没有数据库和框架的情况下自行运行。在这种方法中,我如何提供与数据库模型和实体类的关系作为独立于数据库的关系。我想在将来将框架从Rails更改为Sinatra或数据库。事实上,我如何在这个核心Hexagon中实现完全隔离的rails和mongodb的数据库适配器或框架适配器。有什么想法吗? 最佳答案 ROM呢?(Ruby对象映射器)。还有
我为你们准备了一个简单的。我想要一个特色内容部分,其中排除了当前文章所以这可以通过delete_if使用MiddlemanBlog:但是我使用的是中间人代理,所以我无法访问current_article方法...我有一个YAML结构,其中包含以下模拟数据(以及其他数据),文件夹设置如下:data>site>caseStudy>RANDOM-ID423536.yaml(由CMS生成)在每个yaml文件中,您会发现如下内容::id:2k1YccJrQsKE2siSO6o6ac:title:Heyplace我的config.rb看起来像这样data.site.caseStudy.eachdo
为了简洁起见,我想优化以下代码。x1.each{|x|x2.each{|y|....xN.each{|z|yield{}.merge(x).merge(y)......merge(z)}}}假设x1,x2,...,xN是Enumerator对象。以上内容不够简洁它与x1、x2作为Array一起工作,但不是作为Enumerators因为应该为内部循环重置枚举器迭代器我试过了,但没有成功:[x1,x2,...,xN].reduce(:product).map{|x|x.reduce:merge}有什么建议吗?更新目前解决了:[x1,x2,...,xN].map(:to_a).reduce(
据我了解,Python的扭曲框架为网络通信提供了更高级别的抽象(?)。我正在寻找在Rails应用程序中使用与twisted等效的Ruby。 最佳答案 看看EventMachine.它不像Twisted那样广泛,但它是围绕事件驱动网络编程的相同概念构建的。 关于python-Ruby是否有相当于Python的扭曲框架作为网络抽象层?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/9
我正在为我的网站使用MiddlemanBloggem,但默认情况下,博客文章似乎需要位于/source中,这在查看vim中的树时并不是特别好并尝试在其中找到其他文件之一(例如模板)。通过查看文档,我看不出是否有任何方法可以移动博客文章,以便将它们存储在其他地方,例如blog_articles文件夹或类似文件夹。这可能吗? 最佳答案 将以下内容放入您的config.rb文件中。activate:blogdo|blog|blog.permalink=":year-:month-:day-:title.html"blog.sources=
我想使用比Rails(Sinatra/Ramaze/Camping)更轻的框架,但我担心这样做我将无法使用许多以插件形式为Rails定制的共享库.这是一个主要问题,还是这些插件中的大多数都可以跨不同的Ruby框架使用?使用Ruby框架而不是Rails是否还有其他潜在的缺点? 最佳答案 您仍然可以使用gems在你提到的所有框架中,很多东西都是可重用的。想要交换一个新的ORM,没问题。想要一个花哨的shmacy语法高亮,没问题。Rails一直在大力插入摆脱旧的插件模型,转而使用gems。如果其他框架之一符合您的需求,最好使用它。请记住,