Mybatis-plus基本用法

1.简介

官网:https://mp.baomidou.com

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

2.入门

源码:https://github.com/zhongyushi-git/mybatis-plus-demo.git

2.1数据库准备

使用mysql数据库创建数据,执行脚本在根目录下的sql目录下

2.2环境搭建

1)新建一个SpringBoot的项目,导入需要的坐标

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--mysql数据库依赖-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.9</version>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.8</version>
        </dependency>

2)yml配置

#数据源配置
spring:
  datasource:
    #使用阿里巴巴的druid
    type: com.alibaba.druid.pool.DruidDataSource
    #配置数据库的路径和用户名密码
    url: jdbc:mysql://127.0.0.1:3306/mybatisplus?useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT&zeroDateTimeBehavior=convertToNull&useSSL=false&allowMultiQueries=true
    username: root
    password: zys123456

2.3引入mybatis-plus开发

1)导入依赖

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

2)创建实体类

@Data
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
}

3)创建dao继承BaseMapper

package com.zys.mybatisplusdemo.dao;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.zys.mybatisplusdemo.entity.User;

public interface UserDao extends BaseMapper<User> {

}

4)在启动类上加mapper扫描

@SpringBootApplication
@MapperScan("com.zys.mybatisplusdemo.dao")
public class MybatisPlusDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(MybatisPlusDemoApplication.class, args);
    }

}

5)创建controller

@RestController
@RequestMapping("/users")
public class UserController {

    @Autowired
    private UserDao userDao;

    @GetMapping("/list")
    public List<User> userList(){
        List<User> users = userDao.selectList(null);
        return  users;
    }
}

为了演示方便,这里省略了service的部分而直接调用了dao层,具体见源码。

如果添加了mapper.xml,那么需要配置xml的位置,否则会出现无法绑定。

