MyBatis直接执行SQL的工具SqlMapper

可能有些人也有过类似需求,一般都会选择使用其他的方式如Spring-JDBC等方式解决。

能否通过MyBatis实现这样的功能呢?

为了让通用Mapper更彻底的支持多表操作以及更灵活的操作,在2.2.0版本增加了一个可以直接执行SQL的新类SqlMapper。

我们来了解一下SqlMapper。

SqlMapper提供的方法

SqlMapper提供了以下这些公共方法:

  • Map<String,Object> selectOne(String sql)
  • Map<String,Object> selectOne(String sql, Object value)
  • <T> T selectOne(String sql, Class<T> resultType)
  • <T> T selectOne(String sql, Object value, Class<T> resultType)
  • List<Map<String,Object>> selectList(String sql)
  • List<Map<String,Object>> selectList(String sql, Object value)
  • <T> List<T> selectList(String sql, Class<T> resultType)
  • <T> List<T> selectList(String sql, Object value, Class<T> resultType)
  • int insert(String sql)
  • int insert(String sql, Object value)
  • int update(String sql)
  • int update(String sql, Object value)
  • int delete(String sql)
  • int delete(String sql, Object value)

一共14个方法,这些方法的命名和参数和SqlSession接口的很像,只是基本上第一个参数都成了sql。

其中Object value为入参,入参形式和SqlSession中的入参一样,带有入参的方法,在使用时sql可以包含#{param}或${param}形式的参数,这些参数需要通过入参来传值。需要的参数过多的时候,参数可以使用Map类型。另外这种情况下的sql还支持下面这种复杂形式:

String sql = "<script>select * from sys_user where 1=1" +
    "<if test=\"usertype != null\">usertype = #{usertype}</if></script>";

这种情况用的比较少,不多说。

不带有Object value的所有方法,sql中如果有参数需要手动拼接成一个可以直接执行的sql语句。

在selectXXX方法中,使用Class<T> resultType可以指定返回类型,否则就是Map<String,Object>类型。

实例化SqlMapper

SqlMapper构造参数public SqlMapper(SqlSession sqlSession),需要一个入参SqlSession sqlSession,在一般系统中,可以按照下面的方式获取:

SqlSession sqlSession = (...);//通过某些方法获取sqlSession
//创建sqlMapper
SqlMapper sqlMapper = new SqlMapper(sqlSession);

如果使用的Spring,那么可以按照下面的方式配置<bean>:

<bean id="sqlMapper" class="com.github.abel533.sql.SqlMapper" scope="prototype">
 <constructor-arg ref="sqlSession"/>
</bean>

在Service中使用的时候可以直接使用@Autowired注入。

简单例子

在src/test/java目录的com.github.abel533.sql包中包含这些方法的测试。

下面挑几个看看如何使用。

selectList

//查询,返回List<Map>
List<Map<String, Object>> list = sqlMapper.selectList("select * from country where id < 11");
//查询,返回指定的实体类
List<Country> countryList = sqlMapper.selectList("select * from country where id < 11", Country.class);
//查询,带参数
countryList = sqlMapper.selectList("select * from country where id < #{id}", 11, Country.class);
//复杂点的查询,这里参数和上面不同的地方,在于传入了一个对象
Country country = new Country();
country.setId(11);
countryList = sqlMapper.selectList("<script>" +
    "select * from country " +
    "  <where>" +
    "    <if test=\"id != null\">" +
    "      id < #{id}" +
    "    </if>" +
    "  </where>" +
    "</script>", country, Country.class);

selectOne

Map<String, Object> map = sqlMapper.selectOne("select * from country where id = 35");
map = sqlMapper.selectOne("select * from country where id = #{id}", 35);
Country country = sqlMapper.selectOne("select * from country where id = 35", Country.class);
country = sqlMapper.selectOne("select * from country where id = #{id}", 35, Country.class);

insert,update,delete

