技术栈1.mybatis-plus技术学习

一.mybatis-plus技术学习

1.mybatis-plus简介和简单使用

2.mybatis-plus实战演练

3.mybatis-plus的重点类学习

4.mybatis-plus的注解学习

5.mybatis-plus的分页学习

6.mybatis-plus的乐观锁学习

7.mybatis-plus的查询条件

8.mybatis-plus细节

9.mybatis-plus的代码生成器具体使用

10.mybatis-plus自定义sql的注意点

一.mybatis-plus技术学习

1.mybatis-plu简介

  • 对mybatis做了增强而未改变。
  • 简单的使用
    只需要提供scan entity
    然后mapper接口只需要继承BaseMapper<>即可
    然后service接口只需要继承IService<>即可
    然后serviceImpl实现类只需要继承ServiceImpl<T, T> 实现 前面的Service接口即可。
    最终可直接利用Service进行简单的增删改查操作

2.mybatis-plus实战演练

①总体流程

  • 直接使用写好的sql
    • 在数据库中创建表
    • 在maven工程中引入依赖
    • 创建实体类并让主程序mapperscan到
    • 创建mapper继承baseMapper<实体类>
    • 创建service继承IService<实体类>
    • 创建serviceImpl继承ServiceImp<Mapper,实体类>实现service
    • 直接使用即可
  • 自定义sql
    • 在mapper中自定义方法
    • 在resouces中定义mapper.xml(绑定到mapper上)
    • 直接使用即可。
  • 对比mybatis
    • 无需构建数据库连接池创建sqlsession连接(自动连接)
    • 无需获取动态代理实现类(自动注入)

①创建工程,引入依赖,初始化数据库连接池,主启动

  • 项目结构
    在这里插入图片描述
  • 主启动
package com.atguigu.mybatisplus;


import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;


@MapperScan("com.atguigu.mybatisplus.mapper")
@SpringBootApplication
public class MybatisApplication {
    public static void main(String[] args) {
        SpringApplication.run(MybatisApplication.class,args);
    }
}

  • 引入依赖
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.likejin</groupId>
    <artifactId>mybatis-plus</artifactId>
    <version>1.0-SNAPSHOT</version>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.4.2.RELEASE</version>
        <relativePath />
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.1</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

</project>
  • 初始化数据库连接池
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:13306/mytest?useUnicode=true&characterEncoding=utf8&useSSL=false
spring.datasource.username=root
spring.datasource.password=abc123

mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

②建立数据库

CREATE TABLE USER
(
	id BIGINT(20) NOT NULL COMMENT '主键ID',
	NAME VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
	age INT(11) NULL DEFAULT NULL COMMENT '年龄',
	email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
	PRIMARY KEY (id)
);
INSERT INTO USER (id, NAME, age, email) VALUES
(1, 'Jone', 18, 'test1@baomidou.com'),
(2, 'Jack', 20, 'test2@baomidou.com'),
(3, 'Tom', 28, 'test3@baomidou.com'),
(4, 'Sandy', 21, 'test4@baomidou.com'),
(5, 'Billie', 24, 'test5@baomidou.com');

在这里插入图片描述

③建立对应实体类

package com.atguigu.mybatisplus.entity;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

@Data
@TableName("user")
public class User {
    @TableId(value = "id")//主键列
    private Long id;
    @TableField(value = "name")//mp 会自动将数据库中的下划线风格转换为驼峰风格
    private String name;
    private Integer age;
    private String email;
}

④建立mapper和mapper.xml

  • 使用已有的sql
package com.atguigu.mybatisplus.mapper;


import com.atguigu.mybatisplus.entity.User;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;

import java.util.List;

public interface UserMapper extends BaseMapper<User>{

    List<User> selectAllByName(String name);
}

  • 配置自定义sql查询
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.atguigu.mybatisplus.mapper.UserMapper">

    <sql id="Base_Column_List">
        id, name, age, email
    </sql>

    <select id="selectAllByName" resultType="com.atguigu.mybatisplus.entity.User">
        select
        <include refid="Base_Column_List"/>
        from user
        where
        name = #{name}
    </select>
</mapper>

⑤初始化service和serviceImpl

  • service
package com.atguigu.mybatisplus.service;

import com.atguigu.mybatisplus.entity.User;
import com.baomidou.mybatisplus.extension.service.IService;

import java.util.List;

public interface UserService extends IService<User> {

