为什么我推荐你使用 systemd timer 替代 cronjob?

为什么,推荐,使用,systemd,timer,替代,cronjob · 浏览次数 : 332

小编点评

**OnCalendar时间规格** OnCalendar 是一个用于定义时间事件的系统时间工具,它提供了一种更丰富和更方便的方法来定义事件,包括日期、时间、事件类型等。 **定义时间事件** OnCalendar 的定义方式如下: ``` OnCalendar event_name [start_time] [end_time] [event_type] ``` * **event_name**:事件名称 * **event_type**:事件类型,可选 * **start_time**:事件开始时间,可选 * **end_time**:事件结束时间,可选 * **event_type**:事件类型,可选 **例子** ``` OnCalendar event_name "Meeting" [08:00] OnCalendar event_name "Lunch" [12:00] OnCalendar event_name "Event" [18:00] ``` **定义多个时间事件** OnCalendar 可以定义多个时间事件,它们会被按照顺序执行。 ``` OnCalendar event_name "Meeting" [08:00] [12:00] [18:00] ``` **定义事件类型** OnCalendar 支持定义事件类型,例如: ``` OnCalendar event_name "Meeting" [08:00] [event_type="Meeting"] ``` **使用** OnCalendar 可以用于定义各种时间事件,包括: * **日期** * **时间** * **事件类型** **优点** * 更丰富和更方便的事件定义方法 * 提供了更多的灵活性 * 允许定义事件类型 * 简化了事件的执行 **结论** OnCalendar 是一个强大的系统时间工具,它可以用于定义各种时间事件,包括日期、时间、事件类型等。它提供了了一种更丰富和更方便的方法来定义事件,并允许定义事件类型,简化了事件的执行。

正文

概述

前几天在使用 Terraform + cloud-init 批量初始化我的实验室 Linux 机器。正好发现有一些定时场景需要使用到 cronjob, 进一步了解到 systemd timer 完全可以替换 cronjob, 并且 systemd timer 有一些非常有趣的功能。

回归话题:为什么我推荐你使用 systemd timer 替代 cronjob? 因为相比 cronjob, systemd timer 有这些优势:

  • 可以覆盖 cronjob 的所有功能
  • 统一日志收集到 systemd 日志
  • 针对时间精确度更详细的配置项
  • 除了定时场景,还支持基于 event 的触发
  • 相比 cronjob 更灵活的语法
  • 更丰富的使用/运维命令集

接下来我们一一介绍。

首先我们通过系统自带的 timer 来熟悉这个新玩意。

系统自带的 timer

当 Ubuntu 或任何基于 systemd 的发行版安装在一个新系统上时,它会创建几个 timer,作为任何 Linux 主机后台的系统维护程序的一部分。这些 timer 会触发普通维护任务所需的事件,比如更新系统数据库、清理临时目录、切割日志文件等等。

我们使用systemctl status *timer命令列出我的主机上的所有 timer:

casey@casey-Virtual-Machine:~$ systemctl status *timer
● plocate-updatedb.timer - Update the plocate database daily
     Loaded: loaded (/lib/systemd/system/plocate-updatedb.timer; enabled; vendor preset: enabled)
     Active: active (waiting) since Tue 2023-04-04 16:49:49 CST; 19s ago
    Trigger: Wed 2023-04-05 00:40:16 CST; 7h left
   Triggers: ● plocate-updatedb.service

4 月 04 16:49:49 casey-Virtual-Machine systemd[1]: Started Update the plocate database daily.

● fwupd-refresh.timer - Refresh fwupd metadata regularly
     Loaded: loaded (/lib/systemd/system/fwupd-refresh.timer; enabled; vendor preset: enabled)
     Active: active (waiting) since Tue 2023-04-04 16:49:49 CST; 19s ago
    Trigger: Wed 2023-04-05 01:54:51 CST; 9h left
   Triggers: ● fwupd-refresh.service

