• SpringBoot第六篇:整合通用Mapper


    作者:追梦1819
    原文:https://www.cnblogs.com/yanfei1819/p/10876339.html
    版权声明:本文为博主原创文章,转载请附上博文链接!

    引言

      在以往的项目中,对于dao层的常规 CRUD 操作,我们通常使用 JPA、JDBC 时会做一个所谓的 BaseDaoMapper 以减少代码量。而通用 Mapper 刚好是这一环节的替代品,代码更简单,更优雅,也是 Mybatis 用的很广泛的一个插件。

      不过需要注意的一点是,通用 Mapper 支持单表操作,不支持通用的多表联合查询。


    使用

      下面通过用增删改查的简单示例,演示 Mapper 的用法,本系列的demo都是按照 Java web 的项目架构来,所以还是按照 MVC 的模式进行。不过注意,因为此处只是为了演示最基本的功能。为了防止舍本逐末,故代码作了最简单的优化,只保留最基本的功能代码,实际业务代码可能会复杂得多。

      准备工作,初始化数据库:

    SET NAMES utf8mb4;
    SET FOREIGN_KEY_CHECKS = 0;
    -- ----------------------------
    -- Table structure for user
    -- ----------------------------
    DROP TABLE IF EXISTS `user`;
    CREATE TABLE `user`  (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `name` varchar(40) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
      `age` int(3) NOT NULL,
      PRIMARY KEY (`id`) USING BTREE
    ) ENGINE = InnoDB AUTO_INCREMENT = 50 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
    -- ----------------------------
    -- Records of user
    -- ----------------------------
    INSERT INTO `user` VALUES (14, 'admin', 21);
    INSERT INTO `user` VALUES (48, 'teacher', 20);
    INSERT INTO `user` VALUES (49, 'student', 22);
    
    SET FOREIGN_KEY_CHECKS = 1;
    

      创建 SpringBoot 项目。

      首先,引入maven依赖(因为通用 Mapper 是建立在 Mybatis 的基础上的,所以在引入 Mapper 之前,必须先引入Mybatis 依赖):

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.0.1</version>
    </dependency>
    <dependency>
        <groupId>tk.mybatis</groupId>
        <artifactId>mapper-spring-boot-starter</artifactId>
        <version>2.1.4</version>
    </dependency>
    

      然后,配置数据库信息:

    spring.datasource.driver-class-name=com.mysql.jdbc.Driver
    spring.datasource.url=jdbc:mysql://192.168.1.88:3306/test?serverTimezone=GMT%2B8
    spring.datasource.username=root
    spring.datasource.password=pass123
    

      下一步,创建实体类以作数据库映射:

    package com.yanfei1819.mybatismapperdemo.entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.Id;
    import javax.persistence.Table;
    
    /**
     * Created by 追梦1819 on 2019-05-07.
     */
    @Table(name = "user")
    public class User {
        @Id
        @GeneratedValue(generator = "JDBC") // 自增字段
        private Long id;
        private String name;
        private int age;
    	// set/get 省略
    }
    

    上述的注解:

    • @Table(name = "user") 映射数据表名

    • @Id 主键id

    • @GeneratedValue(generator = "JDBC") 自增字段

      这会令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键(比如:像 MySQL 和 SQL Server 这样的关系数据库管理系统的自动递增字段)。 这种情况对应的xml类似下面这样:

      <insert id="insertAuthor" useGeneratedKeys="true" keyProperty="id">
          insert into Author (username,password,email,bio)
          values (#{username},#{password},#{email},#{bio})
      </insert>
      
    • 如果表字段与实体类属性不一致,可以用注解

      再下一步,创建代理接口:

    package com.yanfei1819.mybatismapperdemo.dao;
    
    import com.yanfei1819.mybatismapperdemo.entity.User;
    import tk.mybatis.mapper.common.Mapper;
    
    /**
     * Created by 追梦1819 on 2019-05-07.
     */
    @org.apache.ibatis.annotations.Mapper
    public interface UserMapper extends Mapper<User> {
    
    }
    

      该接口就是通用 Mapper 的核心部分。该接口继承 Mapper。

      再者,创建service层接口和实现类:

    package com.yanfei1819.mybatismapperdemo.service;
    
    import com.yanfei1819.mybatismapperdemo.entity.User;
    
    import java.util.List;
    
    /**
     * Created by 追梦1819 on 2019-05-07.
     */
    public interface UserService {
        int insertUser(User user);
        int updateUser(User user);
        int deleteUser(Long id);
        List<User> listUsers();
        User getUserById(Long id);
    }
    

      实现类:

    package com.yanfei1819.mybatismapperdemo.service.impl;
    
    import com.yanfei1819.mybatismapperdemo.dao.UserMapper;
    import com.yanfei1819.mybatismapperdemo.entity.User;
    import com.yanfei1819.mybatismapperdemo.service.UserService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    import java.util.List;
    
    /**
     * Created by 追梦1819 on 2019-05-07.
     */
    @Service
    public class UserServiceImpl implements UserService {
        @Autowired
        private UserMapper userMapper;
    
        @Override
        public int insertUser(User user) {
            return userMapper.insert(user);
        }
        @Override
        public int updateUser(User user) {
            return userMapper.updateByPrimaryKey(user);
        }
        @Override
        public int deleteUser(Long id) {
            return userMapper.deleteByPrimaryKey(id);
        }
        @Override
        public List<User> listUsers() {
            return userMapper.selectAll();
        }
        @Override
        public User getUserById(Long id) {
            return userMapper.selectByPrimaryKey(id);
        }
    }
    

      最后,创建controller层:

    package com.yanfei1819.mybatismapperdemo.web.controller;
    
    import com.yanfei1819.mybatismapperdemo.entity.User;
    import com.yanfei1819.mybatismapperdemo.service.UserService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RestController;
    import java.util.List;
    
    /**
     * Created by 追梦1819 on 2019-05-07.
     */
    @RestController
    public class UserController {
    
        @Autowired
        private UserService service;
    
        @GetMapping("/listUsers")
        public List<User> listUser(){
            return service.listUsers();
        }
        @GetMapping("/getUserById/{id}")
        public User getUserById(@PathVariable Long id){
            return service.getUserById(id);
        }
        @PostMapping("/insertUser")
        public int insertUser(User user){
            return service.insertUser(user);
        }
        @PostMapping("/updateUser")
        public int updateUser(User user){
            return service.updateUser(user);
        }
        @GetMapping("/deleteUser/{id}")
        public int deleteUser(@PathVariable Long id){
            return service.deleteUser(id);
        }
    }
    
    

      启动类是:

    package com.yanfei1819.mybatismapperdemo;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    //import tk.mybatis.spring.annotation.MapperScan; // 注意此处引入的jar
    
    @SpringBootApplication
    //@MapperScan("com.yanfei1819.mybatismapperdemo.db")
    public class MybatisMapperDemoApplication {
        public static void main(String[] args) {
            SpringApplication.run(MybatisMapperDemoApplication.class, args);
        }
    }
    
    

      要注意一点, UserMapper 接口中的 @org.apache.ibatis.annotations.Mapper 注解可以被启动类中的注解 @MapperScan(value = {"com.yanfei1819.mybatismapperdemo.db.*"}) 代替。

      但是这里要注意一个坑,使用了通用 Mapper 的导入的 @MapperScan 的jar包,不再是 import org.mybatis.spring.annotation.MapperScan;,而是 import tk.mybatis.spring.annotation.MapperScan; ,不然会报错。

      启动项目,可测试结果。


    常用API

      此处列举一些常用的API:

    • int insert(T record); 保存一个实体,null的属性也会保存,不会使用数据库默认值

      int insertSelective(T record); 保存一个实体,null的属性不会保存,会使用数据库默认值

    • List<T> selectAll(); 查询全部结果

      T selectByPrimaryKey(Object key); 根据主键字段进行查询,方法参数必须包含完整的主键属性,查询条件使用等号

      List<T> selectByExample(Object example); 根据Example条件进行查询

      List<T> select(T record); 根据实体中的属性值进行查询,查询条件使用等号

      T selectOne(T record); 根据实体中的属性进行查询,只能有一个返回值,有多个结果是抛出异常,查询条件使用等号

      int selectCount(T record); 根据实体中的属性查询总数,查询条件使用等号

    • int updateByPrimaryKey(T record); 根据主键更新实体全部字段,null值会被更新

      int updateByExample(@Param("record") T record, @Param("example") Object example); 根据Example条件更新实体record包含的全部属性,null值会被更新

      int updateByPrimaryKeySelective(T record); 根据主键更新属性不为null的值

    • int deleteByPrimaryKey(Object key); 根据主键字段进行删除,方法参数必须包含完整的主键属性

      int delete(T record); 根据实体属性作为条件进行删除,查询条件使用等号

      int deleteByExample(Object example); 根据Example条件删除数据


    参考

      文档一:https://mapperhelper.github.io/docs

      文档二:https://github.com/abel533/Mapper


    总结

      项目中常规的增删改查是避免不了的,而且逻辑几乎不变。如果每一个增删改查都写一个方法,那冗余代码想必不少。即使是代码生成器生成代码【参考本人博客:SpringBoot第八篇:整合 MyBatis-Generator】,也是不利于代码的拓展的。

      针对这个问题,有很多解决方案,甚至自己封装一个通用方法,也未尝不可(本人工作初期,项目中所用的基本都是这种解决方案)。不过在多方案中,个人还是比较喜欢通用 Mapper,一是它与 MyBatis 无缝对接;二是代码量极少,无需配置;当然,更重要的是,已经有现成的轮子了,何必再重复去造轮子呢?
      源码:我的GitHub


    <全文完>


    ![](https://img2018.cnblogs.com/blog/1183871/201905/1183871-20190516170842393-670807849.png)
  • 相关阅读:
    valgrind内存检测
    uosdeepin商店下载的软件deb包位置
    jmeter中获取到token,又因为现在都是JWT的所以需要添加Bearer 和获取到的token进行拼接
    jmeter json提取器
    jmeter命令行启动
    linux 中把文件内容变成空,不删除文件
    94--分布式事务五-Seata AT模式-Spring Cloud微服务案例(添加AT事务)
    94--Docker(概念/镜像操作/数据管理/网络/互联/构建镜像)
    93--分布式事务四-Seata AT模式-Spring Cloud微服务案例(无事务)
    93--分布式事务二-Seata AT 模式
  • 原文地址:https://www.cnblogs.com/yanfei1819/p/10876339.html
Copyright © 2020-2023  润新知