    List<User> listAllUserByName(String name);
}

  • serviceImpl
package com.atguigu.mybatisplus.service.impl;

import com.atguigu.mybatisplus.entity.User;
import com.atguigu.mybatisplus.mapper.UserMapper;
import com.atguigu.mybatisplus.service.UserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper,User> implements UserService {
    @Resource
    UserMapper userMapper;
    @Override
    public List<User> listAllUserByName(String name) {
        return userMapper.selectAllByName(name);
    }
}

⑥测试

  • 测试提供的sql语句
package com.atguigu.mybatisplus;


import com.atguigu.mybatisplus.entity.User;
import com.atguigu.mybatisplus.mapper.UserMapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import javax.annotation.Resource;
import java.util.List;

@RunWith(SpringRunner.class)
@SpringBootTest
public class MapperTest {
    @Resource//按名称注入(autowired按类型注入)
    UserMapper userMapper;

    @Test
    public void testSelcetList(){
        List<User> users = userMapper.selectList(null);
        users.forEach(System.out::println);
    }

}

  • 测试自己写的sql语句
package com.atguigu.mybatisplus;

import com.atguigu.mybatisplus.entity.User;
import com.atguigu.mybatisplus.mapper.UserMapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import javax.annotation.Resource;
import java.util.List;

@RunWith(SpringRunner.class)
@SpringBootTest
public class MyMapperTest {
    @Resource//按名称注入(autowired按类型注入)
    UserMapper userMapper;

    @Test
    public void testSelcetList(){
        List<User> jone = userMapper.selectAllByName("Jone");
        jone.forEach(System.out::println);
    }

}

⑦测试结果

  • 日志打印
    在这里插入图片描述

3.mybatis-plus的重点类学习

  • BaseMapper<>(mapper)
    泛型接口,提供了较多的简单sql语句,只需提供泛型参数即可获得较多的简单sql方法(接口继承接口获得)
    在这里插入图片描述
  • IService<>(service)
    泛型接口,提供对BaseMapper接口的封装service,只需提供泛型参数即可获得(接口继承接口)
    在这里插入图片描述
  • ServiceImpl<Mapper,实体类>(serviceImpl)
    泛型类,实现了Iservice里的抽象方法,故实际使用只需要提供mapper和实体类泛型参数即可获得使用。实际使用要继承service
    在这里插入图片描述

4.mybatis-plus的注解学习

①数据库表名@TableName(value =“t_user”)

  • 解决问题:数据表名和JAVA中实体类名不对应(User,t_user)
  • 具体使用:@TableName(value =“t_user”)
  • 注意:自定义sql可以更改表名但是mybatis-plus自动生成sql语句(User对应user表)

②主键的使用@TabledId(value=“uid”)

  • 解决问题:数据库主键名和JAVA实体类的字段名不对应。(mp自带默认雪花算法给出默认值id)
  • 具体使用:@TabledId(value=“uid”)
  • 注意:不使用mybatis-plus自己生成sql的insert语句时,如果插入并没有带入主键的值(为默认值null)且数据库没有主键策略,那么会报错(主键不能为空)。
  • 注意:使用了mybatis-plus提供的sql的insert语句时,插入不带入主键的值,那么mybatis-plus会用雪花算法生成id(主键名必须为id,或者增加@TabledId注解)。
  • 注意:即我们如果要用雪花算法。要不主键字段名为id,要不声明@TabledId(value=“uid”)
  • 注意:如果要用自增算法,必须数据库中设置自增算法,java配置文件中全局自增设置(默认生成策略是雪花算法)
#全局设置主键生成策略
mybatis-plus.global-config.db-config.id-type=auto

③雪花算法

  • 出现场景
    在数据库列多,查询量大的情况下,我们需要对数据库进行分表。
  • 垂直分表和水平分表
    垂直分表:常被查询的和不常被查询的分表即可。
    水平分表:如果单表用户量很大,并发量很大,则需要水平分表。
  • 主键策略
    垂直分表:第二张表与第一张表主键相同即可。
    水平分表:需要满足每张表自己的主键策略(自增id冲突)。需要满足负载均衡(一张表满了再添加下一张不均衡)。(主键id无法设置)引入雪花算法。
  • 雪花算法
    总共64位数据。
    0位 符号位
    41位 时间戳
    10位 5位数据中心ID+5位机器ID
    12位 序列号(毫秒级时间产生的序号)

