MyBatis源码分析
使用SqlSession操作数据库
MyBatis执行数据库操作主要分为三种:使用SqlSession自带方法、调用Mapper接口方法执行SQL、使用注解执行SQL
SqlSession自带方法
在示例代码中使用了SqlSession.selectOne()方法来查询一条记录,参数为自定义Mapper接口路径(用于查询MappedStatement)和查询SQL的参数。接下来对SqlSession.selectOne()进行源码分析。
在DefaultSqlSession.selectOne()方法中,可以看到selectOne()方法实际是调用在DefaultSqlSession的selectList()方法,如果返回的列表大小大于1则抛出TooManyResultsException异常。
继续往下查看selectList(),在DefaultSqlSession.selectList()方法中可以看到,首先从Configuration对象中获取MappedStatement,而MappedStatement在Configuration中以Map<String, MappedStatement> mappedStatements形式存储,因此可以看出,在解析MappedStatement对象时,是以Mapper.xml配置文件的namespace加上下面具体SQL的id作为键存储的。
获取到MappedStatement对象之后,调用Executor.query()方法执行查询,由于MyBatis默认开启一级缓存,所以此时实际调用的是CachingExecutor.query()。再更进一步的query()方法中,调用BaseExecutor.query(),BaseExecutor.query()方法源码如下
在query()方法中会创建缓存的key,通过查看CacheKey对象可知,cache的key组成为:hashcode+checksum+自定义Mapper路径+方法名+offset+查询SQL+limit+Configuration中Environment的id,示例代码中的cachekey:
-2016638596:1630768115:com.sk.test.mapper.UserMapper.selectUser:0:2147483647:select * from user where id = ?:1:development
在图中方框部分框可以看出,在执行查询时会先去本地缓存中查找,如果有则获取对象返回,非则执行queryFromDatabase()获取结果list并返回
queryFromDatabase()源码如下,在queryFromDatabase()中通过doQuery()方法进行实际查询并返回list,然后再将结果存入缓存中,这里在查询之前会首先加入缓存并占位,在查询结束后再清除该缓存。
在doQuery()中首先通过Configuration获取StatementHandler对象,再调用StatementHandler实现类SimpleStatementHandler.query()执行sql并使用ResultSetHandler对结果进行处理并返回。
整体操作流程
整体执行流程如下:
相关参考
MyBatis源码分析——MyBatis核心组件和开启SqlSession
MyBatis源码分析——使用SqlSession操作数据库
MyBatis源码分析——调用Mapper接口方法执行SQL
MyBatis源码分析——使用注解执行SQL