1.基本配置

1.创建数据库
image.png
2.创建pojo类

  1. @Data
  2. @AllArgsConstructor
  3. @NoArgsConstructor
  4. public class Books {
  5. private int id;
  6. private String name;
  7. private int counts;
  8. private String detail;
  9. }

3导入依赖/创建项目时勾选mybatisplus-framework
image.png
4.配置yaml中的数据库链接池和日志打印

  1. spring:
  2. datasource:
  3. username: root
  4. password: root
  5. #?serverTimezone=UTC解决时区的报错
  6. url: jdbc:mysql://localhost:3306/ssmbuild?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
  7. driver-class-name: com.mysql.cj.jdbc.Driver
  8. type: com.alibaba.druid.pool.DruidDataSource
  9. #Spring Boot 默认是不注入这些属性值的,需要自己绑定
  10. #druid 数据源专有配置
  11. initialSize: 5
  12. minIdle: 5
  13. maxActive: 20
  14. maxWait: 60000
  15. timeBetweenEvictionRunsMillis: 60000
  16. minEvictableIdleTimeMillis: 300000
  17. validationQuery: SELECT 1 FROM DUAL
  18. testWhileIdle: true
  19. testOnBorrow: false
  20. testOnReturn: false
  21. poolPreparedStatements: true
  22. #配置监控统计拦截的filters,stat:监控统计、log4j:日志记录、wall:防御sql注入
  23. #如果允许时报错 java.lang.ClassNotFoundException: org.apache.log4j.Priority
  24. #则导入 log4j 依赖即可,Maven 地址:https://mvnrepository.com/artifact/log4j/log4j
  25. filters: stat,wall,log4j
  26. maxPoolPreparedStatementPerConnectionSize: 20
  27. useGlobalDataSourceStat: true
  28. connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
  29. #日志打印:打印具体执行的sql语句只需要添加以下配置即可
  30. mybatis-plus:
  31. configuration:
  32. log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

5.mapper包下写BaseMapper的子类去继承他

  1. @Repository
  2. public interface BooksMapper extends BaseMapper<Books> {
  3. }

6.主启动类上增加扫描路径注解

  1. @MapperScan("com.yuan.mybatisplus.mapper")

7.测试类中测试

  1. @SpringBootTest
  2. class MybatisPlusApplicationTests {
  3. @Autowired
  4. BooksMapper booksMapper;
  5. @Autowired
  6. DataSource dataSource;
  7. @Test
  8. void contextLoads() {
  9. DruidDataSource dataSource = (DruidDataSource) this.dataSource;
  10. System.out.println("最大连接数是:"+dataSource.getMaxActive());
  11. List<Books> books = booksMapper.selectList(null);
  12. books.forEach(System.out::println);
  13. }
  14. }

2.雪花算法

由于在Java中64bit的整数是long类型,所以在Java中SnowFlake算法生成的id就是long来存储的。

SnowFlake可以保证:

  • 所有生成的id按时间趋势递增
  • 整个分布式系统内不会产生重复id(因为有datacenterId和workerId来做区分)

3.主键自增

我们需要配置主键自增:

1、实体类字段上 @TableId(type = IdType.AUTO)

2、数据库字段一定要是自增!

3、再次测试插入即可!

  1. public enum IdType {
  2. AUTO(0), // 数据库id自增
  3. NONE(1), // 未设置主键
  4. INPUT(2), // 手动输入
  5. ID_WORKER(3), // 默认的全局唯一id
  6. UUID(4), // 全局唯一id uuid
  7. ID_WORKER_STR(5); //ID_WORKER 字符串表示法
  8. }

4.自动填充

4.1 删除数据库的默认值、更新操作!

4.2 实体类字段属性上需要增加注解

  1. // 字段添加填充内容
  2. @TableField(fill = FieldFill.INSERT)
  3. private Date createTime;
  4. @TableField(fill = FieldFill.INSERT_UPDATE)
  5. private Date updateTime;

4.3 编写处理器来处理这个注解即可!

  1. package com.kuang.handler;
  2. import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
  3. import lombok.extern.slf4j.Slf4j;
  4. import org.apache.ibatis.reflection.MetaObject;
  5. import org.springframework.stereotype.Component;
  6. import java.util.Date;
  7. @Slf4j
  8. @Component // 一定不要忘记把处理器加到IOC容器中!
  9. public class MyMetaObjectHandler implements MetaObjectHandler {
  10. // 插入时的填充策略
  11. @Override
  12. public void insertFill(MetaObject metaObject) {
  13. log.info("start insert fill.....");
  14. // setFieldValByName(String fieldName, Object fieldVal, MetaObject
  15. metaObject
  16. this.setFieldValByName("createTime",new Date(),metaObject);
  17. this.setFieldValByName("updateTime",new Date(),metaObject);
  18. }
  19. // 更新时的填充策略
  20. @Override
  21. public void updateFill(MetaObject metaObject) {
  22. log.info("start update fill.....");
  23. this.setFieldValByName("updateTime",new Date(),metaObject);
  24. }
  25. }

5.乐观锁(版本号version)

