J~杰's Blog

人生就一条路,走一步有一步的景观

0%

MCP 解决了一个根本问题:Agent 如何连接真实世界的数据和系统。没有这个连接,Agent 就只是一个沙盒里的玩具。

最近 Anthropic 发布了工程博客《Code execution with MCP: Building more efficient agents》(2025-11-04),系统阐述了 MCP 协议如何让 Agent 更高效地接入生产系统。网上已有不少解读文章,但大多是”官方说了什么”的搬运。

这篇文章不一样。我用一个真实的公司内部运维诊断系统作为案例,手把手展示 MCP 和 Skills 怎么配合——将官方思路落地到我们的实践中,看看每一步到底对不对。

一、MCP 30 秒理解

先解决一个基本问题:MCP 到底是什么?

一句话:MCP 是一个标准协议,让任何 AI Agent 都能用同一套接口连接任何外部系统。

一张图

mcp

根据 Anthropic 官方博客和 MCP 协议的设计意图,Agent 连接外部系统有三条路径:

路径 特点 适用场景
直接 API 调用 最简单,但每个 Agent × 每个系统 = 独立集成 1:1 简单场景
CLI 命令行 轻量快速,但无法穿透到移动端和云端 本地调试
MCP 标准化协议,一次实现处处可用 生产环境,规模化

我们的实践验证:在公司内部,我们选择了 MCP 路径来构建运维诊断系统——Agent 通过 MCP 协议连接监控数据平台,而不是为每个 Agent 写一套独立的 API 集成代码。


二、动手:搭一个 MCP Server

理解了 MCP 是什么,接下来动手。以我们内部的运维诊断 MCP Server 为例。

2.1 一行命令安装

在 Claude Code 中,安装一个远程 MCP Server 只需要一行命令:

1
claude mcp add --transport http ai-ops-mcp https://内部域名/ai-ops/streamablehttp

关键参数说明:

  • --transport http:使用 HTTP 传输协议(远程服务器必须用 HTTP 或 SSE,不能用 stdio)
  • --header "apikey:xxxx":自定义请求头,用于内部网关鉴权

2.2 连通性验证

安装后,Claude Code 自动检测 MCP 工具。在对话中直接问 Claude:

1
"帮我看看有哪些 ai-ops 相关的工具"

Claude 会列出所有 mcp__ai-ops-mcp__ 开头的工具:

1
2
3
4
5
6
7
8
9
10
11
12
13
mcp__ai-ops-mcp__getAppCpuUsageLastHour   → Pod 级别 CPU 使用率
mcp__ai-ops-mcp__getAppQps → 按接口/Pod 请求率
mcp__ai-ops-mcp__getAppResponseTime → 按接口平均响应时间
mcp__ai-ops-mcp__getAppDruidActiveCount → 活跃数据库连接数
mcp__ai-ops-mcp__getAppDruidPoolingCount → 连接池大小
mcp__ai-ops-mcp__getAppJvmGcCms → CMS GC 耗时/次数
mcp__ai-ops-mcp__getAppJvmGcG1Old → G1 Old GC 耗时/次数
mcp__ai-ops-mcp__getAppJvmGcG1Young → G1 Young GC 耗时/次数
mcp__ai-ops-mcp__getAppJvmGcParNew → ParNew GC 耗时/次数
mcp__ai-ops-mcp__getAppJvmThreadCount → 线程数变化量
mcp__ai-ops-mcp__getAppElasticJobFail → 定时任务失败数
mcp__ai-ops-mcp__getAppElasticJobSuccess → 定时任务成功数
mcp__ai-ops-mcp__getAppErrorLog → 最近 100 条错误日志

13 个工具,覆盖了运维诊断的全部核心指标。

Read more »

背景

在中间件统一监控和微服务治理的推进过程中,我们一直面临着一个显著的挑战:由于历史原因,公司内部应用数量庞大,推动业务侧通过 SDK 改造并发布新版本的成本极高,升级的阻力也较大。为了解决这一痛点,我们开始探索通过 Agent 技术统一实现公共的监控和服务治理。

为什么选择 Sermant

Sermant 是一种基于 Java 字节码增强技术的无代理服务网格。其核心原理是通过 JavaAgent 将 Sermant 挂载至目标进程中,借助插件化机制支持多种扩展功能。这种设计不仅降低了业务接入门槛,还显著减少了改造成本。

