mybatis-plus
Mybatis-plus
- 简化数据库操作,帮你完成简单的增删改
第一个mybatis-plus(springboot框架)
-
创建springboot程序,勾选mysqlDriver
-
导入依赖
<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.2</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.23</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> -
写数据库对应实体类,注意命名规则,数据库_,实体类驼峰,或者直接全部小写
-
写dao继承basemapper,@mapper注解(注入用)
package com.zhm.dao; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.zhm.domian.Book; import org.apache.ibatis.annotations.Mapper; @Mapper public interface BookDao extends BaseMapper<Book> { } -
测试
package com.zhm; import com.zhm.dao.BookDao; import com.zhm.domian.Book; 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 BookDao bookDao; @Test void getAllTest() { List<Book> bookList = bookDao.selectList(null); for (Book book : bookList) { System.out.println(book); } } }
优势区间
测试CRUD
-
都是继承BaseMapper的方法
package com.zhm;
import com.zhm.dao.BookDao;
import com.zhm.domian.Book;
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 BookDao bookDao;
@Test
void testInsert(){
Book book = new Book();
book.setName("mb-sb");
book.setCount(999);
book.setDetail("speed");
int i = bookDao.insert(book);
}
@Test
void testDelete(){
int i = bookDao.deleteById(24);
}
@Test
void testUpdate(){
Book book = new Book();
book.setId(19L);
book.setName("mb-sb");
book.setDetail("speed");
int i = bookDao.updateById(book);
}
@Test
void testGetById(){
Book book = bookDao.selectById(19L);
System.out.println(book);
}
@Test
void testGetAll() {
List<Book> bookList = bookDao.selectList(null);
for (Book book : bookList) {
System.out.println(book);
}
}
}
分页
-
配置分页拦截器
package com.zhm.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; @Configuration public class PageConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor(){ // 定义mp拦截器容器,放拦截器 MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor(); // 放入page拦截器使其生效 mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor()); return mybatisPlusInterceptor; } } -
测试
@Test void testPage(){ IPage iPage = new Page(2,3);// 第几页,一页多少 bookDao.selectPage(iPage,null); System.out.println(iPage.getCurrent());// 当前第几页 System.out.println(iPage.getSize());// 页面大小 System.out.println(iPage.getPages());// 多少页 System.out.println(iPage.getTotal());// 多少数据 System.out.println(iPage.getRecords());// 结果 } -
配置拦截器才能生效分页,因为分页实现是在执行语句后面加limit,相当于拦截分页sql,再加上limit
MyBatis-Plus 的分页实现原理
MyBatis-Plus 的分页功能是通过拦截器(插件)机制实现的,具体来说:
- 当调用分页方法(如
baseMapper.selectPage(page, queryWrapper))时 PaginationInnerInterceptor会拦截 SQL 执行过程- 自动在原始 SQL 后追加 LIMIT 分页语句
- 同时自动生成并执行 COUNT 查询 获取总记录数
- 当调用分页方法(如
条件查询
-
bookDao.selectList(lqw) lqw为查询条件,自己选择需要的条件加上
-
一般lqw都是用LambdaQueryWrapper,可以省略lambda()
-
lambda优势
避免硬编码字段名(如
"count"),直接引用实体类的get方法,编译器会检查字段是否存在
@Test
void testDQL() {
// QueryWrapper<Book> lqw = new QueryWrapper<Book>();
LambdaQueryWrapper<Book> lqw = new LambdaQueryWrapper<Book>();
// 链式 默认就是且 &&
// lqw.gt(Book::getCount,100).lt(Book::getCount,800);
// lqw.lambda().gt(Book::getCount,800).or().lt(Book::getCount,100);
// 加or(). 就是或 ||
lqw.gt(Book::getCount,800).or().lt(Book::getCount,100);
List<Book> books = bookDao.selectList(lqw);
for (Book book : books) {
System.out.println(book);
}
}
- lt:less than 小于
- le:less than or equal to 小于等于
- eq:equal to 等于
- ne:not equal to 不等于
- ge:greater than or equal to 大于等于
- gt:greater than 大于
处理null
-
如果传入值为null就不执行,前面条件判断为true就加上这个条件
-
@Test void testDQL() { // QueryWrapper<Book> lqw = new QueryWrapper<Book>(); LambdaQueryWrapper<Book> lqw = new LambdaQueryWrapper<Book>(); // 链式 默认就是且 && // lqw.gt(Book::getCount,100).lt(Book::getCount,800); // lqw.lambda().gt(Book::getCount,800).or().lt(Book::getCount,100); // 加or(). 就是或 || Integer min = 101; Integer max = 800; // 前面条件判断为true就加上这个条件 lqw.gt(max!=null,Book::getCount,max) .or() .lt(min!=null,Book::getCount,min); List<Book> books = bookDao.selectList(lqw); for (Book book : books) { System.out.println(book); } }
查询映射投影
-
只查某些结果,加select条件
@Test void testDQLAS() { // QueryWrapper<Book> qw = new QueryWrapper<>(); // lqw.select("name","count"); LambdaQueryWrapper<Book> lqw = new LambdaQueryWrapper<Book>(); lqw.select(Book::getName,Book::getDetail); List<Book> books = bookDao.selectList(lqw); for (Book book : books) { System.out.println(book); } } -
查询某些条件,映射,分组
用selectmap存结果,键值对可以存所有类型
@Test void testDQLAS2() { QueryWrapper<Book> qw = new QueryWrapper<>(); // lqw.select("name","count"); qw.select("count(*) as count_sum,count") .groupBy("count"); List<Map<String, Object>> books = bookDao.selectMaps(qw); System.out.println(books); }
查询条件
- 条件构造器 | MyBatis-Plus,看这个网址
@Test
void testDQLWrapper() {
LambdaQueryWrapper<Book> lqw = new LambdaQueryWrapper<>();
// eq= lt< gt> le<= ge>= between[a,b](含ab)
// lqw.eq(Book::getName,"mysql").eq(Book::getCount,200);
// lqw.between(Book::getCount,100,200);
// like likeLeft likeRight 代表%位置 %j%和%j和j%
lqw.like(Book::getName,"j");
// lqw.likeLeft(Book::getName,"j");
// lqw.likeRight(Book::getName,"j");
// 查结果只有一个就用 selectone 一般登录验证
// Book book = bookDao.selectOne(lqw);
List<Book> books = bookDao.selectList(lqw);
System.out.println(books);
}
映射相关问题--数据库和实体类不匹配
- @TableName("book") 数据库表名改了
- @TableField("name") 数据库属性名改了
package com.zhm.domian;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
// 数据库表名改了
@TableName("book")
public class Book {
private Long id;
// 数据库属性改名了
@TableField("name")
private String name;
// 不查这个,一般用于密码
@TableField(select = false)
private Integer count;
private String detail;
// 实体类有,数据库没有的
@TableField(exist = false)
private Integer online;
}
Id生成策略
-
有5种,用@TableId(type=IdType.xxx),在实体类id上面写注解
AUTO(0), NONE(1), INPUT(2), ASSIGN_ID(3), ASSIGN_UUID(4),// auto 数据库默认 // input 不自增,要用户传id // ASSIGN_ID 雪花算法 64位2进制 是一个long // 第1位0 表示正 2-42 时间戳精确ms 43-52 机器码表示电脑标识符号 53-64 某一时间段内的第几个请求 // 用户传入大于系统生成 @TableId(type = IdType.ASSIGN_ID) private Long id; -
全局控制
在配置文件设置,id-type所有id生成策略,table-prefix所有表名前缀,user和tbl_user
# 全局设定 mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config: banner: off # 全局设定 db-config: id-type: assign_id table-prefix: tbl_
删除相关
多数据删除,多数据查询
- deleteBatchIds放集合,集合放long类型数据
@Test
void testDeletes(){
List<Long> list = new ArrayList<Long>();
list.add(678L);
list.add(679L);
bookDao.deleteBatchIds(list);
}
@Test
void testSelects(){
List<Long> list = new ArrayList<Long>();
list.add(1L);
list.add(3L);
list.add(5L);
bookDao.selectBatchIds(list);
}
逻辑删除
-
某些情况为了保护数据又要删除数据,只是加一个逻辑判断字段,0未删除,1删除,实际数据库内数据不删除
-
数据库加deleted,实体类属性deleted,
-
@TableLogic(value = "0",delval = "1"),value代表没被删除显示,delval代表被删除后显示
@TableLogic(value = "0",delval = "1") private Integer deleted; -
SELECT id,name,detail,deleted FROM book WHERE deleted=0
之后查询会忽略deleted=1的,如果要获取deleted=1被删的,自己写sql就行
-
全局配置
mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config: banner: off #全局配置 删除字段和值 1删 0不删 db-config: logic-delete-field: deleted logic-delete-value: 1 logic-not-delete-value: 0
乐观锁 并发问题
-
并发,太多个人抢票,出现-1,-2数据非法数据
-
乐观锁,用一个字段version标识用户版本,默认都是1
-
数据库字段version,实体类属性version,实体类加上@Version注解
-
加入乐观锁拦截器,拦截器就是利用aop切面编程,当遇到某种条件执行sql时候,加上sql语句
package com.zhm.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 PageConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor(){ // 定义mp拦截器容器,放拦截器 MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor(); // 放入page拦截器使其生效 mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor()); mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); return mybatisPlusInterceptor; } } -
测试,只要不是同时,就一定会失败一个,因为成功后会version+1,判断不满足
测试要先获取version,设置或者selectbyid获取整个对象
@Test void testUpdateO(){ Book book1 = bookDao.selectById(2);// 第一个用户 获取version=1 Book book2 = bookDao.selectById(2);// 第二个用户 获取version=1 book1.setName("mybatis-plus"); book2.setName("mybatis-nb"); // 判断条件从上面获取到就不变,执行成功会+1,乐观锁解决并发 bookDao.updateById(book1);// 修改条件 where version=1 满足之后 version+1 bookDao.updateById(book2);// 修改条件 where version=1 不满足 }
-
浙公网安备 33010602011771号