④非主键字段名称不匹配@TabledField(value=“username”)

  • 解决问题:非主键字段名称不匹配
  • 具体使用:@TabledField(value=“username”)
  • 注意:如果数据库为下划线,然后JAVA为驼峰,mybatis-plus自动转换
  • 注意:如果没有映射规律,需要手动添加转换

⑤自动填充策略@TableField(fill = FieldFill.INSERT_UPDATE)

  • 解决问题:每个表中的create_time和update_time两个字段都必须自动填充(可以在数据库设置,可以在java端设置)
  • 具体使用:见下面代码
  • 注意:阿里规范,每一个数据表必须有create_time和update_time两个字段
  • 注意:可以在数据表结构中设置create_time和update_time
    设置默认值为CURRENT_TIMESTAMP 并且update_time设置为根据时间更新,也可以在JAVA程序中设置自动填充功能。
  • 自动填充逻辑
    加入注解在插入时填充还是在更新时填充@TableField(fill = FieldFill.INSERT_UPDATE)
    加入配置类并实现MetaObjectHandler提供的两个方法
    根据字段,填充类型,填充数值去填充
    (注意:所有填充内容都可写到该类,如果某一类没用到该填充字段,也会执行,故需要判断该类是否有该字段。如果某一类已经设置过值也会执行,故需要判断该对象是否已经赋值)
  • 实际运用:将全部类都需要填充的如创建时间和更新时间加入到该配置类中,其他不加(麻烦)
    //插入时填充
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;
    //更新时填充
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;
package com.atguigu.mybatisplus.handler;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;


@Component
@Slf4j
public class MyMetaObjectHandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
        //注意此方法只要在填充时就回调用,效率不高,因为多个表需要填充,但是每次可能执行填充一个,但是全部都执行
        log.info("填充插入");
        //实现填充业务逻辑
        this.strictInsertFill(metaObject,"createTime",LocalDateTime.class, LocalDateTime.now());
        this.strictInsertFill(metaObject,"updateTime",LocalDateTime.class, LocalDateTime.now());
        //判断当前对象的自动填充是否包含属性
        boolean author = metaObject.hasSetter("author");
        if(author) {
            log.info("插入其他表");
            this.strictInsertFill(metaObject, "author", LocalDateTime.class, LocalDateTime.now());
        }
        //判断当前对象的自动填充是否已经赋值
        Object age = this.getFieldValByName("age", metaObject);
        if(age==null) {
            this.strictInsertFill(metaObject, "age", Integer.class, 3);
        }
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("填充修改");
        this.strictInsertFill(metaObject,"updateTime",LocalDateTime.class, LocalDateTime.now());
    }
}

⑥逻辑删除@TableLogic

  • 解决问题:即需要我们在删除重要表时改为逻辑删除,而不是直接删除
  • 使用:@TableLogic
  • 数据库增加字段(阿里规范名称)在这里插入图片描述
  • 表中增加字段(阿里规范名称)
    @TableLogic
    @TableField(value = "is_deleted")
    //字段为0表示没删(false),1表示删除了(true)
    private Boolean deleted;
  • 测试
 userMapper.deleteById(2L);

在这里插入图片描述

5.mybatis-plus的分页学习

①分页的使用

  • 配置完分页插件之后,在进行分页查询时,先查询所有记录,然后封装到Page对象
  • 然后再利用Page对象中的页码和数据再进行分页查询即在sql语句后加入limit语句
  • 最终得到的page对象中包含所有的分页的基本信息和本次分页查询的结构

②配置分页插件

package com.atguigu.mybatisplus.config;


import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@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;
    }
}

③分页查询测试

package com.atguigu.mybatisplus;


import com.atguigu.mybatisplus.entity.User;
import com.atguigu.mybatisplus.mapper.UserMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import javax.annotation.Resource;
import java.util.List;

@RunWith(SpringRunner.class)
@SpringBootTest
public class InterceptorTest {
    @Resource
    UserMapper userMapper;

    @Test
    public void testSelectPage(){
        //分页插件填充了userPage的属性值
        //然后执行sql语句也填充了userPage的分页查询
        Page<User> userPage = new Page<>(2, 5);
        userMapper.selectPage(userPage, null);
        List<User> records = userPage.getRecords();
        records.forEach(System.out::println);
    }
}

在这里插入图片描述

④自定义方法分页查询

  • 定义分页查询方法(mybatis-plus查询时检测到有page会自动增加limit)
