MybatisPlus学习笔记及资源分享

举报
陈老老老板 发表于 2022/10/23 10:25:44 2022/10/23
【摘要】 (1)、驱动类driver-class-name spring boot 2.0(内置jdbc5驱动),驱动类使用: driver-class-name: com.mysql.jdbc.Driver spring boot 2.1及以上(内置jdbc8驱动),驱动类使用: driver-class-name: com.mysql.cj.jdbc.Driver 否则运行测试用例的时候会有 WARN

这里只写一些我认为注意的地方,有时间好复习,详细的在资源里都有有springboot版本,与spring版本就是配置不一样。

一、使用的配置信息及非条件构造器常用方法

1.配置文件

spring:
# 配置数据源信息
  datasource:
# 配置数据源类型
    type: com.zaxxer.hikari.HikariDataSource
# 配置连接数据库信息
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/mybatis_plus?characterEncoding=utf-8&useSSL=false
    username: root
    password: 123456
# 配置MyBatis日志
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

注意

(1)、驱动类driver-class-name
spring boot 2.0(内置jdbc5驱动),驱动类使用:
driver-class-name: com.mysql.jdbc.Driver
spring boot 2.1及以上(内置jdbc8驱动),驱动类使用:
driver-class-name: com.mysql.cj.jdbc.Driver
否则运行测试用例的时候会有 WARN 信息
(2)、连接地址url
MySQL5.7版本的url
jdbc:mysql://localhost:3306/mybatis_plus?characterEncoding=utf-8&useSSL=false
MySQL8.0版本的url
jdbc:mysql://localhost:3306/mybatis_plus?
serverTimezone=GMT%2B8&characterEncoding=utf-8&useSSL=false
否则运行测试用例报告如下错误:
java.sql.SQLException: The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecognized or
represents more

2.配置启动类

//在Spring Boot启动类中添加@MapperScan注解,扫描mapper包
@SpringBootApplication
@MapperScan("com.atguigu.mybatisplus.mapper")
    public class MybatisplusApplication {
        public static void main(String[] args) {
            SpringApplication.run(MybatisplusApplication.class, args);
    }
}

3.mapper要extend BaseMapper<>

public interface UserMapper extends BaseMapper<User> {
}

4.无Wrapper参数常用方法