//insert
int result = sqlMapper.insert("insert into country values(1921,'天朝','TC')");
Country tc = new Country();
tc.setId(1921);
tc.setCountryname("天朝");
tc.setCountrycode("TC");
//注意这里的countrycode和countryname故意写反的
result = sqlMapper.insert("insert into country values(#{id},#{countrycode},#{countryname})"
             , tc);
//update
result = sqlMapper.update("update country set countryname = '天朝' where id = 35");
tc = new Country();
tc.setId(35);
tc.setCountryname("天朝");
int result = sqlMapper.update("update country set countryname = #{countryname}" +
      " where id in(select id from country where countryname like 'A%')", tc);
//delete
result = sqlMapper.delete("delete from country where id = 35");
result = sqlMapper.delete("delete from country where id = #{id}", 35);

注意

通过上面这些例子应该能对此有个基本的了解,但是如果你使用参数方式,建议阅读下面的文章:

深入了解MyBatis参数

实现原理

最初想要设计这个功能的时候,感觉会很复杂,想的也复杂,需要很多个类,因此当时没有实现。

突发奇想,设计了现在的这种方式。并且有种强烈的感觉就是幸好昨天没有尝试去实现,因为昨天晚上思考这个问题的时候是晚上10点多,而今天晚上7点开始思考。我很庆幸在一个更清醒的状态下去写这段代码。

下面简单说思路和实现方式。

在写MyBatis分页插件的时候熟悉了MappedStatement类。

在写通用Mapper的时候熟悉了xml转SqlNode结构。

如果我根据SQL动态的创建一个MappedStatement,然后使用MappedStatement的id在sqlSession中执行不就可以了吗?

想到这一点,一切就简单了。

看看下面select查询创建MappedStatement的代码:

/**
 * 创建一个查询的MS
 * @param msId
 * @param sqlSource 执行的sqlSource
 * @param resultType 返回的结果类型
 */
private void newSelectMappedStatement(String msId, SqlSource sqlSource, final Class<?> resultType) {
  MappedStatement ms = new MappedStatement.Builder(
      configuration, msId, sqlSource, SqlCommandType.SELECT)
    .resultMaps(new ArrayList<ResultMap>() {
      {
        add(new ResultMap.Builder(configuration,
            "defaultResultMap",
            resultType,
            new ArrayList<ResultMapping>(0)).build());
      }
    })
    .build();
  //缓存
  configuration.addMappedStatement(ms);
}

代码是不是很简单,这段代码的关键是参数sqlSource,下面是创建SqlSource的方法,分为两种。

一种是一个完整的sql,不需要参数的,可以直接执行的:

StaticSqlSource sqlSource = new StaticSqlSource(configuration, sql);

其中configuration从sqlSession中获取,sql就是用户传入到sql语句,是不是也很简单?

另一种是支持动态sql的,支持参数的SqlSource:

SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, parameterType);

是不是也很简单?这个方法其实可以兼容上面的StaticSqlSource,这里比上面多了一个parameterType,因为这儿是可以传递参数的,另外languageDriver是从configuration中获取的。

是不是很简单?

我一开始也没想到MyBatis直接执行sql实现起来会这么的容易。

insert,delete,update方法的创建更容易,因为他们的返回值都是int,所以处理起来更简单,有兴趣的可以查看SqlMapper的源码。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对我们的支持。如果你想了解更多相关内容请查看下面相关链接

(0)

