精华内容
下载资源
问答
  • 通用Mapper

    2017-10-16 10:04:58
    通用Mapper文档是本博客SSM项目实战中第二天需要用到的资料
  • 通用mapper

    2019-12-26 19:56:52
    通用mapper 1.1 通用mapper简介 通用 Mapper 是一个可以实现任意 MyBatis 通用方法的框架,项目提供了常规的增删改查操作以及Example相关的单表操作。为什么要用通用mapper?我们这里列举一下原生Mybatis的痛点: 1...

    通用mapper
    1.1 通用mapper简介
    通用 Mapper 是一个可以实现任意 MyBatis 通用方法的框架,项目提供了常规的增删改查操作以及Example相关的单表操作。为什么要用通用mapper?我们这里列举一下原生Mybatis的痛点:
    1、mapper.xml文件里有大量的sql,当数据库表字段变动,配置文件就要修改

    2、需要自己实现sql分页,select * from table where . . . limit 1,3

    自己手写分页,除了传参page、pageSize,还需要返回条目总数count。

    3、数据库可移植性差:如果项目更换数据库,比如oracle–>mysql,mapper.xml中的sql要重新写,因为Oracle的PLSQL 和mysql 支持的函数是不同的。

    4、生成的代码量过大。

    5、批量操作,批量插入,批量更新,需要自写。

    而这些,通过通用mapper就可以很轻松的解决了。

    1.2 通用mapper快速入门
    在线官方文档:https://gitee.com/free/Mapper/wikis/Home

    1.2.1 通用mapper与Spring集成
    官方的文档中介绍了通用mapper的三种使用方式 ,纯java使用方式、与Spring集成方式、与SpringBoot集成方式。我们这里给大家介绍的是与Spring集成方式。

    (1)引入依赖

    正常情况下,Spring 和 MyBatis 的集成环境中,应该已经存在下面的依赖:

     org.mybatis  mybatis  3.4.5  org.mybatis  mybatis-spring  1.3.1  org.springframework  spring-context  5.0.5.RELEASE  org.springframework  spring-tx  5.0.5.RELEASE  org.springframework  spring-jdbc  5.0.5.RELEASE 集成通用 Mapper 在上面的基础上添加下面的依赖:    tk.mybatis    mapper    4.1.4 (2)与spring集成

    和通用 Mapper 以前版本一样,可以直接使用 tk.mybatis 提供的 tk.mybatis.spring.mapper.MapperScannerConfigurer 进行配置,这个配置和 MyBatis 官方提供的 org.mybatis.spring.mapper.MapperScannerConfigurer 区别只是第一层的包名,tk 和 org。所以使用这种方式时,如果你项目已经使用 org. 进行了配置,只需要改成 tk. 即可。

        我们项目中采用的是这种xml的配置方式,通用mapper还提供了注解方式的配置,详见文档。

    1.2.2 实体类映射
    实体类映射类似下列形式

    @Table(name=“tb_brand”)
    public class Brand implements Serializable{
      @Id
      private Integer id;
     
      private String name;
      //getter and setter …
    }
    @Table是指定实体类对应的数据库表 @Id指的是主键映射。经过上面简单的配置后,相当于就有了 MyBatis 中的关系映射了

    1.2.3 创建Mapper接口
    public interface BrandMapper extends Mapper {

    }
    这里继承了 tk.mybatis.mapper.common.Mapper 接口,在接口上指定了泛型类型 Brand。当你继承了 Mapper 接口后,此时就已经有了针对 Brand 的大量方法,方法如下:

    这些方法中和 MBG 生成的大部分方法都一致,还有一部分 MBG 之外的常用方法。

    基础接口select

    List select(T record)
    根据T对象中的属性名称查询,类似于select * from table where t.name=#{name} and t.password = #{password}
    T selectOne(T record)
    根据实体中的属性进行查询,只能有一个返回值,有多个结果是抛出异常,查询条件使用等号
    T selectByPrimaryKey(Object key)
    根据主键查询   说明:根据主键字段进行查询,方法参数必须包含完整的主键属性,查询条件使用等号
    int selectCount(T record);
    说明:根据实体中的属性查询总数,查询条件使用等号
    基础接口insert

    int insert(T record);
    说明:保存一个实体,null的属性也会保存,不会使用数据库默认值
    int insertSelective(T record);
    说明:保存一个实体,null的属性不会保存,会使用数据库默认值
    基础接口Update

    int updateByPrimaryKey(T record);
    说明:根据主键更新实体全部字段,null值会被更新
    int updateByPrimaryKeySelective(T record);
    说明:根据主键更新属性不为null的值
    基础接口delete

    int delete(T record);
    说明:根据实体属性作为条件进行删除,查询条件使用等号
    int deleteByPrimaryKey(Object key);
    说明:根据主键字段进行删除,方法参数必须包含完整的主键属性

    展开全文
  • 通用 Mapper

    2020-03-04 19:41:16
    使用通用 Mapper 无需自己创建 Mapper 接口内部方法和 Mapper 映射配置文件,只需要定义 Mapper 接口,并继承【 tk.mybatis.mapper.common.Mapper 】接口即可。 根据业务要求,在其 Service 类中调用对应的方法即可...

    一、简介

    使用通用 Mapper 无需自己创建 Mapper 接口内部方法和 Mapper 映射配置文件,只需要定义 Mapper 接口,并继承【 tk.mybatis.mapper.common.Mapper 】接口即可。

    根据业务要求,在其 Service 类中调用对应的方法即可,但是 Mapper 只适合使用单表查询的情况。

    二、使用步骤

    1、创建项目并引入依赖

    1.1 创建项目

    本示例项目使用 SpringBoot 框架进行创建,项目名为:gmall,项目结构如下图所示:
    在这里插入图片描述

    1.2 引入 Maven 依赖

    <!-- 引入通用 mapper 依赖 -->
    <dependency>
        <groupId>tk.mybatis</groupId>
        <artifactId>mapper-spring-boot-starter</artifactId>
        <version>2.1.5</version>
    </dependency>
    
    <!-- 热部署 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
    </dependency>
    
    <!-- MyBatis -->
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.1.1</version>
    </dependency>
    
    <!-- 数据库连接池 -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.0.9</version>
        <scope>runtime</scope>
    </dependency>
    
    <!-- SpringBoot WEB 模块 -->
    <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>
    

    2、配置项目

    主配置文件:application.yml

    spring:
      profiles:
        active: dev
    

    开发环境配置文件:application-dev.yml

    # 配置服务器端口号
    server:
      port: 8081
      context-path: /
    ---
    # 配置数据源
    spring:
      datasource:
        name: datasource
        type: com.alibaba.druid.pool.DruidDataSource
        url: jdbc:mysql://192.168.80.128:3306/gmall?serverTimezone=Asia/Shanghai
        username: root
        password: 123123
        driver-class-name: com.mysql.jdbc.Driver
    ---
    # 枚举按简单类型处理,如果有枚举字段则需要加上该配置才会做映射,另外一种方法是在枚举类型属性上添加注解,详见4.1
    mapper:
      enum-as-simple-type: true
    

    3、配置 SpringBoot 主启动程序

    GmallUserManagerApplication:

    import tk.mybatis.spring.annotation.MapperScan;
    
    @SpringBootApplication
    @MapperScan("com.atguigu.gmall.gmallusermanager.mapper")
    public class GmallUserManagerApplication {
        public static void main(String[] args) {
            SpringApplication.run(GmallUserManagerApplication.class, args);
        }
    }
    

    注:@MapperScan 注解不是 MyBatis 提供(org.mybatis.~)的配置,而是由通用 Mapper 依赖提供(tk.mybatis.~)的配置,不要导错包。两个 @MapperScan 的作用相同,都是用来扫描 Mapper 接口的。


    4、创建 Java 类

    4.1 创建 Bean

    根据数据库表(user_info)结构,创建相应的 Bean 实体类:UserInfo

    注:使用通用Mapper,Java Bean 的命名必须是对应表明的驼峰式命名,例如:表名(user_info)==> Bean 名(UserInfo)

    user_info 表结构:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ssIcPbmc-1583321988454)(C:\Users\BigBox\AppData\Roaming\Typora\typora-user-images\image-20200226171558922.png)]

    UserInfo Bean:必须实现 Serializable 接口

    import javax.persistence.Column;
    import javax.persistence.GeneratedValue;
    import javax.persistence.GenerationType;
    import javax.persistence.Id;
    import java.io.Serializable;
    
    public class UserInfo implements Serializable {
    
        @Id
        @Column
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
    
        @Column
        private String loginName;
    
        @Column
        private String nickName;
    
        @Column
        private String passwd;
    
        @Column
        private String name;
    
        // 其他字段对应的属性省略
        
        // set 和 get 方法省略
    }
    

    注:通用 Mapper 注解

    • @Column:注解注释属性为表中的一个列;
    • @Id:注释注解属性为主键;
    • @GeneratedValue:注释注解主键的创建方式,根据创建方式,当数据保存到数据库成功后,自动将生成的 id 值添加到该对象中;
    • @Transient:表名该属性不对应表中字段,为该对象特有属性。
    • @ColumnType:在实体类的枚举字段加注解

    4.2 创建 Controller

    UserInfoController:使用 REST 风格

    @RestController
    public class UserInfoController {
    
        @Autowired
        private UserInfoService user;
    
        /**
         * 添加用户
         *
         * @param userInfo
         */
        @PostMapping("/user")
        public void addUser(UserInfo userInfo) {
            user.addUser(userInfo);
        }
    
        /**
         * 根据 id 查询用户
         *
         * @param id
         * @return
         */
        @GetMapping("/user/{id}")
        public Object getUser(@PathVariable("id")Long id) {
            return user.getUserById(id);
        }
    
        /**
         * 根据 id 移除用户
         *
         * @param id
         */
        @DeleteMapping("/user/{id}")
        public void removeUser(@PathVariable("id")Long id) {
            user.removeUser(id);
        }
    
        /**
         * 更新用户信息
         * 
         * @param userInfo
         */
        @PutMapping("/user")
        public void updateUser(UserInfo userInfo) {
            user.updateUser(userInfo);
        }
    }
    

    4.3 创建 Service

    UserInfoServiceImpl:其接口省略

    @Service
    public class UserInfoServiceImpl implements UserInfoService {
    
        @Autowired
        private UsserInfoMapper user;
    
        @Override
        public void updateUser(UserInfo userInfo) {
            user.updateByPrimaryKeySelective(userInfo);
        }
    
        @Override
        public void removeUser(Long id) {
            user.deleteByPrimaryKey(id);
        }
    
        @Override
        public void addUser(UserInfo userInfo) {
            user.insertSelective(userInfo);
        }
    
        @Override
        public UserInfo getUserById(Long id) {
            return user.selectByPrimaryKey(id);
        }
    }
    

    注:在 Service中,根据业务需求调用其相应的方法即可

    4.4 创建 Mapper

    UsserInfoMapper:

    import tk.mybatis.mapper.common.Mapper;
    
    public interface UsserInfoMapper extends Mapper<UserInfo> {
    }
    

    注:使用通用 Mapper 时,Mapper 接口要继承【 tk.mybatis.mapper.common.Mapper 】接口,但是其内部不用定义任何方法,所需的方法在父类接口中均已定义。

    展开全文
  • 通用 mapper

    2018-04-26 19:45:00
    一、为什么需要通用 mapper 插件  通用 mapper 插件可以自动的生成 sql 语句。  虽然 mybatis 有逆向工程,可以直接生成 XxxMapper.xml 文件,但是这种生成的方式存在着局限,比如你的实体类增加或者减少或者...

    一、为什么需要通用 mapper 插件

      通用 mapper 插件可以自动的生成 sql 语句。

      虽然 mybatis 有逆向工程,可以直接生成 XxxMapper.xml 文件,但是这种生成的方式存在着局限,比如你的实体类增加或者减少或者修改了某个字段,那么你的 XxxMapper.xml 也需要跟着修改

      如果使用了通用 mapper 插件,可以省略 XxxMapper.xml,只要实体类发生修改,通用 mapper 帮我们生成的 sql 语句也会跟着发生变化

    转载于:https://www.cnblogs.com/fangwu/p/8954671.html

    展开全文
  • SpringBoot整合mybatis通用Mapper+自定义通用Mapper方法

    万次阅读 多人点赞 2019-04-04 00:43:18
    最近公司在用的通用mapper,自己感兴趣,然后就来搭建了一个springboot项目试验通用mapper 这个项目是国内的大神写的一个mybatis插件,里面有很多的增删改查方法 官方解释的是通用mapper支持3.2.4以及以上的版本 ...

    最近公司在用的通用mapper,自己感兴趣,然后就来搭建了一个springboot项目试验通用mapper

    这个项目是国内的大神写的一个mybatis插件,里面有很多的增删改查方法

    官方解释的是通用mapper支持3.2.4以及以上的版本

    首先引入pom

    <!--Mybatis -->
    		<dependency>
    			<groupId>org.mybatis.spring.boot</groupId>
    			<artifactId>mybatis-spring-boot-starter</artifactId>
    			<version>1.1.1</version>
    		</dependency>
    		<dependency>
    			<groupId>org.mybatis.generator</groupId>
    			<artifactId>mybatis-generator</artifactId>
    			<version>1.3.5</version>
    			<type>pom</type>
    		</dependency>
    		<!--分页插件 -->
    		<dependency>
    			<groupId>com.github.pagehelper</groupId>
    			<artifactId>pagehelper</artifactId>
    			<version>4.2.1</version>
    		</dependency>
    		<!--tkmybatis -->
    		<dependency>
    			<groupId>tk.mybatis</groupId>
    			<artifactId>mapper-spring-boot-starter</artifactId>
    			<version>1.1.4</version>
    		</dependency>

    通用Mapper是tk.mybais中的

    配置文件application.yml:

    server: 
      port: 8081
      # 下面是配置undertow作为服务器的参数
      undertow: 
        # 设置IO线程数, 它主要执行非阻塞的任务,它们会负责多个连接, 默认设置每个CPU核心一个线程
        io-threads: 4
        # 阻塞任务线程池, 当执行类似servlet请求阻塞操作, undertow会从这个线程池中取得线程,它的值设置取决于系统的负载
        worker-threads: 20
        # 以下的配置会影响buffer,这些buffer会用于服务器连接的IO操作,有点类似netty的池化内存管理
        # 每块buffer的空间大小,越小的空间被利用越充分
        buffer-size: 1024
        # 是否分配的直接内存
        direct-buffers: true
    
    spring: 
      datasource: 
        type: com.alibaba.druid.pool.DruidDataSource
        driverClassName: com.mysql.jdbc.Driver
        driver-class-name: com.mysql.jdbc.Driver
        platform: mysql
        url: jdbc:mysql://xxx.xxx.xxx.xxx:5306/miniprogram?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false
        username: xxxxx
        password: xxxxx
        initialSize: 5
        minIdle: 5
        maxActive: 20
        maxWait: 60000
        timeBetweenEvictionRunsMillis: 60000
        minEvictableIdleTimeMillis: 300000
        validationQuery: SELECT1FROMDUAL
        testWhileIdle: true
        testOnBorrow: false
        testOnReturn: false
        filters: stat,wall
        logSlowSql: true
      redis: 
        database: 1
        host: xxxxx
        port: xxxx
        password: xxxx
        timeout: 10000
      activemq: 
        queueName: mvp.queue
        topicName: mvp.topic
        #账号密码
        user: user
        password: user
        #URL of the ActiveMQ broker.
        broker-url: tcp://localhost:61616
        in-memory: false
        #必须使用连接池
        pool: 
          #启用连接池
          enabled: true
          #连接池最大连接数
          max-connections: 5
          #空闲的连接过期时间,默认为30秒
          idle-timeout: 30s
    #    jedis:    有默认值,源码:RedisProperties
    #      pool:
    #        max-active:
    #        max-idle:
    #        max-wait:
    #        min-idle: 
        
    mybatis: 
      typeAliasesPackage: com.pinyu.miniprogram.mysql.entity
      mapper-locations: classpath:mapper/**/*Mapper.xml
    mapper:
      mappers: com.pinyu.miniprogram.mysql.mappers.BaseMapper
      identity: mysql
      
    #logging.config: 
    #  classpath: test/log4j2_test.xml

    xxxx请配置自己的数据库相关信息

    mapper:
      mappers: com.pinyu.miniprogram.mysql.mappers.BaseMapper
      identity: mysql

    ctrl+鼠标点击com.pinyu.miniprogram.mysql.mappers.BaseMapper 进入源码可以看到 MapperProperties类

      是一个集合,意思这里可以mappers配置多个通用Mapper,可以是直接继承它已有的通用Mapper,也可以是定义自己需要的通用Mapper,自定义通用Mapper(代替它的Mapper)继承实现的方式不一样,下面会讲到

    也可以用代码进行配置:

    /**
     * 通用mapper与分页插件的一些配置
     */
    @Configuration
    public class MyBatisMapperScannerConfig {
    	
       /**
       * 使用通用Mapper之前需要初始化的一些信息
       * 使用通用Mapper插件时请勿使用热加载,否则报错,插件作者后续应该会修复
       */
       @Bean
        public MapperScannerConfigurer mapperScannerConfigurer() {
    	   
            MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
            mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactory");
            mapperScannerConfigurer.setBasePackage("com.xx.xx.xx.mapper");//普通mapper的位置
            
            Properties properties = new Properties();
            properties.setProperty("mappers", BaseMapper.class.getName());//通用mapper的全名
            properties.setProperty("notEmpty", "false");
            properties.setProperty("IDENTITY", "MYSQL");//配置数据库方言
            
            mapperScannerConfigurer.setProperties(properties);
            
            return mapperScannerConfigurer;
        }
     
       /**
        * 配置mybatis的分页插件pageHelper
        */
       @Bean
       public PageHelper pageHelper(){
           PageHelper pageHelper = new PageHelper();
           Properties properties = new Properties();
           //设置为true时,会将RowBounds第一个参数offset当成pageNum页码使用
           properties.setProperty("offsetAsPageNum","true");
           //置为true时,使用RowBounds分页会进行count查询
           properties.setProperty("rowBoundsWithCount","true");
           //合理化查询,启用合理化时,
           //如果pageNum<1会查询第一页,如果pageNum>pages会查询最后一页
           //未开启时如果pageNum<1或pageNum>pages会返回空数据
           properties.setProperty("reasonable","true");
           //配置mysql数据库的方言
           properties.setProperty("dialect","mysql");   
           pageHelper.setProperties(properties);
           return pageHelper;
       }
    }

    mappers对应的通用mapper类,不要和自己其他业务的mapper放在一起,不要被@MapperScan扫描到不然会报错,因为继承了通用mapper,会有很多相应的方法,被扫描到以后,mybatis发现没有一个xml配置文件或者相应方法没有进行实现,这时候就会报错。但是继承自己的BaseMapper相关mapper肯定是要被扫描到的

    数据库创建一张表member以及相关字段

    /*
    Navicat MySQL Data Transfer
    
    Source Server         : 120.79.81.103-5306-master
    Source Server Version : 50719
    Source Host           : 120.79.81.103:5306
    Source Database       : miniprogram
    
    Target Server Type    : MYSQL
    Target Server Version : 50719
    File Encoding         : 65001
    
    Date: 2019-04-03 23:09:51
    */
    
    SET FOREIGN_KEY_CHECKS=0;
    
    -- ----------------------------
    -- Table structure for member
    -- ----------------------------
    DROP TABLE IF EXISTS `member`;
    CREATE TABLE `member` (
      `id` bigint(20) NOT NULL AUTO_INCREMENT,
      `member_name` varchar(255) NOT NULL COMMENT '会员用户名',
      `tel` varchar(255) DEFAULT NULL COMMENT '电话',
      `nick_name` varchar(255) NOT NULL COMMENT '昵称',
      `head_img` varchar(255) DEFAULT NULL COMMENT '头像地址',
      `status` int(1) NOT NULL COMMENT '状态 1启用 2禁用',
      `create_date` datetime NOT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间',
      `update_date` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
      `pwd` varchar(255) NOT NULL COMMENT '密码',
      `signature` varchar(255) DEFAULT NULL COMMENT '个性签名',
      `creat_id` bigint(20) DEFAULT NULL,
      `delete_state` int(1) NOT NULL DEFAULT '1',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
    
    -- ----------------------------
    -- Records of member
    -- ----------------------------
    INSERT INTO `member` VALUES ('1', 'dsada', '15928878433', 'dasdas', null, '1', '2019-03-11 18:47:53', '2019-03-11 18:47:53', '123456', null, null, '1');
    INSERT INTO `member` VALUES ('2', 'ypp', '15928878888', '6666', null, '1', '2019-03-11 19:35:39', null, 'EDGM@MAMABDACFDLLG', null, null, '1');
    

    创建实体MemberEntity,一般创建实体我都会抽一些相同的字段出来

    MemberEntity:

    package com.pinyu.miniprogram.mysql.entity.member;
    
    import javax.persistence.Table;
    
    import com.pinyu.miniprogram.mysql.entity.BaseEntity;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    import lombok.experimental.Accessors;
    
    @Data // getter、setter
    @AllArgsConstructor // 全参构造方法
    @NoArgsConstructor // 无参构造方法
    @Accessors(chain = true) // 链式编程写法
    @Table(name="member")
    public class MemberEntity extends BaseEntity {
    
    	/**
    	 * 
    	 */
    	private static final long serialVersionUID = -2601234073734313278L;
    	private String memberName;// 会员登录用户名
    	private String nickName;// 昵称
    	private String tel;// 电话
    	private String pwd;// 密码
    	private String headImg;// 头像图片
    	private String signature;// 个性签名
    	private Integer status;//状态 1禁用 2启用
    }
    

    BaseEntity:

    package com.pinyu.miniprogram.mysql.entity;
    
    import java.util.Date;
    
    import javax.persistence.Column;
    
    import com.pinyu.miniprogram.mysql.entity.member.MemberEntity;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    import lombok.experimental.Accessors;
    
    /**
     * @author ypp 
     * @Description: TODO(用一句话描述该文件做什么)
     */
    @Data // getter、setter
    @AllArgsConstructor // 全参构造方法
    @NoArgsConstructor // 无参构造方法
    @Accessors(chain = true) // 链式编程写法
    public class BaseEntity extends IdEntity {
    
    	/**
    	 * 
    	 */
    	private static final long serialVersionUID = 8575696766261326260L;
    
    	@Column(name="creat_id")
    	private Integer creatId;
    
    	@Column(name="create_date")
    	private Date createDate;
    
    	@Column(name="delete_state")
    	private Integer deleteState;// 删除状态 1正常 2已删除
    
    }
    

    IdEntity:

    package com.pinyu.miniprogram.mysql.entity;
    
    import java.io.Serializable;
    
    import javax.persistence.Column;
    import javax.persistence.GeneratedValue;
    import javax.persistence.GenerationType;
    import javax.persistence.Id;
    
    import com.pinyu.miniprogram.mysql.entity.member.MemberEntity;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    import lombok.experimental.Accessors;
    
    /**
     * @author ypp
     * @Description: TODO(用一句话描述该文件做什么)
     */
    @Data // getter、setter
    @AllArgsConstructor // 全参构造方法
    @NoArgsConstructor // 无参构造方法
    @Accessors(chain = true) // 链式编程写法
    public class IdEntity implements Serializable {
    
    	/**
    	 * 
    	 */
    	private static final long serialVersionUID = -9089706482760436909L;
    
    	@Id
    	@Column(name = "id")
    	@GeneratedValue(strategy = GenerationType.IDENTITY)
    	private Long id;
    
    }
    

    @Table 对应数据库的表,如果不写默认是类名首字母小写作为表名,比Member,不写数据库表默认指向member

    @Column的属性name对应数据库表的字段,如果不写默认是驼峰下划线匹配,比如private Long myId,如果不写得话,就是对应数据库表字段my_id

    @Id:把当前字段作为数据库主键使用,匹配数据库主键。如果不贴此注解,在某些查询语句的时候会把表字段一起作为联合主键查询

    @GeneratedValue  让通用mapper在执行insert操作之后将自动生成的主键值回写到当前实体对象对应的属性当中

    新建一个通用Mapper继承Mapper、MySqlMapper,点击进去看

    package com.pinyu.miniprogram.mysql.mappers;
    
    import com.pinyu.miniprogram.mysql.entity.BaseEntity;
    
    import tk.mybatis.mapper.common.Mapper;
    import tk.mybatis.mapper.common.MySqlMapper;
    
    /** 
    * @author ypp
    * 创建时间:2018年12月27日 下午1:29:03 
    * @Description: TODO(用一句话描述该文件做什么) 
    */
    public interface BaseMapper<T extends BaseEntity> extends Mapper<T>,MySqlMapper<T>{
    
    }
    

     

    BaseMapper是我自己定义的通用Mapper,注意在被继承Mapper上面也有BaseMapper,注意区分,我这里名字取一样了而已。

    被Mapper继承的BaseMapper里面有还有很多增删改查的方法

     这是源码

    看了下,里面有大概20个左右方法,都是比较基础的增删改查

    测试:

    MemberMapper并没有selectAll方法,沿用的继承的selectAll方法

    比较详细的一个入门示例。希望能帮助到用到的小伙伴

     

    自定义通用Mapper,也有可能在实际工作中通用Mapper并不能满足工作,需要额外的一些通用方法,但是这种的情况很少,通用Mapper提供的方法基本都能满足单表操作需求了

    举例我要写一个通用的单表分页:

    1、自己定义的通用Mapper必须包含泛型,例如MysqlMapper<T>。这一点在这里可以忽略,这里并没有自定义自己的通用Mapper,而是使用了它自带的通用Mapper,我们继承的它

    2、自定义的通用Mapper接口中的方法需要有合适的注解。具体可以参考Mapper

    3、需要继承MapperTemplate来实现具体的操作方法。必须要新建一个类继承MapperTemplate,必须继承MapperTemplate,必须继承MapperTemplate

    4、通用Mapper中的Provider一类的注解只能使用相同的type类型(这个类型就是第三个要实现的类。)。实际上method也都写的一样。

     

    在自己的BaseMapper写一个方法,改造后的BaseMapper:

    package com.pinyu.miniprogram.mysql.mappers;
    
    import java.util.List;
    
    import org.apache.ibatis.annotations.Param;
    import org.apache.ibatis.annotations.SelectProvider;
    
    import com.pinyu.miniprogram.mysql.entity.BaseEntity;
    
    import tk.mybatis.mapper.common.Mapper;
    import tk.mybatis.mapper.common.MySqlMapper;
    
    /**
     * @author ypp 创建时间:2018年12月27日 下午1:29:03
     * @Description: TODO(用一句话描述该文件做什么)
     */
    public interface BaseMapper<T extends BaseEntity> extends Mapper<T>, MySqlMapper<T> {
    
    	/**
    	 * * 单表分页查询 * * @param object * @param offset * @param limit * @return 
    	 */
    	@SelectProvider(type = BaseMapperProvider.class, method = "dynamicSQL")
    	List selectPage(@Param("entity") T object, @Param("offset") int offset, @Param("limit") int limit);
    }
    

     

    返回结果为List,入参分别为查询条件和分页参数。在Mapper的接口方法中,当有多个入参的时候建议增加@Param注解,否则就得用param1,param2...来引用参数。

    同时必须在方法上添加注解。查询使用SelectProvider,插入使用@InsertProvider,更新使用UpdateProvider,删除使用DeleteProvider。不同的Provider就相当于xml中不同的节点,如<select>,<insert>,<update>,<delete>

    因为这里是查询,所以要设置为SelectProvider,这4个Provider中的参数都一样,只有type和method。

    type必须设置为实际执行方法的BaseMapperProvider.class(此类在下面),method必须设置为"dynamicSQL"

    通用Mapper处理的时候会根据type反射BaseMapperProvider查找方法,而Mybatis的处理机制要求method必须是type类中只有一个入参,且返回值为String的方法。"dynamicSQL"方法定义在MapperTemplate中,该方法如下:

    public String dynamicSQL(Object record) {
        return "dynamicSQL";
    }

    新建的BaseMapperProvider:上面第三点说到了需要一个类继承MapperTemplate,这是必须的。继承了它然后再进行相应的实现,方法名请和Mapper接口中的方法名一致

    package com.pinyu.miniprogram.mysql.mappers;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Set;
    
    import org.apache.ibatis.mapping.MappedStatement;
    import org.apache.ibatis.scripting.xmltags.IfSqlNode;
    import org.apache.ibatis.scripting.xmltags.MixedSqlNode;
    import org.apache.ibatis.scripting.xmltags.SqlNode;
    import org.apache.ibatis.scripting.xmltags.StaticTextSqlNode;
    import org.apache.ibatis.scripting.xmltags.WhereSqlNode;
    
    import tk.mybatis.mapper.entity.EntityColumn;
    import tk.mybatis.mapper.mapperhelper.EntityHelper;
    import tk.mybatis.mapper.mapperhelper.MapperHelper;
    import tk.mybatis.mapper.mapperhelper.MapperTemplate;
    
    public class BaseMapperProvider extends MapperTemplate {
    
    	public BaseMapperProvider(Class<?> mapperClass, MapperHelper mapperHelper) {
    		super(mapperClass, mapperHelper);
    	}
    
    	public SqlNode selectPage(MappedStatement ms) {
    		Class<?> entityClass = getEntityClass(ms);
    		// 修改返回值类型为实体类型
    		setResultType(ms, entityClass);
    
    		List<SqlNode> sqlNodes = new ArrayList<SqlNode>();
    		// 静态的sql部分:select column ... from table
    		sqlNodes.add(new StaticTextSqlNode(
    				"SELECT " + EntityHelper.getSelectColumns(entityClass) + " FROM " + tableName(entityClass)));
    		// 获取全部列
    		Set<EntityColumn> columns = EntityHelper.getColumns(entityClass);
    
    		List<SqlNode> ifNodes = new ArrayList<SqlNode>();
    		boolean first = true;
    		// 对所有列循环,生成<if test="property!=null">[AND] column = #{property}</if>
    		for (EntityColumn column : columns) {
    			StaticTextSqlNode columnNode = new StaticTextSqlNode(
    					(first ? "" : " AND ") + column.getColumn() + " = #{entity." + column.getProperty() + "} ");
    			if (column.getJavaType().equals(String.class)) {
    				ifNodes.add(new IfSqlNode(columnNode, "entity." + column.getProperty() + " != null and " + "entity."
    						+ column.getProperty() + " != '' "));
    			} else {
    				ifNodes.add(new IfSqlNode(columnNode, "entity." + column.getProperty() + " != null "));
    			}
    			first = false;
    		}
    		// 将if添加到<where>
    		sqlNodes.add(new WhereSqlNode(ms.getConfiguration(), new MixedSqlNode(ifNodes)));
    		// 处理分页
    		sqlNodes.add(new IfSqlNode(new StaticTextSqlNode(" LIMIT #{limit}"), "offset==0"));
    		sqlNodes.add(new IfSqlNode(new StaticTextSqlNode(" LIMIT #{limit} OFFSET #{offset} "), "offset>0"));
    		return new MixedSqlNode(sqlNodes);
    	}
    
    }
    

    在这里有一点要求,那就是BaseMapperProvider处理BaseMapper<T>中的方法时,方法名必须一样,因为这里需要通过反射来获取对应的方法,方法名一致一方面是为了减少开发人员的配置,另一方面和接口对应看起来更清晰。

    除了方法名必须一样外,入参必须是MappedStatement ms,除此之外返回值可以是void或者SqlNode之一。

    这里先讲一下通用Mapper的实现原理。通用Mapper目前是通过拦截器在通用方法第一次执行的时候去修改MappedStatement对象的SqlSource属性。而且只会执行一次,以后就和正常的方法没有任何区别。

    使用Provider注解的这个Mapper方法,Mybatis本身会处理成ProviderSqlSource(一个SqlSource的实现类),由于之前的配置,这个ProviderSqlSource种的SQL是上面代码中返回的"dynamicSQL"。这个SQL没有任何作用,如果不做任何修改,执行这个代码肯定会出错。所以在拦截器中拦截符合要求的接口方法,遇到ProviderSqlSource就通过反射调用如BaseMapperProvider中的具体代码去修改原有的SqlSource。

    最简单的处理Mybatis SQL的方法是什么?就是创建SqlNode,使用DynamicSqlSource,这种情况下我们不需要处理入参,不需要处理代码中的各种类型的参数映射。比执行SQL的方式容易很多。

    有关这部分的内容建议查看通用Mapper的源码和Mybatis源码了解,如果不了解在这儿说多了反而会乱。

     

    对上诉实现代码的描述:

    首先获取了实体类型,然后通过setResultType将返回值类型改为entityClass,就相当于resultType=entityClass。

    这里为什么要修改呢?因为默认返回值是T,Java并不会自动处理成我们的实体类,默认情况下是Object,对于所有的查询来说,我们都需要手动设置返回值类型。

    对于insert,update,delete来说,这些操作的返回值都是int,所以不需要修改返回结果类型。

    之后从List<SqlNode> sqlNodes = new ArrayList<SqlNode>();代码开始拼写SQL,首先是SELECT查询头,在EntityHelper.getSelectColumns(entityClass)中还处理了别名的情况。

    然后获取所有的列,对列循环创建<if entity.property!=null>column = #{entity.property}</if>节点。最后把这些if节点组成的List放到一个<where>节点中。

    这一段使用属性时用的是 entity. + 属性名,entity来自哪儿?来自我们前面接口定义处的Param("entity")注解,后面的两个分页参数也是。如果你用过Mybatis,相信你能明白。

    之后在<where>节点后添加分页参数,当offset==0时和offset>0时的分页代码不同。

    最后封装成一个MixedSqlNode返回。

    返回后通用Mapper是怎么处理的,这里贴下源码:

    SqlNode sqlNode = (SqlNode) method.invoke(this, ms);
    DynamicSqlSource dynamicSqlSource = new DynamicSqlSource(ms.getConfiguration(), sqlNode);
    setSqlSource(ms, dynamicSqlSource);
    返回SqlNode后创建了DynamicSqlSource,然后修改了ms原来的SqlSource。

    测试:

    这里分页参数就随便用了RESTFUL风格随便写了下

    数据库只有2条数据。测试成功

    其实有了Mybatis自动生成插件,通用Mapper优势并不是太突出。

    非SpringBoot项目的话,原理都是一样的,只是某些类需要.xml配置文件进行配置和注入

     

    展开全文

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 5,615
精华内容 2,246
关键字:

通用mapper