当前位置:Gxlcms > 数据库问题 > MyBatis源码分析-SQL语句执行的完整流程

MyBatis源码分析-SQL语句执行的完整流程

时间:2021-07-01 10:21:17 帮助过:10人阅读

2 SQL执行流程

  MyBatis主要设计目的还是为了让我们在执行SQL时对输入输出的数据的管理更加方便,所以方便的让我们写出SQL和方便的获取SQL的执行结果是MyBatis的核心竞争力。下面就用一个例子来从源码角度看一下SQL的完整执行流程。

新建配置文件conf.xml:

技术分享
  1. <span style="color: #0000ff;"><?</span><span style="color: #ff00ff;">xml version="1.0" encoding="UTF-8"</span><span style="color: #0000ff;">?></span>
  2. <span style="color: #0000ff;"><!</span><span style="color: #ff00ff;">DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"</span><span style="color: #0000ff;">></span>
  3. <span style="color: #0000ff;"><</span><span style="color: #800000;">configuration</span><span style="color: #0000ff;">></span>
  4. <span style="color: #0000ff;"><</span><span style="color: #800000;">settings</span><span style="color: #0000ff;">></span>
  5. <span style="color: #0000ff;"><</span><span style="color: #800000;">setting </span><span style="color: #ff0000;">name</span><span style="color: #0000ff;">="cacheEnabled"</span><span style="color: #ff0000;"> value</span><span style="color: #0000ff;">="true"</span><span style="color: #0000ff;">/></span>
  6. <span style="color: #0000ff;"><</span><span style="color: #800000;">setting </span><span style="color: #ff0000;">name</span><span style="color: #0000ff;">="lazyLoadingEnabled"</span><span style="color: #ff0000;"> value</span><span style="color: #0000ff;">="false"</span><span style="color: #0000ff;">/></span>
  7. <span style="color: #008000;"><!--</span><span style="color: #008000;">setting name="logImpl" value="STDOUT_LOGGING"/</span><span style="color: #008000;">--></span> <span style="color: #008000;"><!--</span><span style="color: #008000;"> 日志 </span><span style="color: #008000;">--></span>
  8. <span style="color: #0000ff;"></</span><span style="color: #800000;">settings</span><span style="color: #0000ff;">></span>
  9. <span style="color: #0000ff;"><</span><span style="color: #800000;">typeAliases</span><span style="color: #0000ff;">></span>
  10. <span style="color: #0000ff;"><</span><span style="color: #800000;">typeAlias </span><span style="color: #ff0000;">type</span><span style="color: #0000ff;">="com.luoxn28.dao.User"</span><span style="color: #ff0000;"> alias</span><span style="color: #0000ff;">="User"</span><span style="color: #0000ff;">/></span>
  11. <span style="color: #0000ff;"></</span><span style="color: #800000;">typeAliases</span><span style="color: #0000ff;">></span>
  12. <span style="color: #0000ff;"><</span><span style="color: #800000;">environments </span><span style="color: #ff0000;">default</span><span style="color: #0000ff;">="development"</span><span style="color: #0000ff;">></span>
  13. <span style="color: #0000ff;"><</span><span style="color: #800000;">environment </span><span style="color: #ff0000;">id</span><span style="color: #0000ff;">="development"</span><span style="color: #0000ff;">></span>
  14. <span style="color: #0000ff;"><</span><span style="color: #800000;">transactionManager </span><span style="color: #ff0000;">type</span><span style="color: #0000ff;">="JDBC"</span> <span style="color: #0000ff;">/></span> <span style="color: #008000;"><!--</span><span style="color: #008000;"> 声明使用那种事务管理机制 JDBC/MANAGED </span><span style="color: #008000;">--></span>
  15. <span style="color: #008000;"><!--</span><span style="color: #008000;"> 配置数据库连接信息 </span><span style="color: #008000;">--></span>
  16. <span style="color: #0000ff;"><</span><span style="color: #800000;">dataSource </span><span style="color: #ff0000;">type</span><span style="color: #0000ff;">="POOLED"</span><span style="color: #0000ff;">></span>
  17. <span style="color: #0000ff;"><</span><span style="color: #800000;">property </span><span style="color: #ff0000;">name</span><span style="color: #0000ff;">="driver"</span><span style="color: #ff0000;"> value</span><span style="color: #0000ff;">="com.mysql.jdbc.Driver"</span> <span style="color: #0000ff;">/></span>
  18. <span style="color: #0000ff;"><</span><span style="color: #800000;">property </span><span style="color: #ff0000;">name</span><span style="color: #0000ff;">="url"</span><span style="color: #ff0000;"> value</span><span style="color: #0000ff;">="jdbc:mysql://192.168.1.150:3306/xxx"</span> <span style="color: #0000ff;">/></span>
  19. <span style="color: #0000ff;"><</span><span style="color: #800000;">property </span><span style="color: #ff0000;">name</span><span style="color: #0000ff;">="username"</span><span style="color: #ff0000;"> value</span><span style="color: #0000ff;">="xxx"</span> <span style="color: #0000ff;">/></span>
  20. <span style="color: #0000ff;"><</span><span style="color: #800000;">property </span><span style="color: #ff0000;">name</span><span style="color: #0000ff;">="password"</span><span style="color: #ff0000;"> value</span><span style="color: #0000ff;">="xxx"</span> <span style="color: #0000ff;">/></span>
  21. <span style="color: #0000ff;"></</span><span style="color: #800000;">dataSource</span><span style="color: #0000ff;">></span>
  22. <span style="color: #0000ff;"></</span><span style="color: #800000;">environment</span><span style="color: #0000ff;">></span>
  23. <span style="color: #0000ff;"></</span><span style="color: #800000;">environments</span><span style="color: #0000ff;">></span>
  24. <span style="color: #0000ff;"><</span><span style="color: #800000;">mappers</span><span style="color: #0000ff;">></span>
  25. <span style="color: #0000ff;"><</span><span style="color: #800000;">mapper </span><span style="color: #ff0000;">resource</span><span style="color: #0000ff;">="userMapper.xml"</span><span style="color: #0000ff;">/></span>
  26. <span style="color: #0000ff;"></</span><span style="color: #800000;">mappers</span><span style="color: #0000ff;">></span>
  27. <span style="color: #0000ff;"></</span><span style="color: #800000;">configuration</span><span style="color: #0000ff;">></span>
