- 浏览: 296352 次
- 性别:
- 来自: 杭州
文章分类
最新评论
-
zh554275855:
1 接口是核心,其定义了要做的事情,包含了许多的方法,但没有定 ...
抽象类和接口的区别,使用场景 -
MeowPass:
[color=red][size=xx-large][alig ...
java 字符串split有很多坑,使用时请小心!! -
jayzc1234:
讲的很好 看头像还是个女的 真是牛逼
WEBX学习总结 -
wodexiang:
写的什么狗屎
jetty启动以及嵌入式启动 -
繁星水:
很好,感谢分享与总结,谢谢!
jetty启动以及嵌入式启动
总体来说 iBATIS 的系统结构还是比较简单的,它主要完成两件事情:
根据 JDBC 规范建立与数据库的连接;
通过反射打通 Java 对象与数据库参数交互之间相互转化关系。
iBATIS 的框架结构也是按照这种思想来组织类层次结构的,其实它是一种典型的交互式框架。先期准备好交互的必要条件,然后构建一个交互的环境,交互环境中还划分成会话,每次的会话也有一个环境。当这些环境都准备好了以后,剩下的就是交换数据了。其实涉及到网络通信,一般都会是类似的处理方式。
下图是 iBATIS 框架的主要的类层次结构图
上面的类图中左边 SqlMapClient 接口主要定义了客户端的操作行为包括 select、insert、update、delete。而右边主要是定义了当前客户端在当前线程的执行环境。SqlMapSession 可以共享使用,也可以自己创建,如果是自己创建在结束时必须要调用关闭接口关闭。
当使用者持有了 SqlMapClientImpl 对象就可以使用 iBATIS 来工作了。这里还要提到另外一个类 SqlMapExecutorDelegate 这个类从名字就可以看出他是执行代理类。这个类非常重要,重要是因为他耦合了用户端的执行操作行为和执行的环境,他持有执行操作的所需要的数据,同时提供管理着执行操作依赖的环境。所以他是一个强耦合的类,也可以看做是个工具类。
核心接口
ibatis抽取了以下几个重要接口:
1. SqlMapExecutor
该接口是对SQL操作行为的抽象,提供了SQL单条执行和批处理涉及的所有操作方法。
2. SqlMapTransactionManager
该接口是对事务行为的抽象,提供了事务执行过程中的涉及的所有方法
3. SqlMapClient
该接口定位是SQL执行客户端,是线程安全的,用于处理多个线程的sql执行。它继承了上面两个接口,这意味着该接口具有SQL执行、批处理和事务处理的能力,如果你拥有该接口的实现类,意味着执行任何SQL语句对你来说是小菜一碟。该接口的核心实现类是SqlMapClientImpl。
4. SqlMapSession
该接口在继承关系上和SqlMapClient一致,但它的定位是保存单线程sql执行过程的session信息。该接口的核心实现类是SqlMapSessionImpl。
5. MappedStatement
该接口定位是单条SQL执行时的上下文环境信息,如SQL标识、SQL、参数信息、返回结果、操作行为等。
6. ParameterMap/ResultMap
该接口用于在SQL执行的前后提供参数准备和执行结果集的处理。
这里必须要强调SqlMapExecutorDelegate这个类,他是一个执行代理类,在ibatis框架中地位非常重要,因为他耦合了用户端的操作行为和执行环境,他持有执行操作的所需要的所有数据,同时管理着执行操作依赖的环境。
下面是一个Spring中sqlMapClient的bean配置:
下面看一下SqlMapClientFactoryBean的初始化方法afterPropertiesSet(),用于构建sqlMapClient对象:
看一下buildSqlMapClient()的实现:
SQL执行过程
下面以一个select语句的执行过程,分析一下以上各ibatis核心接口相互如何配合。
1. dao调用SqlMapClientTemplate的query()方法:
2. execute()方法中展示了执行过程中的核心逻辑:获取session -> 获取connection -> 执行sql ->释放connection -> 关闭session。
部分源码如下:
3. action.doInSqlMapClient(session)调用SqlMapSessionImpl().queryForObject()方法。
注意: 这里调用对象主体为SqlMapSessionImpl,表示在线程session中执行sql(session是ThreadLocal的),而不在负责整体协调的SqlMapClientImpl中执行sql语句。
源码如下:
4. SqlMapSessionImpl().queryForObject()的方法很简单,直接交给代理对象SqlMapExecutorDelegate处理:
5. SqlMapExecutorDelegate的queryForObject()方法代码如下:
6. MappedStatement携带了SQL语句和执行过程中的相关信息,MappedStatement.executeQueryForObject()方法部分源码如下:
7. MappedStatement.executeQueryWithCallback()方法包含了参数值映射、sql准备和sql执行等关键过程,部分源码如下:
8. 到了执行中最核心的一步,也是最后一步: MappedStatement.sqlExecuteQuery()方法,它负责sql的最后执行,内部调用了SqlExecutor.executeQuery()方法,部分源码如下:
上面这段代码大家会非常熟悉,和本文开始处的代码很相似,ibatis归根到底,是对JDBC操作一定程度上的封装而已。
下面在总体上概括sql的一般执行过程:
SqlMapClientImpl接到请求后,创建SqlMapSessionImpl对象(ThreadLocal,保证线程安全),SqlMapSessionImpl交由内部的代理类SqlMapExecutorDelegate执行,代理类获取相应的MappedStatement,交由MappedStatement对象执行,MappedStatement交由SqlExecutor执行,最终使用JDBC方式执行sql。
小结
ibatis源码规模较小,整体设计思路清晰,阅读ibatis源码可以按以下思路进行:
1. 了解ibatis框架的整体目标,用于解决哪些问题。
2. ibatis如何解决这些问题,带着问题去学习。
3. 了解ibatis框架的核心接口和整体设计思路。
4. 抓住ibatis核心流程: 初始化和请求处理流程。
5. 详细ibatis框架的关键细节实现,如ibatis中的配置文件解析,参数和结果映射等。
根据 JDBC 规范建立与数据库的连接;
通过反射打通 Java 对象与数据库参数交互之间相互转化关系。
iBATIS 的框架结构也是按照这种思想来组织类层次结构的,其实它是一种典型的交互式框架。先期准备好交互的必要条件,然后构建一个交互的环境,交互环境中还划分成会话,每次的会话也有一个环境。当这些环境都准备好了以后,剩下的就是交换数据了。其实涉及到网络通信,一般都会是类似的处理方式。
下图是 iBATIS 框架的主要的类层次结构图
上面的类图中左边 SqlMapClient 接口主要定义了客户端的操作行为包括 select、insert、update、delete。而右边主要是定义了当前客户端在当前线程的执行环境。SqlMapSession 可以共享使用,也可以自己创建,如果是自己创建在结束时必须要调用关闭接口关闭。
当使用者持有了 SqlMapClientImpl 对象就可以使用 iBATIS 来工作了。这里还要提到另外一个类 SqlMapExecutorDelegate 这个类从名字就可以看出他是执行代理类。这个类非常重要,重要是因为他耦合了用户端的执行操作行为和执行的环境,他持有执行操作的所需要的数据,同时提供管理着执行操作依赖的环境。所以他是一个强耦合的类,也可以看做是个工具类。
核心接口
ibatis抽取了以下几个重要接口:
1. SqlMapExecutor
该接口是对SQL操作行为的抽象,提供了SQL单条执行和批处理涉及的所有操作方法。
2. SqlMapTransactionManager
该接口是对事务行为的抽象,提供了事务执行过程中的涉及的所有方法
3. SqlMapClient
该接口定位是SQL执行客户端,是线程安全的,用于处理多个线程的sql执行。它继承了上面两个接口,这意味着该接口具有SQL执行、批处理和事务处理的能力,如果你拥有该接口的实现类,意味着执行任何SQL语句对你来说是小菜一碟。该接口的核心实现类是SqlMapClientImpl。
4. SqlMapSession
该接口在继承关系上和SqlMapClient一致,但它的定位是保存单线程sql执行过程的session信息。该接口的核心实现类是SqlMapSessionImpl。
5. MappedStatement
该接口定位是单条SQL执行时的上下文环境信息,如SQL标识、SQL、参数信息、返回结果、操作行为等。
6. ParameterMap/ResultMap
该接口用于在SQL执行的前后提供参数准备和执行结果集的处理。
这里必须要强调SqlMapExecutorDelegate这个类,他是一个执行代理类,在ibatis框架中地位非常重要,因为他耦合了用户端的操作行为和执行环境,他持有执行操作的所需要的所有数据,同时管理着执行操作依赖的环境。
下面是一个Spring中sqlMapClient的bean配置:
<bean id="group1SqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean"> <property name="configLocation"> <value>sql-map.xml</value> </property> <property name="dataSource"> <ref local="group1"/> </property> </bean>
下面看一下SqlMapClientFactoryBean的初始化方法afterPropertiesSet(),用于构建sqlMapClient对象:
public void afterPropertiesSet() throws Exception { ... this.sqlMapClient = buildSqlMapClient(this.configLocations, this.mappingLocations, this.sqlMapClientProperties); //初始化核心方法,构建sqlMapClient对象 ... }
看一下buildSqlMapClient()的实现:
protected SqlMapClient buildSqlMapClient( Resource[] configLocations, Resource[] mappingLocations, Properties properties) throws IOException { ... SqlMapClient client = null; SqlMapConfigParser configParser = new SqlMapConfigParser(); for (int i = 0; i < configLocations.length; i++) { InputStream is = configLocations[i].getInputStream(); try { client = configParser.parse(is, properties); //通过SqlMapConfigParser解析配置文件,生成SQLMapClientImpl对象 } catch (RuntimeException ex) { throw new NestedIOException("Failed to parse config resource: " + configLocations[i], ex.getCause()); } } ... return client; }
SQL执行过程
下面以一个select语句的执行过程,分析一下以上各ibatis核心接口相互如何配合。
1. dao调用SqlMapClientTemplate的query()方法:
public Object queryForObject(final String statementName, final Object parameterObject) throws DataAccessException { return execute(new SqlMapClientCallback() { public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException { return executor.queryForObject(statementName, parameterObject); } }); }
2. execute()方法中展示了执行过程中的核心逻辑:获取session -> 获取connection -> 执行sql ->释放connection -> 关闭session。
部分源码如下:
public Object execute(SqlMapClientCallback action) throws DataAccessException { ... SqlMapSession session = this.sqlMapClient.openSession(); //获取session信息 Connection ibatisCon = null; //获取Connection try { Connection springCon = null; DataSource dataSource = getDataSource(); boolean transactionAware = (dataSource instanceof TransactionAwareDataSourceProxy); try { ibatisCon = session.getCurrentConnection(); if (ibatisCon == null) { springCon = (transactionAware ? dataSource.getConnection() : DataSourceUtils.doGetConnection(dataSource)); session.setUserConnection(springCon); ... } } ... // Execute given callback... try { return action.doInSqlMapClient(session); //执行SQL } ... finally { // 关闭Connection try { if (springCon != null) { if (transactionAware) { springCon.close(); } else { DataSourceUtils.doReleaseConnection(springCon, dataSource); } } } if (ibatisCon == null) { session.close(); //关闭session } }
3. action.doInSqlMapClient(session)调用SqlMapSessionImpl().queryForObject()方法。
注意: 这里调用对象主体为SqlMapSessionImpl,表示在线程session中执行sql(session是ThreadLocal的),而不在负责整体协调的SqlMapClientImpl中执行sql语句。
源码如下:
public Object queryForObject(final String statementName, final Object parameterObject) throws DataAccessException { return execute(new SqlMapClientCallback() { //这里的SqlMapExecutor对象类型为SqlMapSessionImpl public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException { return executor.queryForObject(statementName, parameterObject); } }); }
4. SqlMapSessionImpl().queryForObject()的方法很简单,直接交给代理对象SqlMapExecutorDelegate处理:
public Object queryForObject(String id, Object paramObject) throws SQLException { return delegate.queryForObject(session, id, paramObject); }
5. SqlMapExecutorDelegate的queryForObject()方法代码如下:
public Object queryForObject(SessionScope session, String id, Object paramObject, Object resultObject) throws SQLException { Object object = null; MappedStatement ms = getMappedStatement(id); //MappedStatement对象集是上文中提及的初始化方法SqlMapClientFactoryBean.afterPropertiesSet()中,由配置文件构建而成 Transaction trans = getTransaction(session); // 用于事务执行 boolean autoStart = trans == null; try { trans = autoStartTransaction(session, autoStart, trans); RequestScope request = popRequest(session, ms); // 从RequestScope池中获取该次sql执行中的上下文环境RequestScope try { object = ms.executeQueryForObject(request, trans, paramObject, resultObject); // 执行sql } finally { pushRequest(request); //归还RequestScope } autoCommitTransaction(session, autoStart); } finally { autoEndTransaction(session, autoStart); } return object; }
6. MappedStatement携带了SQL语句和执行过程中的相关信息,MappedStatement.executeQueryForObject()方法部分源码如下:
public Object executeQueryForObject(RequestScope request, Transaction trans, Object parameterObject, Object resultObject) throws SQLException { try { Object object = null; DefaultRowHandler rowHandler = new DefaultRowHandler(); executeQueryWithCallback(request, trans.getConnection(), parameterObject, resultObject, rowHandler, SqlExecutor.NO_SKIPPED_RESULTS, SqlExecutor.NO_MAXIMUM_RESULTS); //执行sql语句 //结果处理,返回结果 List list = rowHandler.getList(); if (list.size() > 1) { throw new SQLException("Error: executeQueryForObject returned too many results."); } else if (list.size() > 0) { object = list.get(0); } return object; } .... }
7. MappedStatement.executeQueryWithCallback()方法包含了参数值映射、sql准备和sql执行等关键过程,部分源码如下:
protected void executeQueryWithCallback(RequestScope request, Connection conn, Object parameterObject, Object resultObject, RowHandler rowHandler, int skipResults, int maxResults) throws SQLException { ... try { parameterObject = validateParameter(parameterObject); //验证入参 Sql sql = getSql(); //获取SQL对象 errorContext.setMoreInfo("Check the parameter map."); ParameterMap parameterMap = sql.getParameterMap(request, parameterObject);// 入参映射 errorContext.setMoreInfo("Check the result map."); ResultMap resultMap = sql.getResultMap(request, parameterObject); //结果映射 request.setResultMap(resultMap); request.setParameterMap(parameterMap); errorContext.setMoreInfo("Check the parameter map."); Object[] parameters = parameterMap.getParameterObjectValues(request, parameterObject); //获取参数值 errorContext.setMoreInfo("Check the SQL statement."); String sqlString = sql.getSql(request, parameterObject); //获取拼装后的sql语句 errorContext.setActivity("executing mapped statement"); errorContext.setMoreInfo("Check the SQL statement or the result map."); RowHandlerCallback callback = new RowHandlerCallback(resultMap, resultObject, rowHandler); sqlExecuteQuery(request, conn, sqlString, parameters, skipResults, maxResults, callback); //sql执行 errorContext.setMoreInfo("Check the output parameters."); if (parameterObject != null) { postProcessParameterObject(request, parameterObject, parameters); } errorContext.reset(); sql.cleanup(request); notifyListeners(); .... }
8. 到了执行中最核心的一步,也是最后一步: MappedStatement.sqlExecuteQuery()方法,它负责sql的最后执行,内部调用了SqlExecutor.executeQuery()方法,部分源码如下:
public void executeQuery(RequestScope request, Connection conn, String sql, Object[] parameters, int skipResults, int maxResults, RowHandlerCallback callback) throws SQLException { ... PreparedStatement ps = null; ResultSet rs = null; setupResultObjectFactory(request); try { errorContext.setMoreInfo("Check the SQL Statement (preparation failed)."); Integer rsType = request.getStatement().getResultSetType(); //初始化PreparedStatement,设置sql、参数值等 if (rsType != null) { ps = prepareStatement(request.getSession(), conn, sql, rsType); } else { ps = prepareStatement(request.getSession(), conn, sql); } setStatementTimeout(request.getStatement(), ps); Integer fetchSize = request.getStatement().getFetchSize(); if (fetchSize != null) { ps.setFetchSize(fetchSize.intValue()); } errorContext.setMoreInfo("Check the parameters (set parameters failed)."); request.getParameterMap().setParameters(request, ps, parameters); errorContext.setMoreInfo("Check the statement (query failed)."); ps.execute(); //执行 errorContext.setMoreInfo("Check the results (failed to retrieve results)."); // ResultSet处理 rs = handleMultipleResults(ps, request, skipResults, maxResults, callback); } finally { try { closeResultSet(rs); } finally { closeStatement(request.getSession(), ps); } } }
上面这段代码大家会非常熟悉,和本文开始处的代码很相似,ibatis归根到底,是对JDBC操作一定程度上的封装而已。
下面在总体上概括sql的一般执行过程:
SqlMapClientImpl接到请求后,创建SqlMapSessionImpl对象(ThreadLocal,保证线程安全),SqlMapSessionImpl交由内部的代理类SqlMapExecutorDelegate执行,代理类获取相应的MappedStatement,交由MappedStatement对象执行,MappedStatement交由SqlExecutor执行,最终使用JDBC方式执行sql。
小结
ibatis源码规模较小,整体设计思路清晰,阅读ibatis源码可以按以下思路进行:
1. 了解ibatis框架的整体目标,用于解决哪些问题。
2. ibatis如何解决这些问题,带着问题去学习。
3. 了解ibatis框架的核心接口和整体设计思路。
4. 抓住ibatis核心流程: 初始化和请求处理流程。
5. 详细ibatis框架的关键细节实现,如ibatis中的配置文件解析,参数和结果映射等。
发表评论
-
jetty启动以及嵌入式启动
2013-08-18 21:47 25198首先得下载jetty http:/ ... -
hive原理(未完。。)
2013-01-06 22:46 1989hive就是一个将hiveql(其实是sql的子集或者说一点点 ... -
搜索切换dump之MapReduce讲解
2012-12-23 20:16 1593分享聚合dump的是评价的 ... -
开启mapReduce
2012-12-18 10:53 1134用最简短的语言解释MapReduce: We wa ... -
WEBX学习总结
2012-07-15 22:51 16422把对webx的学习总结搬到iteye上来 一、 WEBX框架的 ... -
Webx之表单验证
2011-12-29 10:55 1984引入服务器端表单验证service,是通过在webx.xml中 ...
相关推荐
根据给定的文件信息,以下是对“Ibatis常用SQL语句”的详细解析,涵盖了一系列Ibatis在数据操作中的应用实例。 ### Ibatis简介 Ibatis是一个支持普通SQL查询、存储过程以及高级映射的优秀持久层框架。Ibatis可以让...
根据MyBatis或iBatis的SQLMapper文件解析生成数据库表,通常是指通过解析MyBatis或iBatis的SQLMapper文件中的SQL语句,然后根据这些SQL语句来生成对应的数据库表结构。这样的需求可能源于需要将已有的SQLMapper文件...
### ibatis SQL语句对条件中特殊字符% # 处理 在开发过程中,经常会遇到SQL查询时需要处理字符串中的特殊字符的情况。特别是在使用类似`LIKE`这样的操作符时,如果用户输入的数据中含有`%`、`_`或`#`等特殊字符,...
它为Java应用程序提供了灵活的数据库访问层,使得开发者可以避免直接编写大量的SQL语句,同时保持对SQL的直接控制,提高了开发效率和代码的可维护性。 《iBATIS 开发指南》一书通常会涵盖以下关键知识点: 1. **...
这应该是一个Java类,它负责读取MyBatis或iBatis的SQL映射文件,解析其中的SQL语句和映射元素,然后根据这些信息生成创建数据库表的DDL语句。 在解析SQL映射文件时,`Sqlmap2Table.java` 可能会使用DOM(Document ...
根据提供的文件信息,本文将对ibatis常用的SQL语句进行详细的解析与说明。这些SQL语句主要用于Oracle数据库中,涉及到了删除、插入以及查询等基本操作,并且在ibatis框架中实现了参数化处理。 ### 一、删除操作 ...
iBATIS 提供了一个SQL映射框架,使得开发者可以编写静态的SQL语句,同时保留了SQL语句的全部能力。它将SQL语句与Java代码分离,通过XML或注解配置文件来定义SQL与Java方法的映射关系,以及参数模型、结果模型等。...
《iBATIS-SqlMaps-中文教程》是一个深入解析iBATIS框架的资源,适合对Java Web开发感兴趣的初学者和进阶者。iBATIS是一个持久层框架,它允许开发者将SQL语句直接写在XML配置文件中,实现了SQL与Java代码的分离,简化...
在SQL语句中,使用问号(`?`)作为参数占位符是一种常见的做法,尤其是在编程语言如Java中与数据库交互时。这种方式被称为预编译语句或参数化查询,它具有重要的安全性和性能优势。 ### SQL参数化查询的概念 参数化...
Ibatis,全称为MyBatis,是一个优秀的Java持久层框架,它主要负责SQL映射,使得开发者能够将SQL语句与Java代码分离,从而更好地管理数据库操作。在Ibatis中,`sql-map`和`sql-map-config`是两个重要的XML配置文件,...
Ibatis,全称为MyBatis,是一个优秀的Java持久层框架,它主要负责SQL映射,使得开发者能够将SQL语句与Java代码分离,从而更好地管理数据库操作。在本篇文章中,我们将深入解析Ibatis的实现原理,探讨其核心功能、...
4. **SQL Mapping映射文件**:在IBatis.NET中,SQL Mapping文件是XML格式的,它定义了SQL语句、存储过程以及它们与实体类之间的映射关系。通过这种方式,开发者可以在不修改业务代码的情况下,调整数据库查询逻辑。 ...
在Ibatis中,复杂查询通常涉及到多个表的联接、条件动态拼接、子查询以及各种数据类型的处理。...在实际开发中,这种灵活性使得Ibatis能够适应各种复杂的业务场景,同时保持SQL语句的清晰和可读性。
IBATIS,现在更广为人知的名字为MyBatis,是一种半自动映射的持久层框架,它允许开发者以声明的方式进行SQL语句的编写,同时提供了动态SQL的功能,这使得SQL语句可以在运行时根据条件动态生成,极大地提高了SQL的...
Dynamic Sql是指在运行时动态构建SQL语句的能力,这种能力对于处理复杂的查询或根据不同的业务逻辑生成不同的SQL语句非常有用。ibatis框架自2.x版本起就提供了Dynamic Sql的支持,但在3.0版本中,这一功能得到了极大...
这个框架的主要目的是简化Java应用程序与数据库之间的交互,通过XML或注解方式将SQL语句映射到Java方法,实现了数据访问逻辑与业务逻辑的分离,提升了开发效率。 在“iBATIS-SqlMaps中文教程集合”中,你将找到四本...
iBATIS是一个Java编程语言中的持久层框架,它允许开发者将SQL语句与Java代码分离,提高了数据访问的灵活性和效率。本指南深入浅出地讲解了如何使用iBATIS的SqlMap配置和映射文件来实现数据库操作。 在version 1.0的...
ibatis在解析动态SQL时,会执行一系列逻辑判断来确定如何构建最终的SQL语句。例如,在给定的Java代码片段中,`public void pushRemoveFirstPrependMarker(SqlTag tag)`方法用于处理`prepend`属性的逻辑。其中,`tag....
把 mybatis 输出的sql日志还原成完整的sql语句。 将日志输出的sql语句中的问号 ? 替换成真正的参数值。 通过 "Tools -> MyBatis Log Plugin" 菜单或快捷键 "Ctrl+Shift+Alt+O" 启用。 点击窗口左边的 "Filter" ...