IPage<User> selectPageByPage(Page<?> page, Integer age);
  • 定义sql语句(xml)
<select id="selectPageByPage" resultType="com.atguigu.mybatisplus.entity.User">
    SELECT <include refid="Base_Column_List"/> FROM user WHERE age > #{age}
</select>
  • 测试(也会先查询所有,然后再进行分页查询,第一次结果封装到pageParam的分页信息中,然后再对第二次分页查询到的具体结果封装)
@Test
public void testSelectPageVo(){
    Page<User> pageParam = new Page<>(1,5);
    userMapper.selectPageByPage(pageParam, 18);
    List<User> users = pageParam.getRecords();
    users.forEach(System.out::println);
}

6.mybatis-plus的乐观锁学习

①乐观锁出现的场景

  • 场景
    数据库中一个商品卖100,老板让小李加50,后面一想太贵了,又让小王减去30。小李做事儿墨迹,于是小王小李同时看到商品此时只有100,小李100+50=150,小王100-30=70,最后小王后提交数据此时只有70元的商品。
  • 增加product商品
CREATE TABLE product
(
    id BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
    name VARCHAR(30) NULL DEFAULT NULL COMMENT '商品名称',
    price INT(11) DEFAULT 0 COMMENT '价格',
    version INT(11) DEFAULT 0 COMMENT '乐观锁版本号',
    PRIMARY KEY (id)
);

INSERT INTO product (id, NAME, price) VALUES (1, '笔记本', 100);

在这里插入图片描述

  • java中增加实体类和mapper
package com.atguigu.mybatisplus.entity;

import lombok.Data;

@Data
public class Product {
    private Long id;
    private String name;
    private Integer price;
    private Integer version;
}
package com.atguigu.mybatisplus.mapper;

import com.atguigu.mybatisplus.entity.Product;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;

public interface ProductMapper extends BaseMapper<Product> {

}

  • 模拟场景
package com.atguigu.mybatisplus;

import com.atguigu.mybatisplus.entity.Product;
import com.atguigu.mybatisplus.mapper.ProductMapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import javax.annotation.Resource;

@RunWith(SpringRunner.class)
@SpringBootTest
public class TestConcurrentUpdate {
    @Resource
    ProductMapper productMapper;
    @Test
    public void test(){
        //小李取数据
        Product product = productMapper.selectById(1L);
        //小王取数据
        Product product1 = productMapper.selectById(1L);
        //小李修改+50
        product.setPrice(product.getPrice()+50);
        productMapper.updateById(product);
        //小王修改-30
        product1.setPrice(product1.getPrice()-30);
        productMapper.updateById(product1);
        //老板看价格
        Product product2 = productMapper.selectById(1L);
        System.out.println("老板看价格"+product2);
    }
}

②乐观锁的使用

  • 增加版本机制
    修改数据时看和自己拿到时的版本号是否相同,修改完成之后将版本号+1,所以小李修改完数据版本号变为1,但是小王发现自己拿的时候的版本号为0但是此时数据的版本号位1,所以重新拿版本号为1的数据修改,最终为120,版本号为2.
  • mybatis-plus的使用(本质修改时看version是否和数据库里的数据相同,如果相同则修改并且version+1,如果不相同则修改失败)
    添加乐观锁的配置,对version字段加入@version注解
package com.atguigu.mybatisplus.config;


import com.baomidou.mybatisplus.annotation.DbType;
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.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@MapperScan("com.atguigu.mybatisplus.mapper")
public class MybatisPlusConfig {
    //注入分页插件
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        //分页插件
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        //乐观锁插件
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return interceptor;
    }
}

package com.atguigu.mybatisplus.entity;

import com.baomidou.mybatisplus.annotation.Version;
import lombok.Data;

@Data
public class Product {
    private Long id;
    private String name;
    private Integer price;
    @Version
    private Integer version;
}
  • 此时结果 小李修改成功,小王修改失败,老板看到150
    小李查到的数据
    在这里插入图片描述
    小王查到的数据
    在这里插入图片描述
    小李修改数据
    在这里插入图片描述
    小王修改数据
    在这里插入图片描述
    老板查看数据

在这里插入图片描述

  • 小王修改失败后再次修改
package com.atguigu.mybatisplus;

import com.atguigu.mybatisplus.entity.Product;
import com.atguigu.mybatisplus.mapper.ProductMapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import javax.annotation.Resource;