4 月 04 16:49:49 casey-Virtual-Machine systemd[1]: Started Refresh fwupd metadata regularly.

● update-notifier-motd.timer - Check to see whether there is a new version of Ubuntu available
     Loaded: loaded (/lib/systemd/system/update-notifier-motd.timer; enabled; vendor preset: enabled)
     Active: active (waiting) since Tue 2023-04-04 16:49:50 CST; 19s ago
    Trigger: Sat 2023-04-08 03:19:02 CST; 3 days left
   Triggers: ● update-notifier-motd.service

4 月 04 16:49:50 casey-Virtual-Machine systemd[1]: Started Check to see whether there is a new version of Ubuntu available.

● fstrim.timer - Discard unused blocks once a week
     Loaded: loaded (/lib/systemd/system/fstrim.timer; enabled; vendor preset: enabled)
     Active: active (waiting) since Tue 2023-04-04 16:49:49 CST; 19s ago
    Trigger: Tue 2023-04-04 17:58:23 CST; 1h 8min left
   Triggers: ● fstrim.service
       Docs: man:fstrim

4 月 04 16:49:49 casey-Virtual-Machine systemd[1]: Started Discard unused blocks once a week.
...

每个 timer 至少有六行信息与之相关:

  • 第一行是 timer 的文件名和对其用途的简短描述。
  • 第二行显示 timer 的状态,它是否被加载,timer unit 文件的完整路径,以及供应商的预设。
  • 第三行显示其活动状态,包括 timer 开始活动的日期和时间。
  • 第四行包含 timer 下次被触发的日期和时间,以及直到触发发生的大致时间。
  • 第五行显示由 timer 触发的事件或服务的名称。
  • 一些(但不是全部)systemd unit 文件有指向相关文档的指针。如上面的 Docs: man:fstrim
  • 最后一行是 timer 所触发的服务的最新实例的日志条目。

创建 timer

优势之一:统一日志收集到 systemd 日志

为了更快了解 timer, 我们创建自己的 service unit 和 timer unit 来触发。

具体用途为:每周定期更新 tailscale 的版本。

首先,创建 tailscale update 服务,如下:

[Unit]
Description=Tailscale update
Wants=tailscale-weekly-update.timer

[Service]
Type=oneshot
ExecStart=/usr/bin/tailscale update -yes

[Install]
WantedBy=multi-user.target

然后,创建 tailscale update timer, 如下:

[Unit]
Description=Tailscale update
Requires=tailscale-weekly-update.service

[Timer]
Unit=tailscale-weekly-update.service
OnCalendar=weekly

[Install]
WantedBy=timers.target

最后,启用 timer:

systemctl enable tailscale-weekly-update.timer 

这样就可以了,但是为了演示,执行:systemctl start tailscale-weekly-update.service 手动运行一次。

输出会直接集成到 systemd 日志里,并可以通过 journalctl 查看:(包含手动执行日志,和后续自动定期执行的日志)

