MyBatis-06 MyBatis XML方式之多个接口参数用法

简介: MyBatis-06 MyBatis XML方式之多个接口参数用法

概述


我们前面几篇文章,所列举的接口方法中只有一个参数,参数的类型可以分为两种

1. 基本类型

2. JavaBean

当参数是一个基本类型的时候,它在XML文件中对应的SQL语句只会使用一个参数,比如delete方法


当参数类型是一个JavaBean类型的时候,它在XML文件中对应的SQL语句中会有多个参数,比如 insert 、 update


在实际应用中使用多个参数的情况再常见不过来。 前面的博文,我们有个方法是将多个参数合并到一个JavaBean中,并使用这个Bean作为接口方法的参数。 这种方法虽然方便,单并不适合全部的情况,因为不可能只为了两三个参数去创建新的JavaBean。


因此对于参数比较少的情况,有两种方式可以采用

  • 使用Map类型作为参数
  • 使用@Param注解


使用Map类型作为参数需要手工创建MAP并且对参数进行赋值,并不简洁。这里推荐使用@Param注解的方式


使用Map类型作为参数需要手工创建MAP并且对参数进行赋值,并不简洁。这里推荐使用@Param注解的方式


模拟场景:根据用户ID和角色的enable状态来查询用户的所有角色

工程结构


20180417073042918.png


多个基本类型参数的场景

我们先来看下如果在接口中使用多个参数但不是用Param注解的情况


1.UserRoleMapper接口增加接口方法

package com.artisan.mybatis.xml.mapper;
import java.util.List;
import com.artisan.mybatis.xml.domain.SysRole;
public interface UserRoleMapper {
    /**
     * 
     * 
     * @Title: selectSysRolesByUserIdAndRoleEnable
     * 
     * @Description: 根据用户ID和角色的Enable属性查询角色
     * 
     * @param userId
     * @param enable
     * @return
     * 
     * @return: List<SysRole>
     */
    List<SysRole> selectSysRolesByUserIdAndRoleEnable(Long userId, Integer enable);
}


2.UserRoleMapper.xml配置查询语句

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
                    "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<!-- 当Mapper接口和XML文件关联的时候, namespace的值就需要配置成接口的全限定名称 -->                    
<mapper namespace="com.artisan.mybatis.xml.mapper.UserRoleMapper">
    <select 
        id="selectSysRolesByUserIdAndRoleEnable" 
        resultType="com.artisan.mybatis.xml.domain.SysRole">
        SELECT
            c.id,
            c.role_name roleName,
            c.enabled,
            c.create_by createBy,
            c.create_time createTime
        FROM
            sys_user a
        INNER JOIN sys_user_role b ON a.id = b.user_id
        INNER JOIN sys_role c ON b.role_id = c.id
        WHERE
            a.id = #{userId}
        AND c.enabled = #{enabled}
    </select>
</mapper>                   


3.单元测试

package com.artisan.mybatis.xml.mapper;
import java.util.List;
import org.apache.ibatis.session.SqlSession;
import org.apache.log4j.Logger;
import org.junit.Assert;
import org.junit.Test;
import com.artisan.mybatis.xml.domain.SysRole;
/**
 * 
 * 
 * @ClassName: UserRoleMapperTest
 * 
 * @Description: UserRoleMapperTest测试类
 * 
 * @author: Mr.Yang
 * 
 * @date: 2018年4月16日 下午3:34:45
 */
