不管是使用spring框架集成ibatis还是直接使用ibatis,ibatis经历的第一步都是装载SqlMapConfig.xml文件,由于本文只是分析一下ibatis的代码,所以已单纯使用ibatis为例:
public static void main(String[] args) {
// TODO Auto-generated method stub
String resource = "dal/sqlmap-config.xml";
Reader reader = null;
try {
reader = Resources.getResourceAsReader(resource);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// SqlMapClientBuilder xmlBuilder = new SqlMapClientBuilder();
SqlMapClient sqlMapClient = SqlMapClientBuilder.buildSqlMapClient(reader);
try {
sqlMapClient.startTransaction();
User user = new User();
user.setName("tony");
user.setSex(0);
sqlMapClient.insert("insertUser", user);
sqlMapClient.commitTransaction();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally{
try {
sqlMapClient.endTransaction();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
SqlMapClientBuilder会制造一个sqlMapClient,所以是我们使用ibatis的入口。
一旦我们拥有了这个入口,我们就能执行sql操作了,以上例中的sqlMapClient.insert("insertUser", user) 为例来说明执行这条sql的时候发生了一些什么事情。
- SqlMapExecutor
sqlMapClient拿着一个statement的id和一个参数对象跑到SqlMapExecutor面前说,你帮我处理一下这两个东西。SqlMapExecutor说好的,然后转身把这个任务转发给了它的玄孙:
SqlMapClientImpl。SqlMapClientImpl看着太公交给他的任务,觉得由他自己来做不是很保险,于是又把它交给了同宗的叔叔SqlMapSessionImpl,让这个苦命的叔叔在他自己的会话里把这件
事情给办好。而这位叔叔对于这份苦差事非常厌倦,就把它给外包了,就这样通过层层的外包,最后来到了GeneralStatement 手上。
- GeneralStatement
public int executeUpdate(RequestScope request, Transaction trans, Object parameterObject)
throws SQLException {
ErrorContext errorContext = request.getErrorContext();
errorContext.setActivity("preparing the mapped statement for execution");
errorContext.setObjectId(this.getId());
errorContext.setResource(this.getResource());
request.getSession().setCommitRequired(true);
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);
int rows = 0;
errorContext.setMoreInfo("Check the parameter map.");
Object[] parameters = parameterMap.getParameterObjectValues(request, parameterObject);
errorContext.setMoreInfo("Check the SQL statement.");
String sqlString = sql.getSql(request, parameterObject);
errorContext.setActivity("executing mapped statement");
errorContext.setMoreInfo("Check the statement or the result map.");
rows = sqlExecuteUpdate(request, trans.getConnection(), sqlString, parameters);
errorContext.setMoreInfo("Check the output parameters.");
if (parameterObject != null) {
postProcessParameterObject(request, parameterObject, parameters);
}
errorContext.reset();
sql.cleanup(request);
notifyListeners();
return rows;
} 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);
}
}
其中标为橙色部分的是几个关键点。ParameterMap负责将sql的insert/update/select/delete参数做映射,ResultMap负责将sql语句执行的结果映射到具体的java对象。
parameterMap.getParameterObjectValues(reqeust,parameterObject)将sql语句中的?与参数对应起来,比如:insert into userinfo(name,sex) values(?,?)就有[tony, 0]与之对应。
剩下的事情就变得容易了,这时SqlExecutor 跳出来说,下面就交给我了。
- SqlExecutor
SqlExecutor一手拿着sql,一手拿着参数,肩上挂着请求,头上顶着链接叫嚣着,快快,快把PreparedStatement给我准备好,我要生了。
public int executeUpdate(RequestScope request, Connection conn, String sql, Object[] parameters) throws SQLException {
ErrorContext errorContext = request.getErrorContext();
errorContext.setActivity("executing update");
errorContext.setObjectId(sql);
PreparedStatement ps = null;
setupResultObjectFactory(request);
int rows = 0;
try {
errorContext.setMoreInfo("Check the SQL Statement (preparation failed).");
ps = prepareStatement(request.getSession(), conn, sql);
setStatementTimeout(request.getStatement(), ps);
errorContext.setMoreInfo("Check the parameters (set parameters failed).");
request.getParameterMap().setParameters(request, ps, parameters);
errorContext.setMoreInfo("Check the statement (update failed).");
ps.execute();
rows = ps.getUpdateCount();
} finally {
closeStatement(request.getSession(), ps);
}
return rows;
}
于是乎数据就被生了下来。