int deleteById(Serializable id);
/**
* 根据实体(ID)删除
* @param entity 实体对象
* @since 3.4.4
*/
更多Java –大数据 – 前端 – UI/UE - Android - 人工智能资料下载,可访问百度:尚硅谷官网(www.atguigu.com)
int deleteById(T entity);
/**
* 根据 columnMap 条件,删除记录
* @param columnMap 表字段 map 对象
*/
int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
/**
* 根据 entity 条件,删除记录
* @param queryWrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where
语句)
*/
int delete(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
/**
* 删除(根据ID 批量删除)
* @param idList 主键ID列表(不能为 null 以及 empty)
*/
int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends
Serializable> idList);
/**
* 根据 ID 修改
* @param entity 实体对象
*/
int updateById(@Param(Constants.ENTITY) T entity);
/**
* 根据 whereEntity 条件,更新记录
* @param entity 实体对象 (set 条件值,可以为 null)
* @param updateWrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成
where 语句)
*/
int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER)
Wrapper<T> updateWrapper);
/**
* 根据 ID 查询
* @param id 主键ID
*/
T selectById(Serializable id);
/**
* 查询(根据ID 批量查询)
* @param idList 主键ID列表(不能为 null 以及 empty)
*/
List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends
Serializable> idList);
/**
* 查询(根据 columnMap 条件)
* @param columnMap 表字段 map 对象
*/
List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object>
columnMap);
/**
更多Java –大数据 – 前端 – UI/UE - Android - 人工智能资料下载,可访问百度:尚硅谷官网(www.atguigu.com)
* 根据 entity 条件,查询一条记录
* <p>查询一条记录,例如 qw.last("limit 1") 限制取一条记录, 注意:多条数据会报异常
</p>
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
default T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper) {
List<T> ts = this.selectList(queryWrapper);
if (CollectionUtils.isNotEmpty(ts)) {
if (ts.size() != 1) {
throw ExceptionUtils.mpe("One record is expected, but the query
result is multiple records");
}
return ts.get(0);
}
return null;
}
/**
* 根据 Wrapper 条件,查询总记录数
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
Long selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
/**
* 根据 entity 条件,查询全部记录
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
/**
* 根据 Wrapper 条件,查询全部记录
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T>
queryWrapper);
/**
* 根据 Wrapper 条件,查询全部记录
* <p>注意: 只返回第一个字段的值</p>
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
/**
* 根据 entity 条件,查询全部记录(并翻页)
* @param page 分页查询条件(可以为 RowBounds.DEFAULT)
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
<P extends IPage<T>> P selectPage(P page, @Param(Constants.WRAPPER)
Wrapper<T> queryWrapper);
/**
* 根据 Wrapper 条件,查询全部记录(并翻页)
* @param page 分页查询条件
* @param queryWrapper 实体对象封装操作类
*/
<P extends IPage<Map<String, Object>>> P selectMapsPage(P page,
@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

5.创建Service接口和实现类

/**
* UserService继承IService模板提供的基础功能
*/
public interface UserService extends IService<User> {
}
/**
* ServiceImpl实现了IService,提供了IService中基础功能的实现
* 若ServiceImpl无法满足业务需求,则可以使用自定的UserService定义方法,并在实现类中实现
*/
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements
UserService {
}

二、常用注解

1.@TableId

问题

经过以上的测试,MyBatis-Plus在实现CRUD时,会默认将id作为主键列,并在插入数据时,默认
基于雪花算法的策略生成id 若实体类和表中表示主键的不是id,而是其他字段,例如uidMyBatis-Plus会自动识别uid为主键列吗?我们实体类中的属性id改为uid,将表中的字段id也改为uid,测试添加功能程序抛出异常,Field 'uid' doesn't have a default value,说明MyBatis-Plus没有将uid作为主键赋值。

解决:在实体类表中的字段加上@TableId注解。

@TeableId的Value属性:
若实体类中主键对应的属性为id,而表中表示主键的字段为uid,此时若只在属性id上添加注解
@TableId,则抛出异常Unknown column 'id' in 'field list',即MyBatis-Plus仍然会将id作为表的
主键操作,而表中表示主键的是字段uid
此时需要通过@TableId注解的value属性,指定表中的主键字段,@TableId("uid")
@TableId(value="uid")
@TableIdtype属性:
描述
IdType.ASSIGN_ID(默
认)
基于雪花算法的策略生成数据id,与数据库id是否设置自增无关
IdType.AUTO
使用数据库的自增策略,注意,该类型请确保数据库设置了id自增, 否则无效

配置全局主键策略: 

mybatis-plus:
  configuration:
# 配置MyBatis日志
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  global-config:
    db-config:
# 配置MyBatis-Plus操作表的默认前缀
      table-prefix: t_
# 配置MyBatis-Plus的主键策略
      id-type: auto

2.@TableField

问题如果实体类中的属性名和字段名不一致的情况,会出现什么问题呢?

如果是驼峰mybatisplus会自动匹配如果不是就要加入@TableField注解

解决

@TableField("username")
private String name;

3.@TableLogic

说明:用于逻辑删除

逻辑删除:假删除,将对应数据中代表是否被删除字段的状态修改为被删除状态,之后在数据库
中仍旧能看到此条数据记录

(1)在数据库加入is_delete字段(int类型 长度11 默认0,0表示未删除,1表示已删除)
(2)在实体类字段中加入@TableLogic注解
@TableLogic
private Integer isDelete

三、条件构造器和常用接口

1wapper介绍如图

编辑


Wrapper : 条件构造抽象类,最顶端父类
AbstractWrapper : 用于查询条件封装,生成 sql where 条件
QueryWrapper : 查询条件封装
UpdateWrapper Update 条件封装
AbstractLambdaWrapper : 使用Lambda 语法
LambdaQueryWrapper :用于Lambda语法使用的查询Wrapper
LambdaUpdateWrapper Lambda 更新封装Wrapper

2.QueryWrapper常用方法

常用like,between,or,and,isNotNull,isNull,order,gt(大于),lt小于可以看我博客有详细介绍。

​​​​​QuerWrapper常用条件参数 https://blog.csdn.net/weixin_47343544/article/details/119796505?spm=1001.2014.3001.5502方法使用形式:(:第一个参数是数据库中的字段名)

@Test
public void test01(){
//查询用户名包含a,年龄在20到30之间,并且邮箱不为null的用户信息
//SELECT id,username AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (username LIKE ? AND age BETWEEN ? AND ? AND email IS NOT NULL)
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.like("username", "a")
                    .between("age", 20, 30)
                    .isNotNull("email");
        List<User> list = userMapper.selectList(queryWrapper);
        list.forEach(System.out::println);
}

3.UpdateWrapper

区别:UpdateWrapper与QueryWrapper区别主要在于使用update方法。updatewrapper有专属的set方法,不用创建实体 对象。

UpdateWrapper:

@Test
public void test07() {
//将(年龄大于20或邮箱为null)并且用户名中包含有a的用户信息修改
//组装set子句以及修改条件
    UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
//lambda表达式内的逻辑优先运算
         updateWrapper
                    .set("age", 18)
                    .set("email", "user@atguigu.com")
                    .like("username", "a")
                    .and(i -> i.gt("age", 20).or().isNull("email"));
}

QueryWrapper:

@Test
public void test04() {
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
//将(年龄大于20并且用户名中包含有a)或邮箱为null的用户信息修改
//UPDATE t_user SET age=?, email=? WHERE (username LIKE ? AND age > ? OR email IS NULL)
            ueryWrapper
                    .like("username", "a")
                    .gt("age", 20)
                    .or()
                    .isNull("email");
            User user = new User();
                user.setAge(18);
                user.setEmail("user@atguigu.com");
            int result = userMapper.update(user, queryWrapper);
            System.out.println("受影响的行数:" + result);
}

4.Condition

如果你想在使用QueryWrapper调用方法传入的字段的参数进行验证的话,不用if else可以使用Condition参数,选择方法带condition参数的方法。

例如:

        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
                queryWrapper
                            .like(StringUtils.isNotBlank(username), "username", "a")
                            .ge(ageBegin != null, "age", ageBegin)
                            .le(ageEnd != null, "age", ageEnd);

5.LambdaQueryWrapper

说明:LambdaQueryWrapper与QueryWrapper的区别主要在于,将数据库表中的字段变成了在实体类中调用方法如:将“user_name” 变为 User::getUserName

例:

@Test
public void test09() {
//定义查询条件,有可能为null(用户未输入)
        String username = "a";
        Integer ageBegin = 10;
        Integer ageEnd = 24;
     LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
//避免使用字符串表示字段,防止运行时错误
        queryWrapper
                .like(StringUtils.isNotBlank(username), User::getName, username)
                .ge(ageBegin != null, User::getAge, ageBegin)
                .le(ageEnd != null, User::getAge, ageEnd);
        List<User> users = userMapper.selectList(queryWrapper);
        users.forEach(System.out::println);
}

四、插件

1.使用分页插件,配置

//创建配置类,添加内部拦截器
@Configuration
@MapperScan("com.atguigu.mybatisplus.mapper") //可以将主类中的注解移到此处
public class MybatisPlusConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}

