谷粒学院_Day01

谷粒学院

Day01

Mybatis入门

一、简介

MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。

二、特性
  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
  • 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
  • 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
  • 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
  • 支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer2005、SQLServer 等多种数据库
  • 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
  • 支持 XML 热加载:Mapper 对应的 XML 支持热加载,对于简单的 CRUD 操作,甚至可以无 XML 启动
  • 支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
  • 支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
  • 支持关键词自动转义:支持数据库关键词(order、key…)自动转义,还可自定义关键词
  • 内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
  • 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
  • 内置性能分析插件:可输出 Sql 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
  • 内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作
  • 内置 Sql 注入剥离器:支持 Sql 注入剥离,有效预防 Sql 注入攻击

MybatisPlus

一、编写代码
1、主类

在 Spring Boot 启动类中添加 @MapperScan 注解,扫描 Mapper 文件夹

@SpringBootApplication
@MapperScan("com.atguigu.mybatisplus.mapper")
public class MybatisPlusApplication {
	......
}
2、实体
@Data
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
}
3、mapper

创建包 mapper 编写Mapper 接口: UserMapper.java

public interface UserMapper extends BaseMapper<User> {
}
4.开始使用
@RunWith(SpringRunner.class)
@SpringBootTest
public class MybatisPlusApplicationTests {

    @Autowired
    private UserMapper userMapper;

    @Test
    public void testSelectList() {
        System.out.println(("----- selectAll method test ------"));
        //UserMapper 中的 selectList() 方法的参数为 MP 内置的条件封装器 Wrapper
        //所以不填写就是无任何条件
        List<User> users = userMapper.selectList(null);
        users.forEach(System.out::println);
    }
}
5.配置日志

查看sql输出日志

#mybatis日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
二、MyBatisPlus的CRUD
1、insert插入操作
@RunWith(SpringRunner.class)
@SpringBootTest
public class CRUDTests {

    @Autowired
    private UserMapper userMapper;

    @Test
    public void testInsert(){

        User user = new User();
        user.setName("Helen");
        user.setAge(18);
        user.setEmail("55317332@qq.com");

        int result = userMapper.insert(user);
        System.out.println(result); //影响的行数
        System.out.println(user); //id自动回填
    }
}

数据库插入id值默认为:全局唯一id

2、主键策略

(1)ID_WORKER

MyBatis-Plus默认的主键策略是:ID_WORKER 全局唯一ID

**参考资料:分布式系统唯一ID生成方案汇总:**https://www.cnblogs.com/haoxinyue/p/5208136.html

(2)自增策略

  • 要想主键自增需要配置如下主键策略

    • 需要在创建数据表的时候设置主键自增
    • 实体字段中配置 @TableId(type = IdType.AUTO)
2、update
1.根据Id更新操作
@Test
public void testUpdateById(){

    User user = new User();
    user.setId(1L);
    user.setAge(28);

    int result = userMapper.updateById(user);
    System.out.println(result);

}
2、自动填充

项目中经常会遇到一些数据,每次都使用相同的方式填充,例如记录的创建时间,更新时间等。

我们可以使用MyBatis Plus的自动填充功能,完成这些字段的赋值工作:

(1)数据库表中添加自动填充字段

在User表中添加datetime类型的新的字段 create_time、update_time

(2)实体上添加注解

@Data
public class User {
    ......
        
    @TableField(fill = FieldFill.INSERT)
    private Date createTime;

    //@TableField(fill = FieldFill.UPDATE)
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;
}
3、乐观锁

**主要适用场景:**当要更新一条记录的时候,希望这条记录没有被别人更新,也就是说实现线程安全的数据更新

乐观锁实现方式:

  • 取出记录时,获取当前version
  • 更新时,带上这个version
  • 执行更新时, set version = newVersion where version = oldVersion
  • 如果version不对,就更新失败

*(1)数据库中添加version字段*

ALTER TABLE `user` ADD COLUMN `version` INT

*(2)实体类添加version字段*

并添加 @Version 注解

@Version
@TableField(fill = FieldFill.INSERT)
private Integer version;
3、select
1、根据id查询记录
@Test
public void testSelectById(){

User user = userMapper.selectById(1L);
System.out.println(user);

}
2、通过多个id批量查询
@Test
public void testSelectBatchIds(){

    List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
    users.forEach(System.out::println);
}
3、简单的条件查询
@Test
public void testSelectByMap(){

    HashMap<String, Object> map = new HashMap<>();
    map.put("name", "Helen");
    map.put("age", 18);
    List<User> users = userMapper.selectByMap(map);

    users.forEach(System.out::println);
}

