关于通用mapper的使用

最近有看到通用mapper的一些新用法,记录一下通用mapper的相关使用

官方文档:

https://gitee.com/free/Mapper/wikis/Home

1 通用Mapper简介

通用 Mapper是一个可以实现任意 MyBatis 通用方法的框架,项目提供了常规的增删改查操作以及Example 相关的单表操作。通用 Mapper 是为了解决 MyBatis 使用中 90% 的基本操作,使用它可以很方便的进行开发,可以节省开发人员大量的时间。

通用Mapper可以通过Mybatis的拦截器原理,动态的帮我们实现单表的增删改查功能.

2 通用Mapper基本原理

先从通用Mapper中提供的通用方法,来查看其原理

/**
 * 通用Mapper接口,查询
 *
 * @param <T> 不能为空
 * @author liuzh
 */
@RegisterMapper
public interface SelectMapper<T> {

    /**
     * 根据实体中的属性值进行查询,查询条件使用等号
     *
     * @param record
     * @return
     */
    @SelectProvider(type = BaseSelectProvider.class, method = "dynamicSQL")
    List<T> select(T record);

}

SelectMapper接口和方法都使用的是泛型, 使用时需要指定泛型类型. 通过反射很容易得到泛型接口的类型信息

Type[] types = mapperClass.getGenericInterfaces();
Class<?> entityClass = null;
for (Type type : types) {
    if (type instanceof ParameterizedType) {
        ParameterizedType t = (ParameterizedType) type;
        //判断父接口是否为 SelectMapper.class
        if (t.getRawType() == SelectMapper.class) {
            //得到泛型类型
            entityClass = (Class<?>) t.getActualTypeArguments()[0];
            break;
        }
    }
}

实体类中添加的 JPA 注解只是一种映射实体和数据库表关系的手段,通过一些默认规则或者自定义注解也很容易设置这种关系,获取实体和表的对应关系后,就可以根据通用接口方法定义的功能来生成和 XML 中一样的 SQL 代码

看到注解SelectProvider上type为BaseSelectProvider.class类, 查看其类代码:

/**
 * BaseSelectProvider实现类,基础方法实现类
 *
 * @author liuzh
 */
public class BaseSelectProvider extends MapperTemplate {

    public BaseSelectProvider(Class<?> mapperClass, MapperHelper mapperHelper) {
        super(mapperClass, mapperHelper);
    }

    /**
     * 查询
     *
     * @param ms
     * @return
     */
    public String selectOne(MappedStatement ms) {
        Class<?> entityClass = getEntityClass(ms);
        //修改返回值类型为实体类型
        setResultType(ms, entityClass);
        StringBuilder sql = new StringBuilder();
        sql.append(SqlHelper.selectAllColumns(entityClass));
        sql.append(SqlHelper.fromTable(entityClass, tableName(entityClass)));
        sql.append(SqlHelper.whereAllIfColumns(entityClass, isNotEmpty()));
        return sql.toString();
    }

    /**
     * 查询
     *
     * @param ms
     * @return
     */
    public String select(MappedStatement ms) {
        Class<?> entityClass = getEntityClass(ms);
        //修改返回值类型为实体类型
        setResultType(ms, entityClass);
        StringBuilder sql = new StringBuilder();
        sql.append(SqlHelper.selectAllColumns(entityClass));
        sql.append(SqlHelper.fromTable(entityClass, tableName(entityClass)));
        sql.append(SqlHelper.whereAllIfColumns(entityClass, isNotEmpty()));
        sql.append(SqlHelper.orderByDefault(entityClass));
        return sql.toString();
    }

    /**
     * 查询
     *
     * @param ms
     * @return
     */
    public String selectByRowBounds(MappedStatement ms) {
        return select(ms);
    }

