本文介紹使用 AT 模式接入 GTS 時的注意事項。

單個事務內操作記錄建議少于 200 條

雖然 GTS 本身支持大事務,可以支持 1 萬行的數據規模,但建議使用時不要超過 200 條。原因有以下兩方面。

  • 造成事務執行時間上升,事務信息規模擴大,導致系統性能下降。
  • 造成潛在的事務數據不一致問題。如果有特殊業務,需要單個事務超過 1000 條 SQL 語句,請提交工單申請。

事務隔離級別

GTS 的缺省事務隔離級別為讀未提交,該模式下可以達到分布式事務的最大性能。如果有特殊業務,需要隔離級別為讀已提交,可以使用 SQL 的 for update。

注意 讀已提交的 for update 必須在一個 GTS 的分布式事務內部才能生效。

GTS 的讀已提交用法示例如下:

SELECT name FROM tb WHERE id =1 FOR UPDATE;            
說明 如果您需要讀已提交以上的隔離級別,或者您對 GTS 的讀未提交有疑慮,請提交工單申請,GTS 技術支持人員會協助您優化您的事務和相關 SQL。

確保 GTS 事務管理范圍內的所有數據不會被 GTS 管理范圍外的系統修改

GTS 的全局數據庫寫鎖僅針對加入了 GTS 事務的數據庫操作,如果一個對數據庫的寫操作不在 GTS 事務管理的范圍內,會造成“臟寫”。例如,一個寫操作在 GTS 事務中對一條數據進行了修改,但是尚未提交,使用 MySQL 控制臺(不在 GTS 事務范圍內)對該數據也進行了修改,而此時業務驅動前面的 GTS 事務回滾,這次回滾會失敗,造成數據不一致。

關閉 Druid 連接池的 SQL 緩存功能

配合 EDAS、DRDS 共同使用的場景中,GTS 事務上下文通過 SQL hint 的形式下發到 DRDS。

在 Druid 開啟 PreparedStatement 緩存功能后,Druid 會緩存前一次執行的包含事務上下文的 SQL 語句。在另一個事務進行時,發送這個包含過期事務上下文的 SQL 就會被認為無效而發生錯誤。

所以,這種場景中,需要關閉 Druid 連接池的 SQL 緩存功能。方法如下:

<bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init">

    <!-- 其他property略 -->
    <!-- 同時配置下面兩個值來關閉PS Cache -->
    <!-- poolPreparedStatements = false -->
    <property name="poolPreparedStatements" value="false" />
    <!-- maxPoolPreparedStatementPerConnectionSize = 0 -->
    <property name="maxPoolPreparedStatementPerConnectionSize" value="0" />
</bean>     

數據源配置

GTS 可以支持 MySQL、DRDS、Oracle、RDS、PostgreSQL 等數據庫。在訪問不同類型數據庫時,配置也有所不同。

  • 訪問 5.3 以下版本的 DRDS 數據庫

    當應用通過 GTS 訪問 DRDS 數據庫時,不能使用 TxcDataSource 數據源,可以使用 JDBC 數據源。

    配置方式如下:

    <bean id="DataSource1" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="url" value="jdbc:mysql://xxx:3306/xxx" />
        <property name="username" value="xxx" />
        <property name="password" value="xxx" />
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    </bean>           
  • 訪問 5.3 及以上版本的 DRDS 或其他關系數據庫

    當應用通過 GTS 訪問非 DRDS 數據庫時,如 MySQL、DRDS(5.3及以上版本)、Oracle、RDS、PostgreSQL 等,必須要使用 txc 的數據源。

    • 直接使用 txc 數據源,配置方式如下:

      <bean id="DataSource_rds" class="com.taobao.txc.datasource.cobar.TxcDataSource">
           <property name="url" value="jdbc:mysql://xxxxx" />
           <property name="username" value="xxx" />
           <property name="password" value="xxx" />
           <property name="driverClassName" value="com.mysql.jdbc.Driver" />
       </bean>                    
    • 使用 Druid 數據源,配置方式如下:

      <bean id="txcDataSource" class="com.taobao.txc.datasource.cobar.TxcDataSource">
             <constructor-arg ref="druidDataSource"/>
         </bean>
      
         <bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init">
             <property name="url" value="jdbc:mysql://xxxxxxxxx:3306/xxx"/>
             <property name="username" value="xxx"/>
             <property name="connectProperties">
                 <props>
                     <prop key="password">xxx</prop>
                 </props>
             </property>
             <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
             <property name="filters" value="stat" />
             <property name="maxActive" value="300" />
             <property name="initialSize" value="10" />
             <property name="maxWait" value="60000" />
             <property name="minIdle" value="1" />
             <property name="timeBetweenEvictionRunsMillis" value="60000" />
             <property name="minEvictableIdleTimeMillis" value="300000" />
             <property name="validationQuery" value="SELECT 'x'" />
             <property name="testWhileIdle" value="true" />
             <property name="testOnBorrow" value="false" />
             <property name="testOnReturn" value="false" />
             <property name="poolPreparedStatements" value="false" />
             <property name="maxPoolPreparedStatementPerConnectionSize" value="0" />
         </bean>