public class UserRoleMapperTest extends BaseMapperTest {
    private static final Logger logger = Logger.getLogger(UserRoleMapperTest.class);
    private SqlSession sqlSession;
    @Test
    public void selectSysRolesByUserIdAndRoleEnableTest(){
        logger.info("selectSysRolesByUserIdAndRoleEnableTest");
        try {
            // 获取SqlSession
            sqlSession = getSqlSession();
            // 获取UserRoleMapper
            UserRoleMapper userRoleMapper = sqlSession.getMapper(UserRoleMapper.class);
            // 通过接口调用方法
            List<SysRole> roleList = userRoleMapper.selectSysRolesByUserIdAndRoleEnable((long) 1, 1);
            // 期望roleList不为空
            Assert.assertNotNull(roleList);
            // 期望roleList> 0
            Assert.assertTrue(roleList.size() > 0);
            for (SysRole sysRole : roleList) {
                logger.info(sysRole);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            sqlSession.close();
            logger.info("sqlSession close successfully ");
        }
    }
}

选中方法,执行单元测试

会得到如下异常

org.apache.ibatis.exceptions.PersistenceException: 
### Error querying database.  Cause: org.apache.ibatis.binding.BindingException: Parameter 'userId' not found. Available parameters are [1, 0, param1, param2]
### Cause: org.apache.ibatis.binding.BindingException: Parameter 'userId' not found. Available parameters are [1, 0, param1, param2]
    at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30)
    at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:122)
    at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:113)
    at org.apache.ibatis.binding.MapperMethod.executeForMany(MapperMethod.java:122)
    at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:64)
    at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:53)
    at com.sun.proxy.$Proxy6.selectSysRolesByUserIdAndRoleEnable(Unknown Source)
    at com.artisan.mybatis.xml.mapper.UserRoleMapperTest.selectSysRolesByUserIdAndRoleEnableTest(UserRoleMapperTest.java:40)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
Caused by: org.apache.ibatis.binding.BindingException: Parameter 'userId' not found. Available parameters are [1, 0, param1, param2]
    at org.apache.ibatis.binding.MapperMethod$ParamMap.get(MapperMethod.java:168)
    at org.apache.ibatis.reflection.wrapper.MapWrapper.get(MapWrapper.java:45)
    at org.apache.ibatis.reflection.MetaObject.getValue(MetaObject.java:122)
    at org.apache.ibatis.executor.BaseExecutor.createCacheKey(BaseExecutor.java:212)
    at org.apache.ibatis.executor.CachingExecutor.createCacheKey(CachingExecutor.java:139)
    at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:81)
    at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:120)


重点信息

### Cause: org.apache.ibatis.binding.BindingException: Parameter 'userId' not found. Available parameters are [1, 0, param1, param2]


这个错误标识,xml可用的参数只有 0、1、param1、param2 , 没有userId.


1, 0, param1, param2 都是Mybatis根据参数位置自定义的名字,如果将xml中的#{userId} 改为#{0}或者#{param1} ,将#{enbale}改为#{1}或者#{param2} ,这个方法是可以被正常调用的 。 这里只是为了演示,实际上并不建议这么做。


20180417074005317.png


20180417074038934.png


修复

现在在接口方法的参数前添加@Param注解

package com.artisan.mybatis.xml.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import com.artisan.mybatis.xml.domain.SysRole;
public interface UserRoleMapper {
    /**
     * 
     * 
     * @Title: selectSysRolesByUserIdAndRoleEnable
     * 
     * @Description: 根据用户ID和角色的Enable属性查询角色
     * 
     * @param userId
     * @param enable
     * @return
     * 
     * @return: List<SysRole>
     */
    List<SysRole> selectSysRolesByUserIdAndRoleEnable(@Param("userId") Long userId, @Param("enable") Integer enable);
}


重新运行单元测试

