当前位置: 首页 > 编程笔记 >

MyBatis直接执行SQL的工具SqlMapper

滕弘新
2023-03-14
本文向大家介绍MyBatis直接执行SQL的工具SqlMapper,包括了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 &lt; #{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的源码。

总结

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

 类似资料:
  • 主要内容:SqlSession发送SQL,Mapper接口发送 SQL,区别本节主要介绍 MyBatis 执行 SQL 语句的两种方式和它们的区别。 MyBatis 有两种执行 SQL 语句的方式,如下: 通过 SqlSession 发送 SQL 通过 SqlSession 获取 Mapper 接口,通过 Mapper 接口发送 SQL SqlSession发送SQL 有映射器之后就可以通过 SqlSession 发送 SQL 了。我们以 getWebsite 这条 SQ

  • #include <stdio.h> int global = 1; int func(void) { return (++global); } int main(void) { printf("%d\n", global); return 0; } 技巧 使用gdb调试程序时,可以使用“call”或“print”命令直接调用函数执行。以上面程序为例: (gdb)

  • 本文向大家介绍MyBatis执行Sql的流程实例解析,包括了MyBatis执行Sql的流程实例解析的使用技巧和注意事项,需要的朋友参考一下 这篇文章主要介绍了MyBatis执行Sql的流程实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 本博客着重介绍MyBatis执行Sql的流程,关于在执行过程中缓存、动态SQl生成等细节不在本博客中体现

  • 本文向大家介绍MyBatis 执行动态 SQL语句详解,包括了MyBatis 执行动态 SQL语句详解的使用技巧和注意事项,需要的朋友参考一下 大家基本上都知道如何使用 MyBatis 执行任意 SQL,使用方法很简单,例如在一个 XXMapper.xml 中: 你可以如下调用: 或者你可以在 XXMapper.java 接口中定义如下方法: 然后使用接口调用方法: 上面这些内容可能都会,下面在此

  • 问题内容: 设想: 我有3个表需要连接在一起,where子句用于限制结果集,并且从每个表中只选择了几列。简单的。但是,执行此操作的查询不是很漂亮,并且在数据库和应用程序之间使用ORM时,就像试图将方形钉放入圆孔中一样。 解决这个问题的方法是创建一个包含查询的视图,现在我的应用程序模型直接映射到数据库中的一个视图。不再疯狂地映射ORM层。 问题:假设这里没有其他因素起作用, 如果直接执行SQL语句

  • 问题内容: 我有一个配置了执行的插件(antrun),该插件具有一个id,并且未绑定到任何阶段。我可以直接从命令行执行此执行吗? 用以下命令运行它: 或者至少 问题答案: 133 此功能已实现为MNG-5768,并且在Maven 3.3.1中可用。 更改将: 扩展直接插件调用语法,以允许可选的@ execution-id参数,例如org.apache.maven.plugins:maven-rem