huo公司的ibatis代码主要对获取数据源的部分进行了二次开发,总体来说和开源的ibatis差不多。
ibatis的使用共分两部分,ibatis的的初始化以及ibatis的数据库访问。对源码的分析也通过这两部分开始。这也应该是看源码的一种方法吧。
1、ibatis的初始化
ibatis的初始化过程如下:
在用户调用Ibatis初始化代码后,BaseDbClient会使用如下代码,配置Ibatis的各个部分,然后配置SqlClient。
private SqlClient createClient(String source) {
Reader reader = null;
SqlClient client = null;
try {
reader = Resources.getResourceAsReader(source);
client = SqlClientBuilder.buildSqlClient(reader);
} catch (Throwable e) {
e.printStackTrace();
daoLog.error("init db client fail " + source, e);
} finally {
try {
if (reader != null) {
reader.close();
}
if (client == null) {
Thread.sleep(1000L);
createClient(source);
}
} catch (Throwable e) {
e.printStackTrace();
daoLog.error("init db client fail in finally " + source, e);
}
}
return client;
}
public SqlConfigParser(XmlConverter sqlConfigConv, XmlConverter sqlConv) {
super(new Variables());
parser.setValidation(true);
parser.setEntityResolver(new SqlClasspathEntityResolver());
vars.sqlConfigConv = sqlConfigConv;
vars.sqlConv = sqlConv;
vars.delegate = new SqlExecutorDelegate();
vars.typeHandlerFactory = vars.delegate.getTypeHandlerFactory();
vars.client = new SqlClientImpl(vars.delegate);
registerDefaultTypeAliases();
addSqlConfigNodelets();
addGlobalPropNodelets();
addSettingsNodelets();
addTypeAliasNodelets();
addTypeHandlerNodelets();
addTransactionManagerNodelets();
addSqlNodelets();
addResultObjectFactoryNodelets();
}
XceDataSourceFactory是事物配置的其中一种。XceDataSourceFactory负责根据数据源,获取数据库连接。这里会根据数据库操作类型判断连接到哪种数据库,Master或者是Slaver(主库从库)。
这段代码会将Ibatis配置文件的的标签与标签解析器建立Map。形如XPath->Notelet。
public SqlClient parse(Reader reader) {
try {
if (vars.sqlConfigConv != null) {
reader = vars.sqlConfigConv.convertXml(reader);
}
usingStreams = false;
parser.parse(reader);
return vars.client;
} catch (Exception e) {
throw new RuntimeException("Error occurred. Cause: " + e, e);
}
}
当执行SqlConfigParser的parser方法时,Ibatis的SqlConfigParser会解析XML配置文件,根据XPath->Notelet。针对不同的标签进行不同的处理。如:遇到transactionManager标签,就会配置transactionManager。遇到sqlMap标签,就会构建从statement name到sql statement的映射。
2、Ibatis的执行
从图中可知sql的实际执行单位是SqlExecutorDelegate。而这个sql执行单位的执行需要多个部分的支持【TODO】
2、Ibatis事物
为了保证事物的原子性、一致性、隔离性、持久性。Transaction接口提供了提交和回滚两个操作。除此之外事物接口还提供了获取连接,获取数据库名称。其中获取数据库连接是通过DataSourceFactory来获取。这里可以做主库从库的路由。
接口SqlTransactionManager这对Transaction进行封装,提供能够给用户使用的接口。
3、SqlSession
SqlSession包含和sql操作以及事物操作。它是应线程安全而生的,也就是说一个线程用有一个SqlSession。每个线程的状态不同,这个标识每个线程状态的接口就是Scope。本来Ibatis的作者系统通过K-V的形式存储每个线程的状态,但是不知道为啥。它没有这样做。原因有待继续向下看。...
private static AtomicLong atomicId = new AtomicLong(1L);
private long id;
// Used by Any
private ExtendedSqlClient sqlClient;
private SqlExecutor sqlExecutor;
private ExtendedSqlClient sqlTxMgr;
private int requestStackDepth;
// Used by TransactionManager
private Transaction transaction;
private TransactionState transactionState;
// Used by SqlExecutorDelegate.setUserProvidedTransaction()
private TransactionState savedTransactionState;
// Used by StandardSqlClient and GeneralStatement
private boolean inBatch;
// Used by SqlExecutor
private Object batch;
private boolean commitRequired;
...
SessionScop记录了这些信息,TransactionState是用来记录事物状态的,事物的回滚也是通过这个标识,判断是否已经成功提交,如果没有,就回滚的。transaction是用来判断这个sql操作是否使用了事物操作【TODO】。
4、Ibatis sql执行
具体执行sql的类是SqlExecutor。