conf.xml

首先建立数据表,这里就以user表为例 :

  1. <span style="color: #0000ff;">DROP</span> <span style="color: #0000ff;">TABLE</span> <span style="color: #0000ff;">IF</span> <span style="color: #808080;">EXISTS</span> <span style="color: #ff00ff;">user</span><span style="color: #000000;">;
  2. </span><span style="color: #0000ff;">CREATE</span> <span style="color: #0000ff;">TABLE</span> <span style="color: #ff00ff;">user</span><span style="color: #000000;"> (
  3. id </span><span style="color: #0000ff;">INT</span> <span style="color: #808080;">NOT</span> <span style="color: #0000ff;">NULL</span> <span style="color: #0000ff;">PRIMARY</span> <span style="color: #0000ff;">KEY</span><span style="color: #000000;"> AUTO_INCREMENT,
  4. name </span><span style="color: #0000ff;">VARCHAR</span>(<span style="color: #800000; font-weight: bold;">32</span>) <span style="color: #808080;">NOT</span> <span style="color: #0000ff;">NULL</span><span style="color: #000000;">,
  5. password </span><span style="color: #0000ff;">VARCHAR</span>(<span style="color: #800000; font-weight: bold;">32</span>) <span style="color: #808080;">NOT</span> <span style="color: #0000ff;">NULL</span><span style="color: #000000;">,
  6. sex </span><span style="color: #0000ff;">int</span><span style="color: #000000;">,
  7. email </span><span style="color: #0000ff;">VARCHAR</span>(<span style="color: #800000; font-weight: bold;">32</span><span style="color: #000000;">),
  8. phone </span><span style="color: #0000ff;">VARCHAR</span>(<span style="color: #800000; font-weight: bold;">16</span><span style="color: #000000;">),
  9. admin </span><span style="color: #0000ff;">VARCHAR</span>(<span style="color: #800000; font-weight: bold;">16</span><span style="color: #000000;">)
  10. );</span>

然后新建与数据表对应的类User:

技术分享
  1. <span style="color: #008000;">/**</span><span style="color: #008000;">
  2. * User - 用户类
  3. </span><span style="color: #008000;">*/</span>
  4. <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">class</span><span style="color: #000000;"> User {
  5. </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">final</span> <span style="color: #0000ff;">int</span> MAN = 0; <span style="color: #008000;">//</span><span style="color: #008000;"> 男生</span>
  6. <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">final</span> <span style="color: #0000ff;">int</span> WOMAN = 1; <span style="color: #008000;">//</span><span style="color: #008000;"> 女生</span>
  7. <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">final</span> <span style="color: #0000ff;">int</span> OTHER = 2; <span style="color: #008000;">//</span><span style="color: #008000;"> 其他</span>
  8. <span style="color: #0000ff;">private</span> <span style="color: #0000ff;">int</span> id; <span style="color: #008000;">//</span><span style="color: #008000;"> 用户id</span>
  9. <span style="color: #0000ff;">private</span> String name; <span style="color: #008000;">//</span><span style="color: #008000;"> 用户名</span>
  10. <span style="color: #0000ff;">private</span> String password; <span style="color: #008000;">//</span><span style="color: #008000;"> 用户密码</span>
  11. <span style="color: #0000ff;">private</span> <span style="color: #0000ff;">int</span> sex; <span style="color: #008000;">//</span><span style="color: #008000;"> 用户性别</span>
  12. <span style="color: #0000ff;">private</span> String email; <span style="color: #008000;">//</span><span style="color: #008000;"> 用户邮箱</span>
  13. <span style="color: #0000ff;">private</span> String phone; <span style="color: #008000;">//</span><span style="color: #008000;"> 用户手机</span>
  14. <span style="color: #0000ff;">private</span> String admin; <span style="color: #008000;">//</span><span style="color: #008000;"> 用户是否是管理员,"admin"表示是管理员,其他为普通用户</span>
  15. <span style="color: #0000ff;">public</span><span style="color: #000000;"> User() { }
  16. </span><span style="color: #0000ff;">public</span> User(String name, String password, <span style="color: #0000ff;">int</span><span style="color: #000000;"> sex, String email, String phone) {
  17. </span><span style="color: #0000ff;">this</span>.name =<span style="color: #000000;"> name;
  18. </span><span style="color: #0000ff;">this</span>.password =<span style="color: #000000;"> password;
  19. </span><span style="color: #0000ff;">this</span>.sex =<span style="color: #000000;"> sex;
  20. </span><span style="color: #0000ff;">this</span>.email =<span style="color: #000000;"> email;
  21. </span><span style="color: #0000ff;">this</span>.phone =<span style="color: #000000;"> phone;
  22. </span><span style="color: #0000ff;">this</span>.admin = ""<span style="color: #000000;">;
  23. }
  24. </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> User(String name, String password, String sex, String email, String phone) {
  25. </span><span style="color: #0000ff;">this</span>.name =<span style="color: #000000;"> name;
  26. </span><span style="color: #0000ff;">this</span>.password =<span style="color: #000000;"> password;
  27. setSex(sex); </span><span style="color: #008000;">//</span><span style="color: #008000;"> this.sex = sex;</span>
  28. <span style="color: #0000ff;">this</span>.email =<span style="color: #000000;"> email;
  29. </span><span style="color: #0000ff;">this</span>.phone =<span style="color: #000000;"> phone;
  30. </span><span style="color: #0000ff;">this</span>.admin = ""<span style="color: #000000;">;
  31. }
  32. </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">int</span><span style="color: #000000;"> getId() {
  33. </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> id;
  34. }
  35. </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> setId(<span style="color: #0000ff;">int</span><span style="color: #000000;"> id) {
  36. </span><span style="color: #0000ff;">this</span>.id =<span style="color: #000000;"> id;
  37. }
  38. </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> String getName() {
  39. </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> name;
  40. }
  41. </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> setName(String name) {
  42. </span><span style="color: #0000ff;">this</span>.name =<span style="color: #000000;"> name;
  43. }
  44. </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> String getPassword() {
  45. </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> password;
  46. }
  47. </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> setPassword(String password) {
  48. </span><span style="color: #0000ff;">this</span>.password =<span style="color: #000000;"> password;
  49. }
  50. </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">int</span><span style="color: #000000;"> getSex() {
  51. </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> sex;
  52. }
  53. </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> setSex(<span style="color: #0000ff;">int</span><span style="color: #000000;"> sex) {
  54. </span><span style="color: #0000ff;">this</span>.sex =<span style="color: #000000;"> sex;
  55. }
  56. </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> setSex(String sexStr) {
  57. </span><span style="color: #0000ff;">int</span> sex =<span style="color: #000000;"> Integer.valueOf(sexStr);
  58. </span><span style="color: #0000ff;">switch</span><span style="color: #000000;"> (Integer.valueOf(sexStr)) {
  59. </span><span style="color: #0000ff;">case</span> 0<span style="color: #000000;">: {
  60. </span><span style="color: #0000ff;">this</span>.sex =<span style="color: #000000;"> MAN;
  61. </span><span style="color: #0000ff;">break</span><span style="color: #000000;">;
  62. }
  63. </span><span style="color: #0000ff;">case</span> 1<span style="color: #000000;">: {
  64. </span><span style="color: #0000ff;">this</span>.sex =<span style="color: #000000;"> WOMAN;
  65. </span><span style="color: #0000ff;">break</span><span style="color: #000000;">;
  66. }
  67. </span><span style="color: #0000ff;">default</span><span style="color: #000000;">: {
  68. </span><span style="color: #0000ff;">this</span>.sex =<span style="color: #000000;"> OTHER;
  69. </span><span style="color: #0000ff;">break</span><span style="color: #000000;">;
  70. }
  71. }
  72. }
  73. </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> String getEmail() {
  74. </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> email;
  75. }
  76. </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> setEmail(String email) {
  77. </span><span style="color: #0000ff;">this</span>.email =<span style="color: #000000;"> email;
  78. }
  79. </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> String getPhone() {
  80. </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> phone;
  81. }
  82. </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> setPhone(String phone) {
  83. </span><span style="color: #0000ff;">this</span>.phone =<span style="color: #000000;"> phone;
  84. }
  85. </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> String getAdmin() {
  86. </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> admin;
  87. }
  88. </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> setAdmin(String admin) {
  89. </span><span style="color: #0000ff;">this</span>.admin =<span style="color: #000000;"> admin;
  90. }
  91. @Override
  92. </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> String toString() {
  93. </span><span style="color: #0000ff;">return</span> "User{" +
  94. "id=" + id +
  95. ", name=‘" + name + ‘\‘‘ +
  96. ", password=‘" + password + ‘\‘‘ +
  97. ", sex=" + sex +
  98. ", email=‘" + email + ‘\‘‘ +
  99. ", phone=‘" + phone + ‘\‘‘ +
  100. ", admin=‘" + admin + ‘\‘‘ +
  101. ‘}‘<span style="color: #000000;">;
  102. }
  103. }</span>