    /**
     * 根据主键进行查询
     *
     * @param ms
     */
    public String selectByPrimaryKey(MappedStatement ms) {
        final Class<?> entityClass = getEntityClass(ms);
        //将返回值修改为实体类型
        setResultType(ms, entityClass);
        StringBuilder sql = new StringBuilder();
        sql.append(SqlHelper.selectAllColumns(entityClass));
        sql.append(SqlHelper.fromTable(entityClass, tableName(entityClass)));
        sql.append(SqlHelper.wherePKColumns(entityClass));
        return sql.toString();
    }

    /**
     * 查询总数
     *
     * @param ms
     * @return
     */
    public String selectCount(MappedStatement ms) {
        Class<?> entityClass = getEntityClass(ms);
        StringBuilder sql = new StringBuilder();
        sql.append(SqlHelper.selectCount(entityClass));
        sql.append(SqlHelper.fromTable(entityClass, tableName(entityClass)));
        sql.append(SqlHelper.whereAllIfColumns(entityClass, isNotEmpty()));
        return sql.toString();
    }

    /**
     * 根据主键查询总数
     *
     * @param ms
     * @return
     */
    public String existsWithPrimaryKey(MappedStatement ms) {
        Class<?> entityClass = getEntityClass(ms);
        StringBuilder sql = new StringBuilder();
        sql.append(SqlHelper.selectCountExists(entityClass));
        sql.append(SqlHelper.fromTable(entityClass, tableName(entityClass)));
        sql.append(SqlHelper.wherePKColumns(entityClass));
        return sql.toString();
    }

    /**
     * 查询全部结果
     *
     * @param ms
     * @return
     */
    public String selectAll(MappedStatement ms) {
        final Class<?> entityClass = getEntityClass(ms);
        //修改返回值类型为实体类型
        setResultType(ms, entityClass);
        StringBuilder sql = new StringBuilder();
        sql.append(SqlHelper.selectAllColumns(entityClass));
        sql.append(SqlHelper.fromTable(entityClass, tableName(entityClass)));

        // 逻辑删除的未删除查询条件
        sql.append("<where>");
        sql.append(SqlHelper.whereLogicDelete(entityClass, false));
        sql.append("</where>");

        sql.append(SqlHelper.orderByDefault(entityClass));
        return sql.toString();
    }
}

在 mybatis 中,每一个方法(注解或 XML )经过处理后,最终会构造成 MappedStatement 对象.

使用@SelectProvider 这种定义,会构造成 ProviderSqlSource,ProviderSqlSource 是一种处于中间的 SqlSource,它本身不能作为最终执行时使用的 SqlSource,但是他会根据指定方法返回的 SQL 去构造一个可用于最后执行的 StaticSqlSource,StaticSqlSource的特点就是静态 SQL,支持在 SQL 中使用#{param} 方式的参数,但是不支持 <if>,<where>等标签

通用 Mapper 从这里入手,利用ProviderSqlSource 可以生成正常的 MappedStatement,在生成 MappedStatement 后,就把 ProviderSqlSource 替换掉了.

接口方法中根据ms 的 id(规范情况下是 接口名.方法名)得到接口,通过接口的泛型可以获取实体类(entityClass),根据实体和表的关系我们可以拼出 XML 方式的动态 SQL

    /**
     * 查询全部结果
     *
     * @param ms
     * @return
     */
    public String selectAll(MappedStatement ms) {
        final Class<?> entityClass = getEntityClass(ms);
        //修改返回值类型为实体类型
        setResultType(ms, entityClass);
        StringBuilder sql = new StringBuilder();
        sql.append(SqlHelper.selectAllColumns(entityClass));
        sql.append(SqlHelper.fromTable(entityClass, tableName(entityClass)));

        // 逻辑删除的未删除查询条件
        sql.append("<where>");
        sql.append(SqlHelper.whereLogicDelete(entityClass, false));
        sql.append("</where>");

        sql.append(SqlHelper.orderByDefault(entityClass));
        return sql.toString();
    }

