老熟女激烈的高潮_日韩一级黄色录像_亚洲1区2区3区视频_精品少妇一区二区三区在线播放_国产欧美日产久久_午夜福利精品导航凹凸

重慶分公司,新征程啟航

為企業提供網站建設、域名注冊、服務器等服務

ShardingSphere中JDBC規范與ShardingSphere如何理解

ShardingSphere中JDBC規范與ShardingSphere如何理解,相信很多沒有經驗的人對此束手無策,為此本文總結了問題出現的原因和解決方法,通過這篇文章希望你能解決這個問題。

創新互聯建站始終堅持【策劃先行,效果至上】的經營理念,通過多達10多年累計超上千家客戶的網站建設總結了一套系統有效的推廣解決方案,現已廣泛運用于各行各業的客戶,其中包括:成都履帶攪拌車等企業,備受客戶夸獎。

JDBC規范與ShardingSphere

ShardingSphere是一種典型的客戶端分片解決方案,而客戶端分片的實現方式之一就是重寫JDBC規范。

JDBC 規范簡介

JDBC(Java Database Connectivity)的設計初衷是提供一套用于各種數據庫的統一標準,而不同的數據庫廠家共同遵守這套標準,并提供各自的實現方案供應用程序調用。JDBC規范具有完整的架構體系,如下圖:

ShardingSphere中JDBC規范與ShardingSphere如何理解

對于開發人員而言,JDBC API是我們訪問數據庫的主要途徑,也是ShardingSphere重寫JDBC規范并添加分片功能的入口。JDBC開發一個訪問數據庫的處理流程,常見的代碼風格如下:

// 創建池化的數據源
PooledDataSource dataSource = new PooledDataSource ();
// 設置MySQL Driver
dataSource.setDriver ("com.mysql.jdbc.Driver");
// 設置數據庫URL、用戶名和密碼
dataSource.setUrl ("jdbc:mysql://localhost:3306/test");
dataSource.setUsername ("root");
dataSource.setPassword ("root");
// 獲取連接
Connection connection = dataSource.getConnection();
// 執行查詢
PreparedStatement statement = connection.prepareStatement ("select * from user");
// 獲取查詢結果應該處理
ResultSet resultSet = statement.executeQuery();
while (resultSet.next()) {
	…
}
// 關閉資源
statement.close();
resultSet.close();
connection.close();

DataSource

DataSource 在JDBC規范中代表的是一種數據源,核心作用是獲取數據庫連接對象Connection。在JDBC規范中,實際可以通過DriverManager獲取Connection。我們知道獲取Connection的過程需要建立與數據庫之間的連接,而這個過程會產生較大的系統開銷。

為了提高性能,通常會建立一個中間層,該中間層將DriverManager生成的Connection存放到連接池中,然后從池中獲取Connection,可以認為,DataSource就是這樣一個中間層。在日常開發過程中,我們通常都會基于DataSource來獲取Connection。而在ShardingSphere中,暴露給業務開發人員的同樣是一個經過增強的DataSource對象。DataSource接口的定義是這樣的:

public interface DataSource  extends CommonDataSource, Wrapper {
  Connection getConnection() throws SQLException;
 
  Connection getConnection(String username, String password)
    throws SQLException;
}

ShardingSphere中JDBC規范與ShardingSphere如何理解

其中,DataSource是官方定義的獲取Connection的基礎接口,ConnectionPoolDataSource是從連接池ConnectionPool中獲取的Connection接口。而XADataSource則用來實現在分布式事務環境下獲取Connection。

DataSource 接口同時還繼承了一個 Wrapper 接口。從接口的命名上看,可以判斷該接口應該起到一種包裝器的作用,事實上,由于很多數據庫供應商提供了超越標準 JDBC API 的擴展功能,所以,Wrapper 接口可以把一個由第三方供應商提供的、非 JDBC 標準的接口包裝成標準接口。以 DataSource 接口為例,如果我們想要實現自己的數據源 MyDataSource,就可以提供一個實現了 Wrapper 接口的 MyDataSourceWrapper 類來完成包裝和適配:

ShardingSphere中JDBC規范與ShardingSphere如何理解

在JDBC規范中,除了DataSource之外,Connection、Statement、ResultSet等核心對象也都繼承了這個接口。顯然,ShardingSphere提供的就是非JDBC 標準的接口,所以也應該會用到這個Wrapper接口,并提供了類似的實現方案。

Connection

