- 创建SQL_Map_Config.xml文件
? ?
monospace; margin-bottom: 1px; padding-top: 2px; padding-bottom: 2px; border: 1px solid #d1d7dc; color: #2b91af;">
- <?xml?version="1.0"?encoding="UTF-8"??>??
- <!DOCTYPE?sqlMapConfig????????
- ????PUBLIC?"-//ibatis.apache.org//DTD?SQL?Map?Config?2.0//EN"????????
- ????"http://ibatis.apache.org/dtd/sql-map-config-2.dtd">??
- <sqlMapConfig>??
- ????<properties?resource="jdbc.properties"?/>??
- ????<transactionManager?type="JDBC">??
- ????????<dataSource?type="SIMPLE">??
- ????????????<property?name="JDBC.Driver"?value="${jdbc.driverClassName}"?/>??
- ????????????<property?name="JDBC.ConnectionURL"?value="${jdbc.url}"?/>??
- ????????????<property?name="JDBC.Username"?value="${jdbc.username}"?/>??
- ????????????<property?name="JDBC.Password"?value="${jdbc.password}"?/>??
- ????????</dataSource>??
- ????</transactionManager>??
- ????<sqlMap?resource="ibatis/resources/User.xml"?/>??
- </sqlMapConfig>??
?
这个文件设置了数据库连接的参数,以及存放SQL的SQLMap文件
?
2.创建SQLMap文件
?
- <?xml?version="1.0"?encoding="UTF-8"?>??
- <!DOCTYPE?sqlMap??????????
-
????PUBLIC?"-//ibatis.apache.org//DTD?SQL?Map?2.0//EN"??"http://ibatis.apache.org/dtd/sql-map-2.dtd"> ?
- <sqlMap>??
- ????<typeAlias?alias="User"?type="cn.yangphere.ibatisdemo.model.User"/>??
- ????<select?id="getAllUsers"?resultClass="User">??
- ????????select?id?as?userId,?userName?as?username,?password,?mobile,?email??
- ????????from?users??
- ????</select>??
- </sqlMap> ?
?
?
3.java调用
- package?ibatis;??
- import?ibatis.model.User;??
- import?java.io.*;??
- import?java.sql.SQLException;??
- import?java.util.List;??
- import?com.ibatis.common.resources.Resources;??
- import?com.ibatis.sqlmap.client.*;??
- public?class?IBatisDemo?{??
- ????public?static?void?main(String[]?args)?throws?IOException,?SQLException?{??
- ????????String?config?=?"ibatis/SqlMapConfig.xml";??
- ????????Reader?reader?=?Resources.getResourceAsReader(config);??
- ????????SqlMapClient?sqlMap?=?SqlMapClientBuilder.buildSqlMapClient(reader);??
- ????????List<User>?list?=?sqlMap.queryForList("getAllUsers");??
- ????????for?(User?user?:?list)?{??
- ????????????System.out.println(user);??
- ????????}??
- ????}??
- } ?
这样一个基本的ibatis使用
例子就完成了
?
?
这个调用代码里,有两个方面的操作,
- 根据sqlmapconfig.xml文件生成client对象
- 用client对象访问CRUD方法,来访问数据库
?
?
先来看看
根据sqlmapconfig.xml文件生成client对象:
1.SqlMapClient?sqlMap?=?SqlMapClientBuilder.buildSqlMapClient(reader);?
?看看
buildSqlMapClient方法的代码:
/**
* Builds an SqlMapClient using the specified reader.根据xml文件输入流 创建一个client对象
* @param reader A Reader instance that reads an sql- map-config.xml file.
* The reader should read an well formed sql- map-config.xml file.
* @return An SqlMapClient instance.
*/
public static SqlMapClient buildSqlMapClient(Reader reader) {
// return new XmlSqlMapClientBuilder().buildSqlMap(reader);
return new SqlMapConfigParser().parse(reader);
}
?
?
?2.接着往下看
?SqlMapClient?com.ibatis.sqlmap.engine.builder.xml.SqlMapConfigParser.parse(Reader?reader)
public SqlMapClient parse(Reader reader) {
try {
if ( vars.sqlMapConfigConv != null) {
reader = vars.sqlMapConfigConv .convertXml(reader);
}
parser.parse(reader);
return vars.client ;
} catch (Exception e) {
throw new NestedRuntimeException("Error occurred. Cause: " + e, e);
}
}
?
?
这里xml文件的输入流被用来转换sql去了
?
但是这个方法返回的client并不是直接从这个方法生成的
?
我们看
public class SqlMapConfigParser extends BaseParser {
public SqlMapConfigParser(XmlConverter sqlMapConfigConv, XmlConverter sqlMapConv) {
super( new Variables());
parser.setValidation( true);
parser.setEntityResolver( new SqlMapClasspathEntityResolver());
vars.sqlMapConfigConv = sqlMapConfigConv;
vars.sqlMapConv = sqlMapConv;
vars.delegate = new SqlMapExecutorDelegate();//直接new了一个
vars.typeHandlerFactory = vars.delegate .getTypeHandlerFactory();
vars.client = new SqlMapClientImpl(vars .delegate );
registerDefaultTypeAliases();
addSqlMapConfigNodelets();
addGlobalPropNodelets();
addSettingsNodelets();
addTypeAliasNodelets();
addTypeHandlerNodelets();
addTransactionManagerNodelets();
addSqlMapNodelets();
}
}
?
发现
SqlMapConfigParser?这个类的构造方法里就有
vars.?delegate?=?new?SqlMapExecutorDelegate();//直接new了一个
vars.?client?=?new?SqlMapClientImpl(vars?
.delegate?
);
?
这两行,生产了client对象 ?至于具体流程 这里不去追究 只需要知道大致是这样就得到了client对象
?
?
?
?
?
用client对象访问CRUD方法,来访问数据库
?
List<User>?list?=?sqlMap.queryForList("getAllUsers");?
?
这里的client是?SqlMapClientImpl对象
这个类包括了所有CRUD方法,
?
SqlMapClientImpl 实现了ExtendedSqlMapClient接口
?
ExtendedSqlMapClient接口又继承了SqlMapClient接口
?
SqlMapClient接口继承了SqlMapExecutor, SqlMapTransactionManager两个接口
?
SqlMapExecutor, SqlMapTransactionManager这两个接口分别让client获得了CRUD方法和事务控制的能力
?
?
有一个图可以简明的表达这个关系:
?
?
?
我们来看SqlMapClientImpl?里面CRUD方法的代码:
?
public class SqlMapClientImpl implements ExtendedSqlMapClient {
public SqlMapExecutorDelegate delegate;
private ThreadLocal localSqlMapSession = new ThreadLocal ();
public Object queryForObject(String id, Object paramObject, Object resultObject) throws SQLException {
return getLocalSqlMapSession().queryForObject(id, paramObject, resultObject);
}
private SqlMapSessionImpl getLocalSqlMapSession() {
SqlMapSessionImpl sqlMapSession = (SqlMapSessionImpl) localSqlMapSession.get();
if (sqlMapSession == null || sqlMapSession.isClosed()) {
sqlMapSession = new SqlMapSessionImpl(this);
localSqlMapSession.set(sqlMapSession);
}
return sqlMapSession;
}
}
?
以queryForObject为例,是获取了SqlMapSessionImpl?对象,然后执行SqlMapSessionImpl?对象里面的queryForObject方法的
?
?
我们再来看SqlMapSessionImpl?
?
public class SqlMapSessionImpl implements SqlMapSession {
protected SqlMapExecutorDelegate delegate;
protected SessionScope session;
protected boolean closed ;
public Object queryForObject(String id, Object paramObject, Object resultObject) throws SQLException {
return delegate.queryForObject(session , id, paramObject, resultObject);
}
}
?
?
可以发现?SqlMapSessionImpl?实现了SqlMapSession?接口
这个对象有
SqlMapExecutorDelegate?CRUD操作代理类对象
SessionScope? 对象 里面存了执行数据库操作所需的各种资源和对象(会话)
queryForObject方法的实现是通过代理类SqlMapExecutorDelegate?的方法queryForObject
?
?
看SqlMapExecutorDelegate?的源码
?
/**
* Execute a select for a single object
*
* @param session - the session scope
* @param id - the statement ID
* @param paramObject - the parameter object
* @param resultObject - the result object (if not supplied or null, a new object will be created)
* @return - the result of the query
* @throws SQLException - if the query fails
*/
public Object queryForObject(SessionScope session, String id, Object paramObject, Object resultObject) throws SQLException {
Object object = null;
MappedStatement ms = getMappedStatement(id);
Transaction trans = getTransaction(session);
boolean autoStart = trans == null;
try {
trans = autoStartTransaction(session, autoStart, trans);
RequestScope request = popRequest(session, ms);
try {
object = ms.executeQueryForObject(request, trans, paramObject, resultObject);
} finally {
pushRequest(request);
}
autoCommitTransaction(session, autoStart);
} finally {
autoEndTransaction(session, autoStart);
}
return object;
}
?
?
首先?MappedStatement ms = getMappedStatement(id); 根据sqlMap里的id 获取到SQL语句对象
Transaction trans = getTransaction(session); 从session中获取Transaction事务管理对象
?
然后RequestScope request = popRequest(session, ms); 从request池中取出request对象
?
object = ms.executeQueryForObject(request, trans, paramObject, resultObject);执行查询
?
pushRequest(request);放回request池
?
autoCommitTransaction(session, autoStart);提交事务
?
?
return?object;返回查询结果
?
?
?
?
?
?
其中?ms.executeQueryForObject(request, trans, paramObject, resultObject);
往下看发现
其实是GeneralStatement类继承了BaseStatement
BaseStatement又实现了MappedStatement?接口
?
所以
这里MappedStatement ms = getMappedStatement(id); 得到的是GeneralStatement实例
?
?
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);
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;
} catch (TransactionException e) {
throw new NestedSQLException("Error getting Connection from Transaction. Cause: " + e, e);
}
}
?
?
这里可以看到 new 了一个rowHandler?对象 ?然后执行executeQueryWithCallback?
方法
?
然后从rowHandler?对象里获取到结果集list?
取list里的第一个元素返回
?
?
?
其中DefaultRowHandler?类也很简单 里面就是一个list
?
public class DefaultRowHandler implements RowHandler {
private List list = new ArrayList();
public void handleRow(Object valueObject) {
list.add(valueObject) ;
}
public List getList() {
return list;
}
}
?
?
?
再看executeQueryWithCallback 方法的实现
?
ibatis.sqlmap.engine.mapping.statement.GeneralStatement.executeQueryWithCallback()
?
protected void executeQueryWithCallback(RequestScope request, Connection conn, Object parameterObject, Object resultObject, RowHandler rowHandler, int skipResults, int maxResults)
throws SQLException {
ErrorContext errorContext = request.getErrorContext();
errorContext .setActivity("preparing the mapped statement for execution");
errorContext .setObjectId(this.getId());
errorContext .setResource(this.getResource());
try {
parameterObject = validateParameter(parameterObject);
Sql sql = getSql();
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 了 可以做个输出
System. out.println( sqlString);
errorContext .setMoreInfo("Check the output parameters." );
if (parameterObject != null) {
postProcessParameterObject(request, parameterObject, parameters);
}
errorContext .reset();
sql.cleanup(request);
notifyListeners();
} catch (SQLException e) {
errorContext .setCause(e);
throw new NestedSQLException(errorContext.toString(), e.getSQLState(), e.getErrorCode(), e);
} catch (Exception e) {
errorContext .setCause(e);
throw new NestedSQLException(errorContext.toString(), e);
}
}
?
?
?
可以看到 获取参数Map ?和结果集Map ?ParameterMap?,ResultMap?
然后是拼接sql语句
String sqlString = sql.getSql(request, parameterObject);?//这个就是拼接SQL的方法
?
?
再执行sql
?
? ? ? RowHandlerCallback callback =?new?RowHandlerCallback(resultMap, resultObject, rowHandler);
????? sqlExecuteQuery(request, conn, sqlString, parameters, skipResults, maxResults, callback);
?
?
?
接下来是最核心的
?到了执行中最核心的一步,也是最后一步: MappedStatement.sqlExecuteQuery()方法,它负责sql的最后执行,内部调用了SqlExecutor.executeQuery()方法
ibatis.sqlmap.engine.mapping.statement.GeneralStatement.sqlExecuteQuery()
protected void sqlExecuteQuery(RequestScope request, Connection conn, String sqlString, Object[] parameters, int skipResults, int maxResults, RowHandlerCallback callback) throws SQLException {
getSqlExecutor().executeQuery(request, conn, sqlString, parameters, skipResults, maxResults, callback);
}
?
?
先获取
SqlExecutor对象
com.ibatis.sqlmap.engine.execution.SqlExecutor.executeQuery()
?
/**
* Long form of the method to execute a query
*
* @param request - the request scope
* @param conn - the database connection
* @param sql - the SQL statement to execute
* @param parameters - the parameters for the statement
* @param skipResults - the number of results to skip
* @param maxResults - the maximum number of results to return
* @param callback - the row handler for the query
*
* @throws SQLException - if the query fails
*/
public void executeQuery(RequestScope request, Connection conn, String sql, Object[] parameters,
int skipResults, int maxResults, RowHandlerCallback callback)
throws SQLException {
ErrorContext errorContext = request.getErrorContext();
errorContext.setActivity( "executing query");
errorContext.setObjectId(sql);
PreparedStatement ps = null;
ResultSet rs = null;
try {
errorContext.setMoreInfo( "Check the SQL Statement (preparation failed).");
Integer rsType = request.getStatement().getResultSetType();
if (rsType != null) {
ps = conn.prepareStatement(sql, rsType.intValue(), ResultSet.CONCUR_READ_ONLY );
} else {
ps = conn.prepareStatement(sql);
}
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();
rs = getFirstResultSet(ps);
if (rs != null) {
errorContext.setMoreInfo( "Check the results (failed to retrieve results).");
handleResults(request, rs, skipResults, maxResults, callback);
}
// clear out remaining results
while (ps.getMoreResults());
} finally {
try {
closeResultSet(rs);
} finally {
closeStatement(ps);
}
}
}
?
可以发现 这是ibatis访问数据库的最后一步了 其实就是我们以前用的jdbc访问数据库的代码
这一步可以得到最终拼接完成的SQL
?
ps = conn.prepareStatement(sql);
ps.execute();
rs = getFirstResultSet(ps);
handleResults(request, rs, skipResults, maxResults, callback); rs放入callback
?
?
?
?
?
?
?
?
?