老司机学习MyBatis之如何处理参数(单个参数或者多个参数)

一、前言

Mybatis在使用Mapper接口进行编程时,底层采用了动态代理机制,表面上是调用的Mapper接口,而实际上是通过动态代理调用的SqlSession的对应方法,其最终会获得一个代理了Mapper接口的MapperProxy对象。MapperProxy对象在调用Mapper接口方法时会把传递的参数做一个转换,然后把转换后的参数作为入参传递给SqlSession对应的操作方法(如selectOne、insert等)。转换过程可以参考MapperMethod的execute()方法实现。简单来说是以下规则:
♦单个参数:可以接受基本类型,对象类型,集合类型的值。这种情况MyBatis可直接使用这个参数,不需要经过任何处理。
♦多个参数:任意多个参数,都会被MyBatis重新包装成一个Map传入。Map的key是param1,param2,0,1…,值就是参数的值。
♦命名参数:为参数使用@Param起一个名字,MyBatis就会将这些参数封装进map中,key就是我们自己指定的名字。
♦POJO:当这些参数属于我们业务POJO时,我们直接传递POJO。
♦Map:我们也可以封装多个参数为map,直接传递。

本节我们将介绍一下,MyBatis是如何处理单个参数和多个参数的?

二、案例

在MySQL下新建数据库表t_user,并插入一条数据

CREATE TABLE t_user (
  id int(10) NOT NULL AUTO_INCREMENT,
  loginId varchar(20) DEFAULT NULL,
  userName varchar(100) DEFAULT NULL,
  role varchar(255) DEFAULT NULL,
  note varchar(255) DEFAULT NULL,
  PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;

INSERT INTO t_user(loginId,userName,role,note) VALUES ('queen', '奎恩', '海贼王副把手', '专门负责提鞋的。。。');

编写UserMapper.xml文件

编写MyBatisTest.java测试类,新增测试方法testOneParam

@Test
public void testOneParam() throws IOException {
	SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
	SqlSession openSession = sqlSessionFactory.openSession();
	try {
		UserMapper mapper = openSession.getMapper(UserMapper.class);
		User user = mapper.findUserById(1);
		System.out.println(user);
	} finally {
		openSession.close();
	}
}

运行测试,控制台打印如下:

2017-08-04 23:07:28,536 [main] [com.queen.mybatis.mapper.UserMapper.findUserById]-[DEBUG] ==>  Preparing: select id, loginId, userName, role, note from t_user where id = ? 
2017-08-04 23:07:28,589 [main] [com.queen.mybatis.mapper.UserMapper.findUserById]-[DEBUG] ==> Parameters: 1(Integer)
2017-08-04 23:07:28,626 [main] [com.queen.mybatis.mapper.UserMapper.findUserById]-[DEBUG] <==      Total: 1
User [id=1, loginId=queen, userName=奎恩, role=海贼王副把手, note=专门负责提鞋的。。。]
其实,当你传递单个参数时,#{xxx}里面这个“xxx”无论你写什么都一样,因为只有一个参数,你可以试着修改UserMapper.xml文件中where id = #{idabcd},如下:

测试查询,同样可以查出数据。单个参数下,MyBatis不会做任何处理。那如果是多个参数呢?

同样是查询User信息,但是我们以ID和userName两个参数去查询,在UserMapper.java中新增查询方法,如下:

/**
* 根据ID和用户名查找用户
* @param id
* @param userName
* @return
 */
public User findUserByIdAndUserName(int id, String userName);

在UserMapper.xnl增加配置如下

编写MyBatisTest.java测试类,新增测试方法testTwoParam

@Test
public void testTwoParam() throws IOException {
	SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
	SqlSession openSession = sqlSessionFactory.openSession();
	try {
		UserMapper mapper = openSession.getMapper(UserMapper.class);
		User user = mapper.findUserByIdAndUserName(1, "奎恩");
		System.out.println(user);
	} finally {
		openSession.close();
	}
}

大家想一想,当我们传递两个参数的时候,这种方式编写能成功吗?我们先试着运行一下testTwoParam方法,看啊看控制台打印何种结果?运行结果如下:

org.apache.ibatis.exceptions.PersistenceException: 
### Error querying database.  Cause: org.apache.ibatis.binding.BindingException: Parameter 'id' not found. Available parameters are [1, 0, param1, param2]
### Cause: org.apache.ibatis.binding.BindingException: Parameter 'id' not found. Available parameters are [1, 0, param1, param2]
	at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:26)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:111)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:102)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:66)
	at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:68)
	at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:52)
	at com.sun.proxy.$Proxy2.findUserByIdAndUserName(Unknown Source)
	at com.queen.mybatis.MyBatisTest.testTwoParam(MyBatisTest.java:46)
	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)
很不凑巧,大失所望,控制台报错:“Parameter ‘id’ not found. Available parameters are [1, 0, param1, param2]”,说绑定异常,参数ID没有找到,有效的参数是[1, 0, param1, param2]。这是什么意思呢?

其实MyBatis在处理多个参数的时候,MyBatis会做特殊处理,多个参数会被封装成一个map,map中是这么存值的

map.put("param1","传入的参数值1");
map.put("param2","传入的参数值2");
map.put("param3","传入的参数值3");
                  .
                  .
                  .
map.put("paramN","传入的参数值N");
#{}就是从map中获取指定的key值。

这个时候我们要将UserMapper.xml中查询方法做如下修改:

或者

测试查询,控制台打印如下:

2017-08-04 23:41:38,401 [main] [com.queen.mybatis.mapper.UserMapper.findUserByIdAndUserName]-[DEBUG] ==>  Preparing: select id, loginId, userName, role, note from t_user where id = ? and userName=? 
2017-08-04 23:41:38,466 [main] [com.queen.mybatis.mapper.UserMapper.findUserByIdAndUserName]-[DEBUG] ==> Parameters: 1(Integer), 奎恩(String)
2017-08-04 23:41:38,503 [main] [com.queen.mybatis.mapper.UserMapper.findUserByIdAndUserName]-[DEBUG] <==      Total: 1
User [id=1, loginId=queen, userName=奎恩, role=海贼王副把手, note=专门负责提鞋的。。。]

虽然这两种方式,都能取到值,但是给人的感觉比较怪怪的,看起来跟我们平时的写法不太一样,按照大家预想where id = #{id} and userName=#{userName} 这种写法方式,是最让人舒服的。为了解决这种方式使用,MyBatis提供了命名参数的方式,在传递参数时,明确指出封装参数时map的key,这样我们在XML中就能使用where id = #{id} and userName=#{userName} 这种写法来传递参数了。


=======欢迎大家拍砖,小手一抖,多多点赞哟!=======

版权声明:本文为博主原创文章,允许转载,但转载必须标明出处。


你可能感兴趣的:(MyBatis教程,老司机学习MyBatis)