从 Sermant 1.0 版本发布开始,我们便启动了相关的探索和实践。在多次版本迭代中,我们发现 Sermant 的功能和稳定性持续优化,能够很好地满足我们的业务需求。目前,我们的系统已全面升级至 Sermant 1.3.1 版本。

目前在我司基本已全量应用接入使用,共200多个服务,1000多台pod。

Read more »

现象

下面我把异常的现象给大家描述一下,小伙伴建了一张表,表的主键是id BigINT,用来存储雪花算法生成的ID,嗯,这个没有问题!

1
2
3
4
5
CREATE TABLE user
(
id BIGINT(20) NOT NULL COMMENT '主键ID',
#其他字段省略
);

使用Long 类型对应数据库ID数据。嗯,也没有问题,雪花算法生成的就是一串数字,Long类型属于标准答案!

1
2
3
4
@Data
public class User {
private Long id;
//其他成员变量省略

在后端下断点。看到数据响应以JSON响应给前端,正常

1
2
3
4
{
id:1297873308628307970,
//其他属性省略
}

最后,这条数据返回给前端,前端接收到之后,修改这条数据,后端再次接收回来。奇怪的问题出现了:后端重新接收回来的id变成了:12978733086283000000,不再是1297873308628307970

Read more »

1.背景

Jedis 是一个很老牌的 Redis 的 Java 开发包,使用很稳定,使用范围最广的 Redis 开发包。但是 Jedis 比较推出时间比较早,整个设计思路比较传统,例如不支持异步操作,接口设计比较繁琐老套(相比其他开发包而已),使用连接池占用很多的物理连接资源。当然,这个是可以理解的,比较一个比较早期的开发包,相对其做大的结构调整是很难的,而且用户也不一定会接受。

相比较 Jedis ,我觉得 Lettuce 的优点有如下几个方面:

  • 更加直观、结构更加良好的接口设计
  • 基于 Netty NIO 可以高效管理 Redis 连接,不用连接池方式
  • 支持异步操作(J2Cache 暂时没用到这个特性)
  • 文档非常详尽

LettuceConnectionFactory 类里面有个参数 shareNativeConnection,默认为 true,意思是共用这一个连接,所以默认情况下 lettuce 的连接池是没有用的;如果需要使用连接池,shareNativeConnection 设置为 false 就可以了。

spring-data-redis中的luttucefactory 默认情况是复用一个redis连接的,如果以下情况,则是会新生成一个connection

  • 1.请求批量下发,即禁止调用命令后立即flush
  • 2.使用BLPOP这种阻塞命令
  • 3.事务操作
  • 4.有多个数据库的情况

但在升级之前,我们还需确认lettuce的性能如何,下面就开始lettuce和jedis的性能测试对比。

Read more »

背景

在给业务方用otter做数据迁移时,发现数据库经常出现死锁问题,数据迁移Load阶段的同步性能比较低下,每隔几批就会出现load阶段执行时间超过3s。

同步日志如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
Jul  9 13:57:28 otter2 otter-node-prd[235942]: 2021-07-09 13:57:28.867 [pipelineId = 1,taskName = SelectWorker] WARN  com.alibaba.otter.node.etl.select.SelectTask - cost processId:502379 Select耗时:10 数量:1000
Jul 9 13:57:32 otter-chd otter-node-prd[28036]: 2021-07-09 13:57:32.230 [pipelineId = 1,taskName = LoadWorker] WARN com.alibaba.otter.node.etl.load.LoadTask - cost processId:502375 Load耗时:3009
Jul 9 13:57:32 otter2 otter-node-prd[235942]: 2021-07-09 13:57:32.673 [pipelineId = 1,taskName = SelectWorker] WARN com.alibaba.otter.node.etl.select.SelectTask - cost processId:502380 Select耗时:14 数量:1000
Jul 9 13:57:35 otter-chd otter-node-prd[28036]: 2021-07-09 13:57:35.926 [pipelineId = 1,taskName = LoadWorker] WARN com.alibaba.otter.node.etl.load.LoadTask - cost processId:502376 Load耗时:3008
Jul 9 13:57:36 otter2 otter-node-prd[235942]: 2021-07-09 13:57:36.369 [pipelineId = 1,taskName = SelectWorker] WARN com.alibaba.otter.node.etl.select.SelectTask - cost processId:502381 Select耗时:14 数量:1000
Jul 9 13:57:37 toh6 otter-node-prd[5575]: 2021-07-09 13:57:37.285 [pipelineId = 4,taskName = LoadWorker] WARN com.alibaba.otter.node.etl.load.LoadTask - cost processId:263714 Load耗时:3
Jul 9 13:57:39 otter-chd otter-node-prd[28036]: 2021-07-09 13:57:39.626 [pipelineId = 1,taskName = LoadWorker] WARN com.alibaba.otter.node.etl.load.LoadTask - cost processId:502377 Load耗时:3008
Jul 9 13:57:40 otter2 otter-node-prd[235942]: 2021-07-09 13:57:40.136 [pipelineId = 1,taskName = SelectWorker] WARN com.alibaba.otter.node.etl.select.SelectTask - cost processId:502382 Select耗时:10 数量:1000
Jul 9 13:57:41 toh6 otter-node-prd[5575]: 2021-07-09 13:57:41.288 [pipelineId = 4,taskName = LoadWorker] WARN com.alibaba.otter.node.etl.load.LoadTask - cost processId:263715 Load耗时:2
Jul 9 13:57:43 toh6 otter-node-prd[5575]: 2021-07-09 13:57:43.280 [pipelineId = 4,taskName = LoadWorker] WARN com.alibaba.otter.node.etl.load.LoadTask - cost processId:263716 Load耗时:3
Jul 9 13:57:43 otter-chd otter-node-prd[28036]: 2021-07-09 13:57:43.393 [pipelineId = 1,taskName = LoadWorker] WARN com.alibaba.otter.node.etl.load.LoadTask - cost processId:502378 Load耗时:3007
Jul 9 13:57:43 otter2 otter-node-prd[235942]: 2021-07-09 13:57:43.892 [pipelineId = 1,taskName = SelectWorker] WARN com.alibaba.otter.node.etl.select.SelectTask - cost processId:502383 Select耗时:12 数量:1000
Jul 9 13:57:53 otter-chd otter-node-prd[28036]: 2021-07-09 13:57:53.226 [pipelineId = 1,taskName = LoadWorker] WARN com.alibaba.otter.node.etl.load.LoadTask - cost processId:502379 Load耗时:9012
Jul 9 13:57:54 otter2 otter-node-prd[235942]: 2021-07-09 13:57:53.955 [pipelineId = 1,taskName = SelectWorker] WARN com.alibaba.otter.node.etl.select.SelectTask - cost processId:502384 Select耗时:13 数量:1000
Jul 9 13:57:57 toh6 otter-node-prd[5575]: 2021-07-09 13:57:57.291 [pipelineId = 4,taskName = LoadWorker] WARN com.alibaba.otter.node.etl.load.LoadTask - cost processId:263717 Load耗时:3
Jul 9 13:57:57 otter-chd otter-node-prd[28036]: 2021-07-09 13:57:57.221 [pipelineId = 1,taskName = LoadWorker] WARN com.alibaba.otter.node.etl.load.LoadTask - cost processId:502380 Load耗时:3010
Jul 9 13:57:57 otter2 otter-node-prd[235942]: 2021-07-09 13:57:57.696 [pipelineId = 1,taskName = SelectWorker] WARN com.alibaba.otter.node.etl.select.SelectTask - cost processId:502385 Select耗时:12 数量:1000
Jul 9 13:57:59 toh6 otter-node-prd[5575]: 2021-07-09 13:57:59.303 [pipelineId = 4,taskName = LoadWorker] WARN com.alibaba.otter.node.etl.load.LoadTask - cost processId:263718 Load耗时:2
Jul 9 13:58:01 otter-chd otter-node-prd[28036]: 2021-07-09 13:58:00.997 [pipelineId = 1,taskName = LoadWorker] WARN com.alibaba.otter.node.etl.load.LoadTask - cost processId:502381 Load耗时:3009
Jul 9 13:58:01 toh6 otter-node-prd[5575]: 2021-07-09 13:58:01.287 [pipelineId = 4,taskName = LoadWorker] WARN com.alibaba.otter.node.etl.load.LoadTask - cost processId:263719 Load耗时:2
Jul 9 13:58:01 otter2 otter-node-prd[235942]: 2021-07-09 13:58:01.464 [pipelineId = 1,taskName = SelectWorker] WARN com.alibaba.otter.node.etl.select.SelectTask - cost processId:502386 Select耗时:13 数量:1000
Jul 9 13:58:03 toh6 otter-node-prd[5575]: 2021-07-09 13:58:03.303 [pipelineId = 4,taskName = LoadWorker] WARN com.alibaba.otter.node.etl.load.LoadTask - cost processId:263720 Load耗时:3
Jul 9 13:58:04 otter-chd otter-node-prd[28036]: 2021-07-09 13:58:04.728 [pipelineId = 1,taskName = LoadWorker] WARN com.alibaba.otter.node.etl.load.LoadTask - cost processId:502382 Load耗时:3009
Jul 9 13:58:05 otter2 otter-node-prd[235942]: 2021-07-09 13:58:05.205 [pipelineId = 1,taskName = SelectWorker] WARN com.alibaba.otter.node.etl.select.SelectTask - cost processId:502387 Select耗时:6 数量:1000
Jul 9 13:58:05 toh6 otter-node-prd[5575]: 2021-07-09 13:58:05.301 [pipelineId = 4,taskName = LoadWorker] WARN com.alibaba.otter.node.etl.load.LoadTask - cost processId:263721 Load耗时:3
Jul 9 13:58:08 otter-chd otter-node-prd[28036]: 2021-07-09 13:58:08.475 [pipelineId = 1,taskName = LoadWorker] WARN com.alibaba.otter.node.etl.load.LoadTask - cost processId:502383 Load耗时:3011
Jul 9 13:58:09 otter2 otter-node-prd[235942]: 2021-07-09 13:58:08.949 [pipelineId = 1,taskName = SelectWorker] WARN com.alibaba.otter.node.etl.select.SelectTask - cost processId:502388 Select耗时:11 数量:1000
Jul 9 13:58:12 otter-chd otter-node-prd[28036]: 2021-07-09 13:58:12.225 [pipelineId = 1,taskName = LoadWorker] WARN com.alibaba.otter.node.etl.load.LoadTask - cost processId:502384 Load耗时:3015
Jul 9 13:58:12 otter2 otter-node-prd[235942]: 2021-07-09 13:58:12.595 [pipelineId = 1,taskName = SelectWorker] WARN com.alibaba.otter.node.etl.select.SelectTask - cost processId:502389 Select耗时:12 数量:1000
Jul 9 13:58:15 toh6 otter-node-prd[5575]: 2021-07-09 13:58:15.301 [pipelineId = 4,taskName = LoadWorker] WARN com.alibaba.otter.node.etl.load.LoadTask - cost processId:263722 Load耗时:3
Jul 9 13:58:15 otter-chd otter-node-prd[28036]: 2021-07-09 13:58:15.851 [pipelineId = 1,taskName = LoadWorker] WARN com.alibaba.otter.node.etl.load.LoadTask - cost processId:502385 Load耗时:3009
Jul 9 13:58:16 otter2 otter-node-prd[235942]: 2021-07-09 13:58:16.326 [pipelineId = 1,taskName = SelectWorker] WARN com.alibaba.otter.node.etl.select.SelectTask - cost processId:502390 Select耗时:12 数量:1000
Jul 9 13:58:17 toh6 otter-node-prd[5575]: 2021-07-09 13:58:17.304 [pipelineId = 4,taskName = LoadWorker] WARN com.alibaba.otter.node.etl.load.LoadTask - cost processId:263723 Load耗时:2
Jul 9 13:58:19 otter-chd otter-node-prd[28036]: 2021-07-09 13:58:19.553 [pipelineId = 1,taskName = LoadWorker] WARN com.alibaba.otter.node.etl.load.LoadTask - cost processId:502386 Load耗时:3009
Jul 9 13:58:20 otter2 otter-node-prd[235942]: 2021-07-09 13:58:20.089 [pipelineId = 1,taskName = SelectWorker] WARN com.alibaba.otter.node.etl.select.SelectTask - cost processId:502391 Select耗时:13 数量:1000
Read more »

Saga简介

Saga 是一种补偿协议,在 Saga 模式下,分布式事务内有多个参与者,每一个参与者都是一个冲正补偿服务,需要用户根据业务场景实现其正向操作和逆向回滚操作。

分布式事务执行过程中,依次执行各参与者的正向操作,如果所有正向操作均执行成功,那么分布式事务提交。如果任何一个正向操作执行失败,那么分布式事务会退回去执行前面各参与者的逆向回滚操作,回滚已提交的参与者,使分布式事务回到初始状态。
状态图如下:

状态图

Saga 模式下分布式事务通常是由事件驱动的,各个参与者之间是异步执行的,Saga 模式是一种长事务解决方案。

事务参与者可能是其它公司的服务或者是遗留系统的服务,无法进行改造和提供 TCC 要求的接口,可以使用 Saga 模式。

Saga模式的优势是:

  • 一阶段提交本地数据库事务,无锁,高性能;
  • 参与者可以采用事务驱动异步执行,高吞吐;
  • 补偿服务即正向服务的“反向”,易于理解,易于实现;

Saga模式缺点:

Saga 模式由于一阶段已经提交本地数据库事务,且没有进行“预留”动作,所以不能保证隔离性。

基于状态机引擎的 Saga 实现

基本原理:

  1. 基于json格式定义服务调用状态图;
  2. 状态图的一个节点可以是一个服务,节点可以配置补偿节点;
  3. 状态图json由状态机执行引擎驱动执行,当出现异常状态时状态机引擎执行反向补偿任务将事物回滚;
  4. 异常状态发生时是否进行补偿由用户自定义决定;
  5. 可以实现服务编排的需求,支持单项选择、并发、异步、子状态机调用、参数转换、参数映射、服务执行状态判断、异常捕获等功能;

状态图

Read more »

TCC简介

在2PC(两阶段提交)协议中,事务管理器分两阶段协调资源管理,资源管理器对外提供了3个操作,分别是一阶段的准备操作,二阶段的提交操作和回滚操作;

TCC服务作为一种事务资源,遵循两阶段提交协议,由业务层面自定义,需要用户根据业务逻辑编码实现;其包含Try、Confirm 和 Cancel 3个操作,其中Try操作对应分布式事务一阶段的准备,Confirm操作对应分布式事务二阶段提交,Cancel对应分布式事务二阶段回滚:

  • Try:资源的检查和预留;

  • Comfirm:使用预留的资源,完成真正的业务操作;要求Try成功Confirm 一定要能成功;

  • Cancel:释放预留资源;

TCC的3个方法均由用户根据业务场景编码实现,并对外发布成微服务,供事务管理器调用;事务管理器在一阶段调用TCC的Try方法,在二阶段提交时调用Confirm方法,在二阶段回滚时调用Cancel方法。

seata tcc实现

TCC服务由用户编码实现并对外发布成微服务,目前支持3种形式的TCC微服务,分别是:

  • SofaRpc服务-蚂蚁开源:用户将实现的TCC操作对外发布成 SofaRpc 服务,事务管理器通过订阅SofaRpc服务,来协调TCC资源;
  • Dubbo服务:将TCC发布成dubbo服务,事务管理器订阅dubbo服务,来协调TCC资源;
  • Local TCC:本地普通的TCC Bean,非远程服务;事务管理器通过本地方法调用,来协调TCC 资源;

目前荐于我司使用的微服务是spring cloud组件,微服务调用的rpc是feign(http协议),故tcc选取用local tcc模式即可!!!

Read more »

seata AT模式简介

AT模式是 Seata 主推的分布式事务解决方案,它使得应用代码可以像使用本地事物一样使用分布式事物,完全屏蔽了底层细节,主要有以下几点:

  • AT模式依赖全局事物注解和代理数据源,其余代码不需要变更,对业务无侵入、接入成本低;
  • AT模式的作用范围在于底层数据,通过保存操作行记录的前后快照和生成反向SQL语句进行补偿操作,对上层应用透明;
  • AT模式需借助全局锁和GlobalLock注解来解决全局事务间的写冲突问题,如果一阶段分支事物成功则二阶段一开始全局锁即被释放,否则需要等到分支事务二阶段回滚完成才能释放全局锁;

seata AT工作流程

seata AT工作流程

概括来讲,AT 模式的工作流程分为两阶段。一阶段进行业务 SQL 执行,并通过 SQL 拦截、SQL 改写等过程生成修改数据前后的快照(Image),并作为 UndoLog 和业务修改在同一个本地事务中提交。

如果一阶段成功那么二阶段仅仅异步删除刚刚插入的 UndoLog;如果二阶段失败则通过 UndoLog 生成反向 SQL 语句回滚一阶段的数据修改。

Read more »

背景

我们公司在升级Apollo1.8.1版本之后,发Item表的创建时间和更新时间字段与portal上展示差了13个小时,现象如下:

Item表结构:

排查过程

  1. 刚开始我们想到肯定是数据库的时区与Adminservice服务器时间的时区不一致导致的。

    Adminservice所在的服务器时区是CST中国标准时间:

    Mysql服务器的时区如下:

    发现服务器和mysql服务器的时区是一致的,在加上和运维沟通后他们最近也没有升级服务器相关,应该不是这里的问题。