DataSource的目的是獲取Connection對象,我們可以把Connection理解為一種會話(Session)機制。Connection 代表一個數據庫連接,負責完成與數據庫之間的通信。所有 SQL 的執行都是在某個特定 Connection 環境中進行的,同時它還提供了一組重載方法,分別用于創建 Statement 和 PreparedStatement。另一方面,Connection 也涉及事務相關的操作,為了實現分片操作,ShardingSphere 同樣也實現了定制化的 Connection 類 ShardingConnection。

statement

JDBC 規范中的 Statement 存在兩種類型,一種是普通的 Statement,一種是支持預編譯的 PreparedStatement。所謂預編譯,是指數據庫的編譯器會對 SQL 語句提前編譯,然后將預編譯的結果緩存到數據庫中,這樣下次執行時就可以替換參數并直接使用編譯過的語句,從而提高 SQL 的執行效率。當然,這種預編譯也需要成本,所以在日常開發中,對數據庫只執行一次性讀寫操作時,用 Statement 對象進行處理比較合適;而當涉及 SQL 語句的多次執行時,可以使用 PreparedStatement。

如果需要查詢數據庫中的數據,只需要調用 Statement 或 PreparedStatement 對象的 executeQuery 方法即可,該方法以 SQL 語句作為參數,執行完后返回一個 JDBC 的 ResultSet 對象。當然,Statement 或 PreparedStatement 中提供了一大批執行 SQL 更新和查詢的重載方法。在 ShardingSphere 中,同樣也提供了 ShardingStatement 和 ShardingPreparedStatement 這兩個支持分片操作的 Statement 對象。

ResultSet

一旦通過 Statement 或 PreparedStatement 執行了 SQL 語句并獲得了 ResultSet 對象后,那么就可以通過調用 Resulset 對象中的 next() 方法遍歷整個結果集。對于分庫分表操作而言,因為涉及從多個數據庫或數據表中獲取目標數據,勢必需要對獲取的結果進行歸并。因此,ShardingSphere 中也提供了分片環境下的 ShardingResultSet 對象。

總結

基于JDBC規范進行數據庫訪問的開發流程圖。

ShardingSphere中JDBC規范與ShardingSphere如何理解

基于適配器模式的JDBC重寫實現方案

在 ShardingSphere 中,實現與 JDBC 規范兼容性的基本策略就是采用了設計模式中的適配器模式(Adapter Pattern)。適配器模式通常被用作連接兩個不兼容接口之間的橋梁,涉及為某一個接口加入獨立的或不兼容的功能。

作為一套適配 JDBC 規范的實現方案,ShardingSphere 需要對上面介紹的 JDBC API 中的 DataSource、Connection、Statement 及 ResultSet 等核心對象都完成重寫。雖然這些對象承載著不同功能,但重寫機制應該是共通的,否則就需要對不同對象都實現定制化開發,顯然,這不符合我們的設計原則。為此,ShardingSphere 抽象并開發了一套基于適配器模式的實現方案,整體結構是這樣的,如下圖所示:

ShardingSphere中JDBC規范與ShardingSphere如何理解

首先,我們看到這里有一個JdbcObject 接口,這個接口泛指JDBC API 中的 DataSource、Connection、Statement等核心接口。這些接口都繼承自包裝器Wrapper接口。ShardingSphere為這個Wrapper接口提供了一個實現類WrapperAdapter。

ShardingSphere基于適配器模式的實現方案圖的底部,有一個ShardingJdbcObject類的定義。這個類也是一種泛指,代表ShardingSphere中用于分片的ShardingDataSource、ShardingConnection、ShardingStatement等對象。

最后發現 ShardingJdbcObject 繼承自一個 AbstractJdbcObjectAdapter,而 AbstractJdbcObjectAdapter 又繼承自 AbstractUnsupportedOperationJdbcObject,這兩個類都是抽象類,而且也都泛指一組類。兩者的區別在于,AbstractJdbcObjectAdapter 只提供了針對 JdbcObject 接口的一部分實現方法,這些方法是我們完成分片操作所需要的。而對于那些我們不需要的方法實現,則全部交由 AbstractUnsupportedOperationJdbcObject 進行實現,這兩個類的所有方法的合集,就是原有 JdbcObject 接口的所有方法定義。

ShardingSphere重寫JDBC規范示例:ShardingConnection

ShardingSphere 的分片引擎中提供了一系列 ShardingJdbcObject 來支持分片操作,包括 ShardingDataSource、ShardingConnection、ShardingStatement、ShardingPreparedStament 等。這里以最具代表性的 ShardingConnection 為例,來講解它的實現過程。請注意,今天我們關注的還是重寫機制,不會對 ShardingConnection 中的具體功能以及與其他類之間的交互過程做過多展開講解。