2018-04-16 19:43:22,404  INFO [main] (BaseMapperTest.java:26) - sessionFactory bulit successfully
2018-04-16 19:43:22,408  INFO [main] (BaseMapperTest.java:29) - reader close successfully
2018-04-16 19:43:22,412  INFO [main] (UserRoleMapperTest.java:31) - selectSysRolesByUserIdAndRoleEnableTest
2018-04-16 19:43:22,910 DEBUG [main] (BaseJdbcLogger.java:142) - ==>  Preparing: SELECT c.id, c.role_name roleName, c.enabled, c.create_by createBy, c.create_time createTime FROM sys_user a INNER JOIN sys_user_role b ON a.id = b.user_id INNER JOIN sys_role c ON b.role_id = c.id WHERE a.id = ? AND c.enabled = ? 
2018-04-16 19:43:22,988 DEBUG [main] (BaseJdbcLogger.java:142) - ==> Parameters: 1(Long), 1(Integer)
2018-04-16 19:43:23,025 TRACE [main] (BaseJdbcLogger.java:148) - <==    Columns: id, roleName, enabled, createBy, createTime
2018-04-16 19:43:23,026 TRACE [main] (BaseJdbcLogger.java:148) - <==        Row: 1, 管理员, 1, 1, 2018-04-13 21:12:46.0
2018-04-16 19:43:23,031 TRACE [main] (BaseJdbcLogger.java:148) - <==        Row: 2, 普通用户, 1, 1, 2018-04-13 21:12:46.0
2018-04-16 19:43:23,032 DEBUG [main] (BaseJdbcLogger.java:142) - <==      Total: 2
2018-04-16 19:43:23,033  INFO [main] (UserRoleMapperTest.java:48) - SysRole [id=1, roleName=管理员, enabled=1, createBy=1, createTime=Fri Apr 13 21:12:46 BOT 2018, user=null, privilegeList=null]
2018-04-16 19:43:23,037  INFO [main] (UserRoleMapperTest.java:48) - SysRole [id=2, roleName=普通用户, enabled=1, createBy=1, createTime=Fri Apr 13 21:12:46 BOT 2018, user=null, privilegeList=null]
2018-04-16 19:43:23,039  INFO [main] (UserRoleMapperTest.java:54) - sqlSession close successfully 


测试通过了,这时的XML文件中对应的SQL的可用参数变成了【userId,enable,param1,param2】 ,如果#{userId} 改为#{param1} ,将#{enbale}改为#{param2}也是可以通过的。


给参数配置@Param注解后,mybatis就会自动将参数封装成Map类型,@Param注解值会作为Map的key 因此在SQL部分就会通过配置的注解值来使用参数。


多个参数为JavaBean类型场景

1. UserRoleMapper接口增加接口方法

// 传递多个JavaBean的场景
    List<SysRole> selectSysRolesByUserIdAndRoleEnable2(@Param("sysUser") SysUser sysUser, @Param("sysRole") SysRole sysRole);


这个时候,在XML中就不能直接使用#{userId}和#{enabled}了,而是要通过点取值方式使用 #{sysUser.id} 和 #{sysRole.enabled} 从两个JavaBean中取出指定属性的值。


2.UserRoleMapper.xml配置SQL

<!-- 传递多个Bean的场景 -->    
    <select 
        id="selectSysRolesByUserIdAndRoleEnable2" 
        resultType="com.artisan.mybatis.xml.domain.SysRole">
        SELECT
            c.id,
            c.role_name roleName,
            c.enabled,
            c.create_by createBy,
            c.create_time createTime
        FROM
            sys_user a
        INNER JOIN sys_user_role b ON a.id = b.user_id
        INNER JOIN sys_role c ON b.role_id = c.id
        WHERE
            a.id = #{sysUser.id}
        AND c.enabled = #{sysRole.enabled}
    </select>

3.单元测试