@RunWith(SpringRunner.class)
@SpringBootTest
public class TestConcurrentUpdate {
    @Resource
    ProductMapper productMapper;
    @Test
    public void test(){
        //小李取数据
        Product product = productMapper.selectById(1L);
        //小王取数据
        Product product1 = productMapper.selectById(1L);
        //小李修改+50
        product.setPrice(product.getPrice()+50);
        productMapper.updateById(product);
        //小王修改-30
        product1.setPrice(product1.getPrice()-30);
        int i = productMapper.updateById(product1);
        if(i==0){
            product1 = productMapper.selectById(1L);
            product1.setPrice(product1.getPrice()-30);
            productMapper.updateById(product1);
        }
        //老板看价格
        Product product2 = productMapper.selectById(1L);
        System.out.println("老板看价格"+product2);
    }
}


在这里插入图片描述

7.mybatis-plus的查询条件

①三个重要的类

  • 不用queryWrapper
    可以用map封装查询条件,缺点是只能用and连接。
    可以自定义sql,缺点是比较麻烦。
  • QueryWrapper
    用于封装where后的条件,或者order By
  • UpdateWrapper
    可以封装where后的条件,或者order By
    可以封装update …set 的条件
  • LambdaQueryWrapper
    可以直接用函数来得到实体类的字段对应于数据库中的字段的名称

②queryWrapper的使用

  • where后面封装什么则写什么
    封装 name like %n%,则写queryWrapper.like(“name”,“n”)
    封装 age between 10 and 20 则写queryWrapper.between(“age”,10,20)
  • 封装order by id desc
    queryWrapper.orderByDesc(“id”)

③测试

package com.atguigu.mybatisplus;


import com.atguigu.mybatisplus.entity.User;
import com.atguigu.mybatisplus.mapper.UserMapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RunWith(SpringRunner.class)
@SpringBootTest
public class WrapperTest {


    @Resource
    UserMapper userMapper;

    @Test
    public void testMapSelect(){
        //map只能用and连接查询条件
        //自定义sql语句

        //SELECT id,name,age,email,create_time,update_time,is_deleted AS deleted FROM user
        // WHERE name = ? AND age = ? AND is_deleted=0
        HashMap<String, Object> map = new HashMap<>();
        map.put("name","Jone");
        map.put("age",18);
        List<User> users = userMapper.selectByMap(map);
        users.forEach(System.out::println);
    }

    //查询名字中包含n,年龄大于等于10且小于等于20,email不为空的用户
    @Test
    public void testWrapper1(){
        //SELECT id,name,age,email,create_time,update_time,is_deleted AS deleted FROM user
        // WHERE is_deleted=0
        // AND (name LIKE ? AND age BETWEEN ? AND ?)
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.like("name","n");//name Like %n%
        queryWrapper.between("age",10,20);//age BETWEEN 10 AND 20


        List<User> users = userMapper.selectList(queryWrapper);
        users.forEach(System.out::println);

    }

    //按年龄降序查询用户,如果年龄相同则按id升序排列
    @Test
    public void testWrapper2(){
        //SELECT id,name,age,email,create_time,update_time,is_deleted AS deleted FROM user
        // WHERE is_deleted=0
        // ORDER BY age DESC,id ASC
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.orderByDesc("age");
        queryWrapper.orderByAsc("id");

        List<User> users = userMapper.selectList(queryWrapper);
        users.forEach(System.out::println);
    }
    //删除email为空的用户
    @Test
    public void testWrapper3(){
        //UPDATE user SET is_deleted=1
        // WHERE is_deleted=0 AND (email IS NULL)
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.isNull("email");
        int delete = userMapper.delete(queryWrapper);
    }
    //查询名字中包含n,且(年龄小于18或email为空的用户),并将这些用户的年龄设置为18,邮箱设置为 user@atguigu.com
    @Test
    public void testWrapper4(){
        //UPDATE user SET age=?, email=?, update_time=?
        // WHERE is_deleted=0 AND
        // (name LIKE ? AND (age < ? OR email IS NULL))
        //组装查询条件注意:不加连接就是and
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper
                .like("name","n")
                .and(i ->i.lt("age",18)
                        .or().isNull("email"));
        //组装更新条件
        User user = new User();
        user.setAge(18);
        user.setEmail("user@atguigu.com");
        //执行更新
        userMapper.update(user,queryWrapper);


    }