$ sudo journalctl -S "2023-03-29 00:00:00" -u tailscale-weekly-update.service
4 月 02 09:14:28 casey-Virtual-Machine systemd[1]: Starting Tailscale node agent...
4 月 02 09:14:30 casey-Virtual-Machine tailscale[6898]: 获取:1 https://pkgs.tailscale.com/stable/ubuntu jammy InRelease
4 月 02 09:14:30 casey-Virtual-Machine tailscale[6898]: 获取:2 https://pkgs.tailscale.com/stable/ubuntu jammy/main amd64 Packages [7,853 B]
4 月 02 09:14:32 casey-Virtual-Machine tailscale[6898]: 已下载 13.9 kB,耗时 1 秒 (14.4 kB/s)
4 月 02 09:14:32 casey-Virtual-Machine tailscale[6898]: 正在读取软件包列表。..
4 月 02 09:14:33 casey-Virtual-Machine tailscale[7101]: 正在读取软件包列表。..
4 月 02 09:14:33 casey-Virtual-Machine tailscale[7101]: 正在分析软件包的依赖关系树。..
4 月 02 09:14:33 casey-Virtual-Machine tailscale[7101]: 正在读取状态信息。..
4 月 02 09:14:33 casey-Virtual-Machine tailscale[7101]: 下列软件包将被升级:
4 月 02 09:14:33 casey-Virtual-Machine tailscale[7101]:   tailscale
4 月 02 09:14:34 casey-Virtual-Machine tailscale[7101]: 升级了 1 个软件包,新安装了 0 个软件包,要卸载 0 个软件包,有 4 个软件包未被升级。
4 月 02 09:14:34 casey-Virtual-Machine tailscale[7101]: 需要下载 23.0 MB 的归档。
4 月 02 09:14:34 casey-Virtual-Machine tailscale[7101]: 解压缩后将会空出 1,024 B 的空间。
4 月 02 09:14:34 casey-Virtual-Machine tailscale[7101]: 获取:1 https://pkgs.tailscale.com/stable/ubuntu jammy/main amd64 tailscale amd64 1.38.3 [23.0 MB]
4 月 02 09:15:13 casey-Virtual-Machine tailscale[7115]: debconf: 无法初始化前端界面:Dialog
4 月 02 09:15:13 casey-Virtual-Machine tailscale[7115]: debconf: (系统未设定 TERM 环境变量,所以对话框界面将不可使用。)
4 月 02 09:15:13 casey-Virtual-Machine tailscale[7115]: debconf: 返回前端界面:Readline
4 月 02 09:15:13 casey-Virtual-Machine tailscale[7115]: debconf: 无法初始化前端界面:Readline
4 月 02 09:15:13 casey-Virtual-Machine tailscale[7115]: debconf: (这个界面要求可控制的 tty。)
4 月 02 09:15:13 casey-Virtual-Machine tailscale[7115]: debconf: 返回前端界面:Teletype
4 月 02 09:15:13 casey-Virtual-Machine tailscale[7115]: dpkg-preconfigure: 重新开启标准输入失败:
4 月 02 09:15:13 casey-Virtual-Machine tailscale[7101]: 已下载 23.0 MB,耗时 40 秒 (577 kB/s)
4 月 02 09:15:14 casey-Virtual-Machine tailscale[7101]: [729B blob data]
4 月 02 09:15:14 casey-Virtual-Machine tailscale[7101]: 准备解压 .../tailscale_1.38.3_amd64.deb  ...
4 月 02 09:15:14 casey-Virtual-Machine tailscale[7101]: 正在解压 tailscale (1.38.3) 并覆盖 (1.38.2) ...
4 月 02 09:15:15 casey-Virtual-Machine tailscale[7101]: 正在设置 tailscale (1.38.3) ...
4 月 02 09:15:23 casey-Virtual-Machine tailscale[7325]: Running kernel seems to be up-to-date.
4 月 02 09:15:23 casey-Virtual-Machine tailscale[7325]: Services to be restarted:
4 月 02 09:15:23 casey-Virtual-Machine tailscale[7325]:  systemctl restart tailscale-weekly-update.service
4 月 02 09:15:23 casey-Virtual-Machine tailscale[7325]: No containers need to be restarted.
4 月 02 09:15:23 casey-Virtual-Machine tailscale[7325]: No user sessions are running outdated binaries.
4 月 02 09:15:23 casey-Virtual-Machine tailscale[7325]: No VM guests are running outdated hypervisor (qemu) binaries on this host.
4 月 02 09:15:24 casey-Virtual-Machine systemd[1]: tailscale-weekly-update.service: Deactivated successfully.
4 月 02 09:15:24 casey-Virtual-Machine systemd[1]: Finished Tailscale node agent.
4 月 02 09:15:24 casey-Virtual-Machine systemd[1]: tailscale-weekly-update.service: Consumed 6.317s CPU time.

