ibatis3出来也很久了,但一直觉得不如旧版好用,发现spring对ibatis的支持相比hibernate也简单得多,于是简单分析了下ibatis的源码。
我们知道应用程序里面使用ibatis 简单点就如下几句,
com.ibatis.sqlmap.client.SqlMapClient sqlMap = null;
java.io.Reader reader = om.ibatis.common.resources.Resources.getResourceAsReader("sql-config.xml");
sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader);
我们从SqlMapClientBuilder.buildSqlMapClient着手,SqlMapClientBuilder中new了一个SqlMapConfigParser类来解析输入流信息,并最终实例化一个SqlMapClient返回
public static SqlMapClient buildSqlMapClient(Reader reader) {
return new SqlMapConfigParser().parse(reader);
}
1.SqlMapConfigParser类的解析
废话不多,贴代码
public class SqlMapConfigParser {
protected final NodeletParser parser = new NodeletParser();
private XmlParserState state = new XmlParserState();
private boolean usingStreams = false;
public SqlMapConfigParser() {
addSqlMapConfigNodelets();
....
}
....
public SqlMapClient parse(Reader reader) {
try {
usingStreams = false;
parser.parse(reader);
return state.getConfig().getClient();
} catch (Exception e) {
throw new RuntimeException("Error occurred. Cause: " + e, e);
}
}
.....
private void addSqlMapConfigNodelets() {
parser.addNodelet("/sqlMapConfig/end()", new Nodelet() {
public void process(Node node) throws Exception {
state.getConfig().finalizeSqlMapConfig();
}
});
}
}
当调用parse时,主要执行了两步操作parser.parse(reader) 和return state.getConfig().getClient(),前者解析xml文档并将解析结果存储到
state中,后者根据解析结果生成一个SqlMapClient实例返回.那NodeletParser和XmlParserState是怎么关联起来的呢?
我们看到SqlMapConfigParser的构造函数中调用了一系列add***方法,
这些方法主要向成员变量 NodeletParser parser中添加一些回调处理类, 当NodeletParser中解析完成后调用这些回调方法将结果存储
到XmlParserState state以及state持有的config对象中.
实际上XmlParserState持有一个SqlMapConfiguration config对象,并且此config早已生成好SqlMapClientImpl对象,最后将解析结果设置进去.
SqlMapConfiguration对象生成了最主要两个类SqlMapExecutorDelegate和SqlMapClientImpl的实例.代码如下:
public class SqlMapConfiguration {
private static final Probe PROBE = ProbeFactory.getProbe();
private ErrorContext errorContext;
private SqlMapExecutorDelegate delegate;
private TypeHandlerFactory typeHandlerFactory;
private SqlMapClientImpl client;
private Integer defaultStatementTimeout;
public SqlMapConfiguration() {
errorContext = new ErrorContext();
delegate = new SqlMapExecutorDelegate();
typeHandlerFactory = delegate.getTypeHandlerFactory();
client = new SqlMapClientImpl(delegate);
registerDefaultTypeAliases();
}
....
}
2.实现类SqlMapClientImpl
SqlMapClientImpl对象一般系统只生成一个,那么此对象是怎么处理线程安全的呢?
首先我主要看一下源码中最主要的几个接口SqlMapSession,SqlMapClient,SqlMapExecutor,SqlMapTransactionManager,
UML描述如下:

SqlMapExecutor定义了CRUD等方法,SqlMapTransactionManager定义了跟事务相关的方法,SqlMapClient 接口和SqlMapSession接口都继承了SqlMapExecutor,SqlMapTransactionManager.只是SqlMapClient 增加了opensession等方法,SqlMapSession接口只增加了一个方法close().
然后看实现类SqlMapClientImpl,我们看到此类此有一个委托类SqlMapExecutorDelegate和一个ThreadLocal对象
.....
public SqlMapExecutorDelegate delegate;
protected ThreadLocal localSqlMapSession = new ThreadLocal();
public SqlMapClientImpl(SqlMapExecutorDelegate delegate) {
this.delegate = delegate;
}
public Object insert(String id, Object param) throws SQLException {
return getLocalSqlMapSession().insert(id, param);
}
......
protected SqlMapSessionImpl getLocalSqlMapSession() {
SqlMapSessionImpl sqlMapSession = (SqlMapSessionImpl) localSqlMapSession.get();
if (sqlMapSession == null || sqlMapSession.isClosed()) {
sqlMapSession = new SqlMapSessionImpl(this);
localSqlMapSession.set(sqlMapSession);
}
return sqlMapSession;
}
...
显然ThreadLocal是存放各个线程的session,然后看SqlMapClientImpl的insert方法,
此方法实际上调用了session实现类SqlMapSessionImpl的insert方法.那么SqlMapSessionImpl类是怎么处理的呢?
SqlMapSessionImpl实现了SqlMapSession,跟SqlMapClientImpl 有共同的实现接口SqlMapExecutor,SqlMapTransactionManager.
看源码可知此类与SqlMapClientImpl持有共同的委托对象SqlMapExecutorDelegate delegate.并且利用此委托对象实例化了一个sessionScope对象
,然后对增删改查的调用均委托对象执行处理并传入这个跟线程绑定的sessionScope对象.
public class SqlMapSessionImpl implements SqlMapSession {
protected SqlMapExecutorDelegate delegate;
protected SessionScope sessionScope;
protected boolean closed;
public SqlMapSessionImpl(SqlMapClientImpl client) {
this.delegate = client.getDelegate();
this.sessionScope = this.delegate.beginSessionScope();
...
public Object insert(String id, Object param) throws SQLException {
return delegate.insert(sessionScope, id, param);
}
SessionScope类,由源码可知此类主要保存了了执行会话一些有关的东西
public class SessionScope {
private static long nextId;
private long id;
// Used by Any
private SqlMapClient sqlMapClient;
private SqlMapExecutor sqlMapExecutor;
private SqlMapTransactionManager sqlMapTxMgr;
private int requestStackDepth;
// Used by TransactionManager
private Transaction transaction;
private TransactionState transactionState;
// Used by SqlMapExecutorDelegate.setUserProvidedTransaction()
private TransactionState savedTransactionState;
// Used by StandardSqlMapClient and GeneralStatement
private boolean inBatch;
// Used by SqlExecutor
private Object batch;
private boolean commitRequired;
private Map preparedStatements;
...
}
3.委托类SqlMapExecutorDelegate
此类持有各种根据xml解析得来的sql信息(由前面介绍的SqlMapConfigParser中的回调类置入).
还持有一个事务管理器TransactionManager txManager和一个sql执行类SqlExecutor sqlExecutor,以及一些类型工厂
代码如下:
public class SqlMapExecutorDelegate {
private static final Probe PROBE = ProbeFactory.getProbe();
private boolean lazyLoadingEnabled;
private boolean cacheModelsEnabled;
private boolean enhancementEnabled;
private boolean useColumnLabel = true;
private boolean forceMultipleResultSetSupport;
private TransactionManager txManager;
private HashMap mappedStatements;
private HashMap cacheModels;
private HashMap resultMaps;
private HashMap parameterMaps;
protected SqlExecutor sqlExecutor;
private TypeHandlerFactory typeHandlerFactory;
private DataExchangeFactory dataExchangeFactory;
....
public List queryForList(SessionScope sessionScope, String id, Object paramObject, int skip, int max) throws SQLException {
List list = null;
//根据传入的id获取具体的MappedStatement对象,每个MappedStatement对象对应xml中的一个id,存放每个执行块的具体信息传入出参数和sql执行语句
MappedStatement ms = getMappedStatement(id);
// 获得sessionScope中的事务对象
Transaction trans = getTransaction(sessionScope);
//若此事务对象为空(说明用户未显示调用session的startTransaction),这将调用sessionScope持有的事务管理器生成一个新的事务
boolean autoStart = trans == null;
try {
trans = autoStartTransaction(sessionScope, autoStart, trans);
//实例化一个StatementScope,与sessionScope对应
StatementScope statementScope = beginStatementScope(sessionScope, ms);
try {
//MappedStatement中调用sqlExecutor对statementScope执行,返回执行结果
list = ms.executeQueryForList(statementScope, trans, paramObject, skip, max);
} finally {
endStatementScope(statementScope);
}
autoCommitTransaction(sessionScope, autoStart);
} finally {
autoEndTransaction(sessionScope, autoStart);
}
return list;
}
分享到:
相关推荐
《深入解析iBatis源码》 iBatis,一个优秀的Java持久层框架,以其轻量级、灵活的特性在众多ORM(Object-Relational Mapping)框架中独树一帜。iBatis的核心在于它的SQL映射机制,它将数据库操作与业务逻辑解耦,...
标题"ibatis源码"指出我们关注的是开源的Java持久层框架iBATIS的源代码。这个框架在Java开发中广泛使用,尤其在处理数据库交互时,它提供了一种灵活的方式,将SQL语句与Java代码解耦合。描述中的"ibatis框架源码剖析...
ibatis源码 学习参考 对于学习ibatis很有帮助
iBATIS框架源码剖析
在本主题中,我们关注的是iBATIS 2.3.4版本的jar包及其源码。 首先,`ibatis-2.3.4.jar` 是包含iBATIS核心库的二进制文件,用于在Java应用中集成iBATIS。这个jar包包含了所有必要的类和资源,如SQL映射接口、数据...
本资源包含了Ibatis的源码、API文档以及jar包,对于深入理解和使用Ibatis非常有帮助。 首先,让我们详细了解Ibatis的核心概念和功能: 1. SQL Map配置文件:Ibatis的核心是SQL Map配置文件,其中包含了SQL语句和...
通过深入分析iBATIS的源码,开发者不仅可以了解其工作原理,还能学习到设计模式、数据库访问的最佳实践以及如何优雅地处理数据库操作。对于提升Java开发者的技能和理解数据库访问层的实现有极大的帮助。在实际开发中...
iBATIS一词来源于“internet”和“abatis”的组合,是一个由Clinton Begin在2001年发起的开放源代码项目。于2010年6月16号被谷歌托管,改名为MyBatis。是一个基于SQL映射支持Java和·NET的持久层框架。
《ibatis框架源码剖析》是一本深入探讨mybatis前身——ibatis的源码解析书籍。通过对源码的深入分析,我们可以理解ibatis的核心机制,掌握数据库操作的底层原理,从而更好地利用和优化这个强大的持久层框架。在这个...
这个“iBatis源码jar包以后上传”可能指的是将要分享或者提供iBatis的源码jar包,以便于开发者深入学习和理解其内部工作原理。 首先,让我们来了解一下iBatis的基本概念和工作流程。iBatis的核心是SQL Map配置文件...
iBATIS一词来源于“internet”和“abatis”的组合,是一个由Clinton Begin在2001年发起的开放源代码项目。最初侧重于密码软件的开发,现在是一个基于Java的持久层框架。iBATIS提供的持久层框架包括SQL Maps和Data ...
通过学习和分析这个源码,开发者不仅可以深入了解SpringMVC和iBatis的协同工作原理,还可以掌握如何在Eclipse这样的IDE中配置和运行这样的项目。这有助于提升对MVC模式的理解,提高数据库操作的能力,以及熟练运用...
ibatis 源码 例子 包含 源码,jar都有 部分代码 package com.icss.dao; import java.io.IOException; import java.io.Reader; import java.sql.SQLException; import java.util.List; import ...
一、**IBatis源码分析** IBatis的源码是开源的,这对于开发者来说是一份宝贵的资源,可以让我们深入了解其工作原理和内部机制。通过阅读源码,我们可以学习到以下知识点: 1. **动态SQL**:IBatis的核心功能之一...
【标题】"ibatis2.3源码"指的是开源的SQL映射框架iBATIS的2.3版本的源代码。iBATIS是Java平台上的一种轻量级持久层框架,它将SQL语句与Java代码分离,使得开发者可以更加灵活地处理数据库操作。 【描述】中的"可以...
ibatis 2.3.4 的源码 public abstract Object insert(String paramString, Object paramObject) throws SQLException; public abstract Object insert(String paramString) throws SQLException; public ...
PUBLIC "-//iBATIS.com//DTD SQL Map Config 2.0//EN" "http://www.ibatis.com/dtd/sql-map-config-2.dtd"> cacheModelsEnabled="true" enhancementEnabled="true" lazyLoadingEnabled="true" ...