    Read more »

背景

在线下环境给业务方同步全量同步数据中,写目标库的时候发生了写入失败,报错信息如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
pid:1 nid:1 exception:setl:com.alibaba.otter.node.etl.load.exception.LoadException: java.util.concurrent.ExecutionException: com.alibaba.otter.node.etl.load.exception.LoadException: com.alibaba.otter.node.etl.load.exception.LoadException: com.alibaba.otter.node.etl.load.exception.LoadException: org.springframework.dao.DataIntegrityViolationException: PreparedStatementCallback; SQL [insert into `drugs`.`user_pro_device_bind_log`(`userProDeviceId` , `userProDeviceBindLogType` , `processDate` , `uuid` , `appDeviceType` , `createDate` , `modifyDate` , `id`) values (? , ? , ? , ? , ? , ? , ? , ?) on duplicate key update `userProDeviceId`=values(`userProDeviceId`) , `userProDeviceBindLogType`=values(`userProDeviceBindLogType`) , `processDate`=values(`processDate`) , `uuid`=values(`uuid`) , `appDeviceType`=values(`appDeviceType`) , `createDate`=values(`createDate`) , `modifyDate`=values(`modifyDate`) , `id`=values(`id`)]; Data truncation: Incorrect datetime value: '0000-00-00 00:00:00' for column 'createDate' at row 1; nested exception is com.mysql.jdbc.MysqlDataTruncation: Data truncation: Incorrect datetime value: '0000-00-00 00:00:00' for column 'createDate' at row 1
at org.springframework.jdbc.support.SQLStateSQLExceptionTranslator.doTranslate(SQLStateSQLExceptionTranslator.java:101)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:72)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:80)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:603)
at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:812)
at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:868)
at com.alibaba.otter.node.etl.load.loader.db.DbLoadAction$DbLoadWorker$2.doInTransaction(DbLoadAction.java:655)
at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:130)
at com.alibaba.otter.node.etl.load.loader.db.DbLoadAction$DbLoadWorker.doCall(DbLoadAction.java:647)
at com.alibaba.otter.node.etl.load.loader.db.DbLoadAction$DbLoadWorker.call(DbLoadAction.java:574)
at com.alibaba.otter.node.etl.load.loader.db.DbLoadAction.doTwoPhase(DbLoadAction.java:485)
at com.alibaba.otter.node.etl.load.loader.db.DbLoadAction.doLoad(DbLoadAction.java:279)
at com.alibaba.otter.node.etl.load.loader.db.DbLoadAction.load(DbLoadAction.java:165)
at com.alibaba.otter.node.etl.load.loader.db.DbLoadAction$$FastClassByCGLIB$$d932a4cb.invoke()
at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:191)
at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:618)
at com.alibaba.otter.node.etl.load.loader.db.DbLoadAction$$EnhancerByCGLIB$$80fd23c2.load()
at com.alibaba.otter.node.etl.load.loader.db.DataBatchLoader$2.call(DataBatchLoader.java:192)
at com.alibaba.otter.node.etl.load.loader.db.DataBatchLoader$2.call(DataBatchLoader.java:183)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)

从业务方了解到,源库是mysql5.6版本,字段类型默认DEFAULT ‘0000-00-00 00:00:00’ 处理,目标库是mysql5.7,表结构如下:

1
2
3
4
5
6
7
8
CREATE TABLE `tanlb...` (
// .......
`fromDate` datetime NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '起始的过期时间',
`toDate` datetime NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '在经过相关业务以后过期时间,业务类型取决于@userProStatLogType',
`createDate` datetime NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '激活时间',
`modifyDate` datetime NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '过期时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=153233 DEFAULT CHARSET=utf8mb4;

解决方案

连接数据库转化为对象出错的解决办法为在数据库连接后面加上参数zeroDateTimeBehavior=convertToNull 这样如果碰到 ‘0000-00-00:00:00:00’的日期类型时,将会转化为null值

1
jdbcurl=jdbc:mysql://192.168.1.52:3306/db?characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull

针对数据插入数据‘0000-00-00:00:00:00’ 数据本身不接受的解决办法为,用root用户登录,重新设置数据库的模式(尽量使用root用户 要不然 GLOBAL设置不成功,但是可以设置SESSION的)

  1. 查询数据库现有的模式

    1
    select @@sql_mode;
  2. 把NO_ZERO_IN_DATE,NO_ZERO_DATE去掉,然后重新设置

    1
    SET GLOBAL sql_mode = 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION'

    这样关闭数据库客户端的连接,重新登录,然后再执行那种比较操蛋的插入语句即可正确的插入。