Fescar - RM UpdateExecutor介紹

開篇

?這篇文章的目的是講解RM Executor模塊當(dāng)中一些通用的方法,這些方法在各個Executor的父類當(dāng)中實現(xiàn)的,各個子類Executor模塊都會復(fù)用,因此抽取出來統(tǒng)一的進(jìn)行講解。

?個人是認(rèn)為抽取通用的內(nèi)容放在一篇文章講解完后可以針對每類Executor講解特有的功能,這樣能夠有更好的理解。這篇文章講解Executor的實現(xiàn)類UpdateExecutor。


類依賴圖


說明:

  • 著重講解UpdateExecutor實現(xiàn)類。


UpdateExecutor方法介紹

public class UpdateExecutor<T, S extends Statement> extends AbstractDMLBaseExecutor<T, S> {

    public UpdateExecutor(StatementProxy statementProxy, StatementCallback statementCallback, SQLRecognizer sqlRecognizer) {
        super(statementProxy, statementCallback, sqlRecognizer);
    }

    @Override
    protected TableRecords beforeImage() throws SQLException {
        SQLUpdateRecognizer recognizer = (SQLUpdateRecognizer)sqlRecognizer;

        TableMeta tmeta = getTableMeta();
        List<String> updateColumns = recognizer.getUpdateColumns();

        StringBuffer selectSQLAppender = new StringBuffer("SELECT ");
        if (!tmeta.containsPK(updateColumns)) {
            // PK should be included.
            selectSQLAppender.append(getColumnNameInSQL(tmeta.getPkName()) + ", ");
        }
        for (int i = 0; i < updateColumns.size(); i++) {
            selectSQLAppender.append(updateColumns.get(i));
            if (i < (updateColumns.size() - 1)) {
                selectSQLAppender.append(", ");
            }
        }
        String whereCondition = null;
        ArrayList<Object> paramAppender = new ArrayList<>();
        if (statementProxy instanceof ParametersHolder) {
            whereCondition = recognizer.getWhereCondition((ParametersHolder)statementProxy, paramAppender);
        } else {
            whereCondition = recognizer.getWhereCondition();
        }
        selectSQLAppender.append(" FROM " + getFromTableInSQL() + " WHERE " + whereCondition + " FOR UPDATE");
        String selectSQL = selectSQLAppender.toString();

        TableRecords beforeImage = null;
        PreparedStatement ps = null;
        Statement st = null;
        ResultSet rs = null;
        try {
            if (paramAppender.isEmpty()) {
                st = statementProxy.getConnection().createStatement();
                rs = st.executeQuery(selectSQL);
            } else {
                ps = statementProxy.getConnection().prepareStatement(selectSQL);
                for (int i = 0; i< paramAppender.size(); i++) {
                    ps.setObject(i + 1, paramAppender.get(i));
                }
                rs = ps.executeQuery();
            }
            beforeImage = TableRecords.buildRecords(tmeta, rs);

        } finally {
            if (rs != null) {
                rs.close();
            }
            if (st != null) {
                st.close();
            }
            if (ps != null) {
                ps.close();
            }
        }
        return beforeImage;
    }
}

說明:

  • UpdateExecutor需要保存SQL執(zhí)行前的鏡像。
  • 執(zhí)行前鏡像的準(zhǔn)備整體思路是按照按照update的更新條件逆向拼接正向查詢SQL。
  • 查詢字段當(dāng)中必須包含主鍵原因是因為afterImage()操作當(dāng)中需要根據(jù)主鍵進(jìn)行查詢。原因猜測因為update會把where條件中字段的值變更,保存主鍵最安全。
  • 查詢的SQL的select的字段從update字段中解析并加上主鍵列
  • 查詢的SQL的條件通過解析update的條件生成。
  • 根據(jù)TableRecords.buildRecords生成執(zhí)行前鏡像。


public class UpdateExecutor<T, S extends Statement> extends AbstractDMLBaseExecutor<T, S> {

