mybatis实现原理

package com.zheng.mybatis.construction;

import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.PreparedStatement;

import java.sql.ResultSet;

import java.util.List;

import java.util.Map;

import org.apache.ibatis.mapping.ParameterMapping;

import org.apache.ibatis.reflection.MetaObject;

/**

* @author ZHENGJIMIN073

* @date 2019/6/26 9:24

*

* public interface UserMapper {

*  List<User>getUserList();

* }

*

* 1、 mybatis都是以sqlSessionFactory为中心展开的,在初始化sqlSessionFactory时指定的SqlSessionFactoryBean

*    实现了initializingBean接口,通过afterPropertiesSet执行this.sqlSessionFactory = buildSqlSessionFactory();

*    这里会初始化xml的解析和数据库连接dataSource。

*    即可查看SqlSessionFactory接口里的两个方法openSession,getConfiguration

*

* 2、 buildSqlSessionFactory做了两件事情:

*          <property name="basePackage" value="com.zheng.mybatis.dao.UserMapper" />*    a)将配置文件的property属性中加载各种组件(如分页的plugins),basePackage的Mapper接口bean初始化等将这些信息解析到configuration中

*        这里Mapper接口注册为beanDefinition对象,beanDefinition对象的beanClass为MapperFactoryBean.class,beanName为userMapper。

*        MapperFactoryBean实现了FactoryBean接口,俗称工厂Bean。即在IOC初始化时通过@Autowired注入对应的dao接口时。

*        返回的对象就是MapperFactoryBean这个工厂bean中的getObject()方法对象。其实getObject() 放回的都是mapper接口的代理类

*    b)加载mapper文件mapperLocations,解析SQL,封装成MappedStatement 对象封装到configuration中

*        通过解析里面的select/delete/update/insert节点,每个节点生成一个MappedStatement对象(key为namespace+id),将其配置到configuration中

*        所以MappedStatement中保存了mapper.xml里面所有的SQL节点,即每一个节点对应一个MappedStatement对象。

*          i) 我们来看下保存sql对的SqlSource对象,sqlSource有一个方法getBoundSql(),而动态生成的各种sqlNode也在sqlSource对象里

*          ii) 静态sql生成staticSqlSource对象,就是生成一个静态sql语句。

*          iii) 动态sql生产DynamicSqlSource对象,比如select * from user WHERE id=#{id}

*              解析中做了两件事,1、将SQL语句中的#{}替换为占位符 2、将#{}里面的字段封装成ParameterMapping对象,添加到parameterMappings。

*              ParameterMapping对象保存的就是参数的类型信息,如果没有配置则为null。 ParameterMapping{property='id', mode=IN, javaType=class java.lang.Object, jdbcType=null, numericScale=null, resultMapId='null', jdbcTypeName='null', expression='null'}

*              最后返回的BoundSql对象就包含一个带有占位符的SQL和参数的具体信息

*

*  3、mybatis的执行SQL过程其实是将JDBC实现方式都通过JDK动态代理封装了一层。

*      a) sqlSession的代理类为sqlSessionProxy,这里的处理器程序为SqlSessionInterceptor(),这里最终会在setSqlSessionFactory这里方法里,sqlSession获得SqlSessionTemplate

*      在SqlSessionTemplate主要包含sqlSessionFactory和sqlSessionProxy。即在设置sqlSessionFactory中调用SqlSessionTemplate构造方法和创建sqlSession接口的代理类

*      b) 每个mapper接口对应的都是自身的代理类,都会通过getObject()方法获得mapper接口的代理类。这里实际处理器为MapperProxy.invoke(Object proxy, Method method, Object[] args)。

*      c) getConnection方法就是获取Connection连接的代理,其代理类的处理器为ConnectionLogger

*      d) prepareStatement(sql)方法其代理类处理器为PreparedStatementLogger,最终执行execute方法,打印对象的参数log。String sql = boundSql.getSql();connection.prepareStatement(sql);

*          mybatis设置的参数,它是根据参数在java类型获取所有jdbc类型的处理器,再根据jdbc的类型获取对应的处理器

*

*  4、总结下mybatis执行方法的整个过程

*      a) 获取sqlSession对象,根据方法的返回类型调用不同的方法,比如是selectList还是selectOne

*      b) 在MappedStatement中获取BoundSql对象,根据传递的参数生产sql语句

*      c) 从数据库连接池中获取Connection对象,并为其创建代理(这里其实可以就是JDBC的各种对象代理),打印log,并执行invoke方法

*      d) 从Connection中获取PreparedStatement预编译对象,并为其创建对象

*      e) 预编译sql,并设置参数

*      f) 执行、返回数据集合

*      g) 将数据集转化为java对象

*/

/*

select * from user where

id=#{id}

order by id

比如上面的select封装的对象dynamicSqlSource由以下3部分组成为:

1、staticTextSqlNode对象=select * from user

2、sqlNode(IfSqlNode)test:id!=nullid=#{id}

3、staticTextSqlNode对象=order by id

* */

    class BoundSql {

//动态生成的SQL,解析完毕带有占位性的SQL

            private final Stringsql =null;

//每个参数的信息。比如参数名称、输入/输出类型、对应的JDBC类型等

            private final ListparameterMappings  =null;

//参数

            private final ObjectparameterObject  =null;

private final MapadditionalParameters  =null;

private final MetaObjectmetaParameters =null;

}

public class mybatisConstruction {

public static void main(String[] args)throws Exception {

Connection conn =getConnection();

String sql ="select * from user where 1=1 and id = ?";

PreparedStatement stmt = conn.prepareStatement(sql);

stmt.setString(1,"501440165655347200");

ResultSet rs = stmt.executeQuery();

while(rs.next()){

String username = rs.getString("username");

System.out.print("姓名: " + username);

}

}

private static Connection getConnection(){

Connection conn =null;

try {

Class.forName("");

conn = DriverManager.getConnection("");

}catch (Exception e) {

e.printStackTrace();

}

return conn;

}

}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容