mybatis-plus.mapperLocations=classpath*:mapper/*.xml

6)测试

启动项目,访问http://localhost:8080/users/list即可看到所有的数据。

3.常用注解

3.1@TableName

其用来将实体对象与数据库表名进行对应。当实体名与数据库表名不一致时使用。

3.2@TableId

其是主键注解,指明是主键,默认把id作为主键。属性type用来指定类型:

1)IdType.AUTO是自动增长;

2)IdType.ASSIGN_UUID是String类型的uuid

3)IdType.INPUT是根据用户的输入作为主键

3.3@TableField

其是表的其他字段注解。属性exist用来指明是否是数据库的字段,值为false时不映射数据库表字段。详细的介绍见后续章节,这里的说明已供使用。

3.4注解开发

1)首先将数据库中表名改为t_user,然后实体User加上注解@TableName

@Data
@TableName(value = "t_user")
public class User {
     ......      
}

启动项目,访问http://localhost:8080/users/list可以正常返回数据。

2)将数据库中表t_user的字段id改为t_id,然后修改实体User的属性id并设置自动增长

@Data
@TableName(value = "t_user")
public class User {
    //指定自动增长
    @TableId(value = "t_id",type = IdType.AUTO)
    private Long id;
    ......
}

3)将数据表t_user的字段name改为t_name,然后修改实体User的属性name

 @TableField(value = "t_name")
 private String name;

4)在实体User上添加一个属性,设置不作为数据库的字段

 //不映射数据库表字段
    @TableField(exist = false)
    private String aaa;

启动项目,同上进行访问,数据正常返回。在实际开发过程中,可根据需求使用注解。

4.条件构造器

方法 说明 示例
eq 等于

allEq({id:1,name:"老王",age:null})--->

id = 1 and name = '老王' and age is null

allEq 全等于 eq("name", "老王")--->name = '老王'
ne 不等于 ne("name", "老王")--->name <> '老王'
gt 大于 gt("age", 18)--->age > 18
ge 大于等于 ge("age", 18)--->age >= 18
lt 小于 lt("age", 18)--->age < 18
le 小于等于 le("age", 18)--->age <= 18
between BETWEEN 值1 AND 值2 between("age", 18, 30)--->age between 18 and 30
notBetween NOT BETWEEN 值1 AND 值2 notBetween("age", 18, 30)--->age not between 18 and 30
like LIKE '%值%' like("name", "王")--->name like '%王%'
notLike NOT LIKE '%值%' notLike("name", "王")--->name not like '%王%'
likeLeft LIKE '%值' likeLeft("name", "王")--->name like '%王'
likeRight LIKE '值%' likeRight("name", "王")--->name like '王%'
isNull 字段为null isNull("name")--->name is null
isNotNull 字段不为null isNotNull("name")--->name is not null
in 同数据库in in("age",{1,2,3})--->age in (1,2,3)
notIn 同数据库not in notIn("age",{1,2,3})--->age not in (1,2,3)
inSql 相当于子查询和in

inSql("id", "select id from table where id < 3")--->

id in (select id from table where id < 3)

notInSql 相当于子查询和not in

notInSql("id", "select id from table where id < 3")--->

id not in (select id from table where id < 3)

groupBy 同数据库group by groupBy("id", "name")--->group by id,name
orderBy/orderByDesc 同数据库order by 字段/order by  字段 desc orderBy("id")--->order by id ASC
having 同数据库having having("sum(age) > 10")--->having sum(age) > 10
or/and 同数据库or/and 略 
netsted 正常嵌套 不带 AND 或者 OR nested(i -> i.eq("name", "李白").ne("status", "活着"))--->(name = '李白' and status <> '活着')
apply 字符串拼接

apply("date_format(dateColumn,'%Y-%m-%d') = {0}", "2008-08-08")--->

date_format(dateColumn,'%Y-%m-%d') = '2008-08-08'")

last 拼接在最后,谨慎使用 last("limit 1")---> limit 1
exists/notExists 拼接sql exists("select id from table where age = 1")--->exists (select id from table where age = 1)
select 指定要查询的字段 select("id", "name", "age")--->只查询这三个字段的内容
set 全局修改 set("name", "")--->数据库字段值变为空字符串

5.CRUD操作

只进行简单的介绍,具体需求请自行开发,都是在这个基础上进行的。需要说明的是,下面的增加和修改操作,只会根据对象中存在不为null的属性来操作数据,当数据为null时不会改变数据库中的数据。

5.1添加insert

    @PostMapping("/")
    public String save(User user){
        int count = userDao.insert(user);
        if(count!=0){
            return "添加成功";
        }else{
            return "添加失败";
        }
    }

5.2删除delete

根据主键删除

  @DeleteMapping("/{id}")
    public String delete(@PathVariable("id")long id){
        int count = userDao.deleteById(id);
        if(count!=0){
            return "删除成功";
        }else{
            return "删除失败";
        }
    }

5.3修改update

根据id进行修改

@PutMapping("/")
    public String update(User user){
        int count = userDao.updateById(user);
        if(count!=0){
            return "修改成功";
        }else{
            return "修改失败";
        }
    }

5.4简单查询

5.4.1selectList

在入门时,controller中设置的查询条件是null,实际上里面需要传递一个QueryWrapper<T>类型的对象,调用dao的selectList(),此对象中才有上面的那些方法。

1)查询年龄大于等于24的信息

    @GetMapping("/list")
    public List<User> userList(){
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        //设置查询条件
        queryWrapper.ge("age",24);//查询年龄大于等于24的信息
        List<User> users = userDao.selectList(queryWrapper);
        return  users;
    }

2)查询名字中含有‘o’的信息

queryWrapper.like("name","o");

5.4.2selectById

根据主键查询

 @GetMapping("/{id}")
    public User selectById(@PathVariable("id")long id){
        return userDao.selectById(id);
    }

5.4.3selectCount

查询符合条件的条数,一般和selectList结合使用。

 @GetMapping("/list")
    public Map<String,Object> userList(){
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        //设置查询条件
        queryWrapper.like("name","o");
        List<User> users = userDao.selectList(queryWrapper);
        Integer integer = userDao.selectCount(queryWrapper);
        Map<String,Object> map=new HashMap<>();
        map.put("data",users);
        map.put("total",integer);
        return  map;
    }

5.5分页查询

5.5.1分页插件配置

新建一个类配置其分页

package com.zys.mybatisplusdemo.config;

import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.pagination.optimize.JsqlParserCountOptimize;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;

/**
 * @Aauthor yushizhong
 * @Date 2020/5/17 16:19
 * @Dec MybatisPlus分页配置
 */
@EnableTransactionManagement
@Configuration
@MapperScan("com.zys.mybatisplusdemo.dao")
public class MybatisPlusConfig {

