腾讯业务百万数据 6s 响应,APIJSON 性能优化背后的故事

2023-11-09

最近发生了一件大事儿,APIJSON 再也不用担心被人质疑性能问题了哈哈!

某周三腾讯 CSIG 某项目组(已经用 APIJSON 做完一期)突然反馈了查询大量数据性能急剧下降的情况:

某张表 2.3KW 记录,用 APIJSON 万能通用接口 /get 查数据 LIMIT 100 要 10s,LIMIT 1000 要 98s!

可把我吓了一跳,这么慢还怎么用。。。想了会先让他们 Log.DEBUG = false 关掉日志看看:

还同样那张表,还是同样的同域 CURL 请求 /get,LIMIT 100 降为 2s,LIMIT 1000 降为 30s。

看起来勉强够用,一般都是分页查 10 条 20 条的样子,但他们的业务“LIMIT 1000 的需求还挺多的”。

这可是腾讯内第一个用 APIJSON 的团队及项目,不仅用了好几个月,还在内网写了多篇文章帮忙推广,

怎么都不能辜负他们的信任和期望,更不能让这个事件成为 APIJSON 性能差的污点从而影响用户口碑。

image

我看着日志寻思着应该是数组内主表生成了 1000 个 SQLConfig 并调用 getSQL 等过程导致解析耗时过长,

而除了第 0 条,剩下的 999 条记录都完全没必要重复这个过程,尤其是期间大量打印日志非常耗时。

当时是为了兼容多表关联查询,自己的业务又几乎没有 LIMIT 100 以上的需求,所以影响不大就忽略了。

现在如果把第 0 条数据的解析结果(ObjectParser, SQLConfig 等类及变量状态)缓存起来给后面的复用

那不就可以把 2s 压缩到只比 SQL 执行耗时 133ms 多出少量 APIJSON 解析过程耗时 的时长了?

“我有方案了,应该可以把 2s 优化到 200ms 左右” “我这周末优化下” 我拍着脑门给出一个承诺。

这个组的后端同事职业本能地探究细节:“现在的 30s 主要耗时在哪里?” “怎么搞?”

“执行 SQL 133ms 耗时正常,整体慢是 日志(大头) 和 解析(小头) 的锅” “SQLExecutor 应该一次返回整个列表给 Parser”

看起来这个同事得到了些许安慰:“这个可以优化的话,LIMIT 1000 耗时 30s 估计也只要几秒了”

周末除了 APIAuto-机器学习 HTTP 接口工具 的简单更新:

  • 零代码回归测试:用经验法解决冷启动问题,在没有校验标准时也能进行断言
  • 自动生成注释:新增根对象全局关键词键值对的语法提示

剩下重点都是 APIJSON 的性能优化,我分成了两步:

1.查数组主表时把 SQLExecutor.execute 查到的原始列表全部返回,缓存到新增的 arrayMainCacheMap

https://github.com/Tencent/APIJSON/commit/bb4896d208e813a3f5eec21f60e1c083621b1f92

2.查数组主表时把第 0 个 ObjectParser 实例缓存到新增的 arrayObjectParserCacheMap

https://github.com/Tencent/APIJSON/commit/a406242a81f2b303a1c55e6a4f5c3c835e62e53a

期间尝试修改返回类型 JSONObject 为 List<JSONObject> 发现改动范围过大,而且只有这个场景需要,

于是就改为在 JSONObject 中加个肯定不会是表字段的特殊字段 @RAW@LIST 来带上 ResultSet 对应的 List;

改完后性能确实大幅提升,但发现除了第 0 条,后面的数组项全都丢了副表记录,于是反复调试修改多次终于解决;

接着按第 2 步优化,性能再次大幅提升,手动测试也没问题,用 APIAuto 一跑回归测试发现计数字段 total 没返回,

这次运气好点,因为之前也碰到过同样问题,我解决后加了比较详细的注释说明,所以回顾审视后没多久就解决了。

每步完成后,我都对 TestRecord[], 朋友圈多层嵌套列表 等查询 LIMIT 100 用优化前后代码各跑 10 次以上,