拼出的 XML 形式的动态 SQL,使用 mybatis 的 XMLLanguageDriver 中的 createSqlSource 方法可以生成 SqlSource。然后使用反射用新的 SqlSource 替换ProviderSqlSource .

tk.mybatis.mapper.mapperhelper.MapperTemplate通用Mapper模板类中

    /**
     * 重新设置SqlSource
     *
     * @param ms
     * @param sqlSource
     */
    protected void setSqlSource(MappedStatement ms, SqlSource sqlSource) {
        MetaObject msObject = MetaObjectUtil.forObject(ms);
        msObject.setValue("sqlSource", sqlSource);
    }

3 通用Mapper使用

通用mapper提供了一些基础的增删改查的方法:

        // 1 新增
        // Mapper接口只提供基础的增删改查  批量新增的需要使用 MySqlMapper 接口,该接口继承自 InsertListMapper 接口
        userMapper.insert(new User());
        userMapper.insertSelective(new User());
        userMapper.insertList(new ArrayList<User>());

        // 2 修改
        userMapper.updateByPrimaryKey(new User());
        userMapper.updateByPrimaryKeySelective(new User());
        userMapper.updateByExample(new User(), new Example(User.class));
        userMapper.updateByExampleSelective(new User(), new Example(User.class));

        // 3 删除
        userMapper.delete(new User());
        userMapper.deleteByPrimaryKey("id");
        userMapper.deleteByExample(new Example(User.class));

        // 4 查询
        userMapper.selectAll();
        userMapper.select(new User());
        userMapper.selectOne(new User());
        userMapper.selectByExample(new Example(User.class));