User

再新建usre表的配置文件:

技术分享
  1. <span style="color: #0000ff;"><?</span><span style="color: #ff00ff;">xml version="1.0" encoding="UTF-8"</span><span style="color: #0000ff;">?></span>
  2. <span style="color: #0000ff;"><!</span><span style="color: #ff00ff;">DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"</span><span style="color: #0000ff;">></span>
  3. <span style="color: #0000ff;"><</span><span style="color: #800000;">mapper </span><span style="color: #ff0000;">namespace</span><span style="color: #0000ff;">="com.luoxn28.dao.UserDao"</span><span style="color: #0000ff;">></span>
  4. <span style="color: #0000ff;"><</span><span style="color: #800000;">select </span><span style="color: #ff0000;">id</span><span style="color: #0000ff;">="getById"</span><span style="color: #ff0000;"> parameterType</span><span style="color: #0000ff;">="int"</span><span style="color: #ff0000;"> resultType</span><span style="color: #0000ff;">="User"</span><span style="color: #0000ff;">></span><span style="color: #000000;">
  5. SELECT * FROM user WHERE id=#{id}; </span><span style="color: #008000;"><!--</span><span style="color: #008000;"> #{xxx} xxx为类中的数据域名称 </span><span style="color: #008000;">--></span>
  6. <span style="color: #0000ff;"></</span><span style="color: #800000;">select</span><span style="color: #0000ff;">></span>
  7. <span style="color: #0000ff;"><</span><span style="color: #800000;">select </span><span style="color: #ff0000;">id</span><span style="color: #0000ff;">="getAll"</span><span style="color: #ff0000;"> resultType</span><span style="color: #0000ff;">="com.luoxn28.dao.User"</span><span style="color: #0000ff;">></span><span style="color: #000000;">
  8. SELECT * FROM user;
  9. </span><span style="color: #0000ff;"></</span><span style="color: #800000;">select</span><span style="color: #0000ff;">></span>
  10. <span style="color: #0000ff;"></</span><span style="color: #800000;">mapper</span><span style="color: #0000ff;">></span>
userMapper.xml