最终无论是 都取最小值,还是 去掉几个最小和最大值后其余取平均值,得出的前后性能对比结论基本一致:

步骤 1 将单表列表耗时降低为原来 42%,朋友圈多层嵌套列表降为原来的 82%;

步骤 2 将单表列表耗时降低为原来 60%,朋友圈多层嵌套列表降为原来的 77%;

算出总体上将单表列表耗时降低为原来 25%,朋友圈多层嵌套列表降为原来的 63%

MacBook Pro 英寸 2015 年初期 13 Intel i5 双核 2.9 GHz,250G SSD,OSX EI Capitan 10.11.6

Docker Community Edition 18.03.1-ce-mac65 (24312)

MySQL Community Server 5.7.17 - 跑在 Docker 里,性能会比直接安装的差不少

Eclipse Java  EE Neon.1a Release (4.6.1) - 全量保留日志,比用有限保留日志的 IntelliJ IDEA 2018.2.8 (IU-182.5262.2) 慢一个数量级

实测结果如下:

TestRecord[] 查询前后对比 耗时降至 35%,性能提升 186% 为原来 2.9 倍:

朋友圈列表查询前后对比 耗时降至 34%,性能提升 192% 为原来 2.9 倍:

改为 [], []/User[], []/[] 组合且每个数组长度 count 都改为 0(对应 100 条),最多返回 100*(1 + 100 + 100*2) = 30100 条记录:

注:找不到 5651ms 对应那张图了,用最接近的图替代

模拟 to C 应用的这个极端情况下 生成 SQL 数从 1397 减少至 750,耗时降至 83%,性能提升 20% 为原来 1.2 倍。

最多才降低耗时为原来 25%?那估计他们组原来 2s 只能优化到  500ms(承诺 200ms 左右),30s 只能优化到 7.5s。

天,牛都吹出去了,这下怎么办?... 算了算了,都一点了,先睡吧,先发版明天让他们试试看,唉...

于是我就打着哈欠把 APIJSON 和 APIAuto 都部署到 apijson.cn,简单自测没问题,然后到两点多就洗洗睡了...

(后面又反复多次自测,虽然结果都和以上接近,但 Release 上用了更保守低调的数值)

第二天上午通知腾讯 CSIG 某项目组的同事更新 APIJSON,下午同事在 APIJSON 咨询群 大赞“给力!”并发了几张截屏。

一看 LIMIT 1000000 我虎躯一震:好家伙,上来就线上生产环境百万数据暴力测试,年轻人不讲武德了么?

---------- | ---------- | ---------- | ---------- | -------------
   Total   |  Received  | Time Total | Time Spent | Current Speed
   72.5M   |    72.5M   |   0:00:05  |   0:00:05  |     20.0M

/get >> http请求结束:5624

一时没控记住记几,在公司连续大喊 “我靠!一百万五秒!一百万五秒!查一百万条记录耗时五秒!”

差点还喊出洗脑广告 “OMG,顶它顶它顶它!!!”

把周边同事吓了一跳,过了一会有几个后端同事反应过来纷纷点赞!

冷静下来我仔细分析:

由于他们这次用 CURL 测试接口时,对应的 APIJSON 服务关掉了日志,不能直接看到服务从接收参数到响应结果的耗时,

所以按以上数据计算是 总耗时 5624ms - 数据 72.5M/下载速度 20.0M每秒 = 1999ms,也就是服务执行过程耗时仅仅 2s!

显然 APIJSON 这次性能优化效果显著远超预期,同时 2.3KW 大表查 100W 记录仅 1s 左右也反应了 腾讯 TDSQL 的迅猛!

然而后来同事反馈,这次带条件查出来实际上不到 100W,只有 12W 多数据。

瞬间把我从丰满的理想拉回了骨感的现实,嗯,革命尚未成功,仍需再接再厉!

经过了几个版本迭代,4.8.0 终于迎来再一次大幅性能提升,这次终于做到了!

APIJSON 4.7.0 和 4.8.0 腾讯 CSIG 某项目性能测试结果

1. 测试环境

1.1 机器配置

