Ibatis 源码解析

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;
    }

SqlConfigParser,被BaseDbClient调用,它的工作是具体配置Ibatis的各个组件,以及构建SqlClient,如下为配置Ibatis各个部分的代码。

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();
                                                                                                                                       
    }

配置的Ibatis的主要组件如下:

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。


你可能感兴趣的:(技术博客)