5.1 给数据库中增加version字段

5.2 实体类增加对应字段

  1. @Version //乐观锁Version注解
  2. private Integer version;

5.3 注册组件

  1. // 扫描我们的 mapper 文件夹
  2. @MapperScan("com.kuang.mapper")
  3. @EnableTransactionManagement
  4. @Configuration // 配置类
  5. public class MyBatisPlusConfig {
  6. // 注册乐观锁插件
  7. @Bean
  8. public OptimisticLockerInterceptor optimisticLockerInterceptor() {
  9. return new OptimisticLockerInterceptor();
  10. }
  11. }

5.4 测试

  1. // 测试乐观锁成功!
  2. @Test
  3. public void testOptimisticLocker(){
  4. // 1、查询用户信息
  5. User user = userMapper.selectById(1L);
  6. // 2、修改用户信息
  7. user.setName("kuangshen");
  8. user.setEmail("24736743@qq.com");
  9. // 3、执行更新操作
  10. userMapper.updateById(user);
  11. }

6.分页查询

6.1 配置拦截器

  1. @MapperScan("com.yuan.mybatis.mapper")
  2. @EnableTransactionManagement
  3. @Component
  4. public class MyBatisPlusConfig {
  5. /* 旧版本配置
  6. @Bean
  7. public PaginationInterceptor paginationInterceptor(){
  8. return new PaginationInterceptor();
  9. }*/
  10. /**
  11. * 新的分页插件
  12. */
  13. @Bean
  14. public MybatisPlusInterceptor mybatisPlusInterceptor() {
  15. MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
  16. interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
  17. return interceptor;
  18. }
  19. }

6.2 直接使用Page对象

  1. // 测试分页查询
  2. @Test
  3. public void testPage(){
  4. // 参数一:当前页
  5. // 参数二:页面大小
  6. // 使用了分页插件之后,所有的分页操作也变得简单的!
  7. Page<User> page = new Page<>(2,5);
  8. userMapper.selectPage(page,null);
  9. page.getRecords().forEach(System.out::println);
  10. System.out.println(page.getTotal());
  11. }

7. 逻辑删除

7.1 what is 逻辑删除

逻辑删除的本质是修改操作,所谓的逻辑删除其实并不是真正的删除,而是在表中将对应的是否删除标识(deleted)或者说是状态字段(status)做修改操作。比如0是未删除,1是删除。在逻辑上数据是被删除的,但数据本身依然存在库中。

此时的delete其实是update

  1. update user set deleted=1 where id =1 and deleted=0

逻辑删除后的查找自动加入deleted字段的判断:

  1. select * from user where deleted=0

7.2 如何使用

7.2.1 application.yaml加入配置

  1. mybatis-plus:
  2. global-config:
  3. db-config:
  4. logic-delete-field: flag #全局逻辑删除字段值 3.3.0开始支持,详情看下面。
  5. logic-delete-value: 1 # 逻辑已删除值(默认为 1)
  6. logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)

7.2.2 实体类字段加上@TableLogic注解&数据库添加字段deleted

  1. @TableLogic
  2. private Integer deleted;

7.2.3 测试

  1. int i = booksMapper.deleteById(1);
  2. System.out.println(i);
  3. Books books = booksMapper.selectById(1);
  4. System.out.println(books);

此时再查询id为1便为null了

8.条件构造器

8.1 常用函数名

image.png

8.2 具体使用操作

1. ge、gt、le、lt、isNull、isNotNull

  1. @Test
  2. public void testDelete() {
  3. QueryWrapper<User> queryWrapper = new QueryWrapper<>();
  4. queryWrapper
  5. .isNull("name")
  6. .ge("age", 12)
  7. .isNotNull("email");
  8. int result = userMapper.delete(queryWrapper);
  9. System.out.println("delete return count = " + result);
  10. }

SQL:

  1. UPDATE user SET deleted=1 WHERE deleted=0 AND name IS NULL AND age >= ? AND email IS NOT NULL

2. eq、ne

注意:seletOne返回的是一条实体记录,当出现多条时会报错

  1. @Test
  2. public void testSelectOne() {
  3. QueryWrapper<User> queryWrapper = new QueryWrapper<>();
  4. queryWrapper.eq("name", "Tom");
  5. User user = userMapper.selectOne(queryWrapper);
  6. System.out.println(user);
  7. }

3.between、notBetween

包含大小边界

  1. @Test
  2. public void testSelectCount() {
  3. QueryWrapper<User> queryWrapper = new QueryWrapper<>();
  4. queryWrapper.between("age", 20, 30);
  5. Integer count = userMapper.selectCount(queryWrapper);
  6. System.out.println(count);
  7. }

4.allEq

  1. @Test
  2. public void testSelectList() {
  3. QueryWrapper<User> queryWrapper = new QueryWrapper<>();
  4. Map<String, Object> map = new HashMap<>();
  5. map.put("id", 2);
  6. map.put("name", "Jack");
  7. map.put("age", 20);9
  8. queryWrapper.allEq(map);
  9. List<User> users = userMapper.selectList(queryWrapper);
  10. users.forEach(System.out::println);
  11. }