0 数据库准备
-- 建表语句
CREATE TABLE `user` (
  `id` int NOT NULL COMMENT '主键',
  `username` varchar(64) DEFAULT NULL COMMENT '名称',
  `phone` varchar(64) DEFAULT NULL COMMENT '电话',
  `icon` varchar(255) DEFAULT NULL COMMENT '二进制',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户表';

-- 添加数据
INSERT INTO `test`.`user`(`id`, `username`, `phone`, `icon`) VALUES (1, '李子柒', '77777', '李子柒的头像');
INSERT INTO `test`.`user`(`id`, `username`, `phone`, `icon`) VALUES (2, '2', '2', 'world');
INSERT INTO `test`.`user`(`id`, `username`, `phone`, `icon`) VALUES (3, '3', '3', '3333');
INSERT INTO `test`.`user`(`id`, `username`, `phone`, `icon`) VALUES (5, '5', '5', '123adb');
INSERT INTO `test`.`user`(`id`, `username`, `phone`, `icon`) VALUES (7, '5', '5', '汉字你好');
1 新建一个SpringBoot环境
2 添加maven依赖
    <!-- https://mvnrepository.com/artifact/tk.mybatis/mapper -->
    <dependency>
      <groupId>tk.mybatis</groupId>
      <artifactId>mapper</artifactId>
      <version>4.1.5</version>
    </dependency>

    <!--mybatis和spring整合-->
    <dependency>
      <groupId>org.mybatis.spring.boot</groupId>
      <artifactId>mybatis-spring-boot-starter</artifactId>
      <version>1.3.1</version>
    </dependency>

    <!--MySQL数据库驱动-->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </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>
    </dependency>
3 添加配置文件
spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF8&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
4 添加实体类
@Data
@Table(name = "user")
public class User {

    @Id
    private String id;
    @Column
    private String username;
    @Column
    private String phone;
    @Column
    private String icon;

    @Transient
    private Date queryTime = new Date();

}
5 添加mapper接口
// MySqlMapper接口主要是使用批量新增功能
public interface UserMapper extends Mapper<User>, MySqlMapper<User> {

}
6 添加controller控制器

@Controller
@RequestMapping("/helloworld")
public class HelloWorld {

    @Autowired
    private UserMapper userMapper;
    
    @GetMapping("/queryByCondition")
    @ResponseBody
    public String queryByCondition(@RequestParam("keyword") String keyword) {

        // 使用example来实现复杂关系的查询
        // 1 example可以查询自己需要的字段,并设置排序规则  (可选,默认是查询所有,无排序条件)
        Example example = new Example(User.class);
        example.selectProperties("id", "phone", "icon")
                .orderBy("id")
                .desc();

        // 2 模糊查询需要自己拼百分号% (mybatis-plus不需要)
        example.createCriteria()
                .andLike("username", "%" + keyword + "%")
                .orEqualTo("phone", keyword);

        List<User> users = userMapper.selectByExample(example);
        System.out.println(users);

        return "<h1>Hello Wrold</h1>";
    }

}
7 添加启动类
@MapperScan("com.cf.demo.mapper")
@SpringBootApplication
public class DemoApplication {

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

8 测试

在本地浏览器访问

http://localhost:8080/helloworld/queryByCondition?keyword=子

浏览器页面展示:

Hello Wrold

控制台展示:

[User(id=1, username=null, phone=77777, icon=李子柒的头像, queryTime=Mon Oct 25 19:25:44 CST 2021)]
  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Mybatis通用Mapper是一个基于Mybatis框架的插件,它可以帮助我们快速地进行数据库操作,避免了手写SQL的繁琐和容易出错的问题。使用Mybatis通用Mapper,我们只需要定义好实体类和Mapper接口,就可以直接调用通用的增删改查方法,非常方便。 具体使用方法如下: 1. 引入Mybatis通用Mapper的依赖包,可以通过Maven或者Gradle进行引入。 2. 定义实体类,需要注意的是实体类的属性名要和数据库表的字段名一致,或者使用@ColumnName注解进行映射。 3. 定义Mapper接口,继承通用Mapper接口,例如: public interface UserMapper extends Mapper<User> {} 4. 在Mybatis的配置文件中配置通用Mapper插件,例如: <plugins> <plugin interceptor="tk.mybatis.mapper.plugin.MapperInterceptor"> <property name="mappers" value="tk.mybatis.mapper.common.Mapper"/> </plugin> </plugins> 5. 在代码中调用通用Mapper的方法,例如: @Autowired private UserMapper userMapper; public void addUser(User user) { userMapper.insert(user); } 以上就是Mybatis通用Mapper使用方法,它可以大大简化我们的开发工作,提高开发效率。 ### 回答2: Mybatis通用Mapper是一个基于Mybatis的通用Mapper插件。它提供了单表的增删改查操作,同时还支持通用的批量操作和条件查询等功能。在使用Mybatis通用Mapper时,我们不需要编写繁琐的Mapper接口和对应的XML文件,只需要使用注解即可完成对数据库的操作。 首先,我们需要在pom.xml文件中添加Mybatis通用Mapper的依赖: ``` <dependency> <groupId>tk.mybatis</groupId> <artifactId>mapper</artifactId> <version>4.1.5</version> </dependency> ``` 接下来,我们需要在Mybatis的配置文件中添加通用Mapper的配置: ``` <plugins> <plugin interceptor="tk.mybatis.mapper.common.MapperInterceptor"> <property name="mappers" value="tk.mybatis.mapper.common.BaseMapper"/> </plugin> </plugins> ``` 完成以上操作后,我们就可以在项目中使用Mybatis通用Mapper了。例如,我们要对一个用户表进行操作,可以创建一个User实体类: ``` public class User { private Integer id; private String username; private String password; private String email; // 省略getter和setter方法 } ``` 然后,我们通过注解在UserMapper接口中定义对用户表的操作: ``` public interface UserMapper extends Mapper<User> { } ``` 这里的Mapper是Mybatis通用Mapper提供的一个接口,通过继承该接口,我们可以直接使用其中定义好的单表操作方法。 接下来,我们就可以直接在代码中使用UserMapper了。例如,我们要插入一条用户记录,可以使用以下代码: ``` User user = new User(); user.setUsername("test"); user.setPassword("123456"); user.setEmail("[email protected]"); userMapper.insert(user); ``` 如果我们需要查询一条用户记录,可以使用以下代码: ``` User user = new User(); user.setId(1); User result = userMapper.selectOne(user); ``` 以上就是使用Mybatis通用Mapper的简单示例。在实际使用中,我们还可以通过注解实现复杂的批量操作和条件查询等功能,具体请参考Mybatis通用Mapper的官方文档。 ### 回答3: Mybatis通用mapper是基于Mybatis的一个工具,简化了Mybatis中XML配置的工作量,提供了一些通用的方法,能够简化我们的增删改查操作。下面简单介绍一下Mybatis通用mapper使用方法。 一、引入依赖和配置 在pom文件中引入mybatis和通用mapper的依赖 ``` <dependency> <groupId>tk.mybatis</groupId> <artifactId>mapper-spring-boot-starter</artifactId> <version>${mybatis-mapper.version}</version> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>${mybatis.version}</version> </dependency> ``` 在application.yml中进行相关配置 ``` mybatis: #配置别名 type-aliases-package: com.xxxx.entity #配置xml映射文件路径 mapper-locations: classpath:mapper/*.xml mapper: #配置通用mapper的包路径 mappers: tk.mybatis.mapper.common.Mapper #配置实体类主键的生成策略 identity: mysql #配置mysql的方言,不配置通用mapper的分页插件会出错 dialect: mysql ``` 二、编写实体类和Mapper接口 在编写实体类时,需要给实体类的属性加上@TableId和@Column注解,用来指明主键和列名。例如: ``` @Data @Table(name = "user") public class User { @Id @GeneratedValue(generator = "JDBC") @Column(name = "id") private Long id; @Column(name = "username") private String username; @Column(name = "password") private String password; @Column(name = "age") private Integer age; @Column(name = "email") private String email; } ``` 在编写Mapper接口时,直接继承Mapper<T>接口即可,T为对应的实体类。例如: ``` @Repository public interface UserMapper extends Mapper<User> { } ``` 三、编写通用方法 Mybatis通用mapper提供了一些通用方法,例如插入数据、更新数据、删除数据和查询数据等。这些方法都可以直接调用或者根据需要进行封装。 (1)插入数据 使用通用mapper的插入方法,代码如下: ``` User user = new User(); user.setUsername("testUser"); user.setPassword("123456"); user.setAge(20); user.setEmail("[email protected]"); userMapper.insert(user); ``` 使用通用mapper的批量插入方法,代码如下: ``` List<User> userList = new ArrayList<>(); User user1 = new User(); user1.setUsername("testUser1"); user1.setPassword("123456"); user1.setAge(20); user1.setEmail("[email protected]"); userList.add(user1); User user2 = new User(); user2.setUsername("testUser2"); user2.setPassword("123456"); user2.setAge(21); user2.setEmail("[email protected]"); userList.add(user2); userMapper.insertList(userList); ``` (2)更新数据 使用通用mapper的更新方法,代码如下: ``` User user = new User(); user.setId(1L); user.setUsername("newTestUser"); userMapper.updateByPrimaryKey(user); ``` (3)删除数据 使用通用mapper的删除方法,代码如下: ``` userMapper.deleteByPrimaryKey(1L); ``` (4)查询数据 使用通用mapper的查询方法,代码如下: ``` User user = userMapper.selectByPrimaryKey(1L); ``` 使用通用mapper的查询所有数据方法,代码如下: ``` List<User> userList = userMapper.selectAll(); ``` 使用通用mapper的条件查询方法,代码如下: ``` Condition condition = new Condition(User.class); condition.createCriteria().andEqualTo("username", "testUser"); List<User> userList = userMapper.selectByExample(condition); ``` 以上就是使用Mybatis通用mapper的一些常用方法,它们都能够简化我们的开发工作。当然,如果有需要,我们还可以自己封装一些方法来实现更加灵活和高效的操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值