最后新建测试类:

  1. <span style="color: #008000;">/**</span><span style="color: #008000;">
  2. * MyBatis测试类
  3. </span><span style="color: #008000;">*/</span>
  4. <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">class</span><span style="color: #000000;"> TestMain {
  5. </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span> main(String[] args) <span style="color: #0000ff;">throws</span><span style="color: #000000;"> IOException {
  6. String resouce </span>= "conf.xml"<span style="color: #000000;">;
  7. InputStream is </span>=<span style="color: #000000;"> Resources.getResourceAsStream(resouce);
  8. </span><span style="color: #008000;">//</span><span style="color: #008000;"> 构建sqlSession工厂</span>
  9. SqlSessionFactory sqlSessionFactory = <span style="color: #0000ff;">new</span><span style="color: #000000;"> SqlSessionFactoryBuilder().build(is);
  10. </span><span style="color: #008000;">//</span><span style="color: #008000;"> 获取sqlSession</span>
  11. SqlSession session =<span style="color: #000000;"> sqlSessionFactory.openSession();
  12. User user;
  13. </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> {
  14. </span><span style="color: #008000;">/**</span><span style="color: #008000;">
  15. * 第一种方式: 直接执行已映射的 SQL 语句
  16. </span><span style="color: #008000;">*/</span><span style="color: #000000;">
  17. String statement </span>= "com.luoxn28.dao.UserDao.getById"<span style="color: #000000;">;
  18. user </span>= session.selectOne(statement, 1<span style="color: #000000;">);
  19. System.out.println(user);
  20. }
  21. </span><span style="color: #0000ff;">finally</span><span style="color: #000000;"> {
  22. session.close();
  23. }
  24. </span><span style="color: #008000;">/**</span><span style="color: #008000;">
  25. * 第二种方式: 执行更清晰和类型安全的代码
  26. </span><span style="color: #008000;">*/</span>
  27. <span style="color: #008000;">//</span><span style="color: #008000;"> UserDao userDao = session.getMapper(UserDao.class);
  28. </span><span style="color: #008000;">//</span><span style="color: #008000;"> user = userDao.getById(1);
  29. </span><span style="color: #008000;">//</span><span style="color: #008000;"> System.out.println(user);</span>
  30. <span style="color: #000000;"> }
  31. }</span>

  由于我们分析的是SQL的执行流程,那就重点关注下 user = session.selectOne(statement, 1); 这行代码~ 注意,传进去的参数是1。

  session是DefaultSqlSession类型的,因为sqlSessionFactory默认生成的SqlSession是DefaultSqlSession类型。selectOne()会调用selectList()。

  1. <span style="color: #008000;">//</span><span style="color: #008000;"> DefaultSqlSession类</span>
  2. <span style="color: #0000ff;">public</span> <E> List<E><span style="color: #000000;"> selectList(String statement, Object parameter, RowBounds rowBounds) {
  3. </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> {
  4. MappedStatement ms </span>=<span style="color: #000000;"> configuration.getMappedStatement(statement);
  5. </span><span style="color: #008000;">//</span><span style="color: #008000;"> CURD操作是交给Excetor去处理的</span>
  6. <span style="color: #0000ff;">return</span><span style="color: #000000;"> executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
  7. } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (Exception e) {
  8. </span><span style="color: #0000ff;">throw</span> ExceptionFactory.wrapException("Error querying database. Cause: " +<span style="color: #000000;"> e, e);
  9. } </span><span style="color: #0000ff;">finally</span><span style="color: #000000;"> {
  10. ErrorContext.instance().reset();
  11. }
  12. }</span>

  在DefaultSqlSession.selectList中的各种CURD操作都是通多Executor进行的,这里executor的类型是CachingExecutor,接着跳转到其中的query方法中。

  1. <span style="color: #008000;">//</span><span style="color: #008000;"> CachingExecutor 类</span>
  2. <span style="color: #0000ff;">public</span> <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) <span style="color: #0000ff;">throws</span><span style="color: #000000;"> SQLException {
  3. BoundSql boundSql </span>= ms.getBoundSql(parameterObject); <span style="color: #008000;">//</span><span style="color: #008000;"> 获取绑定的sql命令,比如"SELECT * FROM xxx"</span>
  4. CacheKey key =<span style="color: #000000;"> createCacheKey(ms, parameterObject, rowBounds, boundSql);
  5. </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
  6. }</span>

  getBoundSql为了获取绑定的sql命令,在创建完cacheKey之后,就进入到CachingExecutor 类中的另一个query方法中。

  1. <span style="color: #008000;">//</span><span style="color: #008000;"> CachingExecutor 类</span>
  2. <span style="color: #000000;">@Override
  3. </span><span style="color: #0000ff;">public</span> <E> List<E><span style="color: #000000;"> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
  4. </span><span style="color: #0000ff;">throws</span><span style="color: #000000;"> SQLException {
  5. Cache cache </span>=<span style="color: #000000;"> ms.getCache();
  6. </span><span style="color: #0000ff;">if</span> (cache != <span style="color: #0000ff;">null</span><span style="color: #000000;">) {
  7. flushCacheIfRequired(ms);
  8. </span><span style="color: #0000ff;">if</span> (ms.isUseCache() && resultHandler == <span style="color: #0000ff;">null</span><span style="color: #000000;">) {
  9. ensureNoOutParams(ms, parameterObject, boundSql);
  10. @SuppressWarnings(</span>"unchecked"<span style="color: #000000;">)
  11. List</span><E> list = (List<E><span style="color: #000000;">) tcm.getObject(cache, key);
  12. </span><span style="color: #0000ff;">if</span> (list == <span style="color: #0000ff;">null</span><span style="color: #000000;">) {
  13. list </span>= delegate.<E><span style="color: #000000;"> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
  14. tcm.putObject(cache, key, list); </span><span style="color: #008000;">//</span><span style="color: #008000;"> issue #578 and #116</span>
  15. <span style="color: #000000;"> }
  16. </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> list;
  17. }
  18. }
  19. </span><span style="color: #0000ff;">return</span> delegate.<E><span style="color: #000000;"> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
  20. }</span>

  这里真正执行query操作的是SimplyExecutor代理来完成的,接着就进入到了SimplyExecutor的父类BaseExecutor的query方法中。

  1. <span style="color: #008000;">//</span><span style="color: #008000;"> SimplyExecutor的父类BaseExecutor类</span>
  2. @SuppressWarnings("unchecked"<span style="color: #000000;">)
  3. @Override
  4. </span><span style="color: #0000ff;">public</span> <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) <span style="color: #0000ff;">throws</span><span style="color: #000000;"> SQLException {
  5. ErrorContext.instance().resource(ms.getResource()).activity(</span>"executing a query"<span style="color: #000000;">).object(ms.getId());
  6. </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (closed) {
  7. </span><span style="color: #0000ff;">throw</span> <span style="color: #0000ff;">new</span> ExecutorException("Executor was closed."<span style="color: #000000;">);
  8. }
  9. </span><span style="color: #0000ff;">if</span> (queryStack == 0 &&<span style="color: #000000;"> ms.isFlushCacheRequired()) {
  10. clearLocalCache();
  11. }
  12. List</span><E><span style="color: #000000;"> list;
  13. </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> {
  14. queryStack</span>++<span style="color: #000000;">;
  15. </span><span style="color: #008000;">/**</span><span style="color: #008000;">
  16. * localCache是一级缓存,如果找不到就调用queryFromDatabase从数据库中查找
  17. </span><span style="color: #008000;">*/</span><span style="color: #000000;">
  18. list </span>= resultHandler == <span style="color: #0000ff;">null</span> ? (List<E>) localCache.getObject(key) : <span style="color: #0000ff;">null</span><span style="color: #000000;">;
  19. </span><span style="color: #0000ff;">if</span> (list != <span style="color: #0000ff;">null</span><span style="color: #000000;">) {
  20. handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
  21. } </span><span style="color: #0000ff;">else</span><span style="color: #000000;"> {
  22. list </span>=<span style="color: #000000;"> queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
  23. }
  24. } </span><span style="color: #0000ff;">finally</span><span style="color: #000000;"> {
  25. queryStack</span>--<span style="color: #000000;">;
  26. }
  27. </span><span style="color: #0000ff;">if</span> (queryStack == 0<span style="color: #000000;">) {
  28. </span><span style="color: #0000ff;">for</span><span style="color: #000000;"> (DeferredLoad deferredLoad : deferredLoads) {
  29. deferredLoad.load();
  30. }
  31. </span><span style="color: #008000;">//</span><span style="color: #008000;"> issue #601</span>
  32. <span style="color: #000000;"> deferredLoads.clear();
  33. </span><span style="color: #0000ff;">if</span> (configuration.getLocalCacheScope() ==<span style="color: #000000;"> LocalCacheScope.STATEMENT) {
  34. </span><span style="color: #008000;">//</span><span style="color: #008000;"> issue #482</span>
  35. <span style="color: #000000;"> clearLocalCache();
  36. }
  37. }
  38. </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> list;
  39. }</span>

  因为是第一次SQL查询操作,所以会调用queryFromDatabase方法来执行查询。

  1. <span style="color: #008000;">//</span><span style="color: #008000;"> SimplyExecutor的父类BaseExecutor类</span>
  2. <span style="color: #0000ff;">private</span> <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) <span style="color: #0000ff;">throws</span><span style="color: #000000;"> SQLException {
  3. List</span><E><span style="color: #000000;"> list;
  4. localCache.putObject(key, EXECUTION_PLACEHOLDER);
  5. </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> {
  6. list </span>=<span style="color: #000000;"> doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
  7. } </span><span style="color: #0000ff;">finally</span><span style="color: #000000;"> {
  8. localCache.removeObject(key);
  9. }
  10. localCache.putObject(key, list);
  11. </span><span style="color: #0000ff;">if</span> (ms.getStatementType() ==<span style="color: #000000;"> StatementType.CALLABLE) {
  12. localOutputParameterCache.putObject(key, parameter);
  13. }
  14. </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> list;
  15. }</span>

  从数据库中查询数据,进入到SimplyExecutor中进行操作。

  1. <span style="color: #008000;">//</span><span style="color: #008000;"> SimplyExecutor类</span>
  2. <span style="color: #0000ff;">public</span> <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) <span style="color: #0000ff;">throws</span><span style="color: #000000;"> SQLException {
  3. Statement stmt </span>= <span style="color: #0000ff;">null</span><span style="color: #000000;">;
  4. </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> {
  5. Configuration configuration </span>=<span style="color: #000000;"> ms.getConfiguration();
  6. StatementHandler handler </span>=<span style="color: #000000;"> configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
  7. </span><span style="color: #008000;">//</span><span style="color: #008000;"> 子流程1:SQL查询参数的设置</span>
  8. stmt =<span style="color: #000000;"> prepareStatement(handler, ms.getStatementLog());
  9. </span><span style="color: #008000;">//</span><span style="color: #008000;"> StatementHandler封装了Statement
  10. </span><span style="color: #008000;">//</span><span style="color: #008000;"> 子流程2:SQL查询操作和结果集的封装</span>
  11. <span style="color: #0000ff;">return</span> handler.<E><span style="color: #000000;">query(stmt);
  12. } </span><span style="color: #0000ff;">finally</span><span style="color: #000000;"> {
  13. closeStatement(stmt);
  14. }
  15. }</span>

  注意,在prepareStatement方法中会进行SQL查询参数的设置,也就是咱们最开始传递进来的参数,其值为1。handler.<E>query(stmt)方法中会进行实际的SQL查询操作和结果集的封装(封装成Java对象)。当流程走到这里时,程序已经压栈有一定深度了,因为接下来程序分析会兵分两路,一方面深入到SQL查询及结果集的设置子流程1中,然后再深入到SQL查询操作和结果集的封装子流程2,因为还会回到这里,所以就来一张调用栈的特写吧:

技术分享

子流程1:SQL查询参数的设置

  1. <span style="color: #008000;">//</span><span style="color: #008000;"> SimplyExecutor类</span>
  2. <span style="color: #0000ff;">private</span> Statement prepareStatement(StatementHandler handler, Log statementLog) <span style="color: #0000ff;">throws</span><span style="color: #000000;"> SQLException {
  3. Statement stmt;
  4. </span><span style="color: #008000;">//</span><span style="color: #008000;"> 获取一个Connection</span>
  5. Connection connection =<span style="color: #000000;"> getConnection(statementLog);
  6. stmt </span>=<span style="color: #000000;"> handler.prepare(connection, transaction.getTimeout());
  7. handler.parameterize(stmt); </span><span style="color: #008000;">//</span><span style="color: #008000;"> 设置SQL查询中的参数值</span>
  8. <span style="color: #0000ff;">return</span><span style="color: #000000;"> stmt;
  9. }</span>

  通过getConnection方法来获取一个Connection,调用prepare方法来获取一个Statement(这里的handler类型是RoutingStatementHandler,RoutingStatementHandler的prepare方法调用的是PrepareStatementHandler的prepare方法,因为PrepareStatementHandler并没有覆盖其父类的prepare方法,其实最后调用的是BaseStatementHandler中的prepare方法。是不是绕晕了,那就再看一遍吧 :) )。调用parameterize方法来设置SQL的参数值(这里最后调用的是PrepareStatementHandler中的parameterize方法,而PrepareStatementHandler.parameterize方法调用的是DefaultParameterHandler中的setParameters方法)。

  1. <span style="color: #008000;">//</span><span style="color: #008000;"> PrepareStatementHandler类</span>
  2. <span style="color: #000000;">@Override
  3. </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> parameterize(Statement statement) <span style="color: #0000ff;">throws</span><span style="color: #000000;"> SQLException {
  4. parameterHandler.setParameters((PreparedStatement) statement);
  5. }</span>
  1. <span style="color: #008000;">//</span><span style="color: #008000;"> DefaultParameterHandler类</span>
  2. <span style="color: #000000;">@Override
  3. </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> setParameters(PreparedStatement ps) {
  4. ErrorContext.instance().activity(</span>"setting parameters"<span style="color: #000000;">).object(mappedStatement.getParameterMap().getId());
  5. List</span><ParameterMapping> parameterMappings =<span style="color: #000000;"> boundSql.getParameterMappings();
  6. </span><span style="color: #0000ff;">if</span> (parameterMappings != <span style="color: #0000ff;">null</span><span style="color: #000000;">) {
  7. </span><span style="color: #0000ff;">for</span> (<span style="color: #0000ff;">int</span> i = 0; i < parameterMappings.size(); i++<span style="color: #000000;">) {
  8. ParameterMapping parameterMapping </span>=<span style="color: #000000;"> parameterMappings.get(i);
  9. </span><span style="color: #0000ff;">if</span> (parameterMapping.getMode() !=<span style="color: #000000;"> ParameterMode.OUT) {
  10. Object value;
  11. String propertyName </span>=<span style="color: #000000;"> parameterMapping.getProperty();
  12. </span><span style="color: #0000ff;">if</span> (boundSql.hasAdditionalParameter(propertyName)) { <span style="color: #008000;">//</span><span style="color: #008000;"> issue #448 ask first for additional params</span>
  13. value =<span style="color: #000000;"> boundSql.getAdditionalParameter(propertyName);
  14. } </span><span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span> (parameterObject == <span style="color: #0000ff;">null</span><span style="color: #000000;">) {
  15. value </span>= <span style="color: #0000ff;">null</span><span style="color: #000000;">;
  16. } </span><span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span><span style="color: #000000;"> (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
  17. value </span>=<span style="color: #000000;"> parameterObject;
  18. } </span><span style="color: #0000ff;">else</span><span style="color: #000000;"> {
  19. MetaObject metaObject </span>=<span style="color: #000000;"> configuration.newMetaObject(parameterObject);
  20. value </span>=<span style="color: #000000;"> metaObject.getValue(propertyName);
  21. }
  22. TypeHandler typeHandler </span>=<span style="color: #000000;"> parameterMapping.getTypeHandler();
  23. JdbcType jdbcType </span>=<span style="color: #000000;"> parameterMapping.getJdbcType();
  24. </span><span style="color: #0000ff;">if</span> (value == <span style="color: #0000ff;">null</span> && jdbcType == <span style="color: #0000ff;">null</span><span style="color: #000000;">) {
  25. jdbcType </span>=<span style="color: #000000;"> configuration.getJdbcTypeForNull();
  26. }
  27. </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> {
  28. typeHandler.setParameter(ps, i </span>+ 1<span style="color: #000000;">, value, jdbcType);
  29. } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (TypeException e) {
  30. </span><span style="color: #0000ff;">throw</span> <span style="color: #0000ff;">new</span> TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " +<span style="color: #000000;"> e, e);
  31. } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (SQLException e) {
  32. </span><span style="color: #0000ff;">throw</span> <span style="color: #0000ff;">new</span> TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " +<span style="color: #000000;"> e, e);
  33. }
  34. }
  35. }
  36. }
  37. }</span>

  到这里为止,已经给Statement设置了最初传递进去的参数(值为1)了,那么接着分析流程2:

流程2:SQL查询及结果集的设置

  1. <span style="color: #008000;">//</span><span style="color: #008000;"> RoutingStatementHandler类</span>
  2. <span style="color: #000000;">@Override
  3. </span><span style="color: #0000ff;">public</span> <E> List<E> query(Statement statement) <span style="color: #0000ff;">throws</span><span style="color: #000000;"> SQLException {
  4. </span><span style="color: #0000ff;">return</span> delegate.<E><span style="color: #000000;">query(statement);
  5. }</span>
  1. <span style="color: #008000;">//</span><span style="color: #008000;"> RoutingStatementHandler类</span>
  2. <span style="color: #000000;">@Override
  3. </span><span style="color: #0000ff;">public</span> <E> List<E> query(Statement statement) <span style="color: #0000ff;">throws</span><span style="color: #000000;"> SQLException {
  4. </span><span style="color: #008000;">//</span><span style="color: #008000;"> 这里就到了熟悉的PreparedStatement了</span>
  5. PreparedStatement ps =<span style="color: #000000;"> (PreparedStatement) statement;
  6. </span><span style="color: #008000;">//</span><span style="color: #008000;"> 执行SQL查询操作</span>
  7. <span style="color: #000000;"> ps.execute();
  8. </span><span style="color: #008000;">//</span><span style="color: #008000;"> 结果交给ResultHandler来处理</span>
  9. <span style="color: #0000ff;">return</span> resultSetHandler.<E><span style="color: #000000;"> handleResultSets(ps);
  10. }</span>
  1. <span style="color: #008000;">//</span><span style="color: #008000;"> DefaultResultSetHandler类(封装返回值,将查询结果封装成Object对象)</span>
  2. <span style="color: #000000;">@Override
  3. </span><span style="color: #0000ff;">public</span> List<Object> handleResultSets(Statement stmt) <span style="color: #0000ff;">throws</span><span style="color: #000000;"> SQLException {
  4. ErrorContext.instance().activity(</span>"handling results"<span style="color: #000000;">).object(mappedStatement.getId());
  5. </span><span style="color: #0000ff;">final</span> List<Object> multipleResults = <span style="color: #0000ff;">new</span> ArrayList<Object><span style="color: #000000;">();
  6. </span><span style="color: #0000ff;">int</span> resultSetCount = 0<span style="color: #000000;">;
  7. ResultSetWrapper rsw </span>=<span style="color: #000000;"> getFirstResultSet(stmt);
  8. List</span><ResultMap> resultMaps =<span style="color: #000000;"> mappedStatement.getResultMaps();
  9. </span><span style="color: #0000ff;">int</span> resultMapCount =<span style="color: #000000;"> resultMaps.size();
  10. validateResultMapsCount(rsw, resultMapCount);
  11. </span><span style="color: #0000ff;">while</span> (rsw != <span style="color: #0000ff;">null</span> && resultMapCount ><span style="color: #000000;"> resultSetCount) {
  12. ResultMap resultMap </span>=<span style="color: #000000;"> resultMaps.get(resultSetCount);
  13. handleResultSet(rsw, resultMap, multipleResults, </span><span style="color: #0000ff;">null</span><span style="color: #000000;">);
  14. rsw </span>=<span style="color: #000000;"> getNextResultSet(stmt);
  15. cleanUpAfterHandlingResultSet();
  16. resultSetCount</span>++<span style="color: #000000;">;
  17. }
  18. String[] resultSets </span>=<span style="color: #000000;"> mappedStatement.getResultSets();
  19. </span><span style="color: #0000ff;">if</span> (resultSets != <span style="color: #0000ff;">null</span><span style="color: #000000;">) {
  20. </span><span style="color: #0000ff;">while</span> (rsw != <span style="color: #0000ff;">null</span> && resultSetCount <<span style="color: #000000;"> resultSets.length) {
  21. ResultMapping parentMapping </span>=<span style="color: #000000;"> nextResultMaps.get(resultSets[resultSetCount]);
  22. </span><span style="color: #0000ff;">if</span> (parentMapping != <span style="color: #0000ff;">null</span><span style="color: #000000;">) {
  23. String nestedResultMapId </span>=<span style="color: #000000;"> parentMapping.getNestedResultMapId();
  24. ResultMap resultMap </span>=<span style="color: #000000;"> configuration.getResultMap(nestedResultMapId);
  25. handleResultSet(rsw, resultMap, </span><span style="color: #0000ff;">null</span><span style="color: #000000;">, parentMapping);
  26. }
  27. rsw </span>=<span style="color: #000000;"> getNextResultSet(stmt);
  28. cleanUpAfterHandlingResultSet();
  29. resultSetCount</span>++<span style="color: #000000;">;
  30. }
  31. }
  32. </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> collapseSingleResultList(multipleResults);
  33. }</span>

  ResultSetWrapper是ResultSet的包装类,调用getFirstResultSet方法获取第一个ResultSet,同时获取数据库的MetaData数据,包括数据表列名、列的类型、类序号等,这些信息都存储在ResultSetWrapper类中了。然后调用handleResultSet方法来来进行结果集的封装。

  1. <span style="color: #008000;">//</span><span style="color: #008000;"> DefaultResultSetHandler类</span>
  2. <span style="color: #0000ff;">private</span> <span style="color: #0000ff;">void</span> handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults, ResultMapping parentMapping) <span style="color: #0000ff;">throws</span><span style="color: #000000;"> SQLException {
  3. </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> {
  4. </span><span style="color: #0000ff;">if</span> (parentMapping != <span style="color: #0000ff;">null</span><span style="color: #000000;">) {
  5. handleRowValues(rsw, resultMap, </span><span style="color: #0000ff;">null</span><span style="color: #000000;">, RowBounds.DEFAULT, parentMapping);
  6. } </span><span style="color: #0000ff;">else</span><span style="color: #000000;"> {
  7. </span><span style="color: #0000ff;">if</span> (resultHandler == <span style="color: #0000ff;">null</span><span style="color: #000000;">) {
  8. DefaultResultHandler defaultResultHandler </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> DefaultResultHandler(objectFactory);
  9. handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, </span><span style="color: #0000ff;">null</span><span style="color: #000000;">);
  10. multipleResults.add(defaultResultHandler.getResultList());
  11. } </span><span style="color: #0000ff;">else</span><span style="color: #000000;"> {
  12. handleRowValues(rsw, resultMap, resultHandler, rowBounds, </span><span style="color: #0000ff;">null</span><span style="color: #000000;">);
  13. }
  14. }
  15. } </span><span style="color: #0000ff;">finally</span><span style="color: #000000;"> {
  16. </span><span style="color: #008000;">//</span><span style="color: #008000;"> issue #228 (close resultsets)</span>
  17. <span style="color: #000000;"> closeResultSet(rsw.getResultSet());
  18. }
  19. }</span>

  这里调用handleRowValues方法来进行值的设置:

  1. <span style="color: #008000;">//</span><span style="color: #008000;"> DefaultResultSetHandler类</span>
  2. <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) <span style="color: #0000ff;">throws</span><span style="color: #000000;"> SQLException {
  3. </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (resultMap.hasNestedResultMaps()) {
  4. ensureNoRowBounds();
  5. checkResultHandler();
  6. handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
  7. } </span><span style="color: #0000ff;">else</span><span style="color: #000000;"> {
  8. </span><span style="color: #008000;">//</span><span style="color: #008000;"> 封装数据</span>
  9. <span style="color: #000000;"> handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
  10. }
  11. }</span>
  1. <span style="color: #008000;">//</span><span style="color: #008000;"> DefaultResultSetHandler类
  2. </span><span style="color: #008000;">//</span><span style="color: #008000;"> 封装数据</span>
  3. <span style="color: #0000ff;">private</span> <span style="color: #0000ff;">void</span> handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?><span style="color: #000000;"> resultHandler, RowBounds rowBounds, ResultMapping parentMapping)
  4. </span><span style="color: #0000ff;">throws</span><span style="color: #000000;"> SQLException {
  5. DefaultResultContext</span><Object> resultContext = <span style="color: #0000ff;">new</span> DefaultResultContext<Object><span style="color: #000000;">();
  6. skipRows(rsw.getResultSet(), rowBounds);
  7. </span><span style="color: #0000ff;">while</span> (shouldProcessMoreRows(resultContext, rowBounds) &&<span style="color: #000000;"> rsw.getResultSet().next()) {
  8. ResultMap discriminatedResultMap </span>= resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, <span style="color: #0000ff;">null</span><span style="color: #000000;">);
  9. Object rowValue </span>=<span style="color: #000000;"> getRowValue(rsw, discriminatedResultMap);
  10. storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
  11. }
  12. }</span>
  1. <span style="color: #008000;">//</span><span style="color: #008000;"> DefaultResultSetHandler类</span>
  2. <span style="color: #0000ff;">private</span> Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap) <span style="color: #0000ff;">throws</span><span style="color: #000000;"> SQLException {
  3. </span><span style="color: #0000ff;">final</span> ResultLoaderMap lazyLoader = <span style="color: #0000ff;">new</span><span style="color: #000000;"> ResultLoaderMap();
  4. </span><span style="color: #008000;">//</span><span style="color: #008000;"> createResultObject为新创建的对象,数据表对应的类</span>
  5. Object resultObject = createResultObject(rsw, resultMap, lazyLoader, <span style="color: #0000ff;">null</span><span style="color: #000000;">);
  6. </span><span style="color: #0000ff;">if</span> (resultObject != <span style="color: #0000ff;">null</span> && !<span style="color: #000000;">hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
  7. </span><span style="color: #0000ff;">final</span> MetaObject metaObject =<span style="color: #000000;"> configuration.newMetaObject(resultObject);
  8. </span><span style="color: #0000ff;">boolean</span> foundValues = !<span style="color: #000000;">resultMap.getConstructorResultMappings().isEmpty();
  9. </span><span style="color: #0000ff;">if</span> (shouldApplyAutomaticMappings(resultMap, <span style="color: #0000ff;">false</span><span style="color: #000000;">)) {
  10. </span><span style="color: #008000;">//</span><span style="color: #008000;"> 这里把数据填充进去,metaObject中包含了resultObject信息</span>
  11. foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, <span style="color: #0000ff;">null</span>) ||<span style="color: #000000;"> foundValues;
  12. }
  13. foundValues </span>= applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, <span style="color: #0000ff;">null</span>) ||<span style="color: #000000;"> foundValues;
  14. foundValues </span>= lazyLoader.size() > 0 ||<span style="color: #000000;"> foundValues;
  15. resultObject </span>= foundValues ? resultObject : <span style="color: #0000ff;">null</span><span style="color: #000000;">;
  16. </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> resultObject;
  17. }
  18. </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> resultObject;
  19. }</span>
  1. <span style="color: #008000;">//</span><span style="color: #008000;"> DefaultResultSetHandler类(把ResultSet中查询结果填充到JavaBean中)</span>
  2. <span style="color: #0000ff;">private</span> <span style="color: #0000ff;">boolean</span> applyAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) <span style="color: #0000ff;">throws</span><span style="color: #000000;"> SQLException {
  3. List</span><UnMappedColumnAutoMapping> autoMapping =<span style="color: #000000;"> createAutomaticMappings(rsw, resultMap, metaObject, columnPrefix);
  4. </span><span style="color: #0000ff;">boolean</span> foundValues = <span style="color: #0000ff;">false</span><span style="color: #000000;">;
  5. </span><span style="color: #0000ff;">if</span> (autoMapping.size() > 0<span style="color: #000000;">) {
  6. </span><span style="color: #008000;">//</span><span style="color: #008000;"> 这里进行for循环调用,因为user表中总共有7项,所以也就调用7次</span>
  7. <span style="color: #0000ff;">for</span><span style="color: #000000;"> (UnMappedColumnAutoMapping mapping : autoMapping) {
  8. </span><span style="color: #008000;">//</span><span style="color: #008000;"> 这里将esultSet中查询结果转换为对应的实际类型</span>
  9. <span style="color: #0000ff;">final</span> Object value =<span style="color: #000000;"> mapping.typeHandler.getResult(rsw.getResultSet(), mapping.column);
  10. </span><span style="color: #0000ff;">if</span> (value != <span style="color: #0000ff;">null</span><span style="color: #000000;">) {
  11. foundValues </span>= <span style="color: #0000ff;">true</span><span style="color: #000000;">;
  12. }
  13. </span><span style="color: #0000ff;">if</span> (value != <span style="color: #0000ff;">null</span> || (configuration.isCallSettersOnNulls() && !<span style="color: #000000;">mapping.primitive)) {
  14. </span><span style="color: #008000;">//</span><span style="color: #008000;"> gcode issue #377, call setter on nulls (value is not ‘found‘)</span>
  15. <span style="color: #000000;"> metaObject.setValue(mapping.property, value);
  16. }
  17. }
  18. }
  19. </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> foundValues;
  20. }</span>

  mapping.typeHandler.getResult会获取查询结果值的实际类型,比如我们user表中id字段为int类型,那么它就对应Java中的Integer类型,然后通过调用statement.getInt("id")来获取其int值,其类型为Integer。metaObject.setValue方法会把获取到的Integer值设置到Java类中的对应字段。

  1. <span style="color: #008000;">//</span><span style="color: #008000;"> MetaObject类</span>
  2. <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> setValue(String name, Object value) {
  3. PropertyTokenizer prop </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> PropertyTokenizer(name);
  4. </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (prop.hasNext()) {
  5. MetaObject metaValue </span>=<span style="color: #000000;"> metaObjectForProperty(prop.getIndexedName());
  6. </span><span style="color: #0000ff;">if</span> (metaValue ==<span style="color: #000000;"> SystemMetaObject.NULL_META_OBJECT) {
  7. </span><span style="color: #0000ff;">if</span> (value == <span style="color: #0000ff;">null</span> && prop.getChildren() != <span style="color: #0000ff;">null</span><span style="color: #000000;">) {
  8. </span><span style="color: #008000;">//</span><span style="color: #008000;"> don‘t instantiate child path if value is null</span>
  9. <span style="color: #0000ff;">return</span><span style="color: #000000;">;
  10. } </span><span style="color: #0000ff;">else</span><span style="color: #000000;"> {
  11. metaValue </span>=<span style="color: #000000;"> objectWrapper.instantiatePropertyValue(name, prop, objectFactory);
  12. }
  13. }
  14. metaValue.setValue(prop.getChildren(), value);
  15. } </span><span style="color: #0000ff;">else</span><span style="color: #000000;"> {
  16. objectWrapper.set(prop, value);
  17. }
  18. }</span>

  metaValue.setValue方法最后会调用到Java类中对应数据域的set方法,这样也就完成了SQL查询结果集的Java类封装过程。最后贴一张调用栈到达Java类的set方法中的快照:

技术分享

 

参考:

  1、MyBatis源码

  2、《深入分析Java Web技术内幕》的iBatis章节

  3、《深入理解mybatis原理》 MyBatis的架构设计以及实例分析

  4、luoxn28/tuiku

  5、Java JDBC基础学习小结

MyBatis源码分析-SQL语句执行的完整流程

标签:

人气教程排行