@Test
    public void selectSysRolesByUserIdAndRoleEnable2Test() {
        logger.info("selectSysRolesByUserIdAndRoleEnable2Test");
        try {
            // 获取SqlSession
            sqlSession = getSqlSession();
            // 获取UserRoleMapper
            UserRoleMapper userRoleMapper = sqlSession.getMapper(UserRoleMapper.class);
            // 构造SysUser
            SysUser sysUser = new SysUser();
            sysUser.setId((long) 1);
            // 构造SysRole
            SysRole sysRole = new SysRole();
            sysRole.setEnabled(1);
            // 通过接口调用方法
            List<SysRole> roleList = userRoleMapper.selectSysRolesByUserIdAndRoleEnable2(sysUser, sysRole);
            // 期望roleList不为空
            Assert.assertNotNull(roleList);
            // 期望roleList> 0
            Assert.assertTrue(roleList.size() > 0);
            for (SysRole sysRole2 : roleList) {
                logger.info(sysRole2);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            sqlSession.close();
            logger.info("sqlSession close successfully ");
        }
    }


日志

2018-04-16 20:13:06,731  INFO [main] (BaseMapperTest.java:26) - sessionFactory bulit successfully
2018-04-16 20:13:06,734  INFO [main] (BaseMapperTest.java:29) - reader close successfully
2018-04-16 20:13:06,738  INFO [main] (UserRoleMapperTest.java:62) - selectSysRolesByUserIdAndRoleEnable2Test
2018-04-16 20:13:07,361 DEBUG [main] (BaseJdbcLogger.java:142) - ==>  Preparing: SELECT c.id, c.role_name roleName, c.enabled, c.create_by createBy, c.create_time createTime FROM sys_user a INNER JOIN sys_user_role b ON a.id = b.user_id INNER JOIN sys_role c ON b.role_id = c.id WHERE a.id = ? AND c.enabled = ? 
2018-04-16 20:13:07,449 DEBUG [main] (BaseJdbcLogger.java:142) - ==> Parameters: 1(Long), 1(Integer)
2018-04-16 20:13:07,483 TRACE [main] (BaseJdbcLogger.java:148) - <==    Columns: id, roleName, enabled, createBy, createTime
2018-04-16 20:13:07,484 TRACE [main] (BaseJdbcLogger.java:148) - <==        Row: 1, 管理员, 1, 1, 2018-04-13 21:12:46.0
2018-04-16 20:13:07,487 TRACE [main] (BaseJdbcLogger.java:148) - <==        Row: 2, 普通用户, 1, 1, 2018-04-13 21:12:46.0
2018-04-16 20:13:07,488 DEBUG [main] (BaseJdbcLogger.java:142) - <==      Total: 2
2018-04-16 20:13:07,489  INFO [main] (UserRoleMapperTest.java:86) - SysRole [id=1, roleName=管理员, enabled=1, createBy=1, createTime=Fri Apr 13 21:12:46 BOT 2018, user=null, privilegeList=null]
2018-04-16 20:13:07,494  INFO [main] (UserRoleMapperTest.java:86) - SysRole [id=2, roleName=普通用户, enabled=1, createBy=1, createTime=Fri Apr 13 21:12:46 BOT 2018, user=null, privilegeList=null]
2018-04-16 20:13:07,495  INFO [main] (UserRoleMapperTest.java:92) - sqlSession close successfully 


小结


除了上述常用的类型,接口的参数还可以是集合或者数组,后续介绍。

相关文章
|
XML Java 数据库连接
微服务——SpringBoot使用归纳——Spring Boot集成MyBatis——基于 xml 的整合
本教程介绍了基于XML的MyBatis整合方式。首先在`application.yml`中配置XML路径,如`classpath:mapper/*.xml`,然后创建`UserMapper.xml`文件定义SQL映射,包括`resultMap`和查询语句。通过设置`namespace`关联Mapper接口,实现如`getUserByName`的方法。Controller层调用Service完成测试,访问`/getUserByName/{name}`即可返回用户信息。为简化Mapper扫描,推荐在Spring Boot启动类用`@MapperScan`注解指定包路径避免逐个添加`@Mapper`
1116 0
|
SQL XML Java
菜鸟之路Day35一一Mybatis之XML映射与动态SQL
本文介绍了MyBatis框架中XML映射与动态SQL的使用方法,作者通过实例详细解析了XML映射文件的配置规范,包括namespace、id和resultType的设置。文章还对比了注解与XML映射的优缺点,强调复杂SQL更适合XML方式。在动态SQL部分,重点讲解了`&lt;if&gt;`、`&lt;where&gt;`、`&lt;set&gt;`、`&lt;foreach&gt;`等标签的应用场景,如条件查询、动态更新和批量删除,并通过代码示例展示了其灵活性与实用性。最后,通过`&lt;sql&gt;`和`&lt;include&gt;`实现代码复用,优化维护效率。
1308 5
|
XML Java 数据库连接
二、搭建MyBatis采用xml方式,验证CRUD(增删改查操作)
二、搭建MyBatis采用xml方式,验证CRUD(增删改查操作)
472 21
|
SQL Java 数据库连接
MyBatis-Plus的几种常见用法
MyBatis-Plus 为 MyBatis 提供了许多增强功能,使得开发更加便捷高效。通过基础的 CRUD 操作、条件构造器、分页插件和自动填充等功能,开发者可以显著减少代码量,提高开发效率。在实际应用中,根据具体需求选择合适的功能模块,能够更好地利用 MyBatis-Plus 提升项目开发效率。
526 22
|
SQL Java 数据库连接
MyBatis-Plus高级用法:最优化持久层开发
MyBatis-Plus 通过简化常见的持久层开发任务,提高了开发效率和代码的可维护性。通过合理使用条件构造器、分页插件、逻辑删除和代码生成器等高级功能,可以进一步优化持久层开发,提升系统性能和稳定性。掌握这些高级用法和最佳实践,有助于开发者构建高效、稳定和可扩展的企业级应用。
1022 13
|
人工智能 Java 数据库连接
MyBatis Plus 使用 Service 接口进行增删改查
本文介绍了基于 MyBatis-Plus 的数据库操作流程,包括配置、实体类、Service 层及 Mapper 层的创建。通过在 `application.yml` 中配置 SQL 日志打印,确保调试便利。示例中新建了 `UserTableEntity` 实体类映射 `sys_user` 表,并构建了 `UserService` 和 `UserServiceImpl` 处理业务逻辑,同时定义了 `UserTableMapper` 进行数据交互。测试部分展示了查询、插入、删除和更新的操作方法及输出结果,帮助开发者快速上手 MyBatis-Plus 数据持久化框架。
1107 0
|
SQL 缓存 Java
MyBatis如何关闭一级缓存(分注解和xml两种方式)
MyBatis如何关闭一级缓存(分注解和xml两种方式)
860 5
|
SQL Java 数据库连接
mybatis使用四:dao接口参数与mapper 接口中SQL的对应和对应方式的总结,MyBatis的parameterType传入参数类型
这篇文章是关于MyBatis中DAO接口参数与Mapper接口中SQL的对应关系,以及如何使用parameterType传入参数类型的详细总结。
670 10
|
Java 数据库连接 数据库
Spring boot 使用mybatis generator 自动生成代码插件
本文介绍了在Spring Boot项目中使用MyBatis Generator插件自动生成代码的详细步骤。首先创建一个新的Spring Boot项目,接着引入MyBatis Generator插件并配置`pom.xml`文件。然后删除默认的`application.properties`文件,创建`application.yml`进行相关配置,如设置Mapper路径和实体类包名。重点在于配置`generatorConfig.xml`文件,包括数据库驱动、连接信息、生成模型、映射文件及DAO的包名和位置。最后通过IDE配置运行插件生成代码,并在主类添加`@MapperScan`注解完成整合
1708 1
Spring boot 使用mybatis generator 自动生成代码插件
|
前端开发 Java 数据库连接
Java后端开发-使用springboot进行Mybatis连接数据库步骤
本文介绍了使用Java和IDEA进行数据库操作的详细步骤,涵盖从数据库准备到测试类编写及运行的全过程。主要内容包括: 1. **数据库准备**:创建数据库和表。 2. **查询数据库**:验证数据库是否可用。 3. **IDEA代码配置**:构建实体类并配置数据库连接。 4. **测试类编写**:编写并运行测试类以确保一切正常。
881 2