**注意:**map中的key对应的是数据库中的列名。例如数据库user_id,实体类是userId,这时map的key需要填写user_id

4、分页

MyBatis Plus自带分页插件,只要简单的配置即可实现分页功能

(1)创建配置类

此时可以删除主类中的 @MapperScan 扫描注解

  • /**
    * 分页插件
    */
       @Bean
       public PaginationInterceptor paginationInterceptor() {
       return new PaginationInterceptor();
       }
    

(2)测试selectPage分页

@Test
public void testSelectPage() {

    Page<User> page = new Page<>(1,5);
    userMapper.selectPage(page, null);

    page.getRecords().forEach(System.out::println);
    System.out.println(page.getCurrent());
    System.out.println(page.getPages());
    System.out.println(page.getSize());
    System.out.println(page.getTotal());
    System.out.println(page.hasNext());
    System.out.println(page.hasPrevious());
}

控制台sql语句打印:SELECT id,name,age,email,create_time,update_time FROM user LIMIT 0,5

(3)测试selectMapsPage分页:结果集是Map

@Test
public void testSelectMapsPage() {

    Page<User> page = new Page<>(1, 5);

    IPage<Map<String, Object>> mapIPage = userMapper.selectMapsPage(page, null);

    //注意:此行必须使用 mapIPage 获取记录列表,否则会有数据类型转换错误
    mapIPage.getRecords().forEach(System.out::println);
    System.out.println(page.getCurrent());
    System.out.println(page.getPages());
    System.out.println(page.getSize());
    System.out.println(page.getTotal());
    System.out.println(page.hasNext());
    System.out.println(page.hasPrevious());
}
4、delete
1、根据id删除记录
@Test
public void testDeleteById(){

    int result = userMapper.deleteById(8L);
    System.out.println(result);
}
2、批量删除
    @Test
    public void testDeleteBatchIds() {

        int result = userMapper.deleteBatchIds(Arrays.asList(8, 9, 10));
        System.out.println(result);
    }
3、简单的条件查询删除
@Test
public void testDeleteByMap() {

    HashMap<String, Object> map = new HashMap<>();
    map.put("name", "Helen");
    map.put("age", 18);

    int result = userMapper.deleteByMap(map);
    System.out.println(result);
}
4、逻辑删除
  • 物理删除:真实删除,将对应数据从数据库中删除,之后查询不到此条被删除数据
  • 逻辑删除:假删除,将对应数据中代表是否被删除字段状态修改为“被删除状态”,之后在数据库中仍旧能看到此条数据记录

(1)数据库中添加 deleted字段

ALTER TABLE `user` ADD COLUMN `deleted` boolean

(2)实体类添加deleted *字段*

并加上 @TableLogic 注解 和 @TableField(fill = FieldFill.INSERT) 注解

@TableLogic
@TableField(fill = FieldFill.INSERT)
private Integer deleted;

(3)元对象处理器接口添加deleted的insert默认值

@Override
public void insertFill(MetaObject metaObject) {
    ......
    this.setFieldValByName("deleted", 0, metaObject);
}

(4)在 MybatisPlusConfig 中注册 Bean

@Bean
public ISqlInjector sqlInjector() {
    return new LogicSqlInjector();
}

(5)测试逻辑删除

  • 测试后发现,数据并没有被删除,deleted字段的值由0变成了1
  • 测试后分析打印的sql语句,是一条update
  • **注意:**被删除数据的deleted 字段的值必须是 0,才能被选取出来执行逻辑删除的操作
/**
 * 测试 逻辑删除
 */
@Test
public void testLogicDelete() {

    int result = userMapper.deleteById(1L);
    System.out.println(result);
}

(6)测试逻辑删除后的查询

MyBatis Plus中查询操作也会自动添加逻辑删除字段的判断

/**
 * 测试 逻辑删除后的查询:
 * 不包括被逻辑删除的记录
 */
@Test
public void testLogicDeleteSelect() {
    User user = new User();
    List<User> users = userMapper.selectList(null);
    users.forEach(System.out::println);
}
5、性能分析

性能分析拦截器,用于输出每条 SQL 语句及其执行时间

SQL 性能执行分析,开发环境使用,超过指定时间,停止运行。有助于发现问题

1、配置插件

(1)参数说明

参数:maxTime: SQL 执行最大时长,超过自动停止运行,有助于发现问题。

