Mybatis 也是遵循 JDBC 规范的。
nputStream in=Resource.setAsStream("sqlMapConfig,xml");
SqlSessionFactory sqlsessionfactory=new SqlSessionFactoryBuilder.build(in);
SqlSession sqlsession=sqlsessionfactory.opensession();
全局配置文件源码解析
sqlMapConfig.xml 中 有 <configuration> </configuration>
节点,会被解析成 Configuration 类的对象,这个对象十分重要,它是全局的配置对象,保存的是 MyBatis 所有的配置文件和接口。
先看 SqlSessionFactoryBuilder 的 build() 方法中,有个 XMLConfigBuilder,会先对 XML 文件进行解析 : parse() 解析每个子节点,得到一个 Configuration对象,然后再调用 build 方法,会返回一个默认的 DefaultsqlSessionFactory 。
而如何解析 mappers 这个子节点呢? 是 mapperElement(XNode parent) 方法,先遍历子节点,mapper 的子节点有两种:<mappers> <mapper> / <package>【包】 </mappers>
,会到相应的逻辑进行解析。
mapper配置文件源码解析
如果是 节点,先获取属性,有 3 个,
<mapper resource> ... resource /或是 url / 或是class </mapper>.
,只能配置一个。
【包】:定义了所有的 mapper 都是在这个包下,而这个包还有 类、接口,当然还有 xml,所以 Mybatis 是调用 configuration 的 addMappers(mapperPackage),把 mappers 加到全局配置变量中,是从包中扫描内所有的类和接口,而不扫描 XML,接下来判断是否接口 isInterface(),只获取到接口,接下来会解析接口,具体是:先判断 isResourceLoaded( resource ),判断是否已经加载过,没有的话调用 loadResource(),这里的资源指的是 XML 资源。
SQL语句执行流程源码解析
是在 configurationElement(XNode context)中有 sqlElement(context.evalNodes(/mapper/sql)),就能解析到 SQL 语句,然后接下来执行 buildStatementFromContext(context.evalNodes(select|insert|update|delete))
${} 与 #{}
(
#将传入的数据都当成一个字符串,会对传入的数据自动加上引号;
$将传入的数据直接显示生成在 SQL 中。
)
Mybatis 会把 SQL 语句先转化成 Sqlsource:
带 “#
” 是静态的 Sqlsource ,在解析配置文件的时候把 #{ }
替换成 “?
”,执行SQL 的时候会给 “?
” 进行赋值,。
SQL语句中带有 “${ }
” 的是动态Sqlsource ,只要有一个 “$
”,就会当成动态 Sqlsource,在解析配置文件的时候不会翻译成 “?”,仍保存原来的 SQL 语句,执行的时候才会给 “${ }
” 替换成变量的值 ,而如果有 “#{ }
“会经过
BoundSql boundSql=prepareStatement.getBoundSql(parameterObject);
,就会把”#{ }
“改成”?
”,(也就是说,只要有#{ }
的话,解析时就变成"?
"了),“${ }
”会导致 SQL注入的。
SqlSessionFactory sqlsessionfactory=new SqlSessionFactory();
SqlSession sqlsession=sqlsessionfactory.openSession();
这里返回的是 一个默认的 DefaultsqlSessionFactory ,然后会调用sqlsession 的 getmapper(UserMapper.class) 方法,会构造一个代理对象,后续调用代理对象的方法,有通过代理工厂 new 一个实例:mapperProxyFactory.newInstance(sqlsession)
mapperProxyFactory 中的源码:
protected T newInstance(MapperProxy<T> mapperProxy)
{
return(T) Proxy.newProxyInstance(mapperInterface.getClassLoader,new Class[ ] {mapperInterface},mapperProxy);
}
public T newInstance(SqlSession sqlSession)
{
funal MapperProxy<T> mapperProxy = new MrapperProxy<>(sqlSession,mapperInterface,methodCache);
}
mapperProxy 是实现了 InvocationHandler 接口的,它有实现 invoke 方法。这个方法中正是实现了 SQL 的执行过程。
会根据调用的方法,比如 select、delete、update、insert,会生成 MapperStatement 对象,每个对象对应一个 节点<select id>...</select>
… …
有个
Object param=method.convertArgusToqlCommandParam(args);
如果是多个参数,就会生成一个 map;
比如:
“arg0”=“123”;
“arg1”=“aa”;
“param”=“aa”;
“param2”=“123”;
如果只有一个参数,只会返回一个值。
对于不同类型的 参数,比如 String,有对应的 StringTypePeHandler (继承自 BaseTypeHandler ) 会调用 setString 方法,最后通过 doQuery() 方法,该方法中先要获取到 Configuration ,然后会去调用 prepareStatement ,就是在这个方法中完成 JDBC操作,其中有个 StatementHandler.parameterize(statement) 参数化。
最后会执行 executeForMany (SqlSession sqlSession,Object[] args) ,args 表示执行时传入的值。
Mybatis 相关可移步
https://blog.csdn.net/weixin_41750142/article/details/104722898