问题
来看一个例子。比如如下的接口方法
public interface UserMapper {
List<User> getUserList();
User getUserById(int id);
}
和其对应的mapper.xml文件里的内容
<select id="getUserList" resultType="com.hj.pojo.User">
select * from mybatis.user
</select>
<select id="getUserById" parameterType="int" resultType="com.hj.pojo.User">
select * from mybatis.user where id=#{id}
</select>
可以看到这两个接口的方法的返回值一个是List一个是User,但是在xml文件中都统一写的User。或者直接更加简洁一点,我们不写xml文件了,我们直接在原来的接口语句中加上注解来实现sql语句。
public interface UserMapper {
//查询全部用户
@Select("select * from user")
List<User> getUserList();
//根据ID查询用户
@Select("select * from user where ")
User getUserById(int id);
}
这里直接连Mapper.xml都没有写了。
那么为什么在测试的时候能够给我们返回他对应的类型呢?(即getUserList能返回一个List类型,getUserById返回一个User类型)(代码里的MybatisUtils类可以到:MyBatis学习(一)之初探MyBatis大体结构与简单实现里找到)
@Test
public void test() {
SqlSession sqlSession;
//获得SqlSession对象
sqlSession = MybatisUtils.getSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class); //获取对应的接口的对象
List<User> userList = userMapper.getUserList();//返回的结果就是List类型的
for (User user : userList) {
System.out.println(user);
}
sqlSession.close();
}
@Test
public void getUserById() {
SqlSession sqlSession;
//获得SqlSession对象
sqlSession = MybatisUtils.getSqlSession();
//获取mapper对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//那些实现的接口都在mapper对象里调用
User userById = userMapper.getUserById(5); //返回的结果就是User类型的
System.out.println(userById);
sqlSession.close();
}
我们可以断点调试看看在getMapper方法后mapper对象到底是个什么东西。
可以看到userMapper包含了sqlSession、mapperInterface、methodCache三个东西。
sqlSession
这里面的sqlSession还是一个执行器,就是会帮我们执行sql语句。
mapperInterface
mapperInterface就是mapper接口,里面记录了找到的对应的类的一些信息。
所以sqlSession.getMapper(UserMapper.class)
语句就是通过反射获取到了UserMapper类的包名,然后反射能获取到这个类的方法和属性(不了解反射机制的同学可以先移步Java自学(十四、Java反射))
methodCache
methodCache里则是记录了方法的一些详细的内容。
可以看到方法名,对应的类,参数类型以及这个方法的根都有。最后调用就是调用从这个根里来的方法。
点开这个root后可以看到通过反射它加载了它的返回值类型、参数类型、注解等等。因为反射是可以获取到方法的所有东西的,所以他会根据我们在接口里写的方法中的返回值,自动推导这边的返回值类型。
所以mybatis的底层就是基于反射实现的。