腾讯云tke docker pod, 4 核 / 16G。

1.2 db机器配置

腾讯云8核32000MB内存,805GB存储空间

1.3 测试表建表DML、数据量(mysql 5.7)

CREATE TABLE `t_xxxx_xxxx` (
    `x_id` bigint(11) unsigned NOT NULL AUTO_INCREMENT,
    `x_xxxx_id` int(11) unsigned NOT NULL DEFAULT '0' COMMENT 'xID',
    `x_xid` int(11) unsigned NOT NULL DEFAULT '0' COMMENT 'xxID',
    `x_xx_id` int(11) unsigned NOT NULL DEFAULT '0' COMMENT 'xID',
    `x_xxxx_id` int(11) unsigned NOT NULL DEFAULT '0' COMMENT 'xxxID',
    `x_xxxxx_id` int(11) unsigned NOT NULL DEFAULT '0' COMMENT 'xxID',
    `x_xxxx_id` int(11) unsigned NOT NULL DEFAULT '0' COMMENT 'xxID',
    `x_uin` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'xxuin',
    `x_send_time` datetime DEFAULT NULL COMMENT '推送消息时间',
    `x_xxxx_result` int(11) unsigned NOT NULL DEFAULT '0' COMMENT 'xx结果',
    `x_xxx_xxxx_result` varchar(255) DEFAULT '' COMMENT 'xx结果',
    `x_result` tinyint(4) unsigned NOT NULL DEFAULT '0' COMMENT '0错误 1正确 2未设置',
    `x_create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间, 落地时间',
    `x_credit` int(11) unsigned NOT NULL DEFAULT '0' COMMENT 'xx数量',
    `x_xxxxxx_xxx_id` varchar(32) NOT NULL COMMENT '公共参数, 上报应用',
    `x_xxxxxx_source` varchar(32) NOT NULL COMMENT '公共参数, 上报服务名',
    `x_xxxxxx_server` varchar(32) NOT NULL COMMENT '公共参数, 上报服务端ip',
    `x_xxxxxx_event_time` datetime NOT NULL COMMENT '公共参数, 上报时间',
    `x_xxxxxx_client` varchar(32) NOT NULL COMMENT '公共参数, 客户端ip',
    `x_xxxxxx_trace_id` varchar(64) NOT NULL COMMENT '公共参数',
    `x_xxxxxx_sdk` varchar(16) NOT NULL COMMENT '公共参数, sdk版本',
    PRIMARY KEY (`x_id`, `x_uin`),
    UNIQUE KEY `udx_uid_xxxxid` (`x_uin`, `x_xxxx_id`),
    KEY `idx_xid` (`x_xid`)
  ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4  COMMENT = 'xx事件表'; 
  • 数据量:18558903

  • mysql版本:5.7

  • 数据分布:使用group by 统计,基于其中x_xid来group by,得到以下表格:

select x_xid, count(x_id) counter from t_xxxx_xxxx group by x_xid order by counter desc limit 10;

x_xid counter
xxxx36 696376
xxxx38 418576
xxxx63 384503
xxxx40 372080
xxxx41 301364
xxxx08 248243
xxxx46 223820
xxxx07 220234
xxxx44 207721
xxxx02 152795

1.4 日志打印设置

Log.DEBUG = false;

AbstractParser.IS_PRINT_REQUEST_STRING_LOG = false;
AbstractParser.IS_PRINT_REQUEST_ENDTIME_LOG = false;
AbstractParser.IS_PRINT_BIG_LOG = false;

2. 测试脚本 (使用Table[]: {Table: {}}格式)

脚本统计方式:

  • 基于linux time命令输出的realtime来统计。

  • 分2个场景测试:一个不带where条件、一个带x_xid in (xxxx36,xxxx38)的条件,该条件能匹配出100W+数据,方便覆盖10W-100W之间的任何数据量场景,这里事先用select x_xid, count(x_id) c from t_xxxx_xxxx group by x_xid order by c desc;这样的语句对表做了统计,x_xid=xxxx36有696376条记录,x_xid=xxxx38有418576条记录。

脚本:apitest.sh

#!/bin/bash
printf -- '--------------------------\n开始不带where条件的情况测试\n'
time curl  -X POST -H 'Content-Type:application/json' 'http://x.xxx.xx.xxx:xxxx/get' -d '{"T_xxxx_xxxx[]":{"count":100000, "T_xxxx_xxxx":{"@column":"x_uin,x_send_time,x_xxxx_id,x_xid,x_xx_id,x_xxxxx_id,x_xxxx_result,x_result,x_credit"}}}' > 10w_no_where.log

time curl  -X POST -H 'Content-Type:application/json' 'http://x.xxx.xx.xxx:xxxx/get' -d '{"T_xxxx_xxxx[]":{"count":200000, "T_xxxx_xxxx":{"@column":"x_uin,x_send_time,x_xxxx_id,x_xid,x_xx_id,x_xxxxx_id,x_xxxx_result,x_result,x_credit"}}}' > 20w_no_where.log

time curl  -X POST -H 'Content-Type:application/json' 'http://x.xxx.xx.xxx:xxxx/get' -d '{"T_xxxx_xxxx[]":{"count":500000, "T_xxxx_xxxx":{"@column":"x_uin,x_send_time,x_xxxx_id,x_xid,x_xx_id,x_xxxxx_id,x_xxxx_result,x_result,x_credit"}}}' > 50w_no_where.log

time curl  -X POST -H 'Content-Type:application/json' 'http://x.xxx.xx.xxx:xxxx/get' -d '{"T_xxxx_xxxx[]":{"count":800000, "T_xxxx_xxxx":{"@column":"x_uin,x_send_time,x_xxxx_id,x_xid,x_xx_id,x_xxxxx_id,x_xxxx_result,x_result,x_credit"}}}' > 80w_no_where.log

time curl  -X POST -H 'Content-Type:application/json' 'http://x.xxx.xx.xxx:xxxx/get' -d '{"T_xxxx_xxxx[]":{"count":1000000, "T_xxxx_xxxx":{"@column":"x_uin,x_send_time,x_xxxx_id,x_xid,x_xx_id,x_xxxxx_id,x_xxxx_result,x_result,x_credit"}}}' > 100w_no_where.log



printf -- '--------------------------\n开始带where条件的情况测试\n'
time curl  -X POST -H 'Content-Type:application/json' 'http://x.xxx.xx.xxx:xxxx/get' -d '{"T_xxxx_xxxx[]":{"count":100000, "T_xxxx_xxxx":{"x_xid{}":[xxxx36,xxxx38],"@column":"x_uin,x_send_time,x_xxxx_id,x_xid,x_xx_id,x_xxxxx_id,x_xxxx_result,x_result,x_credit"}}}' > 10w_with_where.log

time curl  -X POST -H 'Content-Type:application/json' 'http://x.xxx.xx.xxx:xxxx/get' -d '{"T_xxxx_xxxx[]":{"count":200000, "T_xxxx_xxxx":{"x_xid{}":[xxxx36,xxxx38],"@column":"x_uin,x_send_time,x_xxxx_id,x_xid,x_xx_id,x_xxxxx_id,x_xxxx_result,x_result,x_credit"}}}' > 20w_with_where.log

time curl  -X POST -H 'Content-Type:application/json' 'http://x.xxx.xx.xxx:xxxx/get' -d '{"T_xxxx_xxxx[]":{"count":500000, "T_xxxx_xxxx":{"x_xid{}":[xxxx36,xxxx38],"@column":"x_uin,x_send_time,x_xxxx_id,x_xid,x_xx_id,x_xxxxx_id,x_xxxx_result,x_result,x_credit"}}}' > 50w_with_where.log

time curl  -X POST -H 'Content-Type:application/json' 'http://x.xxx.xx.xxx:xxxx/get' -d '{"T_xxxx_xxxx[]":{"count":800000, "T_xxxx_xxxx":{"x_xid{}":[xxxx36,xxxx38],"@column":"x_uin,x_send_time,x_xxxx_id,x_xid,x_xx_id,x_xxxxx_id,x_xxxx_result,x_result,x_credit"}}}' > 80w_with_where.log

time curl  -X POST -H 'Content-Type:application/json' 'http://x.xxx.xx.xxx:xxxx/get' -d '{"T_xxxx_xxxx[]":{"count":1000000, "T_xxxx_xxxx":{"x_xid{}":[xxxx36,xxxx38],"@column":"x_uin,x_send_time,x_xxxx_id,x_xid,x_xx_id,x_xxxxx_id,x_xxxx_result,x_result,x_credit"}}}' > 100w_with_where.log

也就是 MySQL 5.7 共 1.9KW 记录的大表,统计 CRUL 10-20M/s 网速从发起请求到接收完回包的总时长

数量级 4.7.0(5次取平均值) 4.8.0(5次取平均值) 是否正常回包 where条件 性能提升
10W 1.739s 1.159s 50%。即((1/1.159-1/1.739)/(1/1.739))*100%
20W 3.518s 2.676s 31.5%
50W 9.257s 6.952s 33.2%
80W 16.236s 10.697s -Xmx=3192M时无法正常回包,OOM错误,调大-Xmx参数后ok。 51.8%
100W 19.748s 14.466s -Xmx=3192M时无法正常回包,OOM错误,调大-Xmx参数后ok 36.5%
10W 1.928s 1.392s "x_xid{}":[xxxx36,xxxx38],覆盖数据超过100W数据。 38.5%
20W 4.149s 2.852s "x_xid{}":[xxxx36,xxxx38] 45.5%
50W 10.652s 7.231s "x_xid{}":[xxxx36,xxxx38] 47.3%
80W 16.975s 12.465s 调整了-Xmx后正常回包 "x_xid{}":[xxxx36,xxxx38] 36.2%
100W 20.632s 16.481s 调整了-Xmx后正常回包 "x_xid{}":[xxxx36,xxxx38] 25.2%

感谢同事给的详细测试报告,在他已脱敏的基础上二次脱敏,并和他确认后对外公开~

以之前的 APIJSON 4.6.0 连接 2.3KW 大表带条件查出 12W+ 数据来估计:

---------- | ---------- | ---------- | ---------- | -------------
   Total   |  Received  | Time Total | Time Spent | Current Speed
   72.5M   |    72.5M   |   0:00:05  |   0:00:05  |     20.0M

/get >> http请求结束:5624

4.6.0-4.7.2 都没有明显的性能优化,所以 4.7.0 只花了约 2s 应该是因为换了张表,平均每行数据量减少了约 65% 为原来的 35%。
APIJSON 4.6.0 查原来 2.3KW 大表中 100W 数据按新旧表数据量比例估计耗时 = 20.632s / 65% = 31.7s;
APIJSON 4.6.0 查原来 2.3KW 大表中 100W 数据按同表查出数据量比例估计耗时 = 100W*72.5M/(12-13W)/(20M/s) = 27.9s-30.2s。

两种方式估算结果基本一致,也可以按这个 35% 新旧表平均每行数据量比例估算排除网络耗时后的整个服务耗时:

APIJSON 4.6.0 查原来 2.3KW 大表中 12W+ 数据量服务耗时 = 总耗时 5.624s - 数据 72.5M/下载速度 20.0Mbps = 2.00s;
APIJSON 4.7.0 查现在 1.9KW 大表中 10W 数据量服务耗时 = 总耗时 1.928s - 数据 72.5M*35%(10/12)/(下载速度 10-20.0Mbps) = 0.00-0.87s;
APIJSON 4.8.0 查现在 1.9KW 大表中 10W 数据量服务耗时 = 总耗时 1.392s - 数据 72.5M*35%
(10/12)/(下载速度 10-20.0Mbps) = 0.00-0.33s,降低 62%;
APIJSON 4.7.0 查现在 1.9KW 大表中 100W 数据量服务耗时 = 总耗时 20.632s - 数据 725M*35%(10/12)/(下载速度 10-20.0Mbps) = 0.00-10.06s;
APIJSON 4.8.0 查现在 1.9KW 大表中 100W 数据量服务耗时 = 总耗时 16.481s - 数据 725M*35%
(10/12)/(下载速度 10-20.0Mbps) = 0.00-5.91s,降低 41%。

也就是 1.9KW 大表带条件查出 100W 条记录,APIJSON 4.8.0 的从 完成接收参数 到 开始返回数据 的整个服务耗时不到 6s!

APIJSON - 零代码接口和文档

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

腾讯业务百万数据 6s 响应,APIJSON 性能优化背后的故事 的相关文章

  • Android在排序列表时忽略大小写

    我有一个名为路径的列表 我目前正在使用以下代码对字符串进行排序 java util Collections sort path 这工作正常 它对我的 列表进行排序 但是它以不同的方式处理第一个字母的情况 即它用大写字母对列表进行排序 然后用
  • MySQL PHP邮政编码比较具体距离

    我试图找出比较一个邮政编码 用户提供的 和一大堆其他邮政编码 现在大约有 200 个邮政编码 之间的距离的最有效方法 相对于加载时间 但它会随着时间的推移而增加 我不需要任何精确的东西 只是在球场上 我下载了整个美国的邮政编码 csv 文件
  • java中如何连接字符串

    这是我的字符串连接代码 StringSecret java public class StringSecret public static void main String args String s new String abc s co
  • 如何安全地解决这个 Java 上下文类加载器问题?

    我的数百名用户中只有一位在启动我的 Java 桌面应用程序时遇到问题 他只有大约三分之一的时间开始 另外三分之二的时间在启动时抛出 NullPointerException Exception in thread AWT EventQueu
  • 画透明圆,外面填充

    我有一个地图视图 我想在其上画一个圆圈以聚焦于给定区域 但我希望圆圈倒转 也就是说 圆的内部不是被填充 而是透明的 其他所有部分都被填充 请参阅这张图片了解我的意思 http i imgur com zxIMZ png 上半部分显示了我可以
  • 将 SignedHash 插入 PDF 中以进行外部签名过程 -workingSample

    遵循电子书第 4 3 3 节 PDF 文档的数字签名 https jira nuxeo com secure attachment 49931 digitalsignatures20130304 pdf 我正在尝试创建一个工作示例 其中 客
  • 很好地处理数据库约束错误

    再一次 它应该很简单 我的任务是在我们的应用程序的域对象中放置一个具有唯一约束的特定字段 这本身并不是一个很大的挑战 我刚刚做了以下事情 public class Location more fields Column unique tru
  • 在游戏视图下添加 admob

    我一直试图将 admob 放在我的游戏视图下 这是我的代码 public class HoodStarGame extends AndroidApplication Override public void onCreate Bundle
  • 编辑文件名在 JComboBox 中的显示方式,同时保持对文件的访问

    我对 Java 很陌生 对堆栈溢出也很陌生 我正在尝试利用 JMF API 创建一个用 Java 编码的简单媒体播放器 到目前为止 我已经能够设置一个简单的队列 播放列表来使用JComboBox called playListHolder
  • 如何在selenium服务器上提供自定义功能?

    我知道可以通过某种方法获得一些硒功能 其中之一如下 driver getCapabilities getBrowserName 它返回浏览器名称的值 但如果它指的是一个可用的方法 如果我没有误解的话 这似乎与自定义功能有关 就像我的意思是
  • IntelliJ - 调试模式 - 在程序内存中搜索文本

    我正在与无证的第三方库合作 我知道有一定的String存储在库深处的某个字段中的某处 我可以预测的动态值 但我想从库的 API 中获取它 有没有一种方法可以通过以下方式进行搜索 类似于全文搜索 full程序内存处于调试模式并在某个断点处停止
  • Java整数双除法混淆[重复]

    这个问题在这里已经有答案了 方案1 int sum 30 double avg sum 4 result is 7 0 not 7 5 VS 方案2 int sum 30 double avg sum 4 0 Prints lns 7 5
  • 我可以创建自定义 java.* 包吗?

    我可以创建一个与预定义包同名的自己的包吗在Java中 比如java lang 如果是这样 结果会怎样 这难道不能让我访问该包的受保护的成员 如果不是 是什么阻止我这样做 No java lang被禁止 安全管理器不允许 自定义 类java
  • Laravel leftJoin 仅右表的最后一条记录

    我是 Laravel 的新手 我有两张桌子 1 产品 2 价格 products id product int p key name varchar prices id price int p key id product int
  • MySQL 按重复项从上到下排序

    我有一个lammer问题 因为我不是mysql专业人士 我有类似的字段 id color 1 red 2 green 3 yellow 4 green 5 green 6 red 我想按重复项进行分组 最常见的重复项先进行分组 所以应该这样
  • Java中的Object类是什么?

    什么是或什么类型private Object obj Object http download oracle com javase 6 docs api java lang Object html是Java继承层次结构中每个类的最终祖先 从
  • Eclipse 中 Spring MVC 模型对象的 (jsp /jstl) 视图中的代码辅助

    在 Spring MVC 中 当将对象放置在视图模型中时 如下所示 public String getUser Model model fetch user model addAttribute user user return viewN
  • 具有特定参数的 Spring AOP 切入点

    我需要创建一个我觉得很难描述的方面 所以让我指出一下想法 com x y 包 或任何子包 中的任何方法 一个方法参数是接口 javax portlet PortletRequest 的实现 该方法中可能有更多参数 它们可以是任何顺序 我需要
  • 为什么这个作业不起作用?

    我有课Results which extends ArrayList
  • 如何在 JFreeChart 中设置多个系列的线条粗细?

    我创建了很多图表 在他们每个人中我都需要打电话 renderer setSeriesStroke i new BasicStroke 2 0f 对于每个系列 renderer is chart getXYPlot getRenderer 我

随机推荐

  • Ubuntu 安装配置Samba服务器

    一 描述 Samba文件服务器可以在网络上实现不同操作系统的文件共享 它可以让你从笔记本电脑访问你的桌面文件 并与Windows和macOS用户共享文件 Samba是通过Network LAN 局域网来实现的 二 安装 要安装Samba 我
  • 架构是什么

    是什么 架构是什么 众说纷纭 架构 Architecture 一词最早源自建筑学术语 后来才被计算机科学领域借用 以下是其在维基百科 Wikipedia 中的定义 架构是规划 设计和构建建筑及其物理结构的过程与产物 在计算机工程中 架构是描
  • 苏嵌嵌入式Linux实训 第2天

    今天是嵌入式学习的第二天 也是正式教学开始的第一天 全程由梁老师为我们讲解 由于仅仅是新手的接触 不懂的地方还有很多 有时甚至跟不上老师的节奏 当然这也需要我们课后的复习和总结 不断积累才能不断收获 1 课程内容 今天的课程主要是对嵌入式开
  • 删除当前目录下所有.py[cdo]文件的命令

    rm f py 命令会删除当前目录下所有的 py 文件 但不会删除包含这些文件的目录 这个命令并没有错误 但是如果你只希望删除当前目录下的 py 文件而不包括子目录中的文件 你可以使用 rm f py cdo 在解释这个命令之前 首先来了解
  • Ubuntu 下安装 QQ

    安装流程 一 QQ Linux版本下载 二 安装 一 QQ Linux版本下载 1 使用以下指令查看自己的 Ubuntu 版本的类型 uname a 可查看到我的 Ubuntu 版本为 x86 64的版本 因此可以点击此处链接前往 QQ 官
  • Springboot + MySQL+ JPA II save方法详解

    JPA没有专门的update接口 save接口同时支持update操作 一 save 单条添加 Service层中添加save方法 save是三方件自带接口不需要再dao层中添加 Transactional public User save
  • Java:继承和多态

    继承 什么是继承以及为什么需要继承 继承机制 是面向对象程序设计是代码实现复用中至关重要的一步 它允许程序在保持原有类的特性的基础上来进行扩充 增加新功能等 总的来说 继承就是将不同类之间的共性进行抽取 抽取出来的这些共同的特性就可以单独写
  • Jupyter Notebook工具中ndarry数组的使用(一)

    今天学习了jupyter notebook工具中ndarray数组的使用 具体包括 第一步 导入numpy包 import numpy as np 第二步 创建ndarray数组 通过numpy模块中的常用的几个函数进行创建ndarray多
  • 月薪过万的Java面试

    写了一个月 篇幅太长了 都写不下了 被逼无奈 只能拆分 面试题 HashMap底层实现原理 红黑树 B 树 B树的结构原理 volatile关键字 CAS 比较与交换 实现原理 答案 理论 第一章 HashMap底层实现原理 红黑树 B 树
  • JAVA图片压缩

    图片压缩代码操作 需要压缩的原图片路径为 src 压缩后存放的路径为 dist 需要压缩的宽度为 width 需要压缩的后的高度为 height File srcfile new File src 原图片是否存在 if srcfile ex
  • python几个轻量级web框架

    我最近发表了一篇名为 7 Minimal Node js Web Frameworks for 2014 and Beyond 的博文 目前它是我博客访问量最高的文章 超过10000人浏览 分享和评论了这些我总结到一起的web框架 这教会了
  • 金晟富:4.17黄金冲高遇阻急需调整!后市黄金原油操作建议

    前言导读 各位投资朋友 转眼间又到周末了 祝大家周末愉快 此刻的你还在到处看文章找策略吗 不知晟富每日及时给到你的现价单你关注了多少呢 每天的多空是否让你犹豫再犹豫 一单损完又害怕下一单 如果你还在迷茫犹豫的道路上 不妨可留意下金晟富的文章
  • simulink中PID控制器搭建

    Simulink 是一个用于仿真 建模和仿真的软件工具 您可以在其中搭建 PID 控制器 以下是如何搭建一个简单的 PID 控制器的步骤 启动 Simulink 打开一个新模型 在模型窗口中插入一个 PID 控制器 模块 可以在 Simul
  • STM32 电机教程 1 - 用ST Motor Profiler 测量无刷电机参数

    前言 在对电机进行控制前 往往需要先知道电机的一些参数 但是在实际应用过程中 经常会出现在控制一个电机参 但对电机的参数如相电阻电感的参数不够了解的情况 本节给大家演示基本ST Motor Profiler测量电机参数的操作过程 让大家在以
  • Spring Cloud 与 Dubbo 区别

    1 定位点不同 SpringCloud SpirngCloud 定位为微服务架构下的一站式解决方案 Dubbo 关注点主要在于服务的调用 流量分发 流量监控和熔断 2 dubbo基于rpc 底层netty SpirngCloud基于http
  • 【点云处理之论文狂读前沿版7】—— Masked Autoencoders for Point Cloud Self-supervised Learning

    Masked Autoencoders for Point Cloud Self supervised Learning 摘要 1 引言 3 Point MAE 3 1 Point Cloud Masking and Embedding 3
  • Docker专题(八)-Docker-Docker部署SpringBoot项目

    1 手工方式 1 1 准备Springboot jar项目 将项目打包成jar 1 2 编写Dockerfile FROM java 8 VOLUME tmp ADD elk web 1 0 SNAPSHOT jar elk jar EXP
  • PhpStorm最全攻略

    本教程主要内容的是日常开发 测试 部署工作流的一些技巧和工具配置方法 并尽量将最有用的部分提取出来并结合实际场景做介绍 而并不是仅仅对PhpStorm的功能的简单罗列 如果读者有改善的建议 可以在教程下方留言或直接与作者联系 共同促进内容的
  • 工具:npm/node版本更换(Windows版本) 含报错exit status 1报错,出现乱码的解决方法

    npm版本更换 更换指定版本 npm g install npm 6 14 11 更换最新版本 npm install g npm node版本更换 方法1 下载nvm https www runoob com w3cnote nvm ma
  • 腾讯业务百万数据 6s 响应,APIJSON 性能优化背后的故事

    最近发生了一件大事儿 APIJSON 再也不用担心被人质疑性能问题了哈哈 某周三腾讯 CSIG 某项目组 已经用 APIJSON 做完一期 突然反馈了查询大量数据性能急剧下降的情况 某张表 2 3KW 记录 用 APIJSON 万能通用接口