前面我们已经对Mybatis组件有了宏观的认识,并且有提到SqlSession会话使用了门面模式,这里我们先提出两个问题:
1、SqlSession门面模式,方便在了哪里?
2、SqlSession门面带来的方便,Mybatis是否满意了呢?
默认实现DefaultSqlSession#selectList源码
//statement Mapper接口方法的全限定名
//parameter SQL参数
//rowBounds 分页参数
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
try {
//MappedStatement对应xml中的一个语句,如select、update、delete
MappedStatement ms = configuration.getMappedStatement(statement);
//调用Executor执行器处理
return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
从代码可以看出,SqlSession就像是一个接待者,对于接收到的请求,最终都会丢给Executor执行器来处理。SqlSession和Executor的关系是一对一
Executor查询接口
从上图可以看出,对于查询操作,Executor只提供了最基础的2种api:返回List列表<E>和返回游标Cursor
SqlSession查询接口
可以看到SqlSession对于查询,提供了更加丰富的api,selectOne、selectMap等,方便了用户调用
SqlSession和Executor使用对比
public class SqlSessionTest {
private SqlSession sqlSession;
private Configuration configuration;
@Before
public void init(){
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = sqlSessionFactoryBuilder.build(this.getClass().getResourceAsStream("/mybatis-config.xml"));
sqlSession = factory.openSession();
configuration = factory.getConfiguration();
}
@Test
public void testSqlSession() throws SQLException {
//使用Executor查询id=10的User 这里实例化的是重用执行器
Executor executor = configuration.newExecutor(new JdbcTransaction(sqlSession.getConnection()), ExecutorType.REUSE);
//传入查询方法的全限定名,获得MappedStatement对象
MappedStatement mappedStatement = configuration.getMappedStatement("org.coderead.mybatis.UserMapper.selectByid");
List<User> list = executor.query(mappedStatement, 10, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER);
//需要自己对结果进行get0
User user0 = list.get(0);
System.out.println(user0);
//使用SqlSession提供的selectOne查询id=10的User 直接得到User 需要传入查询方法的全限定名
User user1 = sqlSession.selectOne("org.coderead.mybatis.UserMapper.selectByid", 10);
System.out.println(user1);
//使用getMapper得到UserMapper动态代理对象,不需要传入全限定名,调用更加方便
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user2 = userMapper.selectByid(10);
System.out.println(user2);
}
}
可以看出,使用SqlSession提供的selectOne接口,精简了调用参数和返回结果。但是这还不是最满意的效果,SqlSession提供了getMapper接口得到动态代理对象,这样我们就可以直接调用接口方法,更加方便了我们的使用。
而在spring和mybatis整合后,SqlSession也被透明化了,我们都是直接使用接口代理对象,用户对SqlSession,甚至Mybatis的任何类都完全无感。
Sqlsession总结
- 透明化了Executor的具体实现,用户不用关心是哪一个Executor执行SQL
- 提供更加丰富的api,selectOne,selectMap
- 调用接口需要传入方法全限定名,容易出错,因此进一步提供了getMapper方法得到接口的代理实现,直接调用接口方法