SELECT id,name,age,email,create_time,update_time,deleted,version FROM user WHERE deleted=0 AND name = ? AND id = ? AND age = ?

5. like、notLike、likeLeft、likeRight

selectMaps返回Map集合列表

  1. @Test
  2. public void testSelectMaps() {
  3. QueryWrapper<User> queryWrapper = new QueryWrapper<>();
  4. queryWrapper
  5. .notLike("name", "e")
  6. .likeRight("email", "t");
  7. List<Map<String, Object>> maps = userMapper.selectMaps(queryWrapper);//返回值是Map列表
  8. maps.forEach(System.out::println);
  9. }

SELECT id,name,age,email,create_time,update_time,deleted,version FROM user WHERE deleted=0 AND name NOT LIKE ? AND email LIKE ?

6. in、notIn、inSql、notinSql、exists、notExists

in notIn

  1. notIn("age",{1,2,3})--->age not in (1,2,3)
  2. notIn("age", 1, 2, 3)--->age not in (1,2,3)

inSql,notInSql

  1. 例: inSql("age", "1,2,3,4,5,6")--->age in (1,2,3,4,5,6)
  2. 例: inSql("id", "select id from table where id < 3")--->id in (select id from table where id < 3)

SELECT id,name,age,email,create_time,update_time,deleted,version FROM user WHERE deleted=0 AND id IN (select id from user where id < 3)

7. or、and

注意:这里使用的是 UpdateWrapper 不调用or则默认为使用 and 连

  1. @Test
  2. public void testUpdate1() {
  3. //修改值
  4. User user = new User();
  5. user.setAge(99);
  6. user.setName("Andy");
  7. //修改条件
  8. UpdateWrapper<User> userUpdateWrapper = new UpdateWrapper<>();
  9. userUpdateWrapper
  10. .like("name", "h")
  11. .or()
  12. .between("age", 20, 30);
  13. int result = userMapper.update(user, userUpdateWrapper);
  14. System.out.println(result);
  15. }

UPDATE user SET name=?, age=?, update_time=? WHERE deleted=0 AND name LIKE ? OR age BETWEEN ? AND ?

8. 嵌套or、嵌套and

这里使用了lambda表达式,or中的表达式最后翻译成sql时会被加上圆括号

  1. @Test
  2. public void testUpdate2() {
  3. //修改值
  4. User user = new User();
  5. user.setAge(99);
  6. user.setName("Andy");
  7. //修改条件
  8. UpdateWrapper<User> userUpdateWrapper = new UpdateWrapper<>();
  9. userUpdateWrapper
  10. .like("name", "h")
  11. .or(i -> i.eq("name", "李白").ne("age", 20));
  12. int result = userMapper.update(user, userUpdateWrapper);
  13. System.out.println(result);
  14. }

UPDATE user SET name=?, age=?, update_time=?

WHERE deleted=0 AND name LIKE ?

OR ( name = ? AND age <> ? )

9. orderBy、orderByDesc、orderByAsc

  1. @Test
  2. public void testSelectListOrderBy() {
  3. QueryWrapper<User> queryWrapper = new QueryWrapper<>();
  4. queryWrapper.orderByDesc("id");
  5. List<User> users = userMapper.selectList(queryWrapper);
  6. users.forEach(System.out::println);
  7. }

SELECT id,name,age,email,create_time,update_time,deleted,version

FROM user WHERE deleted=0 ORDER BY id DESC

10. last

直接拼接到 sql 的最后

注意:只能调用一次,多次调用以最后一次为准 有sql注入的风险,请谨慎使用

  1. @Test
  2. public void testSelectListLast() {
  3. QueryWrapper<User> queryWrapper = new QueryWrapper<>();
  4. queryWrapper.last("limit 1");
  5. List<User> users = userMapper.selectList(queryWrapper);
  6. users.forEach(System.out::println);
  7. }

11. 指定要查询的列

  1. @Test
  2. public void testSelectListColumn() {
  3. QueryWrapper<User> queryWrapper = new QueryWrapper<>();
  4. queryWrapper.select("id", "name", "age");
  5. List<User> users = userMapper.selectList(queryWrapper);
  6. users.forEach(System.out::println);
  7. }

SELECT id,name,age FROM user WHERE deleted=0

12. set、setSql

最终的sql会合并 user.setAge(),以及 userUpdateWrapper.set() 和 setSql() 中 的字段

  1. @Test
  2. public void testUpdateSet() {
  3. //修改值
  4. User user = new User();
  5. user.setAge(99);
  6. //修改条件
  7. UpdateWrapper<User> userUpdateWrapper = new UpdateWrapper<>();
  8. userUpdateWrapper
  9. .like("name", "h")
  10. .set("name", "老李头")//除了可以查询还可以使用set设置修改的字段
  11. .setSql(" email = '123@qq.com'");//可以有子查询
  12. int result = userMapper.update(user, userUpdateWrapper);
  13. }

UPDATE user SET age=?, update_time=?, name=?, email = ‘123@qq.com’ WHERE deleted=0 AND name LIKE ?