$ sudo journalctl -S "2023-03-29 00:00:00" -u tailscale-weekly-update.timer
4 月 02 09:14:28 casey-Virtual-Machine systemd[1]: Started Tailscale node agent.
4 月 02 20:01:52 casey-Virtual-Machine systemd[1]: tailscale-weekly-update.timer: Deactivated successfully.
4 月 02 20:01:52 casey-Virtual-Machine systemd[1]: Stopped Tailscale node agent.

如上面的日志,可以很方便地检查 timer 和服务的状态。

在日志这方面,你不需要做任何特别的事情,就可以使tailscale-weekly-update.service unit 中的ExecStart触发器的STDOUT存储在日志中。这都是使用 systemd 运行服务的一部分。

Systemd timer 时间精度

优势之一:针对时间精确度更详细的配置项

从上面日志,如果细看,timer 不会在:00秒的时候准确触发,甚至不会在上一个实例的一分钟内准确触发。这是故意的,但如果有必要的话,可以覆盖它的默认配置。

这种行为的原因是为了防止多个服务在完全相同的时间被触发。例如,你可以使用时间规格,如每周、每天,等等。这些快捷方式都被定义为在它们被触发的那一天的 00:00:00 时触发。当多个 timer 被这样指定时,它们很有可能会试图同时启动。

systemd timer 被有意设计成在指定时间内随机触发,以防止同时触发。它们在一个时间窗口内半随机地触发。根据systemd.timer手册,这个触发时间相对于所有其他定义的 timer 单位来说,保持在一个稳定的位置。

大多数时候,这种概率性的触发时间是没有问题的。当安排备份等任务运行时,只要它们在非工作时间运行,就不会有问题。一个系统管理员可以选择一个确定的开始时间,如典型的 cronjob 规范中的 01:05:00,以不与其他任务冲突,但有很大范围的时间值可以达到这个目的。启动时间中的一分钟随机性通常是不相关的。

然而,对于某些任务,精确的触发时间是一个绝对要求。对于这些任务,你可以通过在 timer unit 文件的 Timer 部分添加这样的配置来指定更高的触发时间跨度精度(如精度在一微秒内):

AccuracySec=1us

时间跨度可用于指定所需的精度,以及为重复性或一次性事件定义时间跨度。它可以识别以下单位:

  • usec, us, µs
  • msec, ms
  • seconds, second, sec, s
  • minutes, minute, min, m
  • hours, hour, hr, h
  • days, day, d
  • weeks, week, w
  • months, month, M (定义为 30.44 天)
  • years, year, y (定义为 365.25 天)

/usr/lib/systemd/system中的所有默认 timer 都指定了一个更大的精度范围,因为精确的时间并不关键。看看系统创建的 timer 中的一些规格:

$ grep Accur /usr/lib/systemd/system/*timer
/usr/lib/systemd/system/fstrim.timer:AccuracySec=1h
/usr/lib/systemd/system/logrotate.timer:AccuracySec=1h
/usr/lib/systemd/system/plocate-updatedb.timer:AccuracySec=20min
/usr/lib/systemd/system/snapd.snap-repair.timer:AccuracySec=10min

Timer 类型

优势之一:除了定时场景,还支持基于 event 的触发

systemd timer 具有 cron 所不具备的其他功能,cron 只在特定的、重复的、实时的日期和时间触发。但是,一个 timer 可以被配置为在系统启动后,或在启动后,或在某个定义的服务 unit 激活后的特定时间内触发。这些被称为单调性 timer。单调指的是一个持续增加的计数或序列。这些 timer 不是持久的,因为它们在每次启动后都会重置。

表 1 列出了单调的 timer 以及每个 timer 的简短定义,还有 "OnCalendar" timer,它不是单调的,用于指定未来的时间,可能是重复的,也可能不是。

Timer 单调性 定义
OnActiveSec= X 这定义了一个相对于 timer 被激活的时刻的 timer。
OnBootSec= X 这定义了一个相对于机器启动时间的 timer。
OnStartupSec= X 这定义了一个相对于服务管理器首次启动时间的计时器。对于系统 timer unit,这与OnBootSec=非常相似,因为系统服务管理器通常在启动时很早就启动。当配置在每个用户服务管理器中运行的单元时,它主要是有用的,因为用户服务管理器一般只在第一次登录时启动,而不是在启动时。
OnUnitActiveSec= X 这定义了一个相对于要激活的 timer 最后一次被激活的时间。
OnUnitInactiveSec= X 这定义了一个相对于要激活的 timer 最后被停用的时间的定时器。
OnCalendar= 这就用日历事件表达式定义了实时 timer。更多关于日历事件表达式的语法信息请参见systemd.time(7)。否则,其语义与OnActiveSec=及相关设置类似。这个 timer 是最像那些与 cron 服务一起使用的 timer。

表 1: systemd timer 定义

单调 timer 的时间跨度可以使用与前面提到的AccuracySec语句相同的快捷名称,但 systemd 将这些名称规范化为秒。例如,你可能想指定一个 timer,在系统启动 5 天后触发一次事件,可以这样写: OnBootSec=5d。如果主机在2020-06-15 09:45:27启动,timer 将在2020-06-20 09:45:27或之后一分钟内触发。

Calendar event 定义

优势之一:相比 cronjob 更灵活的语法

Calendar event 定义是在所需的重复时间触发 timer 的关键部分。首先看一下OnCalendar设置中使用的一些规格。

systemd 及其 timer 使用的时间和日期规格与 crontab 中使用的格式不同。它比 crontab 更灵活,允许以at命令的方式模糊日期和时间。

使用OnCalendar=的 systemdtimer 的基本格式是DOW YYYY-MM-DD HH:MM:SS。DOW(星期)是可选的,其他字段可以使用星号(*)来匹配该位置的任何值。所有日历时间形式都被转换为规范化的形式。如果没有指定时间,则假定其为 00:00:00。如果没有指定日期但指定了时间,那么下一个匹配可能是今天或明天,这取决于当前的时间。名称或数字可用于月份和星期。可以指定每个单位的逗号分隔的列表。单位范围可以在开始和结束值之间用...来指定。

有几个有趣的选项用于指定日期。波浪号(~)可以用来指定该月的最后一天或该月最后一天之前的指定天数。"/"可以用来指定一周中的某一天作为修饰语。

下面是一些在OnCalendar语句中使用的典型时间规格的例子:

Calendar event 定义 描述
DOW YYYY-MM-DD HH:MM:SS
*-*-* 00:15:30 每年的每个月的每一天,在午夜后的 15 分钟 30 秒。
Weekly 每个星期一的 00:00:00
Mon *-*-* 00:00:00 与每周相同
Mon 与每周相同
Wed 2020-*-* 2020 年的每个星期三,00:00:00
Mon..Fri 2021-*-* 2021 年的每个工作日的 00:00:00
2023-6,7,8-1,15 01:15:00 2023 年 6 月、7 月和 8 月的 1 日和 15 日凌晨 01:15:00
Mon *-05~03 任何一年的 5 月的下一个星期一,也是月末的第三天。
Mon..Fri *-08~04 任何年份的 8 月底前的第 4 天,如果该天也是工作日,则为 8 月底。
*-05~03/2 从五月底开始的第三天,两天后再来一次。每年都会重复。请注意,这个表达式使用了(~)。
*-05-03/2 五月的第三天,然后在五月的其余时间里每隔一天。每年重复一次。注意,这个表达式使用了破折号(-)。

表 2: 示例OnCalendar event 定义

测试 calendar 定义

优势之一:更丰富的使用/运维命令集

systemd 提供了一个很好的工具来验证和检查 timer 中的日历时间事件规范。systemd-analyze calendar工具解析了一个日历时间事件规范,并提供了规范化的形式以及其他有趣的信息,比如下一个 "elapse"(即匹配)的日期和时间,以及达到触发时间前的大致时间。

首先,看一下未来的一个没有时间的日期:

$ systemd-analyze calendar 2030-06-17
  Original form: 2030-06-17
Normalized form: 2030-06-17 00:00:00
    Next elapse: Mon 2030-06-17 00:00:00 CST
       (in UTC): Sun 2030-06-16 16:00:00 UTC
       From now: 7 years 2 months left

现在添加一个时间。在这个例子中,日期和时间作为非相关实体被单独分析:

$ systemd-analyze calendar 2030-06-17 15:21:16
  Original form: 2030-06-17
Normalized form: 2030-06-17 00:00:00
    Next elapse: Mon 2030-06-17 00:00:00 CST
       (in UTC): Sun 2030-06-16 16:00:00 UTC
       From now: 7 years 2 months left

  Original form: 15:21:16
Normalized form: *-*-* 15:21:16
    Next elapse: Wed 2023-04-05 15:21:16 CST
       (in UTC): Wed 2023-04-05 07:21:16 UTC
       From now: 21h left

要把日期和时间作为一个 unit 来分析,需要用引号把它们括起来。

$ systemd-analyze calendar "2030-06-17 15:21:16"
Normalized form: 2030-06-17 15:21:16
    Next elapse: Mon 2030-06-17 15:21:16 CST
       (in UTC): Mon 2030-06-17 07:21:16 UTC
       From now: 7 years 2 months left

现在测试表 2 中的条目。选一个复杂的:

$ systemd-analyze calendar "2023-6,7,8-1,15 01:15:00"
  Original form: 2023-6,7,8-1,15 01:15:00
Normalized form: 2023-06,07,08-01,15 01:15:00
    Next elapse: Thu 2023-06-01 01:15:00 CST
       (in UTC): Wed 2023-05-31 17:15:00 UTC
       From now: 1 month 26 days left

让我们看一个例子,在这个例子中,我们列出了时间戳表达式的下五个执行时间:

$ systemd-analyze calendar --iterations=5 "Mon *-05~3"
  Original form: Mon *-05~3
Normalized form: Mon *-05~03 00:00:00
    Next elapse: Mon 2023-05-29 00:00:00 CST
       (in UTC): Sun 2023-05-28 16:00:00 UTC
       From now: 1 month 23 days left
       Iter. #2: Mon 2028-05-29 00:00:00 CST
       (in UTC): Sun 2028-05-28 16:00:00 UTC
       From now: 5 years 1 month left
       Iter. #3: Mon 2034-05-29 00:00:00 CST
       (in UTC): Sun 2034-05-28 16:00:00 UTC
       From now: 11 years 1 month left
       Iter. #4: Mon 2045-05-29 00:00:00 CST
       (in UTC): Sun 2045-05-28 16:00:00 UTC
       From now: 22 years 1 month left
       Iter. #5: Mon 2051-05-29 00:00:00 CST
       (in UTC): Sun 2051-05-28 16:00:00 UTC
       From now: 28 years 1 month left

这应该给你足够的信息来开始测试你的OnCalendar时间规格。

总结

systemd timer 可以用来执行与 cron 工具相同类型的任务,但在触发事件的 calendar 和单调的时间规格方面提供了更多的灵活性。

除此之外,systemd timer 还有的优势包括:

  • 统一日志收集到 systemd 日志
  • 针对时间精确度更详细的配置项
  • 更丰富的使用/运维命令集

快去尝试迁移你的 cronjob 到 systemd timer 吧~😛😛😛

参考资料

三人行, 必有我师; 知识共享, 天下为公. 本文由东风微鸣技术博客 EWhisper.cn 编写.

与为什么我推荐你使用 systemd timer 替代 cronjob?相似的内容:

为什么我推荐你使用 systemd timer 替代 cronjob?

概述 前几天在使用 Terraform + cloud-init 批量初始化我的实验室 Linux 机器。正好发现有一些定时场景需要使用到 cronjob, 进一步了解到 systemd timer 完全可以替换 cronjob, 并且 systemd timer 有一些非常有趣的功能。 回归话题:

关于.Net 6.0 在Linux ,Docker容器中,不安装任何依赖就生成图形验证码!!!!!!!!!!!

在.Net Framework时代,我们生成验证码大多都是用System.Drawing。 在.Net 6中使用也是没有问题的。 但是,System.Drawing却依赖于Windows GDI+。 为了实现跨平台,我陷入了沉思!! 微软推荐使用SkiaSharp 进行替代,所以就开始了,踩坑之旅

刺激!ChatGPT给我虚构了一本书?

ChatGPT很强大,可以帮我们处理很多问题,但这些问题的答案的正确性您是否有考证过呢? 昨晚,DD就收到了一个有趣的反馈: 提问:有什么关于数据权限设计的资料推荐吗? ChatGPT居然介绍了一本根本不存在的书《数据权限设计与实现》,作者居然还是我... 那么你在使用ChatGPT的时候,有碰到过

15.3K Star,超好用的开源协作式数字白板:tldraw

大家好,我是TJ 今天给大家推荐一个开源协作式数字白板:tldraw。 tldraw的编辑器、用户界面和其他底层库都是开源的,你可以在它的开源仓库中找到它们。它们也在NPM上分发,提供开发者使用。您可以使用tlDraw为您的产品创建一个临时白板,或者将其作为构建自己应用的工具来使用。 在线体验 tl

为什么不推荐使用Linq?

相信很多.NETer看了标题,都会忍不住好奇,点进来看看,并且顺便准备要喷作者! 这里,首先要申明一下,作者本人也非常喜欢Linq,也在各个项目中常用Linq。 我爱Linq,Linq优雅万岁!!!(PS:顺便吐槽一下,隔壁Java从8.0版本推出的Streams API,抄了个四不像,一点都不优雅

android中Room数据库的基本使用

简介: 还在使用原生的sqllite?有这么清爽且稳如狗的room为啥不用呢? Room是Google官方推荐使用的数据库,相比较某些优秀数据库框架来说,不用过于担心某天库会停止维护,且访问数据库非常流畅,并且提供了与常规的ORM框架一样,通过添加编译期注解来进行表和字段的配置,譬如@Databas

记录一次全栈经验,所有遇到的坑。(文中无需梯子,免费使用chatGPT方法喔)

## 1、先推荐一下自己搭的网站 ### 1.1 网站地址:[chatGPT](https://www.hangyejingling.cn/) ### 1.2 建站原因 为了方便大家在国内使用chatGPT,所以我调研了一下。在国内用腾讯云使用代理访问,gpt3.5API。最后模仿了openAI的官

[转帖]为什么不推荐使用/etc/fstab

https://www.jianshu.com/p/af49a5d0553f 对于工作中使用服务器的公司来讲,每到节假日来临时,总免不了对服务器进行下电。而收假回来的早上,则会有一个早上的时间会花费在服务区的开机和修复工作上。是的,修复无法开启或开机失败的服务器。 几乎每次节假日售价回来,恢复服务器

如何创建一个线程池,为什么不推荐使用Executors去创建呢?

我们在学线程的时候了解了几种创建线程的方式,比如继承Thread类,实现Runnable接口、Callable接口等,那对于线程池的使用,也需要去创建它,在这里我们提供2种构造线程池的方法: 方法一: 通过ThreadPoolExecutor构造函数来创建(首选) 这是JDK中最核心的线程池工具类,

为什么 java 容器推荐使用 ExitOnOutOfMemoryError 而非 HeapDumpOnOutOfMemoryError ?

前言 好久没写文章了, 今天之所以突然心血来潮, 是因为昨天出现了这样一个情况: 我们公司的某个手机APP后端的用户(customer)微服务出现内存泄露, 导致OutOfMemoryError, 但是因为经过我们精心优化的openjdk容器参数, 这次故障对用户完全无感知. :muscle::mu