2.常用分页方法

@Test
public void testPage(){
//设置分页参数
    Page<User> page = new Page<>(1, 5);
    userMapper.selectPage(page, null);
//获取分页数据
    List<User> list = page.getRecords();
    list.forEach(System.out::println);
    System.out.println("当前页:"+page.getCurrent());
    System.out.println("每页显示的条数:"+page.getSize());
    System.out.println("总记录数:"+page.getTotal());
    System.out.println("总页数:"+page.getPages());
    System.out.println("是否有上一页:"+page.hasPrevious());
    System.out.println("是否有下一页:"+page.hasNext());
}

3.实现乐观锁

(1.)实现流程

SELECT id,`name`,price,`version` FROM product WHERE id=1
UPDATE product SET price=price+50, `version`=`version` + 1 WHERE id=1 AND
`version`=1

(2)在数据库表中添加version(int类型)字段。在实体类中添加version属性,添加@Version注解。

@Data
public class Product {
    private Long id;
    private String name;
    private Integer price;
    @Version
    private Integer version;
}

(3)添加乐观锁插件配置

在配置类中添加乐观锁拦截器

@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
    MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
//添加分页插件
    interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
//添加乐观锁插件
    interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
    return interceptor;
}

(4)进行测试,在p2修改失败后,在进行一次查询版本号,在重新插入。

4.通用枚举

(1)在数据库表中加入sex字段(int类型),创建枚举实体类

@Data
public enum SexEnum {
    MALE(1, "男"),
    FEMALE(2, "女");
    @EnumValue
    private Integer sex;
    private String sexName;
}

(2)进行配置

mybatis-plus:
  type-enums-package: com.atguigu.mybatisplus.enums

五、代码生成器

1.引入依赖

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-generator</artifactId>
    <version>3.5.1</version>
</dependency>
<dependency>
    <groupId>org.freemarker</groupId>
    <artifactId>freemarker</artifactId>
    <version>2.3.31</version>
</dependency>

2.输入代码

public class FastAutoGeneratorTest {
public static void main(String[] args) {
    FastAutoGenerator.create("jdbc:mysql://127.0.0.1:3306/mybatis_plus?characterEncoding=utf-8&userSSL=false", "root", "123456").globalConfig(builder -> {
                    builder.author("atguigu") // 设置作者
                    //.enableSwagger() // 开启 swagger 模式
                    .fileOverride() // 覆盖已生成文件
                    .outputDir("D://mybatis_plus"); // 指定输出目录
                    })
                    .packageConfig(builder -> {
                    builder.parent("com.atguigu") // 设置父包名
                    .moduleName("mybatisplus") // 设置父包模块名
                    .pathInfo(Collections.singletonMap(OutputFile.mapperXml,                  
                               "D://mybatis_plus"));
                    // 设置mapperXml生成路径
                    })
                    .strategyConfig(builder -> {
                    builder.addInclude("t_user") // 设置需要生成的表名
                    .addTablePrefix("t_", "c_"); // 设置过滤表前缀
                    })
                    .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker
                    引擎模板,默认的是Velocity引擎模板
                    .execute();
        }
}

结束语:

裸体一旦成为艺术,便是最圣洁的。道德一旦沦为虚伪,便是最下流的。勇敢去做你认为正确的事,不要被世俗的流言蜚语所困扰。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。