    @Bean
    public PaginationInterceptor paginationInterceptor() {
        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
        return paginationInterceptor;
    }
}

5.5.2单表分页查询

@GetMapping("/list")
    public IPage<User> userList(Integer curr,Integer limit){
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        //设置分页,默认值是1,10
        IPage<User> page=new Page<>(curr,limit);
        IPage<User> user = userDao.selectPage(page, queryWrapper);
        return  user;
    }

5.5.3单表自定义分页查询

有时使用默认的分页查询无法实现需要的功能时,可以自定义分页查询。

先分析一下其自带的分页的方法,打开源码,看到接口中的selectPage方法:

<E extends com.baomidou.mybatisplus.core.metadata.IPage<T>> E selectPage(E page,
@org.apache.ibatis.annotations.Param("ew") com.baomidou.mybatisplus.core.conditions.Wrapper<T> queryWrapper);

那么自定义也就是模仿其写法,步骤如下:

1)在dao的接口中定义方法

 IPage<User> selectPageList(IPage<User> page, @Param(Constants.WRAPPER) QueryWrapper<User> queryWrapper);

对第二个参数queryWrapper使用了@Param注解起别名,其名称使用的是常量的值(实际值是ew),常量的定义也是由官方定义好的,截图如下:

2)在xml中编写sql

    <select id="selectPageList" resultType="com.zys.mybatisplusdemo.entity.User">
        select * from user ${ew.customSqlSegment}
    </select>

那么后面的条件就直接使用"${ew.customSqlSegment}"进行代替了,它会根据设置的条件去查询。

5.5.4多表自定义分页查询

多表分页和单表的分页原来是一样的道理。现假设有两个表,t_student(学生表)和t_clazz(班级表)

1)先创建两个表

CREATE TABLE `clazz` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(50) DEFAULT NULL COMMENT '班级名称',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

CREATE TABLE `student` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) DEFAULT NULL COMMENT '学生姓名',
  `clazzId` int(11) DEFAULT NULL COMMENT '班级id',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;

insert into clazz values(1,'计算机1班'),(2,'计算机2班'),(3,'计算机3班');
insert into student values(null,'赵敏',1),(null,'张明',3),(null,'李慧',3),(null,'赵美美',2),(null,'张峰',2),(null,'孙强',2);

2)创建学生实体类

@Data
@TableName(value = "user")
public class Student {

    @TableId(value = "id",type = IdType.AUTO)
    private Long id;

    @TableField(value = "name")
    private String name;

    @TableField(value = "clazzId")
    private Integer clazzId;

    @TableField(exist = false)
    private String clazzName;
}

3)创建controller接口

    @GetMapping("/list")
    public JSONObject getList(Integer curr, Integer limit) {
        QueryWrapper<Student> queryWrapper = new QueryWrapper<>();
        queryWrapper.like("t1.name", "");
        IPage<Student> page = new Page<>(curr, limit);
        IPage<Student> stu = studentDao.selectPageList(page, queryWrapper);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("data", stu.getRecords());
        jsonObject.put("total", stu.getTotal());
        return jsonObject;
        
    }

4)在dao接口定义方法

IPage<Student> selectPageList(IPage<Student> page, @Param(Constants.WRAPPER) QueryWrapper<Student> queryWrapper);

5)在xml编写sql

<select id="selectPageList" resultType="com.zys.mybatisplusdemo.entity.Student">
        select t1.*,t2.name "clazzName" from student t1
        left join clazz t2 on t1.clazzId = t2.id
         ${ew.customSqlSegment}
</select>

6)调用此接口,数据可以正常查询。执行日志如下:

当然,对于多表查询,如果使用默认的条件查询不能满足要求,可以把QueryMapper换成Mmap,那么在xml中使用对应的参数查询即可。 不过这种方式有些麻烦,但是可以实现更为复杂的需求

dao接口的方法:

IPage<Student> selectPageList2(IPage<Student> page, @Param(Constants.WRAPPER)Map<String, Object> map);

