开发者

Mybatis-Plus适配联合主键实现方式

目录
  • MyBATis-Plus适配联合主键
    • 1、引入依赖
    • 2、实体类定义
    • 3、Mapper(dao)定义
    • 4、简单使用
    • 5、Service 定义
    • 6、ServiceImpl 定义
    • 7、使用
  • 总结

    Mybatis-Plus适配联合主键

    背景是这样的,最近js着手修改一个老项目,平时其他项目用的都是 JPA、倒不是不会用 Mybatis,只是这个项目是用来解析 XML 为对象并进行存储的,而且有的类字段特别多,觉得写 mapper 和 sql 太麻烦了,于是想到了 mybatis-plus(以下简称mp)。

    本来以为很好解决的事情,没想到默认的 mp 不支持联合主键,于是查询了一些资料,有一个 mybatisplus-plus(以下简称mpp) 的工具,因此总结一个 demo 出来,包括整合过程和其中遇到的问题和解决方式。

    1、引入依赖

    	<properties>
    		<mybatis-plus.version>3.4.0</mybatis-plus.version>
    		<mybatis-plus-plus.version>1.5.1-RELEASE</mybatis-plus-plus.version>
    	</properties>
    
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-boot-starter</artifactId>
                <version>${mybatis-plus.version}</version>
            </dependency>
            <dependency>
                <groupId>com.github.jeffreyning</groupId>
                <artifactId>mybatisplus-plus</artifactId>
                <version>${mybatis-plus-plus.version}</version>
            </dependency>
    

    注意事项:

    • mp 和 mpp 的版本号对应关系是有要求的,版本不匹配会出现意想不到的错误

    2、实体类定义

    package com.xsdl.pojo;
    
    import com.baomidou.mybatisplus.annotation.TableField;
    import com.baomidou.mybatisplus.annotation.TableName;
    import com.github.jeffreyning.mybatisplus.anno.MppMultiId;
    import lombok.Data;
    
    @Data
    @TableName(value = "MP_USER")
    public class User {
    
        @MppMultiId
        @TableField(value = "id")
        private String uuid;
    
        @MppMultiId
        @TableField(value = "xh")
        private Integer xh;
    
        private String name;
    
        private Integer age;
    
        private String email;
    
    }
    

    我在项目中日常遇到的联合主键就是 uuid + xh 来解决,当然用 uuid 做主键,再用另一个字段来关联其他表也可以,而且也没有联合主键这个问题。

    注意事项:

    • 使用的是 @MppMultiId 而不是 @TableId
    • 虽然数据库字段叫 id, 但我在类中的定义却是 uuid

    3、Mapper(dao)定义

    package com.xsdl.mapper;
    
    import com.github.jeffreyning.mybatisplus.base.MppBaseMapper;
    import com.xsdl.pojo.User;
    import http://www.devze.comorg.apache.ibatis.annotations.Mapper;
    
    @Mapper
    public interface UserMapper extends MppBaseMapper<User> {
    
    }
    

    注意事项:

    • 继承的是 MppBaseMapper,而不是 BaseMapper

    4、简单使用

    如果你只是想要使用它进行简单的持久化操作,现在已经足够了,例如下面的用法

    package com.xsdl.controller;
    
    import com.xsdl.mapper.UserMapper;
    import com.xsdl.pojo.User;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMappjsing;
    import org.springframework.web.bind.annotation.RestController;
    
    import Java.util.List;
    import java.util.stream.Collectors;
    import java.util.stream.IntStream;
    
    @RestController
    @RequestMapping("/user")
    @Slf4j
    public class UserController {
    
        @Autowired
        private UserMapper userMapper;
    
        @GetMapping("/list")
        public void list() {
            List<User> users = userMapper.selectList(null);
            for (User user : users) {
                log.info("user:{}", user);
            }
            for (int i = 0; i < users.size(); i++) {
                User user = users.get(i);
                user.setName("xsdl" + i);
                userMapper.updateByMultiId(user);
            }
        }
    
    }
    

    注意事项:

    • 这里的 update 操作,我用的是 updateByMultiId,不能用 updateById

    但是我都用联合主键了,说明我大概率是想要批量保存的,而 MppBaseMapper 并不支持这样的操作,于是需要引入 Service

    5、Service 定义

    package com.xsdl.service;
    
    import com.github.jeffreyning.mybatisplus.service.IMppService;
    import com.xsdl.pojo.User;
    
    public interface UserService extends IMppService<User> {
    
    }
    

    注意事项:

    • 继承了 IMppService

    6、ServiceImpl 定义

    package com.xsdl.service;
    
    import com.github.jeffreyning.mybatisplus.service.MppServiceImpl;
    import com.xsdl.mapper.UserMapper;
    import com.xsdl.pojo.User;
    import org.springframework.stereotype.Service;
    
    @Service("userSehttp://www.devze.comrvice")
    public class UserServiceImpl extends MppServiceImpl<UserMapper, User> implements UserService {
    
    }
    

    注意事项:

    • 先继承 MppServiceImpl,并把对应的 Mapper 传入再实现对应的 Service

    7、使用

    package com.xsdl.controllerhttp://www.devze.com;
    
    import com.xsdl.mapper.UserMapper;
    import com.xsdl.pojo.User;
    import com.xsdl.service.UserService;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.List;
    import java.util.stream.Collectors;
    import java.util.stream.IntStream;
    
    @RestController
    @RequestMapping("/user")
    @Slf4j
    public class UserController {
    
        @Autowired
        private UserMapper userMapper;
        @Autowired
        private UserService userService;
    
        @GetMapping("/list")
        public void list() {
            List<User> users = userMapper.selectList(null);
            for (User user : users) {
                log.info("user:{}", user);
            }
            for (int i = 0; i < users.size(); i++) {
                User user = users.get(i);
                user.setName("zss" + i);
                userMapper.updateByMultiId(user);
            }
    
            List<User> userList = IntStream.rangeClosed(1, 10).mapToObj(i -> {
                User user = new User();
                user.setUuid(i + "" + i);
                user.setXh(i);
                user.setName("zss" + i);
                user.setAge(i);
                user.setEmail("zss" + i + "@qq.com");
                return user;
            }).collect(Collectors.toList());
            userService.saveBatch(userList);
    
            List<User> list = userService.list();
            for (User user : list) {
                log.info("user:{}", user);
            }
        }
    
    }
    

    注意启动类上需要加上: @EnableMPP 注解

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

    可能出现的问题:

    1、我在第二步 实体类定义 这里强调说,虽然数据库字段名是 id,但我的属性名却是 uuid,如果设置为 id,启动项目会出现这样的错误

    org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name ‘userController’: Unsatisfied dependency expressed through field ‘userMapper’; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘userMapper’ defined in file Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: java.lang.RuntimeException: not found column for id

    大概意思就是说创建 UserMapper 失败,原因是找不到 id 列,我没详细去解决这个错误,推测原因可能是 mp 里把类里的 id 属性自动解释为主键,解决方式就是像我一样,给它起个新的名字,然后使用 @TableField(value = "id") 标记一下

    2、因为我接手的这个项目早期是 mybatis 嘛,我虽然引入了 mp,但不敢删除之前的 mybatis 的依赖,于是二者共存了,有机会遇到这样的错误

    Error creating bean with name ‘com.github.jeffreyning.mybatisplus.conf.PlusConfig’: Invocation of init method failed; nested exception is java.lang.NoSuchFieldException: CLASS_RESOLVER

    这个错误就通俗易懂多了,说创建这个 bean 失败,原因是根本就没有一个 CLASS_RESOLVER 的字段,进入 PlusConfig 查看源码

    package com.github.jeffreyning.mybatisplus.conf;
    
    @Import({PlusACUtils.class, MppSqlInjector.class})
    @Configuration
    public class PlusConfig {
        private static final Logger logger = LoggerFactory.getLogger(PlusConfig.class);
        @Autowired
        private Environment env;
    
        public PlusConfig() {
        }
    
        @PostConstruct
        public void initRM() throws Exception {
            NhOgnlClassResolver resolver = new NhOgnlClassResolver();
            resolver.baseList.add("com.github.jeffreyning.mybatisplus.check");
            LambdaUtil.setValue(OgnlCache.class, "CLASS_RESOLVER", resolver);
            String utilBasePaths = this.env.getProperty("mpp.utilBasePath");
        }
    }
    

    17 行通过工具类向 OgnlCache 的 CLASS_RESOLVER 设置值,但是这个字段在 OgnlCache 类不存在,这个其实是 mybatis 和 mpp 版本问题,mybatis 的早期版本中,OgnlCache 没有这个字段,因此修改下 mybatis 的版本就可以了,我这里修改到了 3.5.5

       	<dependency>
       		<groupId>org.mybatis</groupId>
       		<artifactId>mybatis</artifactId>
       		<version>3.5.5</version>
       	</dependency>
    

    不过我后来发现 mp 和 springboot 的依赖中其实已经引入了 mybatis 的依赖,似乎把老的删了就行,总之这个问题跟 mybatis 的版本有关系

    总结

    以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程客栈(www.devze.com)。

    0

    上一篇:

    下一篇:

    精彩评论

    暂无评论...
    验证码 换一张
    取 消

    最新开发

    开发排行榜