    //查询所有用户的用户名和年龄
    @Test
    public void testWrapper5(){
        //SELECT name,age FROM user
        // WHERE is_deleted=0

        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        //组装select语句,通常会和selectMaps一起出现
        queryWrapper.select("name","age");

        List<Map<String, Object>> maps = userMapper.selectMaps(queryWrapper);
        maps.forEach(System.out::println);
    }

    //查询id不大于3的所有用户的id列表
    @Test
    public void testWrapper6(){
        //SELECT id,name,age,email,create_time,update_time,is_deleted AS deleted
        // FROM user
        // WHERE is_deleted=0 AND
        // (id IN (select id from user where id <= 3))
        //不推荐,不如直接写sql语句。
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.inSql("id","select id from user where id <= 3");

        List<User> users = userMapper.selectList(queryWrapper);
        users.forEach(System.out::println);
    }


    //查询名字中包含n,且(年龄小于18或email为空的用户),并将这些用户的年龄设置为18,邮箱设置为 user@atguigu.com
    @Test
    public void testWrapper7(){
        //UPDATE user SET age=?,email=?
        // WHERE is_deleted=0 AND
        // (name LIKE ? AND (age < ? OR email IS NULL))
        UpdateWrapper<User> wrapper = new UpdateWrapper<>();
        wrapper
                .set("age",18)
                .set("email","user@atguigu.com")
                .like("name","n")
                .and(i ->i.lt("age",18)
                        .or().isNull("email"));
        //执行更新
        //前面为null,没有自动填充功能,为user,有自动填充功能
        userMapper.update(new User(),wrapper);

    }

    //查询名字中包含n,年龄大于10且小于20的用户,查询条件来源于用户输入,是可选的
    @Test
    public void testWrapper8(){

        // SELECT id,name,age,email,create_time,update_time,is_deleted AS deleted FROM user
        // WHERE is_deleted=0
        // AND (name LIKE ? AND age >= ? AND age <= ?)
        String name = "n";
        Integer ageBegin = 10;
        Integer ageEnd = 20;
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        //如果用户没有输入则不进行查询
        if(StringUtils.isNotBlank(name)){
            queryWrapper.like("name",name);
        }
        //简化开发,直接将判断条件写入
        queryWrapper.ge(ageBegin != null,"age",ageBegin);

        if(ageEnd != null){
            queryWrapper.le("age",ageEnd);
        }
        List<User> users = userMapper.selectList(queryWrapper);
        users.forEach(System.out::println);
    }


    //lambda就是可以直接利用User::getName可以直接获得在数据库表中的名称
    @Test
    public void testWrapper9(){
        String name = "n";
        Integer ageBegin = 10;
        Integer ageEnd = 20;
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        if(StringUtils.isNotBlank(name)){
        //User::getName可以获得user类的name属性在数据库user表中对应的字段名称(即前面写的@TableField)
            queryWrapper.like(User::getName,name);
        }
        //简化开发
        queryWrapper.ge(ageBegin != null,User::getAge,ageBegin);

        if(ageEnd != null){
            queryWrapper.le(User::getAge,ageEnd);
        }
        List<User> users = userMapper.selectList(queryWrapper);
        users.forEach(System.out::println);
    }
}

8.mybatis-plus细节

①resource和autowaired的区别

区别:resource是按优先名称注入,autowired是优先按类型注入。前者不是spring框架里的,后者是spring框架里的。
使用:在注入时,利用autowired注入会报红色,因为autowired是根据类型注入,而resource是根据名称注入,故用resource不会报红

②自定义xml文件时

可以在Resources中创建mapper包下的xml文件,默认扫描mapper包下的xml文件为sql。类似于mybatis中的Resource。(默认配置)
可以在Resources中创建对应的mapper接口的全类名的包,在mapperScan的时候就会扫描到并且绑定mapper接口和mapper.xml文件。类似于mybatis中的Package。(mapperscan)

③mapper.xml中注意可以生成字段

    <sql id="Base_Column_List">
        id, name, age, email
    </sql>
	<include refid="Base_Column_List"/>

④在serviceImpl中调用mapper时

不需要注入mapper,因为serviceImpl继承的ServiceImpl<Mapper,实体类>里面有结构为baseMapper(就是泛型参数的mapper),故也可以直接使用baseMapper.method

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper,User> implements UserService {
    @Resource
    UserMapper userMapper;
    @Override
    public List<User> listAllUserByName(String name) {
        //等价于return userMapper.selectAllByName(name);
        return baseMapper.selectAllByName(name);
        
    }
}

⑤数据表为uid(主键),java实体类也为uid

插入时(不显式声明uid的值),会报错,即uid不会有值(不会用默认的雪花算法),mybatis-plus只会对字段名为id使用雪花算法然后带入默认值
解决:在uid字段上写@TabledId 就指明该uid为具体主键。
注意使用时@TabledId可以显式指明为自增策略,但是如果数据库不指明自增,则会报错。(数据库和业务都没有指明id,id是主键不为空,报错)
如果所有的字段的id都是自增,可以设置

#全局设置主键生成策略
mybatis-plus.global-config.db-config.id-type=auto

9.mybatis-plus的代码生成器具体使用

①代码生成器的作用

  • 代码生成器能够根据数据表产生pojo的类,产生mapper,产生mapper.xml,生成service,产生controller,实际编写时只需要注重controller的逻辑即可。

②代码生成器的使用

  • 引入依赖(父项目管理版本,看版本号在maven的父项目例子中)
        <!--mysql-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!--mybatis-plus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
        </dependency>
        <!--mybatis-plus 代码生成器-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
        </dependency>
        <!-- Mybatis Plus 代码生成器模板引擎,  -->
        <dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity-engine-core</artifactId>
        </dependency>
  • 创建数据库中的表(注意规范,最好有注释,可以满足接口生成器Swagger的使用)
    举例数据库表设计
    在这里插入图片描述

  • 在测试中创建代码生成器(@API是swagger接口文档生成器类注释)

package com.atguigu.srb.core;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import org.junit.Test;

public class CodeGenerator {
    @Test
    public void genCode() {

        // 1、创建代码生成器
        AutoGenerator mpg = new AutoGenerator();

        // 2、全局配置
        GlobalConfig gc = new GlobalConfig();
        String projectPath = System.getProperty("user.dir");
        gc.setOutputDir(projectPath + "/src/main/java");
        gc.setAuthor("Likejin");
        //open等于true时,生成完代码后,打开资源管理器
        gc.setOpen(false); //生成后是否打开资源管理器
        //去掉service接口前缀I
        gc.setServiceName("%sService");	//去掉Service接口的首字母I
        //自增策略
        gc.setIdType(IdType.AUTO); //主键策略
        //自动生成接口文档@API
        gc.setSwagger2(true);//开启Swagger2模式
        mpg.setGlobalConfig(gc);

        // 3、数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://localhost:13306/db200921_srb_core?useUnicode=true&characterEncoding=utf8&useSSL=false");
        dsc.setDriverName("com.mysql.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("abc123");
        dsc.setDbType(DbType.MYSQL);
        mpg.setDataSource(dsc);

        // 4、包配置
        PackageConfig pc = new PackageConfig();
        pc.setParent("com.atguigu.srb.core");
        pc.setEntity("pojo.entity"); //此对象与数据库表结构一一对应,通过 DAO 层向上传输数据源对象。
        mpg.setPackageInfo(pc);

        // 5、策略配置
        //能够完成数据库表名从下划线到类的驼峰习惯
        StrategyConfig strategy = new StrategyConfig();
        strategy.setNaming(NamingStrategy.underline_to_camel);//数据库表映射到实体的命名策略


        //能够完成数据库字段名从下划线到类的属性驼峰习惯
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);//数据库表字段映射到实体的命名策略
        //使用lombok的注解修饰
        strategy.setEntityLombokModel(true); // lombok
        //生成逻辑删除字段名
        strategy.setLogicDeleteFieldName("is_deleted");//逻辑删除字段名
        //符合阿里巴巴规范,去掉is前缀
        strategy.setEntityBooleanColumnRemoveIsPrefix(true);//去掉布尔值的is_前缀(确保tinyint(1))

        //和controller的生成有关,全部使用@RestController
        strategy.setRestControllerStyle(true); //restful api风格控制器,restController返回json数据
        mpg.setStrategy(strategy);

        // 6、执行
        mpg.execute();
    }
}

  • 自动生成文档结构
    在这里插入图片描述

10.mybatis-plus自定义sql的注意点

  • 在mapper中定义方法
    参数(Long userId,Long amount)
  • 在xml中注入参数用
    #{userId}
    #{amount}
  • 注意
    如果在sql语句中不按顺序注入,则会报错绑定参数错误,需要在方法的参数中绑定@Param(“userId”)和@Param(“amount”)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值