前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >基于Druid的长事务监听实现

基于Druid的长事务监听实现

原创
作者头像
宇宙无敌暴龙战士之心悦大王
发布2022-12-01 14:25:53
4.2K0
发布2022-12-01 14:25:53
举报
文章被收录于专栏:kwai

1,增加一个Druid过滤器

代码语言:javascript
复制
/**
 * @Project
 * @Description 大事务监控
 * @Date 2022/10/1 下午3:52
 */
public class MyDruidTxMonitorFilter extends FilterEventAdapter {
    //记录事务状态与事务开启时间
    private static final ThreadLocal<Long> TX_BEGIN_TIME = new ThreadLocal<>();
    //记录事务过程中执行的sql(保留执行顺序)
    private static final ThreadLocal<List<String>> TX_SQL_LIST = new ThreadLocal<List<String>>();
 
 
    @Override
    public void connection_setAutoCommit(FilterChain chain, ConnectionProxy connection, boolean autoCommit)
            throws SQLException {
        super.connection_setAutoCommit(chain, connection, autoCommit);
        if (!autoCommit) {
            monitorReady();
        }
    }
 
 
 
 
 
 
    @Override
    protected void statementExecuteBefore(StatementProxy statement, String sql) {
        monitorSql(sql);
    }
    @Override
    protected void statementExecuteUpdateBefore(StatementProxy statement, String sql) {
        monitorSql(sql);
    }
    @Override
    protected void statementExecuteQueryBefore(StatementProxy statement, String sql) {
        monitorSql(sql);
    }
 
 
    @Override
    public void connection_commit(FilterChain chain, ConnectionProxy connection) throws SQLException {
        try {
            super.connection_commit(chain, connection);
            //提交完成后清理本次事务的开始时间、执行的sql等线程绑定的内容
            monitorTransactionTime();
        } finally {
            monitorRemove();
        }
    }
 
 
    @Override
    public void connection_rollback(FilterChain chain, ConnectionProxy connection) throws SQLException {
        try {
            super.connection_rollback(chain, connection);
            //回滚完成后清理本次事务的开始时间、执行的sql等线程绑定的内容
            monitorTransactionTime();
        } finally {
            monitorRemove();
        }
    }
 
 
    @Override
    public void connection_rollback(FilterChain chain, ConnectionProxy connection, Savepoint savepoint)
            throws SQLException {
        try {
            super.connection_rollback(chain, connection, savepoint);
            //回滚完成后清理本次事务的开始时间、执行的sql等线程绑定的内容
            monitorTransactionTime();
        } finally {
            monitorRemove();
        }
    }
 
 
    /**
     * 监控准备
     */
    private void monitorReady() {
        try {
            if (monitorUnable()) return;
            long beginTime = System.currentTimeMillis();
            TX_BEGIN_TIME.set(beginTime);
            LinkedList<String> list = new LinkedList<>();
            list.add("transaction begin time:"+beginTime);
            TX_SQL_LIST.set(list);
        }catch (Throwable e){
            e.printStackTrace();
        }
 
 
    }
 
 
    /**
     * 是否已禁用
     * @return
     */
    private boolean monitorUnable() {
        LongTxMonitor config = SpringUtil.getBean(LongTxMonitor.class);
        if (!config.getHealthCheckLongTxEnable()) {
            return true;
        }
        return false;
    }
 
 
    /**
     * sql记录
     * @param sql
     */
    private void monitorSql(String sql) {
        try {
            if (monitorUnable()) return;
            if (TX_BEGIN_TIME.get() != null) {
                //只记录开启了事务的sql
                TX_SQL_LIST.get().add("current time:"+System.currentTimeMillis()+",");
                TX_SQL_LIST.get().add(sql+";");
            }
        }catch (Throwable e){
            e.printStackTrace();
        }
 
 
    }
    /**
     * 清理
     */
    private void monitorRemove() {
        try {
            if (monitorUnable()) return;
            TX_BEGIN_TIME.remove();
            TX_SQL_LIST.remove();
        }catch (Throwable e){
            e.printStackTrace();
        }
 
 
    }
 
 
    /**
     * 监控事务持续时间
     */
    private void monitorTransactionTime() {
        try {
            if (monitorUnable()) return;
            //1、计算本次事务持续时间  2、长事务告警(记录本次事务涉及到的sql+记录本次事务的应用层调用栈)
            if (TX_BEGIN_TIME.get()!=null) {
                long currentTime = System.currentTimeMillis();
                long timeCost = currentTime - TX_BEGIN_TIME.get().longValue();
 
 
                LongTxMonitor config = SpringUtil.getBean(LongTxMonitor.class);
                if (config.getHealthCheckLongTxEnable()) {
                    if (timeCost>=config.getHealthCheckLongTx()) {
                        //长事务告警
                        CommonEvent.CommonDto commonDto = new CommonEvent.CommonDto();
                        commonDto.setEventTime(LocalDateTime.now().toString());
                        commonDto.setEventType("长事务");
 
 
                        StringBuilder sqls = new StringBuilder("SQL详情:");
                        TX_SQL_LIST.get().forEach((sql)->{sqls.append(sql);});
 
 
                        commonDto.setArgs(sqls.toString());
                        commonDto.setTimeCost(timeCost);
                        commonDto.setLogId(ThreadContext.get(CommonConst.logId));
                        //获取调用方接口名称和方法
                        commonDto.setStackTraceElements(HealthCheckUtil.getCurrentTTKThreadTrace());
                        SpringUtil.getApplicationEventPublisher().publishEvent(new CommonEvent(commonDto));
                    }
 
 
                }
            }
        }catch (Throwable e){
            e.printStackTrace();
        }
 
 
    }
 
 
 
 
}

2,配置拦截器,使其生效

代码语言:javascript
复制
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
   <property name="url" value="${jdbc.url}" />
   <property name="username" value="${jdbc.username}" />
   <property name="password" value="${jdbc.password}" />
   <property name="proxyFilters">
      <list>
         <bean id="txMonitor" class="com.xxx.MyDruidTxMonitorFilter" />
      </list>
   </property>
</bean>

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档