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 {

*  ListgetUserList();

* }

*

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

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

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

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

*

* 2、 buildSqlSessionFactory做了两件事情:

*          *    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;

}

}

你可能感兴趣的:(mybatis实现原理)