xml的sql:

    <select id="selectPageList2" resultType="com.zys.mybatisplusdemo.entity.Student">
        select t1.*, t2.name "clazzName"
        from student t1
                 left join clazz t2 on t1.clazzId = t2.id
        <where>
            <if test="ew.name != null and ew.name != ''">
                and t1.name like concat('%',#{ew.name},'%')
            </if>
        </where>
    </select>

需要注意的是,在if标签中也需要带ew,否则会报错。

6.代码生成器

代码生成器自动生成包及需要的类名,节省开发的时间。前提是数据库中表已经建好,原因是它根据数据库表进行创建的。

首先导入依赖

     <!--mybatis-plus代码生成器-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.4.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity-engine-core</artifactId>
            <version>2.2</version>
        </dependency>

创建生成器类,然后执行main方法

package com.zys.mybatisplusdemo.config;

import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;

import java.util.ArrayList;
import java.util.List;

/**
 * @Aauthor yushizhong
 * @Date 2020/5/17 16:45
 * @Dec 代码生成器
 */
public class CodeGenerator {

    public static void main(String[] args) {

        // 代码生成器
        AutoGenerator map = new AutoGenerator();

        // 全局配置
        GlobalConfig globalConfig = new GlobalConfig();
        //配置生成文件的输出目录
        globalConfig.setOutputDir(System.getProperty("user.dir") + "/src/main/java");
        //设置开发人员名称
        globalConfig.setAuthor("yushizhong");
        //是否打开输出目录
        globalConfig.setOpen(false);
        //mapper 命名方式
        globalConfig.setMapperName("%sDao");
        //service 命名方式
        globalConfig.setServiceName("%sService");
        map.setGlobalConfig(globalConfig);

        //数据源配置
        DataSourceConfig dataSourceConfig = new DataSourceConfig();
        //数据库的路径
        dataSourceConfig.setUrl("jdbc:mysql://localhost:3306/test?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=CTT");
        //数据库驱动名称
        dataSourceConfig.setDriverName("com.mysql.jdbc.Driver");
        //数据库的登录用户名
        dataSourceConfig.setUsername("root");
        //数据库的登录密码
        dataSourceConfig.setPassword("123456");
        map.setDataSource(dataSourceConfig);

        // 包配置
        PackageConfig pc = new PackageConfig();
        //设置父包名
        pc.setParent("com.zys.mybatisplusdemo");
        pc.setMapper("dao");
        map.setPackageInfo(pc);

        // 自定义配置
        InjectionConfig cfg = new InjectionConfig() {
            @Override
            public void initMap() {
            }
        };
        String templatePath = "/templates/mapper.xml.vm";
        // 自定义输出配置
        List<FileOutConfig> focList = new ArrayList<>();
        // 自定义配置会被优先输出
        focList.add(new FileOutConfig(templatePath) {
            @Override
            public String outputFile(TableInfo tableInfo) {
                //设置xml的输出路径
                return System.getProperty("user.dir") + "/src/main/resources/mapper/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
            }
        });
        cfg.setFileOutConfigList(focList);
        map.setCfg(cfg);

        // 配置模板
        TemplateConfig templateConfig = new TemplateConfig();
        //在代码总不生成xml
        templateConfig.setXml(null);
        map.setTemplate(templateConfig);

        // 策略配置
        StrategyConfig strategy = new StrategyConfig();
        //数据库表映射到实体的命名策略:把下划线变成大写
        strategy.setNaming(NamingStrategy.underline_to_camel);
        //数据库表字段映射到实体的命名策略:把下划线变成大写
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        //是否使用lombok
        strategy.setEntityLombokModel(true);
        strategy.setRestControllerStyle(true);
        // 写于父类中的公共字段
        strategy.setSuperEntityColumns("id");
        strategy.setControllerMappingHyphenStyle(true);
        //表前缀
        strategy.setTablePrefix(pc.getModuleName() + "_");
        map.setStrategy(strategy);

        //执行
        map.execute();
    }


}

7.实现缓存

对于有些查询比较频繁的数据,可以放到缓存中,这里就以redis为例。mybatis-plus的缓存和mybatis的缓存实现原理类似,也有区别,mybatis的缓存实现请参考https://www.cnblogs.com/zys2019/p/11447169.html#_label7

7.1实战演练

1)导入redis的依赖,配置redis数据库参数(见源码)

<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

2)在配置文件中开启缓存

mybatis-plus:
  configuration:
    #开启缓存
    cache-enabled: true

如果不开启,那么缓存就不会生效。

3)获取spring创建的工厂

