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
* }
*
* 1、 mybatis都是以sqlSessionFactory为中心展开的,在初始化sqlSessionFactory时指定的SqlSessionFactoryBean
* 实现了initializingBean接口,通过afterPropertiesSet执行this.sqlSessionFactory = buildSqlSessionFactory();
* 这里会初始化xml的解析和数据库连接dataSource。
* 即可查看SqlSessionFactory接口里的两个方法openSession,getConfiguration
*
* 2、 buildSqlSessionFactory做了两件事情:
*
* 这里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!=nullid=#{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;
}
}