ShardingSphere中JDBC規范與ShardingSphere如何理解

ShardingConnection 類的一條類層結構支線就是適配器模式的具體應用,這部分內容的類層結構與前面介紹的重寫機制的類層結構是完全一致的,如下圖所示: ShardingSphere中JDBC規范與ShardingSphere如何理解

AbstractConnectionAdapter

我們首先來看看 AbstractConnectionAdapter 抽象類,ShardingConnection 直接繼承了它。在 AbstractConnectionAdapter 中發現了一個 cachedConnections 屬性,它是一個 Map 對象,該對象其實緩存了這個經過封裝的 ShardingConnection 背后真實的 Connection 對象。如果我們對一個 AbstractConnectionAdapter 重復使用,那么這些 cachedConnections 也會一直被緩存,直到調用 close 方法。可以從 AbstractConnectionAdapter 的 getConnections 方法中理解具體的操作過程:

    public final List getConnections(final ConnectionMode connectionMode, final String dataSourceName, final int connectionSize) throws SQLException {
		// 獲取DataSource
        DataSource dataSource = getDataSourceMap().get(dataSourceName);
        Preconditions.checkState(null != dataSource, "Missing the data source name: '%s'", dataSourceName);
        Collection connections;
		// 根據dataSourceName 從cachedConnections中獲取connections
        synchronized (cachedConnections) {
            connections = cachedConnections.get(dataSourceName);
        }
        List result;
		// 如果connections多于想要的connectionsSize,則只獲取所需部分
        if (connections.size() >= connectionSize) {
            result = new ArrayList<>(connections).subList(0, connectionSize);
        } else if (!connections.isEmpty()) { // 如果connections不夠
            result = new ArrayList<>(connectionSize);
            result.addAll(connections);
			// 創建不夠的 connections
            List newConnections = createConnections(dataSourceName, connectionMode, dataSource, connectionSize - connections.size());
            result.addAll(newConnections);
            synchronized (cachedConnections) {
				// 將新創建的connections也放入緩存中進行管理
                cachedConnections.putAll(dataSourceName, newConnections);
            }
        } else {
			// 如果緩存中沒有對應dataSource的Connections,同樣進行創建并放入到緩存中
            result = new ArrayList<>(createConnections(dataSourceName, connectionMode, dataSource, connectionSize));
            synchronized (cachedConnections) {
                cachedConnections.putAll(dataSourceName, result);
            }
        }
        return result;
    }

我們主要關注 createConnections方法:

    private List createConnections(final String dataSourceName, final ConnectionMode connectionMode, final DataSource dataSource, final int connectionSize) throws SQLException {
        if (1 == connectionSize) {
            Connection connection = createConnection(dataSourceName, dataSource);
            replayMethodsInvocation(connection);
            return Collections.singletonList(connection);
        }
        if (ConnectionMode.CONNECTION_STRICTLY == connectionMode) {
            return createConnections(dataSourceName, dataSource, connectionSize);
        }
        synchronized (dataSource) {
            return createConnections(dataSourceName, dataSource, connectionSize);
        }
    }

這段代碼涉及了 ConnectionMode(連接模式),這是 ShardingSphere 執行引擎中的重要概念,今天我們先不展開。可以看到 createConnections 方法批量調用了一個 createConnection 抽象方法,該方法需要 AbstractConnectionAdapter 的子類進行實現:

protected abstract Connection createConnection(String dataSourceName, DataSource dataSource) throws SQLException;

同時,我們看到對于創建Connection對象,都需要執行這樣一個語句:

    replayMethodsInvocation(connection);

這行代碼比較難以理解,讓我們來看看定義它的地方,即WrapperAdapter類。

WrapperAdapter

從命名上看,WrapperAdapter是一個包裝器的適配類,實現了JDBC中的Wrapper接口。我們在該類中找到了這樣一對方法定義:

	//記錄方法調用
    public final void recordMethodInvocation(final Class targetClass, final String methodName, final Class[] argumentTypes, final Object[] arguments) {
        jdbcMethodInvocations.add(new JdbcMethodInvocation(targetClass.getMethod(methodName, argumentTypes), arguments));
    }
	//重放方法調用
    public final void replayMethodsInvocation(final Object target) {
        for (JdbcMethodInvocation each : jdbcMethodInvocations) {
            each.invoke(target);
        }
    }

這兩個方法都用到了JdbcMethodInvocation類:

public class JdbcMethodInvocation {
    
    @Getter
    private final Method method;
    
    @Getter
    private final Object[] arguments;
    
    /**
     * Invoke JDBC method.
     * 
     * @param target target object
     */
    @SneakyThrows
    public void invoke(final Object target) {
        method.invoke(target, arguments);
    }
}

JdbcMethodInvocation 類中用到了反射技術根據傳入的 method 和 arguments 對象執行對應方法。 recordMethodInvocation用于記錄需要執行的方法和參數,而replayMethodsInvocation則根據這些方法和參數通過反射技術進行執行。

對于執行 replayMethodsInvocation,我們必須先找到 recordMethodInvocation 的調用入口。通過代碼的調用關系,可以看到在 AbstractConnectionAdapter 中對其進行了調用,具體來說就是 setAutoCommit、setReadOnly 和 setTransactionIsolation 這三處方法。這里以 setReadOnly 方法為例給出它的實現:

    @Override
    public final void setReadOnly(final boolean readOnly) throws SQLException {
        this.readOnly = readOnly;
 
        //調用recordMethodInvocation方法記錄方法調用的元數據
        recordMethodInvocation(Connection.class, "setReadOnly", new Class[]{boolean.class}, new Object[]{readOnly});

        //執行回調
        forceExecuteTemplate.execute(cachedConnections.values(), new ForceExecuteCallback() {

            @Override
            public void execute(final Connection connection) throws SQLException {
                connection.setReadOnly(readOnly);
            }
        });
    }

AbstractUnsupportedOperationConnection

從類層次關系上,可以看到AbstractConnectionAdapter直接繼承的是AbstractUnsupportedOperationConnection。在AbstractUnsupportedOperationConnection中都是一組直接拋出異常的方法。這里截取部分代碼:

public abstract class AbstractUnsupportedOperationConnection extends WrapperAdapter implements Connection {

    @Override
    public final CallableStatement prepareCall(final String sql) throws SQLException {
        throw new SQLFeatureNotSupportedException("prepareCall");
    }

    @Override
    public final CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency) throws SQLException {
        throw new SQLFeatureNotSupportedException("prepareCall");
}
…
}

AbstractUnsupportedOperationConnection 這種處理方式的目的就是明確哪些操作是 AbstractConnectionAdapter 及其子類 ShardingConnection 所不能支持的,屬于職責分離的一種具體實現方法。

看完上述內容,你們掌握ShardingSphere中JDBC規范與ShardingSphere如何理解的方法了嗎?如果還想學到更多技能或想了解更多相關內容,歡迎關注創新互聯行業資訊頻道,感謝各位的閱讀!


當前文章:ShardingSphere中JDBC規范與ShardingSphere如何理解
網站網址:http://www.xueling.net.cn/article/jeijhj.html

其他資訊

在線咨詢
服務熱線
服務熱線:028-86922220
TOP
主站蜘蛛池模板: 久久国产精品99久久久大便 | 国内午夜国产精品小视频 | 美女一区二区三区视频 | 天美传媒国色天香乱码 | 色欲AV永久无码精品无码蜜桃 | 免费久久99精品国产自在现线 | 精品人妻无码视频中文字幕一区二区三区 | 久久久人成影片一区二区三区 | FREEXXXXHD麻豆精品A∨ | 亚洲毛片免费在线观看 | 公车上玩弄白嫩少妇 | 国产一区二区三区四区成男人 | 亚洲午夜无码久久久久软件 | 亚洲777理论| 影院一区二区 | 又大又粗进去爽A片免费 | 女人18毛片A级毛片嫰阝 | 国产91丝袜香蕉在线播放 | 欧美真人性做爰一二区 | 国产精品久久久久一区二区国产 | 久久久久免费看 | 黄污视频在线免费观看 | 青青一区二区三区 | 欧美日韩高清丝袜 | 蜜桃视频麻豆女神沈芯语免费观看 | 久久久久成人免费视频 | 国产精品白丝喷水娇喘视频 | 久久精品国产清自在天天线 | 成人国产午夜在线观看 | 九月婷婷人人澡人人添人人爽 | 免费观看全黄做爰的视频 | 亚洲熟女综合色一区二区三区 | 国产极品粉嫩福利在线观看 | 日韩精品成人 | 中文字幕免费在线观看动作大片 | 国产91精品久久久久久久网曝门 | 石原莉奈一区二区在线播放 | 日韩高清片 | 91caoporn超碰最新地址 | 好爽进去了视频在线观看国版 | 远方的山楂树免费观看视频48集 |