package com.zys.mybatisplusdemo.util;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Configuration;

/**
 * @author zhongyushi
 * @date 2020/9/16 0016
 * @dec 获取spring创建的工厂
 */
@Configuration
public class ApplicationContextUtil implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    //把非spring创建好的工厂赋值给applicationContext,applicationContext在这个应用中是唯一的
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    //此创建好工厂后再获取对象
    public static Object getBean(String beanName){
        return applicationContext.getBean(beanName);
    }
}

4)创建redis缓存配置类,实现Cache,重写方法

package com.zys.mybatisplusdemo.config;

import com.zys.mybatisplusdemo.util.ApplicationContextUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.cache.Cache;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * @author zhongyushi
 * @date 2020/9/28 0028
 * @dec MybatisPlus缓存配置,使用redis作为缓存服务器
 */
@Slf4j
public class MybatisPlusCache implements Cache {
    // 读写锁
    private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);

    //这里使用了redis缓存,使用springboot自动注入
    private RedisTemplate<String, Object> redisTemplate;

    private String id;

    //是mybatis必须要求的,必写。此id是xml中的namespace的值
    public MybatisPlusCache(final String id) {
        if (id == null) {
            throw new IllegalArgumentException("未获取到缓存实例id");
        }
        this.id = id;
    }

    //返回cache的唯一名称
    @Override
    public String getId() {
        return this.id;
    }

    //缓存存值
    @Override
    public void putObject(Object key, Object value) {
        //id是namespace的值,key是方法名,value是查询的结果
        getRedisTemplate().opsForHash().put(id, key.toString(), value);
    }

    //缓存取值
    @Override
    public Object getObject(Object key) {
        return getRedisTemplate().opsForHash().get(id, key.toString());
    }

    //mybatis保留方法
    @Override
    public Object removeObject(Object key) {
        return null;
    }

    //清空缓存,在增删改时会自动调用
    @Override
    public void clear() {
        getRedisTemplate().delete(id);
    }

    @Override
    public int getSize() {
        return getRedisTemplate().opsForHash().size(id).intValue();
    }

    @Override
    public ReadWriteLock getReadWriteLock() {
        return this.readWriteLock;
    }

    //获取RedisTemplate,不能通过注入的方式,原因是此类是由mybatis实例化的
    private RedisTemplate getRedisTemplate() {
        //从上下文中获取redisTemplate
        RedisTemplate redisTemplate = (RedisTemplate) ApplicationContextUtil.getBean("redisTemplate");
        //设置key是string类型的序列
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        //设置hashKey是string类型的序列
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        return redisTemplate;
    }
}

在这个类中,分别重写了缓存设置、获取和删除的方法,把数据放到redis中。但是在此类中无法直接注入RedisTemplate,此类是由mybatis实例化的,不是由工厂实例化的。但是可以通过applicationContext来获取。

4)开启缓存

在UserDao接口上添加注解,指定缓存的配置类

@CacheNamespace(implementation= MybatisPlusCache.class,eviction=MybatisPlusCache.class)
public interface UserDao extends BaseMapper<User> {
    ...
}

5)测试。启动项目,第一次访问http://localhost:8080/users/list,查看控制台,会发现打印了sql的执行日志,多次访问此路径,它就从redis中获取数据了,同时可以在redis中看到此缓存信息。

 对于增删改操作,都会清空缓存。因此作为缓存的数据一般是频繁查询,很少修改的信息。

7.2注意事项

通过对比mybatis的缓存可以发现,这里指定缓存的配置类是在dao接口上用注解配置的,而mybatis是在xml中配置的。实际上,也可以在xml中配置,但是二者不可兼得。

1)在dao接口中配置,那么只能缓存使用mybatis-plus查询出来的数据。也就是说,在xml中编写的查询语句所查询的结果是不会存入缓存的。

2)在xml中配置,那么只能缓存xml中编写的查询语句所查询的结果,使用mybatis-plus查询出来的数据是不会存入缓存的。

xml中配置如下:

 <cache type="com.zys.mybatisplusdemo.config.MybatisPlusCache"/>

说明:使用mybatis-plus查询出来的数据指的是不编写sql,直接调用其内部已经编写好的查询方法。

8.@TableField注解详细说明

8.1说明