参数:format: SQL是否格式化,默认false。

(2)在 MybatisPlusConfig 中配置

/**
 * SQL 执行性能分析插件
 * 开发环境使用,线上不推荐。 maxTime 指的是 sql 最大执行时长
 */
@Bean
@Profile({"dev","test"})// 设置 dev test 环境开启
public PerformanceInterceptor performanceInterceptor() {
    PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
    performanceInterceptor.setMaxTime(100);//ms,超过此处设置的ms则sql不执行
    performanceInterceptor.setFormat(true);
    return performanceInterceptor;
}

(3)Spring Boot 中设置dev环境

#环境设置:dev、test、prod
spring.profiles.active=dev
2、测试

(1)常规测试

/**
 * 测试 性能分析插件
 */
@Test
public void testPerformance() {
    User user = new User();
    user.setName("我是Helen");
    user.setEmail("helen@sina.com");
    user.setAge(18);
    userMapper.insert(user);
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-e98blq3T-1618971346037)(file:///C:/Users/16376/Documents/My%20Knowledge/temp/7950e076-033e-4663-ba7c-ca438b2ea71e/128/index_files/bb355a17-3cdc-4f0a-82f2-232defbd235b.png)]

(2)将maxTime 改小之后再次进行测试

performanceInterceptor.setMaxTime(5);//ms,超过此处设置的ms不执行

如果执行时间过长,则抛出异常:The SQL execution time is too large, [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ufqDEB5Y-1618971346040)(file:///C:/Users/16376/Documents/My%20Knowledge/temp/7950e076-033e-4663-ba7c-ca438b2ea71e/128/index_files/1ae5ae68-b6b2-4801-ae26-29835b175b24.png)]

MyBatisPlus条件构造器

1、wapper介绍

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-II1acCsU-1618971346041)(file:///C:/Users/16376/Documents/My%20Knowledge/temp/14541f6f-c3f4-42bc-9ffd-b34b209ac1f0/128/index_files/27b56b5e-39a6-42ba-b7ed-4f109b6ad7bf.png)]

Wrapper : 条件构造抽象类,最顶端父类

  • AbstractWrapper : 用于查询条件封装,生成 sql 的 where 条件
  • QueryWrapper : Entity 对象封装操作类,不是用lambda语法
  • UpdateWrapper : Update 条件封装,用于Entity对象更新操作
  • AbstractLambdaWrapper : Lambda 语法使用 Wrapper统一处理解析 lambda 获取 column。
  • LambdaQueryWrapper :看名称也能明白就是用于Lambda语法使用的查询Wrapper
  • LambdaUpdateWrapper : Lambda 更新封装Wrapper
2、AbstractWrapper

**注意:**以下条件构造器的方法入参中的 column均表示数据库字段

1、ge、gt、le、lt、isNull、isNotNull
@Test
public void testDelete() {

    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper
        .isNull("name")
        .ge("age", 12)
        .isNotNull("email");
    int result = userMapper.delete(queryWrapper);
    System.out.println("delete return count = " + result);
}
SQLUPDATE user SET deleted=1 WHERE deleted=0 AND name IS NULL AND age >= ? AND email IS NOT NULL
2、eq、ne
@Test
public void testSelectOne() {

    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.eq("name", "Tom");

    User user = userMapper.selectOne(queryWrapper);
    System.out.println(user);
}
SELECT id,name,age,email,create_time,update_time,deleted,version FROM user WHERE deleted=0 AND name = ? 
3、between、notBetween

包含大小边界

@Test
public void testSelectCount() {

    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.between("age", 20, 30);

    Integer count = userMapper.selectCount(queryWrapper);
    System.out.println(count);
}
4、allEq
@Test
public void testSelectList() {

    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    Map<String, Object> map = new HashMap<>();
    map.put("id", 2);
    map.put("name", "Jack");
    map.put("age", 20);

    queryWrapper.allEq(map);
    List<User> users = userMapper.selectList(queryWrapper);

    users.forEach(System.out::println);
}
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
@Test
public void testSelectMaps() {

    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper
        .notLike("name", "e")
        .likeRight("email", "t");

    List<Map<String, Object>> maps = userMapper.selectMaps(queryWrapper);//返回值是Map列表
    maps.forEach(System.out::println);
}
SELECT id,name,age,email,create_time,update_time,deleted,version 

FROM user WHERE deleted=0 AND name NOT LIKE ? AND email LIKE ? 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值