    public UpdateExecutor(StatementProxy statementProxy, StatementCallback statementCallback, SQLRecognizer sqlRecognizer) {
        super(statementProxy, statementCallback, sqlRecognizer);
    }


    @Override
    protected TableRecords afterImage(TableRecords beforeImage) throws SQLException {
        SQLUpdateRecognizer recognizer = (SQLUpdateRecognizer)sqlRecognizer;

        TableMeta tmeta = getTableMeta();
        if (beforeImage == null || beforeImage.size() == 0) {
            return TableRecords.empty(getTableMeta());
        }
        List<String> updateColumns = recognizer.getUpdateColumns();

        StringBuffer selectSQLAppender = new StringBuffer("SELECT ");
        if (!tmeta.containsPK(updateColumns)) {
            // PK should be included.
            selectSQLAppender.append(getColumnNameInSQL(tmeta.getPkName()) + ", ");
        }
        for (int i = 0; i < updateColumns.size(); i++) {
            selectSQLAppender.append(updateColumns.get(i));
            if (i < (updateColumns.size() - 1)) {
                selectSQLAppender.append(", ");
            }
        }
        List<Field> pkRows = beforeImage.pkRows();
        selectSQLAppender.append(
            " FROM " + getFromTableInSQL() + " WHERE " + buildWhereConditionByPKs(pkRows) + " FOR UPDATE");
        String selectSQL = selectSQLAppender.toString();

        TableRecords afterImage = null;
        PreparedStatement pst = null;
        ResultSet rs = null;
        try {
            pst = statementProxy.getConnection().prepareStatement(selectSQL);
            int index = 0;
            for (Field pkField : pkRows) {
                index++;
                pst.setObject(index, pkField.getValue(), pkField.getType());
            }
            rs = pst.executeQuery();
            afterImage = TableRecords.buildRecords(tmeta, rs);

        } finally {
            if (rs != null) {
                rs.close();
            }
            if (pst != null) {
                pst.close();
            }
        }
        return afterImage;
    }
}

說明:

  • UpdateExecutor需要保存SQL執(zhí)行后的鏡像。
  • UpdateExecutor執(zhí)行后的鏡像通過查詢更新的字段字段生成的。
  • 查詢更新后鏡像的SQL的select的字段從update字段中解析并加上主鍵列。
  • 查詢更新后鏡像的SQL的條件是beforeImage()查詢得到的主鍵key。
  • 根據(jù)TableRecords.buildRecords生成執(zhí)行前鏡像。


期待

??UpdateExecutor生成執(zhí)行前后鏡像的過程分析完后,接下去會分析生成鏡像日志的流程。


Fescar源碼分析連載

Fescar 源碼解析系列

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 轉(zhuǎn) # https://www.cnblogs.com/easypass/archive/2010/12/ 08/...
    呂品?閱讀 10,108評論 0 44
  • 1 Mybatis入門 1.1 單獨使用jdbc編程問題總結(jié) 1.1.1 jdbc程序 上邊使...
    哇哈哈E閱讀 3,410評論 0 38
  • MYSQL 基礎(chǔ)知識 1 MySQL數(shù)據(jù)庫概要 2 簡單MySQL環(huán)境 3 數(shù)據(jù)的存儲和獲取 4 MySQL基本操...
    Kingtester閱讀 8,050評論 5 115
  • 你是否在某些時候開始迷茫,感到不知所措,開始受到身邊人的影響,別人做什么你也跟著做什么。 今天的我突然意識到自己迷...
    溫執(zhí)空閱讀 354評論 4 2
  • 今早忘記晨效打卡,這應(yīng)該是第二次,不僅自己沒有做到,也拖了小組后腿,我很愧疚! 今早6點半打卡,起床做早飯,蒸蛋羹...
    美梨太太閱讀 238評論 0 0

友情鏈接更多精彩內(nèi)容