使用说明

本文介绍如何使用数据访问代理连接器来进行 SQL 链路追踪、指定分库分表路由和拦截器扩展。

SQL 链路追踪

使用以下 HINT 语句,根据 traceIdRpcId 对 SQL 数据库进行追踪:

/*+DBP: $SYS={TRACE(TraceId#RpcId)}*/select*from{table_name}

HINT 语句示例:

/*+DBP: $SYS={TRACE(0a0fe91c1514974353459100919649#0.1)}*/select*from test

数据访问代理连接器会将包括追踪信息在内的 SQL 执行信息输出到本地日志 dbp-connector-digest.log 中。

  • 默认情况下,对于执行时间小于 3ms 且执行成功的 SQL 命令,按照 10/1 的比例抽样打印;

  • 对于执行失败或执行时间大于 3ms 的 SQL 命令,全量打印。

输出的日志格式如下:

日志输出时间,应用名称,traceId,RpcId,SQL 语句,执行结果(success/failed),执行耗时(ms),连接建立时间,数据库执行时间,当前线程名

输出的日志示例如下:

2018-01-0318:12:33.541,xxx,0a0fe91c1514974353459100919649,0.1,select*from test,success,81ms,77ms,4ms,main

分库分表路由指定

使用以下 HINT 语句,指定 SQL 访问某一特定的分库分表:

/*+DBP: $ROUTE={GROUP_ID(分库位),TABLE_NAME(物理表名)}*/ SQL 语句

HINT 语法格式说明:

  • GROUP_ID:指定分库位,等同于 dbRule 返回的结果;

  • TABLE_NAME:指定物理表名。

另外,数据访问代理连接器提供了拦截器,当您在工程代码中指定分库分表后,在 SQL 语句执行前自动拼接路由 HINT 语句。当您在脚本中定义以下字段后:

RouteParameters routeParameters =RouteCondition.newRouteParameters();
routeParameters.setGroupId("分库位");
routeParameters.setTargetTables(Collections.singletonList("物理表名"));
cn = dbpDataSource.getConnection();
ps = cn.prepareStatement("select * from xxxx");

数据访问代理连接器会将其自动转换为以下 HINT 语句:

/*+DBP: $ROUTE={GROUP_ID(分库位),TABLE_NAME(物理表名)}*/select*from xxxx

拦截器扩展

您可通过实现拦截器接口获得更多扩展功能。配置方法如下:

  1. 在 Spring 的配置文件中,添加以下 bean(以 sqlCountInterceptor 类为例):

    <bean id="simpleDataSourceConnector" class="com.alipay.sofa.dbp.DbpDataSource" init-method="init">
    <property name="delegate" ref="simpleDataSource"/>
    <property name="securitySpec" ref="securitySpecImpl"/>
    <property name="interceptors">
    <list>
    <ref bean="sqlCountInterceptor"/>
    </list>
    </property>
    </bean>
    
    <bean id="sqlCountInterceptor" class="com.alipay.sofa.dbp.SqlCountInterceptor"/>
  2. 为添加的 bean 定义拦截器的代码实现,如下所示:

    @NotThreadSafe
    public class SqlCountInterceptor implements Interceptor {
        private static final Map<String, Integer> sqlCounter = new HashMap<>();
    
        @Override
        public Object intercept(Chain chain) throws Exception {
            String sql = chain.sql();
            Integer count = sqlCounter.get(sql);
            if (count == null) {
                sqlCounter.put(sql, 1);
            } else {
                count += 1;
                sqlCounter.put(sql, count);
            }
            return chain.proceed();
        }
    
        public int getSqlExecuteCount(String sql) {
            Integer count = sqlCounter.get(sql);
            if (count == null) {
                return0;
            }
            return count;
        }
    }