相关推荐

  • Mybatis mapper动态代理的原理解析

    前言 在开始动态代理的原理讲解以前,我们先看一下集成mybatis以后dao层不使用动态代理以及使用动态代理的两种实现方式,通过对比我们自己实现dao层接口以及mybatis动态代理可以更加直观的展现出mybatis动态代理替我们所做的工作,有利于我们理解动态代理的过程,讲解完以后我们再进行动态代理的原理解析,此讲解基于mybatis的环境已经搭建完成,并且已经实现了基本的用户类编写以及用户类的Dao接口的声明,下面是Dao层的接口代码 public interface UserDao { /*

  • Spring Boot整合mybatis并自动生成mapper和实体实例解析

    最近一直都在学习Java,发现目前Java招聘中,mybatis出现的频率挺高的,可能是目前Java开发中使用比较多的数据库ORM框架.于是我准备研究下Spring Boot和mybatis的整合. 1.在pom.xml文件中添加下面的配置 <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-

  • 详解Mybatis通用Mapper介绍与使用

    使用Mybatis的开发者,大多数都会遇到一个问题,就是要写大量的SQL在xml文件中,除了特殊的业务逻辑SQL之外,还有大量结构类似的增删改查SQL.而且,当数据库表结构改动时,对应的所有SQL以及实体类都需要更改.这工作量和效率的影响或许就是区别增删改查程序员和真正程序员的屏障.这时,通用Mapper便应运而生-- 什么是通用Mapper 通用Mapper就是为了解决单表增删改查,基于Mybatis的插件.开发人员不需要编写SQL,不需要在DAO中增加方法,只要写好实体类,就能支持相应的增删

  • Spring Boot集成MyBatis实现通用Mapper的配置及使用

    什么是通用Mapper 通用Mapper就是为了解决单表增删改查,基于Mybatis的插件.开发人员不需要编写SQL,不需要在DAO中增加方法,只要写好实体类,就能支持相应的增删改查方法. 关于MyBatis,大部分人都很熟悉.MyBatis 是一款优秀的持久层框架,它支持定制化 SQL.存储过程以及高级映射.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Pla

  • Java的MyBatis框架中Mapper映射配置的使用及原理解析

    Mapper的内置方法 model层就是实体类,对应数据库的表.controller层是Servlet,主要是负责业务模块流程的控制,调用service接口的方法,在struts2就是Action.Service层主要做逻辑判断,Dao层是数据访问层,与数据库进行对接.至于Mapper是mybtis框架的映射用到,mapper映射文件在dao层用. 下面是介绍一下Mapper的内置方法: 1.countByExample ===>根据条件查询数量 int countByExample(UserE

  • Mybatis MapperScannerConfigurer自动扫描Mapper接口生成代理注入到Spring的方法

    前言 Mybatis MapperScannerConfigurer 自动扫描 将Mapper接口生成代理注入到Spring Mybatis在与Spring集成的时候可以配置 MapperFactoryBean来生成Mapper接口的代理. 例如: <bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean"> <property name="mappe

  • SpringBoot整合MyBatis逆向工程及 MyBatis通用Mapper实例详解

    一.添加所需依赖,当前完整的pom文件如下: <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd&q

  • MyBatis直接执行SQL的工具SqlMapper

    可能有些人也有过类似需求,一般都会选择使用其他的方式如Spring-JDBC等方式解决. 能否通过MyBatis实现这样的功能呢? 为了让通用Mapper更彻底的支持多表操作以及更灵活的操作,在2.2.0版本增加了一个可以直接执行SQL的新类SqlMapper. 我们来了解一下SqlMapper. SqlMapper提供的方法 SqlMapper提供了以下这些公共方法: Map<String,Object> selectOne(String sql) Map<String,Object&

  • 详解MyBatis直接执行SQL查询及数据批量插入

    一.直接执行SQL查询: 1.mappers文件节选 <resultMap id="AcModelResultMap" type="com.izumi.InstanceModel"> <result column="instanceid" property="instanceID" jdbcType="VARCHAR" /> <result column="insta

  • Mybatis如何直接执行SQL语句

    目录 Mybatis直接执行SQL语句 第一种方法 第二种方法 测试Mybatis执行SQL语句步骤 mybatis核心类:SqlSessionFactory 举例 Mybatis直接执行SQL语句 有时候我们如果要对传入的SQL验证语法方面怎么办呢,首先我们是不是要有一条完整的SQL,而且让mybatis去执行,这是小白最近遇到的,对于用户输入进来的语法与参数,进行拼接并且去执行,判断SQL语句有没有语法错误. 第一种方法 建立一个SQL工具进行SQL处理再返回完整的SQL语句 1.建立工具类

  • 在mybatis执行SQL语句之前进行拦击处理实例

    比较适用于在分页时候进行拦截.对分页的SQL语句通过封装处理,处理成不同的分页sql. 实用性比较强. import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.List; import java.util.Properties; import org.apache.ibatis.e

  • 基于mybatis注解动态sql中foreach工具的方法

    目录 实现目标 工具类 测试 集成进spring后的使用方法 Mapper层 Provider层 Ognl问题 解决方案 创建一个DefaultMemberAccess.java文件 改造ForeachMybatisUtils.java类 实现目标 由于在注解版mybatis中手动循环拼接动态sql容易出错 请看mybatis注解动态sql注入map和list(防sql注入攻击),所以封装了这个类似于foreach标签的工具方法. 由于mybatis(3.5.6.3.5.7 or earlier

  • 解决mybatis执行SQL语句部分参数返回NULL问题

    今天在写代码的时候发现一个问题:mybatis执行sql语句的时候返回bean的部分属性为null,在数据库中执行该sql语句能够正常返回,把相关代码反反复复翻了个遍,甚至都重启eclipse了,依旧没解决问题,后来网上搜了一下,还真有类似的问题. 闲话少说,直接说问题,该sql语句是自己写的,resultType直接用了该bean全名称,最终导致部分属性显示为null, 原来的写法: <select id="selectByArticle" parametertype=&quo

  • MyBatis执行Sql的流程实例解析

    这篇文章主要介绍了MyBatis执行Sql的流程实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 本博客着重介绍MyBatis执行Sql的流程,关于在执行过程中缓存.动态SQl生成等细节不在本博客中体现,相应内容后面再单独写博客分析吧. 还是以之前的查询作为列子: public class UserDaoTest { private SqlSessionFactory sqlSessionFactory; @Before public v

  • 浅谈MyBatis 如何执行一条 SQL语句

    前言 Mybatis 是 Java 开发中比较常用的 ORM 框架.在日常工作中,我们都是直接通过 Spring Boot 自动配置,并直接使用,但是却不知道 Mybatis 是如何执行一条 SQL 语句的,而这篇文章就是来揭开 Mybatis 的神秘面纱. 基础组件 我们要理解 Mybatis 的执行过程,就必须先了解 Mybatis 中都有哪一些重要的类,这些类的职责都是什么? SqlSession 我们都很熟悉,它对外提供用户和数据库之间交互需要使用的方法,隐藏了底层的细节.它默认是实现类

  • 浅谈MyBatis执行SQL的两种方式

    目录 前言 准备接口和Mapper配置文件: 使用SqlSession 发送 SQL 使用 Mapper 接口发送 SQL 比较两种发送 SQL 方式 前言 本文介绍MyBatis执行SQL语句的2种方式:SqlSession和Mapper接口以及它们的区别. 准备接口和Mapper配置文件: 定义UserMapper接口: package cn.cvs.dao; import cn.cvs.pojo.User; import java.util.List; public interface U

  • 使用mybatis的interceptor修改执行sql以及传入参数方式

    目录 mybatis interceptor修改执行sql以及传入参数 总体思路 1.Interceptor 代码实现 2.AutoConfiguration代码实现 mybatis interceptor 处理查询参数及查询结果 拦截器:拦截update,query方法 添加xml配置 mybatis interceptor修改执行sql以及传入参数 项目中途遇到业务需求更改,在查询某张表时需要增加条件,由于涉及的sql语句多而且依赖其他服务的jar,逐个修改sql语句和接口太繁杂.项目使用m

随机推荐