属性名 描述
value 映射数据库的字段名
update 预处理set进行自定义注入(结合fill)
condition  预处理where进行自定义条件查询(不常用)
exist 是否映射数据库的字段(默认是true,值为false则不映射)
fill 字段填充,需结合FieldFill使用

 

对于value和exist在前面已经介绍,在此不再赘述。

8.2 update-修改时操作

1)注入当前的时间

假如在每次更新数据时都需要把时间改成当前操作的时间,那么可以对其进行配置为数据库的时间:

@TableField(value = "update_time", update = "now()",fill = FieldFill.UPDATE)
private Date updateTime;

需要结合fill使用,将其设置为更新时更新数据。设置后需调用mybatisplus自带的修改方法update(),否则不生效

输入的SQL如下:

UPDATE 表 SET update_time=now() WHERE 条件

2)修改变量的值

在每次修改时需要记录修改次数时,可以使用下面的方式。

@TableField(value = "count",update = "%s+1", fill = FieldFill.UPDATE)
private Integer count;

其中"%s"是填充的字段,在这里是count,输出的SQL如下:

UPDATE 表 SET count=count+1 WHERE 条件

不过需要注意的是,在使用时,count在数据库中必须有值,为空时不会修改其值。

8.3 fill与FieldFill

对数据进行自动填充操作。上一小节结合update属性进行了说明。本小节不结合update属性进行添加或修改。

若需要在添加时插入添加时间,修改时同步修改时间。可对对象的字段进行设置,使用fill:

@TableField(value = "create_time", fill = FieldFill.INSERT)
private Date createTime;

@TableField(value = "update_time", fill = FieldFill.UPDATE)
private Date updateTime;

还需要添加一个配置类实现MetaObjectHandler接口,重写两个方法

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.context.annotation.Configuration;

import java.util.Date;

@Configuration
public class MyMetaObjectHandler implements MetaObjectHandler {

    @Override
    public void insertFill(MetaObject metaObject) {
        this.setFieldValByName("createTime", new Date(), metaObject);
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        this.setFieldValByName("updateTime", new Date(), metaObject);
    }
}

可以看出在配置类中对方法重写时,指定了字段名和时间,从而实现自定义插入时间。其他的公共字段也可以使用这种方式。

这种方式显而易见有很大的局限性,对时间的两个字段进行了限定,那么对象的这两个字段就固定了。可根据实际需求选择是否使用这种方式。

8.4记录操作人信息

在每次新增时将插入时间,插入人,修改时间和修改人都赋值,修改时将修改时间和修改人进行更新。那么需要在上述的基础上配置登录用户的信息,若有用户对象如下

import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.experimental.Accessors;

import java.util.Date;

@Data
@TableName(value = "t_user")
@Accessors(chain = true)
public class User1 {
    @TableId(type = IdType.AUTO)
    private Long id;
    private String name;
    private Integer age;
    private String email;
    @TableField(value = "insert_by", fill = FieldFill.INSERT)
    private String insertBy;
    @TableField(value = "update_by", fill = FieldFill.INSERT_UPDATE)
    private String updateBy;
    @TableField(value = "insert_time", fill = FieldFill.INSERT)
    private Date insertTime;
    @TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;
}

更新人和更新时间都需要设置为"INSERT_UPDATE"才能在新增时同步插入值,若不需要插入,则设置为"UPDATE"即可。那么需要配置如下:

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.context.annotation.Configuration;

import java.util.Date;

@Configuration
public class MyMetaObjectHandler implements MetaObjectHandler {
    //模拟获取登录用户信息
    private String loginName="22222";

    @Override
    public void insertFill(MetaObject metaObject) {
        this.setFieldValByName("insertTime", new Date(), metaObject);
        this.setFieldValByName("updateTime", new Date(), metaObject);
        this.setFieldValByName("insertBy", loginName, metaObject);
        this.setFieldValByName("updateBy", loginName, metaObject);
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        this.setFieldValByName("updateTime", new Date(), metaObject);
        this.setFieldValByName("updateBy", loginName, metaObject);
    }
}

上述就并未按照上一章节的字段进行说明,使用了新的基础字段,不过在项目中,这些字段都会在重要的表中进行统一,那么这种方式也符合了需求。

posted @ 2020-05-17 21:39  钟小嘿  阅读(4608)  评论(0编辑  收藏  举报