时间:2021-07-01 10:21:17 帮助过:10人阅读
MyBatis主要设计目的还是为了让我们在执行SQL时对输入输出的数据的管理更加方便,所以方便的让我们写出SQL和方便的获取SQL的执行结果是MyBatis的核心竞争力。下面就用一个例子来从源码角度看一下SQL的完整执行流程。
新建配置文件conf.xml:
conf.xml
- <span style="color: #0000ff;"><?</span><span style="color: #ff00ff;">xml version="1.0" encoding="UTF-8"</span><span style="color: #0000ff;">?></span>
- <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>
- <span style="color: #0000ff;"><</span><span style="color: #800000;">configuration</span><span style="color: #0000ff;">></span>
- <span style="color: #0000ff;"><</span><span style="color: #800000;">settings</span><span style="color: #0000ff;">></span>
- <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>
- <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>
- <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>
- <span style="color: #0000ff;"></</span><span style="color: #800000;">settings</span><span style="color: #0000ff;">></span>
- <span style="color: #0000ff;"><</span><span style="color: #800000;">typeAliases</span><span style="color: #0000ff;">></span>
- <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>
- <span style="color: #0000ff;"></</span><span style="color: #800000;">typeAliases</span><span style="color: #0000ff;">></span>
- <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>
- <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>
- <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>
- <span style="color: #008000;"><!--</span><span style="color: #008000;"> 配置数据库连接信息 </span><span style="color: #008000;">--></span>
- <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>
- <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>
- <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>
- <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>
- <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>
- <span style="color: #0000ff;"></</span><span style="color: #800000;">dataSource</span><span style="color: #0000ff;">></span>
- <span style="color: #0000ff;"></</span><span style="color: #800000;">environment</span><span style="color: #0000ff;">></span>
- <span style="color: #0000ff;"></</span><span style="color: #800000;">environments</span><span style="color: #0000ff;">></span>
- <span style="color: #0000ff;"><</span><span style="color: #800000;">mappers</span><span style="color: #0000ff;">></span>
- <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>
- <span style="color: #0000ff;"></</span><span style="color: #800000;">mappers</span><span style="color: #0000ff;">></span>
- <span style="color: #0000ff;"></</span><span style="color: #800000;">configuration</span><span style="color: #0000ff;">></span>
首先建立数据表,这里就以user表为例 :
- <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;">;
- </span><span style="color: #0000ff;">CREATE</span> <span style="color: #0000ff;">TABLE</span> <span style="color: #ff00ff;">user</span><span style="color: #000000;"> (
- 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,
- 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;">,
- 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;">,
- sex </span><span style="color: #0000ff;">int</span><span style="color: #000000;">,
- email </span><span style="color: #0000ff;">VARCHAR</span>(<span style="color: #800000; font-weight: bold;">32</span><span style="color: #000000;">),
- phone </span><span style="color: #0000ff;">VARCHAR</span>(<span style="color: #800000; font-weight: bold;">16</span><span style="color: #000000;">),
- admin </span><span style="color: #0000ff;">VARCHAR</span>(<span style="color: #800000; font-weight: bold;">16</span><span style="color: #000000;">)
- );</span>
然后新建与数据表对应的类User:
User
- <span style="color: #008000;">/**</span><span style="color: #008000;">
- * User - 用户类
- </span><span style="color: #008000;">*/</span>
- <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">class</span><span style="color: #000000;"> User {
- </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>
- <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>
- <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>
- <span style="color: #0000ff;">private</span> <span style="color: #0000ff;">int</span> id; <span style="color: #008000;">//</span><span style="color: #008000;"> 用户id</span>
- <span style="color: #0000ff;">private</span> String name; <span style="color: #008000;">//</span><span style="color: #008000;"> 用户名</span>
- <span style="color: #0000ff;">private</span> String password; <span style="color: #008000;">//</span><span style="color: #008000;"> 用户密码</span>
- <span style="color: #0000ff;">private</span> <span style="color: #0000ff;">int</span> sex; <span style="color: #008000;">//</span><span style="color: #008000;"> 用户性别</span>
- <span style="color: #0000ff;">private</span> String email; <span style="color: #008000;">//</span><span style="color: #008000;"> 用户邮箱</span>
- <span style="color: #0000ff;">private</span> String phone; <span style="color: #008000;">//</span><span style="color: #008000;"> 用户手机</span>
- <span style="color: #0000ff;">private</span> String admin; <span style="color: #008000;">//</span><span style="color: #008000;"> 用户是否是管理员,"admin"表示是管理员,其他为普通用户</span>
- <span style="color: #0000ff;">public</span><span style="color: #000000;"> User() { }
- </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) {
- </span><span style="color: #0000ff;">this</span>.name =<span style="color: #000000;"> name;
- </span><span style="color: #0000ff;">this</span>.password =<span style="color: #000000;"> password;
- </span><span style="color: #0000ff;">this</span>.sex =<span style="color: #000000;"> sex;
- </span><span style="color: #0000ff;">this</span>.email =<span style="color: #000000;"> email;
- </span><span style="color: #0000ff;">this</span>.phone =<span style="color: #000000;"> phone;
- </span><span style="color: #0000ff;">this</span>.admin = ""<span style="color: #000000;">;
- }
- </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> User(String name, String password, String sex, String email, String phone) {
- </span><span style="color: #0000ff;">this</span>.name =<span style="color: #000000;"> name;
- </span><span style="color: #0000ff;">this</span>.password =<span style="color: #000000;"> password;
- setSex(sex); </span><span style="color: #008000;">//</span><span style="color: #008000;"> this.sex = sex;</span>
- <span style="color: #0000ff;">this</span>.email =<span style="color: #000000;"> email;
- </span><span style="color: #0000ff;">this</span>.phone =<span style="color: #000000;"> phone;
- </span><span style="color: #0000ff;">this</span>.admin = ""<span style="color: #000000;">;
- }
- </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">int</span><span style="color: #000000;"> getId() {
- </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> id;
- }
- </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) {
- </span><span style="color: #0000ff;">this</span>.id =<span style="color: #000000;"> id;
- }
- </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> String getName() {
- </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> name;
- }
- </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> setName(String name) {
- </span><span style="color: #0000ff;">this</span>.name =<span style="color: #000000;"> name;
- }
- </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> String getPassword() {
- </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> password;
- }
- </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> setPassword(String password) {
- </span><span style="color: #0000ff;">this</span>.password =<span style="color: #000000;"> password;
- }
- </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">int</span><span style="color: #000000;"> getSex() {
- </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> sex;
- }
- </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) {
- </span><span style="color: #0000ff;">this</span>.sex =<span style="color: #000000;"> sex;
- }
- </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> setSex(String sexStr) {
- </span><span style="color: #0000ff;">int</span> sex =<span style="color: #000000;"> Integer.valueOf(sexStr);
- </span><span style="color: #0000ff;">switch</span><span style="color: #000000;"> (Integer.valueOf(sexStr)) {
- </span><span style="color: #0000ff;">case</span> 0<span style="color: #000000;">: {
- </span><span style="color: #0000ff;">this</span>.sex =<span style="color: #000000;"> MAN;
- </span><span style="color: #0000ff;">break</span><span style="color: #000000;">;
- }
- </span><span style="color: #0000ff;">case</span> 1<span style="color: #000000;">: {
- </span><span style="color: #0000ff;">this</span>.sex =<span style="color: #000000;"> WOMAN;
- </span><span style="color: #0000ff;">break</span><span style="color: #000000;">;
- }
- </span><span style="color: #0000ff;">default</span><span style="color: #000000;">: {
- </span><span style="color: #0000ff;">this</span>.sex =<span style="color: #000000;"> OTHER;
- </span><span style="color: #0000ff;">break</span><span style="color: #000000;">;
- }
- }
- }
- </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> String getEmail() {
- </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> email;
- }
- </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> setEmail(String email) {
- </span><span style="color: #0000ff;">this</span>.email =<span style="color: #000000;"> email;
- }
- </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> String getPhone() {
- </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> phone;
- }
- </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> setPhone(String phone) {
- </span><span style="color: #0000ff;">this</span>.phone =<span style="color: #000000;"> phone;
- }
- </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> String getAdmin() {
- </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> admin;
- }
- </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> setAdmin(String admin) {
- </span><span style="color: #0000ff;">this</span>.admin =<span style="color: #000000;"> admin;
- }
- @Override
- </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> String toString() {
- </span><span style="color: #0000ff;">return</span> "User{" +
- "id=" + id +
- ", name=‘" + name + ‘\‘‘ +
- ", password=‘" + password + ‘\‘‘ +
- ", sex=" + sex +
- ", email=‘" + email + ‘\‘‘ +
- ", phone=‘" + phone + ‘\‘‘ +
- ", admin=‘" + admin + ‘\‘‘ +
- ‘}‘<span style="color: #000000;">;
- }
- }</span>
再新建usre表的配置文件:
userMapper.xml
- <span style="color: #0000ff;"><?</span><span style="color: #ff00ff;">xml version="1.0" encoding="UTF-8"</span><span style="color: #0000ff;">?></span>
- <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>
- <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>
- <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;">
- SELECT * FROM user WHERE id=#{id}; </span><span style="color: #008000;"><!--</span><span style="color: #008000;"> #{xxx} xxx为类中的数据域名称 </span><span style="color: #008000;">--></span>
- <span style="color: #0000ff;"></</span><span style="color: #800000;">select</span><span style="color: #0000ff;">></span>
- <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;">
- SELECT * FROM user;
- </span><span style="color: #0000ff;"></</span><span style="color: #800000;">select</span><span style="color: #0000ff;">></span>
- <span style="color: #0000ff;"></</span><span style="color: #800000;">mapper</span><span style="color: #0000ff;">></span>
最后新建测试类:
- <span style="color: #008000;">/**</span><span style="color: #008000;">
- * MyBatis测试类
- </span><span style="color: #008000;">*/</span>
- <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">class</span><span style="color: #000000;"> TestMain {
- </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 {
- String resouce </span>= "conf.xml"<span style="color: #000000;">;
- InputStream is </span>=<span style="color: #000000;"> Resources.getResourceAsStream(resouce);
- </span><span style="color: #008000;">//</span><span style="color: #008000;"> 构建sqlSession工厂</span>
- SqlSessionFactory sqlSessionFactory = <span style="color: #0000ff;">new</span><span style="color: #000000;"> SqlSessionFactoryBuilder().build(is);
- </span><span style="color: #008000;">//</span><span style="color: #008000;"> 获取sqlSession</span>
- SqlSession session =<span style="color: #000000;"> sqlSessionFactory.openSession();
- User user;
- </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> {
- </span><span style="color: #008000;">/**</span><span style="color: #008000;">
- * 第一种方式: 直接执行已映射的 SQL 语句
- </span><span style="color: #008000;">*/</span><span style="color: #000000;">
- String statement </span>= "com.luoxn28.dao.UserDao.getById"<span style="color: #000000;">;
- user </span>= session.selectOne(statement, 1<span style="color: #000000;">);
- System.out.println(user);
- }
- </span><span style="color: #0000ff;">finally</span><span style="color: #000000;"> {
- session.close();
- }
- </span><span style="color: #008000;">/**</span><span style="color: #008000;">
- * 第二种方式: 执行更清晰和类型安全的代码
- </span><span style="color: #008000;">*/</span>
- <span style="color: #008000;">//</span><span style="color: #008000;"> UserDao userDao = session.getMapper(UserDao.class);
- </span><span style="color: #008000;">//</span><span style="color: #008000;"> user = userDao.getById(1);
- </span><span style="color: #008000;">//</span><span style="color: #008000;"> System.out.println(user);</span>
- <span style="color: #000000;"> }
- }</span>
由于我们分析的是SQL的执行流程,那就重点关注下 user = session.selectOne(statement, 1); 这行代码~ 注意,传进去的参数是1。
session是DefaultSqlSession类型的,因为sqlSessionFactory默认生成的SqlSession是DefaultSqlSession类型。selectOne()会调用selectList()。
- <span style="color: #008000;">//</span><span style="color: #008000;"> DefaultSqlSession类</span>
- <span style="color: #0000ff;">public</span> <E> List<E><span style="color: #000000;"> selectList(String statement, Object parameter, RowBounds rowBounds) {
- </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> {
- MappedStatement ms </span>=<span style="color: #000000;"> configuration.getMappedStatement(statement);
- </span><span style="color: #008000;">//</span><span style="color: #008000;"> CURD操作是交给Excetor去处理的</span>
- <span style="color: #0000ff;">return</span><span style="color: #000000;"> executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
- } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (Exception e) {
- </span><span style="color: #0000ff;">throw</span> ExceptionFactory.wrapException("Error querying database. Cause: " +<span style="color: #000000;"> e, e);
- } </span><span style="color: #0000ff;">finally</span><span style="color: #000000;"> {
- ErrorContext.instance().reset();
- }
- }</span>
在DefaultSqlSession.selectList中的各种CURD操作都是通多Executor进行的,这里executor的类型是CachingExecutor,接着跳转到其中的query方法中。
- <span style="color: #008000;">//</span><span style="color: #008000;"> CachingExecutor 类</span>
- <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 {
- BoundSql boundSql </span>= ms.getBoundSql(parameterObject); <span style="color: #008000;">//</span><span style="color: #008000;"> 获取绑定的sql命令,比如"SELECT * FROM xxx"</span>
- CacheKey key =<span style="color: #000000;"> createCacheKey(ms, parameterObject, rowBounds, boundSql);
- </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
- }</span>
getBoundSql为了获取绑定的sql命令,在创建完cacheKey之后,就进入到CachingExecutor 类中的另一个query方法中。
- <span style="color: #008000;">//</span><span style="color: #008000;"> CachingExecutor 类</span>
- <span style="color: #000000;">@Override
- </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)
- </span><span style="color: #0000ff;">throws</span><span style="color: #000000;"> SQLException {
- Cache cache </span>=<span style="color: #000000;"> ms.getCache();
- </span><span style="color: #0000ff;">if</span> (cache != <span style="color: #0000ff;">null</span><span style="color: #000000;">) {
- flushCacheIfRequired(ms);
- </span><span style="color: #0000ff;">if</span> (ms.isUseCache() && resultHandler == <span style="color: #0000ff;">null</span><span style="color: #000000;">) {
- ensureNoOutParams(ms, parameterObject, boundSql);
- @SuppressWarnings(</span>"unchecked"<span style="color: #000000;">)
- List</span><E> list = (List<E><span style="color: #000000;">) tcm.getObject(cache, key);
- </span><span style="color: #0000ff;">if</span> (list == <span style="color: #0000ff;">null</span><span style="color: #000000;">) {
- list </span>= delegate.<E><span style="color: #000000;"> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
- tcm.putObject(cache, key, list); </span><span style="color: #008000;">//</span><span style="color: #008000;"> issue #578 and #116</span>
- <span style="color: #000000;"> }
- </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> list;
- }
- }
- </span><span style="color: #0000ff;">return</span> delegate.<E><span style="color: #000000;"> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
- }</span>
这里真正执行query操作的是SimplyExecutor代理来完成的,接着就进入到了SimplyExecutor的父类BaseExecutor的query方法中。
- <span style="color: #008000;">//</span><span style="color: #008000;"> SimplyExecutor的父类BaseExecutor类</span>
- @SuppressWarnings("unchecked"<span style="color: #000000;">)
- @Override
- </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 {
- ErrorContext.instance().resource(ms.getResource()).activity(</span>"executing a query"<span style="color: #000000;">).object(ms.getId());
- </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (closed) {
- </span><span style="color: #0000ff;">throw</span> <span style="color: #0000ff;">new</span> ExecutorException("Executor was closed."<span style="color: #000000;">);
- }
- </span><span style="color: #0000ff;">if</span> (queryStack == 0 &&<span style="color: #000000;"> ms.isFlushCacheRequired()) {
- clearLocalCache();
- }
- List</span><E><span style="color: #000000;"> list;
- </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> {
- queryStack</span>++<span style="color: #000000;">;
- </span><span style="color: #008000;">/**</span><span style="color: #008000;">
- * localCache是一级缓存,如果找不到就调用queryFromDatabase从数据库中查找
- </span><span style="color: #008000;">*/</span><span style="color: #000000;">
- list </span>= resultHandler == <span style="color: #0000ff;">null</span> ? (List<E>) localCache.getObject(key) : <span style="color: #0000ff;">null</span><span style="color: #000000;">;
- </span><span style="color: #0000ff;">if</span> (list != <span style="color: #0000ff;">null</span><span style="color: #000000;">) {
- handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
- } </span><span style="color: #0000ff;">else</span><span style="color: #000000;"> {
- list </span>=<span style="color: #000000;"> queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
- }
- } </span><span style="color: #0000ff;">finally</span><span style="color: #000000;"> {
- queryStack</span>--<span style="color: #000000;">;
- }
- </span><span style="color: #0000ff;">if</span> (queryStack == 0<span style="color: #000000;">) {
- </span><span style="color: #0000ff;">for</span><span style="color: #000000;"> (DeferredLoad deferredLoad : deferredLoads) {
- deferredLoad.load();
- }
- </span><span style="color: #008000;">//</span><span style="color: #008000;"> issue #601</span>
- <span style="color: #000000;"> deferredLoads.clear();
- </span><span style="color: #0000ff;">if</span> (configuration.getLocalCacheScope() ==<span style="color: #000000;"> LocalCacheScope.STATEMENT) {
- </span><span style="color: #008000;">//</span><span style="color: #008000;"> issue #482</span>
- <span style="color: #000000;"> clearLocalCache();
- }
- }
- </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> list;
- }</span>
因为是第一次SQL查询操作,所以会调用queryFromDatabase方法来执行查询。
- <span style="color: #008000;">//</span><span style="color: #008000;"> SimplyExecutor的父类BaseExecutor类</span>
- <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 {
- List</span><E><span style="color: #000000;"> list;
- localCache.putObject(key, EXECUTION_PLACEHOLDER);
- </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> {
- list </span>=<span style="color: #000000;"> doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
- } </span><span style="color: #0000ff;">finally</span><span style="color: #000000;"> {
- localCache.removeObject(key);
- }
- localCache.putObject(key, list);
- </span><span style="color: #0000ff;">if</span> (ms.getStatementType() ==<span style="color: #000000;"> StatementType.CALLABLE) {
- localOutputParameterCache.putObject(key, parameter);
- }
- </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> list;
- }</span>
从数据库中查询数据,进入到SimplyExecutor中进行操作。
- <span style="color: #008000;">//</span><span style="color: #008000;"> SimplyExecutor类</span>
- <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 {
- Statement stmt </span>= <span style="color: #0000ff;">null</span><span style="color: #000000;">;
- </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> {
- Configuration configuration </span>=<span style="color: #000000;"> ms.getConfiguration();
- StatementHandler handler </span>=<span style="color: #000000;"> configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
- </span><span style="color: #008000;">//</span><span style="color: #008000;"> 子流程1:SQL查询参数的设置</span>
- stmt =<span style="color: #000000;"> prepareStatement(handler, ms.getStatementLog());
- </span><span style="color: #008000;">//</span><span style="color: #008000;"> StatementHandler封装了Statement
- </span><span style="color: #008000;">//</span><span style="color: #008000;"> 子流程2:SQL查询操作和结果集的封装</span>
- <span style="color: #0000ff;">return</span> handler.<E><span style="color: #000000;">query(stmt);
- } </span><span style="color: #0000ff;">finally</span><span style="color: #000000;"> {
- closeStatement(stmt);
- }
- }</span>
注意,在prepareStatement方法中会进行SQL查询参数的设置,也就是咱们最开始传递进来的参数,其值为1。handler.<E>query(stmt)方法中会进行实际的SQL查询操作和结果集的封装(封装成Java对象)。当流程走到这里时,程序已经压栈有一定深度了,因为接下来程序分析会兵分两路,一方面深入到SQL查询及结果集的设置子流程1中,然后再深入到SQL查询操作和结果集的封装子流程2,因为还会回到这里,所以就来一张调用栈的特写吧:
子流程1:SQL查询参数的设置
- <span style="color: #008000;">//</span><span style="color: #008000;"> SimplyExecutor类</span>
- <span style="color: #0000ff;">private</span> Statement prepareStatement(StatementHandler handler, Log statementLog) <span style="color: #0000ff;">throws</span><span style="color: #000000;"> SQLException {
- Statement stmt;
- </span><span style="color: #008000;">//</span><span style="color: #008000;"> 获取一个Connection</span>
- Connection connection =<span style="color: #000000;"> getConnection(statementLog);
- stmt </span>=<span style="color: #000000;"> handler.prepare(connection, transaction.getTimeout());
- handler.parameterize(stmt); </span><span style="color: #008000;">//</span><span style="color: #008000;"> 设置SQL查询中的参数值</span>
- <span style="color: #0000ff;">return</span><span style="color: #000000;"> stmt;
- }</span>
通过getConnection方法来获取一个Connection,调用prepare方法来获取一个Statement(这里的handler类型是RoutingStatementHandler,RoutingStatementHandler的prepare方法调用的是PrepareStatementHandler的prepare方法,因为PrepareStatementHandler并没有覆盖其父类的prepare方法,其实最后调用的是BaseStatementHandler中的prepare方法。是不是绕晕了,那就再看一遍吧 :) )。调用parameterize方法来设置SQL的参数值(这里最后调用的是PrepareStatementHandler中的parameterize方法,而PrepareStatementHandler.parameterize方法调用的是DefaultParameterHandler中的setParameters方法)。
- <span style="color: #008000;">//</span><span style="color: #008000;"> PrepareStatementHandler类</span>
- <span style="color: #000000;">@Override
- </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 {
- parameterHandler.setParameters((PreparedStatement) statement);
- }</span>
- <span style="color: #008000;">//</span><span style="color: #008000;"> DefaultParameterHandler类</span>
- <span style="color: #000000;">@Override
- </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> setParameters(PreparedStatement ps) {
- ErrorContext.instance().activity(</span>"setting parameters"<span style="color: #000000;">).object(mappedStatement.getParameterMap().getId());
- List</span><ParameterMapping> parameterMappings =<span style="color: #000000;"> boundSql.getParameterMappings();
- </span><span style="color: #0000ff;">if</span> (parameterMappings != <span style="color: #0000ff;">null</span><span style="color: #000000;">) {
- </span><span style="color: #0000ff;">for</span> (<span style="color: #0000ff;">int</span> i = 0; i < parameterMappings.size(); i++<span style="color: #000000;">) {
- ParameterMapping parameterMapping </span>=<span style="color: #000000;"> parameterMappings.get(i);
- </span><span style="color: #0000ff;">if</span> (parameterMapping.getMode() !=<span style="color: #000000;"> ParameterMode.OUT) {
- Object value;
- String propertyName </span>=<span style="color: #000000;"> parameterMapping.getProperty();
- </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>
- value =<span style="color: #000000;"> boundSql.getAdditionalParameter(propertyName);
- } </span><span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span> (parameterObject == <span style="color: #0000ff;">null</span><span style="color: #000000;">) {
- value </span>= <span style="color: #0000ff;">null</span><span style="color: #000000;">;
- } </span><span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span><span style="color: #000000;"> (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
- value </span>=<span style="color: #000000;"> parameterObject;
- } </span><span style="color: #0000ff;">else</span><span style="color: #000000;"> {
- MetaObject metaObject </span>=<span style="color: #000000;"> configuration.newMetaObject(parameterObject);
- value </span>=<span style="color: #000000;"> metaObject.getValue(propertyName);
- }
- TypeHandler typeHandler </span>=<span style="color: #000000;"> parameterMapping.getTypeHandler();
- JdbcType jdbcType </span>=<span style="color: #000000;"> parameterMapping.getJdbcType();
- </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;">) {
- jdbcType </span>=<span style="color: #000000;"> configuration.getJdbcTypeForNull();
- }
- </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> {
- typeHandler.setParameter(ps, i </span>+ 1<span style="color: #000000;">, value, jdbcType);
- } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (TypeException e) {
- </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);
- } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (SQLException e) {
- </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);
- }
- }
- }
- }
- }</span>
到这里为止,已经给Statement设置了最初传递进去的参数(值为1)了,那么接着分析流程2:
流程2:SQL查询及结果集的设置
- <span style="color: #008000;">//</span><span style="color: #008000;"> RoutingStatementHandler类</span>
- <span style="color: #000000;">@Override
- </span><span style="color: #0000ff;">public</span> <E> List<E> query(Statement statement) <span style="color: #0000ff;">throws</span><span style="color: #000000;"> SQLException {
- </span><span style="color: #0000ff;">return</span> delegate.<E><span style="color: #000000;">query(statement);
- }</span>
- <span style="color: #008000;">//</span><span style="color: #008000;"> RoutingStatementHandler类</span>
- <span style="color: #000000;">@Override
- </span><span style="color: #0000ff;">public</span> <E> List<E> query(Statement statement) <span style="color: #0000ff;">throws</span><span style="color: #000000;"> SQLException {
- </span><span style="color: #008000;">//</span><span style="color: #008000;"> 这里就到了熟悉的PreparedStatement了</span>
- PreparedStatement ps =<span style="color: #000000;"> (PreparedStatement) statement;
- </span><span style="color: #008000;">//</span><span style="color: #008000;"> 执行SQL查询操作</span>
- <span style="color: #000000;"> ps.execute();
- </span><span style="color: #008000;">//</span><span style="color: #008000;"> 结果交给ResultHandler来处理</span>
- <span style="color: #0000ff;">return</span> resultSetHandler.<E><span style="color: #000000;"> handleResultSets(ps);
- }</span>
- <span style="color: #008000;">//</span><span style="color: #008000;"> DefaultResultSetHandler类(封装返回值,将查询结果封装成Object对象)</span>
- <span style="color: #000000;">@Override
- </span><span style="color: #0000ff;">public</span> List<Object> handleResultSets(Statement stmt) <span style="color: #0000ff;">throws</span><span style="color: #000000;"> SQLException {
- ErrorContext.instance().activity(</span>"handling results"<span style="color: #000000;">).object(mappedStatement.getId());
- </span><span style="color: #0000ff;">final</span> List<Object> multipleResults = <span style="color: #0000ff;">new</span> ArrayList<Object><span style="color: #000000;">();
- </span><span style="color: #0000ff;">int</span> resultSetCount = 0<span style="color: #000000;">;
- ResultSetWrapper rsw </span>=<span style="color: #000000;"> getFirstResultSet(stmt);
- List</span><ResultMap> resultMaps =<span style="color: #000000;"> mappedStatement.getResultMaps();
- </span><span style="color: #0000ff;">int</span> resultMapCount =<span style="color: #000000;"> resultMaps.size();
- validateResultMapsCount(rsw, resultMapCount);
- </span><span style="color: #0000ff;">while</span> (rsw != <span style="color: #0000ff;">null</span> && resultMapCount ><span style="color: #000000;"> resultSetCount) {
- ResultMap resultMap </span>=<span style="color: #000000;"> resultMaps.get(resultSetCount);
- handleResultSet(rsw, resultMap, multipleResults, </span><span style="color: #0000ff;">null</span><span style="color: #000000;">);
- rsw </span>=<span style="color: #000000;"> getNextResultSet(stmt);
- cleanUpAfterHandlingResultSet();
- resultSetCount</span>++<span style="color: #000000;">;
- }
- String[] resultSets </span>=<span style="color: #000000;"> mappedStatement.getResultSets();
- </span><span style="color: #0000ff;">if</span> (resultSets != <span style="color: #0000ff;">null</span><span style="color: #000000;">) {
- </span><span style="color: #0000ff;">while</span> (rsw != <span style="color: #0000ff;">null</span> && resultSetCount <<span style="color: #000000;"> resultSets.length) {
- ResultMapping parentMapping </span>=<span style="color: #000000;"> nextResultMaps.get(resultSets[resultSetCount]);
- </span><span style="color: #0000ff;">if</span> (parentMapping != <span style="color: #0000ff;">null</span><span style="color: #000000;">) {
- String nestedResultMapId </span>=<span style="color: #000000;"> parentMapping.getNestedResultMapId();
- ResultMap resultMap </span>=<span style="color: #000000;"> configuration.getResultMap(nestedResultMapId);
- handleResultSet(rsw, resultMap, </span><span style="color: #0000ff;">null</span><span style="color: #000000;">, parentMapping);
- }
- rsw </span>=<span style="color: #000000;"> getNextResultSet(stmt);
- cleanUpAfterHandlingResultSet();
- resultSetCount</span>++<span style="color: #000000;">;
- }
- }
- </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> collapseSingleResultList(multipleResults);
- }</span>
ResultSetWrapper是ResultSet的包装类,调用getFirstResultSet方法获取第一个ResultSet,同时获取数据库的MetaData数据,包括数据表列名、列的类型、类序号等,这些信息都存储在ResultSetWrapper类中了。然后调用handleResultSet方法来来进行结果集的封装。
- <span style="color: #008000;">//</span><span style="color: #008000;"> DefaultResultSetHandler类</span>
- <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 {
- </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> {
- </span><span style="color: #0000ff;">if</span> (parentMapping != <span style="color: #0000ff;">null</span><span style="color: #000000;">) {
- handleRowValues(rsw, resultMap, </span><span style="color: #0000ff;">null</span><span style="color: #000000;">, RowBounds.DEFAULT, parentMapping);
- } </span><span style="color: #0000ff;">else</span><span style="color: #000000;"> {
- </span><span style="color: #0000ff;">if</span> (resultHandler == <span style="color: #0000ff;">null</span><span style="color: #000000;">) {
- DefaultResultHandler defaultResultHandler </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> DefaultResultHandler(objectFactory);
- handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, </span><span style="color: #0000ff;">null</span><span style="color: #000000;">);
- multipleResults.add(defaultResultHandler.getResultList());
- } </span><span style="color: #0000ff;">else</span><span style="color: #000000;"> {
- handleRowValues(rsw, resultMap, resultHandler, rowBounds, </span><span style="color: #0000ff;">null</span><span style="color: #000000;">);
- }
- }
- } </span><span style="color: #0000ff;">finally</span><span style="color: #000000;"> {
- </span><span style="color: #008000;">//</span><span style="color: #008000;"> issue #228 (close resultsets)</span>
- <span style="color: #000000;"> closeResultSet(rsw.getResultSet());
- }
- }</span>
这里调用handleRowValues方法来进行值的设置:
- <span style="color: #008000;">//</span><span style="color: #008000;"> DefaultResultSetHandler类</span>
- <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 {
- </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (resultMap.hasNestedResultMaps()) {
- ensureNoRowBounds();
- checkResultHandler();
- handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
- } </span><span style="color: #0000ff;">else</span><span style="color: #000000;"> {
- </span><span style="color: #008000;">//</span><span style="color: #008000;"> 封装数据</span>
- <span style="color: #000000;"> handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
- }
- }</span>
- <span style="color: #008000;">//</span><span style="color: #008000;"> DefaultResultSetHandler类
- </span><span style="color: #008000;">//</span><span style="color: #008000;"> 封装数据</span>
- <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)
- </span><span style="color: #0000ff;">throws</span><span style="color: #000000;"> SQLException {
- DefaultResultContext</span><Object> resultContext = <span style="color: #0000ff;">new</span> DefaultResultContext<Object><span style="color: #000000;">();
- skipRows(rsw.getResultSet(), rowBounds);
- </span><span style="color: #0000ff;">while</span> (shouldProcessMoreRows(resultContext, rowBounds) &&<span style="color: #000000;"> rsw.getResultSet().next()) {
- ResultMap discriminatedResultMap </span>= resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, <span style="color: #0000ff;">null</span><span style="color: #000000;">);
- Object rowValue </span>=<span style="color: #000000;"> getRowValue(rsw, discriminatedResultMap);
- storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
- }
- }</span>
- <span style="color: #008000;">//</span><span style="color: #008000;"> DefaultResultSetHandler类</span>
- <span style="color: #0000ff;">private</span> Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap) <span style="color: #0000ff;">throws</span><span style="color: #000000;"> SQLException {
- </span><span style="color: #0000ff;">final</span> ResultLoaderMap lazyLoader = <span style="color: #0000ff;">new</span><span style="color: #000000;"> ResultLoaderMap();
- </span><span style="color: #008000;">//</span><span style="color: #008000;"> createResultObject为新创建的对象,数据表对应的类</span>
- Object resultObject = createResultObject(rsw, resultMap, lazyLoader, <span style="color: #0000ff;">null</span><span style="color: #000000;">);
- </span><span style="color: #0000ff;">if</span> (resultObject != <span style="color: #0000ff;">null</span> && !<span style="color: #000000;">hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
- </span><span style="color: #0000ff;">final</span> MetaObject metaObject =<span style="color: #000000;"> configuration.newMetaObject(resultObject);
- </span><span style="color: #0000ff;">boolean</span> foundValues = !<span style="color: #000000;">resultMap.getConstructorResultMappings().isEmpty();
- </span><span style="color: #0000ff;">if</span> (shouldApplyAutomaticMappings(resultMap, <span style="color: #0000ff;">false</span><span style="color: #000000;">)) {
- </span><span style="color: #008000;">//</span><span style="color: #008000;"> 这里把数据填充进去,metaObject中包含了resultObject信息</span>
- foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, <span style="color: #0000ff;">null</span>) ||<span style="color: #000000;"> foundValues;
- }
- foundValues </span>= applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, <span style="color: #0000ff;">null</span>) ||<span style="color: #000000;"> foundValues;
- foundValues </span>= lazyLoader.size() > 0 ||<span style="color: #000000;"> foundValues;
- resultObject </span>= foundValues ? resultObject : <span style="color: #0000ff;">null</span><span style="color: #000000;">;
- </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> resultObject;
- }
- </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> resultObject;
- }</span>
- <span style="color: #008000;">//</span><span style="color: #008000;"> DefaultResultSetHandler类(把ResultSet中查询结果填充到JavaBean中)</span>
- <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 {
- List</span><UnMappedColumnAutoMapping> autoMapping =<span style="color: #000000;"> createAutomaticMappings(rsw, resultMap, metaObject, columnPrefix);
- </span><span style="color: #0000ff;">boolean</span> foundValues = <span style="color: #0000ff;">false</span><span style="color: #000000;">;
- </span><span style="color: #0000ff;">if</span> (autoMapping.size() > 0<span style="color: #000000;">) {
- </span><span style="color: #008000;">//</span><span style="color: #008000;"> 这里进行for循环调用,因为user表中总共有7项,所以也就调用7次</span>
- <span style="color: #0000ff;">for</span><span style="color: #000000;"> (UnMappedColumnAutoMapping mapping : autoMapping) {
- </span><span style="color: #008000;">//</span><span style="color: #008000;"> 这里将esultSet中查询结果转换为对应的实际类型</span>
- <span style="color: #0000ff;">final</span> Object value =<span style="color: #000000;"> mapping.typeHandler.getResult(rsw.getResultSet(), mapping.column);
- </span><span style="color: #0000ff;">if</span> (value != <span style="color: #0000ff;">null</span><span style="color: #000000;">) {
- foundValues </span>= <span style="color: #0000ff;">true</span><span style="color: #000000;">;
- }
- </span><span style="color: #0000ff;">if</span> (value != <span style="color: #0000ff;">null</span> || (configuration.isCallSettersOnNulls() && !<span style="color: #000000;">mapping.primitive)) {
- </span><span style="color: #008000;">//</span><span style="color: #008000;"> gcode issue #377, call setter on nulls (value is not ‘found‘)</span>
- <span style="color: #000000;"> metaObject.setValue(mapping.property, value);
- }
- }
- }
- </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> foundValues;
- }</span>
mapping.typeHandler.getResult会获取查询结果值的实际类型,比如我们user表中id字段为int类型,那么它就对应Java中的Integer类型,然后通过调用statement.getInt("id")来获取其int值,其类型为Integer。metaObject.setValue方法会把获取到的Integer值设置到Java类中的对应字段。
- <span style="color: #008000;">//</span><span style="color: #008000;"> MetaObject类</span>
- <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> setValue(String name, Object value) {
- PropertyTokenizer prop </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> PropertyTokenizer(name);
- </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (prop.hasNext()) {
- MetaObject metaValue </span>=<span style="color: #000000;"> metaObjectForProperty(prop.getIndexedName());
- </span><span style="color: #0000ff;">if</span> (metaValue ==<span style="color: #000000;"> SystemMetaObject.NULL_META_OBJECT) {
- </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;">) {
- </span><span style="color: #008000;">//</span><span style="color: #008000;"> don‘t instantiate child path if value is null</span>
- <span style="color: #0000ff;">return</span><span style="color: #000000;">;
- } </span><span style="color: #0000ff;">else</span><span style="color: #000000;"> {
- metaValue </span>=<span style="color: #000000;"> objectWrapper.instantiatePropertyValue(name, prop, objectFactory);
- }
- }
- metaValue.setValue(prop.getChildren(), value);
- } </span><span style="color: #0000ff;">else</span><span style="color: #000000;"> {
- objectWrapper.set(prop, value);
- }
- }</span>
metaValue.setValue方法最后会调用到Java类中对应数据域的set方法,这样也就完成了SQL查询结果集的Java类封装过程。最后贴一张调用栈到达Java类的set方法中的快照:
参考:
1、MyBatis源码
2、《深入分析Java Web技术内幕》的iBatis章节
3、《深入理解mybatis原理》 MyBatis的架构设计以及实例分析
4、
Java JDBC基础学习小结
MyBatis源码分析-SQL语句执行的完整流程
标签: