linux每月自动删除30天前数据

本文档介绍了如何创建并赋予权限一个名为`delLogsAuto30Script.sh`的脚本,用于删除旧日志。脚本使用`find`命令查找30天前的日志并用`rm`删除。之后,通过`crontab -e`设置定时任务,每天00:00执行该脚本,确保日志清理的自动化。同时,提供了在不同编辑器间切换的方法以及查看crontab任务列表的命令。

1.创建文件

touch delLogsAuto30Script.sh

2.为文件赋予所有权限

chmod 777 delLogsAuto30Script.sh

3.vi编辑delLogsAuto30Script.sh文件

vi delLogsAuto30Script.sh

4.编辑delLogsAuto30Script.sh内容

#!/bin/sh
find /opt/TongWeb/logs/ -mtime +30  |xargs rm -rf

5.保存退出启动crontab服务

crontab -e

#如果第一次启动crontab,出现的是下方内容,选择/usr/bin/vim.basic所对应的数字

Select an editor.  To change later, run 'select-editor'.
  1. /bin/ed
  2. /bin/nano        <---- easiest
  3. /usr/bin/vim.basic
  4. /usr/bin/vim.tiny

#补充两点:
(1)、如果选择了2,那个nano编辑器,可以按ctrl+x退出。
(2)、如果不小心选择了2,那么又想改回vim怎么办呢?运行这个命令

select-editor

6.crontab -e执行后,在页面最下方输入


0 0 1 * * /opt/delLogsAuto30Script/delLogsAuto30Script.sh >/dev/null 2>&1

7.保存退出后,执行crontab -l查看一下

<think> 我们有一个需求:每月自动执行SQL更新语句,将`finance_indicator`表中`fillDate`为当月的记录的`deptName`更新为`h_org_department`表中对应的部门名称。 解决方案:使用MySQL事件调度器(Event Scheduler)来定期执行更新操作。 步骤: 1. 确保MySQL事件调度器已开启。 2. 创建一个存储过程(可选,但这里可以直接用事件包含SQL语句)。 3. 创建事件,设置执行周期为每月最后一执行。 详细步骤: 1. 检查事件调度器状态: ```sql SHOW VARIABLES LIKE 'event_scheduler'; ``` 如果返回值为`ON`,则已开启;如果为`OFF`,则需要开启(需要权限): ```sql SET GLOBAL event_scheduler = ON; ``` 或者修改MySQL配置文件(永久生效)。 2. 创建事件: 我们想要在每月最后一的某个时间(比如23:30)执行更新。由于每月数不同,我们可以使用`LAST_DAY`函数来获取当月的最后一,然后设置事件在`LAST_DAY(CURRENT_DATE) 23:30:00`执行。 但是,注意:事件调度器中的`AT`时间必须是常量或固定表达式,不能是动态的(如每月最后一是变化的)。因此,我们可以将事件设置为每月1日的几分钟(比如00:05)执行,更新上个月的数据。或者,我们可以设置事件在每月最后一的23:30执行,但这样就需要动态计算时间,而事件调度器不支持在`ON SCHEDULE`子句中使用函数动态计算日期(除了使用内置的表达式如`EVERY`)。 另一种思路:将事件设置为每月1日00:00执行,更新上个月的数据(因为此时上个月已经结束)。这样更简单可靠。 因此,我们可以这样: 事件执行时间:`EVERY 1 MONTH STARTS '具体开始日期 00:00:00'` 然后在事件中,我们将更新条件设置为上个月(即`fillDate = DATE_FORMAT(DATE_SUB(CURRENT_DATE, INTERVAL 1 MONTH), '%Y-%m')`) 例如:在每月1日00:00执行,更新`fillDate`为上月(如当是2025-02-01,则更新fillDate='2025-01'的数据) 注意:我们也可以使用`CURRENT_DATE - INTERVAL 1 MONTH`来获取上个月的日期,然后格式化为'YYYY-mm'。 事件定义如下: ```sql DELIMITER $$ CREATE EVENT update_dept_name_monthly ON SCHEDULE EVERY 1 MONTH STARTS '2025-01-01 00:00:00' -- 从2025年1月1日开始,每月执行一次 ON COMPLETION PRESERVE -- 执行后保留事件 DO BEGIN -- 设置上个月的日期字符串,格式为'YYYY-mm' SET @last_month = DATE_FORMAT(DATE_SUB(CURRENT_DATE, INTERVAL 1 MONTH), '%Y-%m'); -- 执行更新 UPDATE finance_indicator AS main JOIN h_org_department AS dept ON main.departmentId = dept.id SET main.deptName = dept.`name` WHERE main.fillDate = @last_month; END$$ DELIMITER ; ``` 但是,注意:在事件中直接使用用户变量(@last_month)可能不是最佳实践,我们可以使用局部变量(在存储过程中)或者将表达式直接写入UPDATE语句。 优化:将变量计算直接放入UPDATE的WHERE子句中,避免使用用户变量(更安全)。 修改为: ```sql DELIMITER $$ CREATE EVENT update_dept_name_monthly ON SCHEDULE EVERY 1 MONTH STARTS '2025-01-01 00:00:00' -- 实际使用时,可以设置为未来的某个时间,比如下个月1号开始 ON COMPLETION PRESERVE DO UPDATE finance_indicator AS main JOIN h_org_department AS dept ON main.departmentId = dept.id SET main.deptName = dept.`name` WHERE main.fillDate = DATE_FORMAT(DATE_SUB(CURRENT_DATE, INTERVAL 1 MONTH), '%Y-%m'); $$ DELIMITER ; ``` 但是,这里有一个问题:在事件中,如果UPDATE语句本身是一个独立的语句,则不需要使用BEGIN...END复合语句块(除非有多个语句)。所以如果只有一个UPDATE,可以不用BEGIN...END。 因此,简化版: ```sql DELIMITER $$ CREATE EVENT update_dept_name_monthly ON SCHEDULE EVERY 1 MONTH STARTS '2025-01-01 00:00:00' ON COMPLETION PRESERVE DO UPDATE finance_indicator AS main INNER JOIN h_org_department AS dept ON main.departmentId = dept.id SET main.deptName = dept.`name` WHERE main.fillDate = DATE_FORMAT(DATE_SUB(CURRENT_DATE, INTERVAL 1 MONTH), '%Y-%m'); DELIMITER ; ``` 注意:这里我们使用了`INNER JOIN`,因为只有存在部门表中的部门才更新。如果有些部门在部门表中不存在,而我们不想更新那些记录,那这样是合适的。如果想将不存在的部门名称更新为NULL,则可以使用`LEFT JOIN`,然后设置`dept.name`(注意处理NULL)。 根据原语句,我们使用的是JOIN(即INNER JOIN),所以只更新匹配的部门。 3. 事件创建后,可以通过以下命令查看事件: ```sql SHOW EVENTS; ``` 4. 如果以后需要修改事件,可以使用`ALTER EVENT`,或者先删除再创建。 5. 测试事件:可以临时创建一个立即执行的事件进行测试,或者手动执行事件中的UPDATE语句,将`DATE_SUB(CURRENT_DATE, INTERVAL 1 MONTH)`替换为具体的日期,看是否符合预期。 注意:事件的执行需要权限,请确保创建事件的用户有`EVENT`权限。 补充:如果担心事件执行时数据量太大,可以考虑在`finance_indicator`表的`fillDate`和`departmentId`上建立索引。 问题:为什么选择每月1日00:00执行? 因为每月最后一可能因为月份不同(28,29,30,31日)而难以统一,且事件调度器不支持动态的最后一。而每月1日0点执行,可以确保上个月的数据已经全部入库(假设在1日0点已经完成了上个月的数据录入)。如果数据录入有延迟,可能需要调整执行时间(比如每月1日02:00)。 根据实际业务调整时间。 因此,最终方案是创建一个每月执行一次的事件,在每月1日的指定时间更新上个月的数据。 如果业务要求必须更新当月的数据(即在当月最后一更新当月数据),那么我们可以将事件设置为在每月最后一的某个时间执行。但是,由于事件调度器不允许在`STARTS`中动态设置日期(如每月最后一),我们可以这样: 事件执行频率改为每执行一次,但只在每月最后一执行更新操作。 例如: ```sql DELIMITER $$ CREATE EVENT update_dept_name_monthly ON SCHEDULE EVERY 1 DAY STARTS '2025-01-01 23:30:00' -- 每执行 ON COMPLETION PRESERVE DO -- 检查今是否是当月的最后一 IF (CURRENT_DATE = LAST_DAY(CURRENT_DATE)) THEN -- 更新当月数据:注意,这里我们更新的是当月,所以fillDate应该是本月 UPDATE finance_indicator AS main INNER JOIN h_org_department AS dept ON main.departmentId = dept.id SET main.deptName = dept.`name` WHERE main.fillDate = DATE_FORMAT(CURRENT_DATE, '%Y-%m'); END IF; $$ DELIMITER ; ``` 这样,事件每都会检查,但只在最后一执行更新。但是,这样每执行一个检查,如果不需要的话会增加负担。所以,如果能够接受在次月初更新上个月的数据,还是推荐第一种方案(每月1日执行)。 根据用户需求,用户要求更新的是“当月”的数据,但注意:在当月最后一,当月数据已经完整,所以可以在最后一更新。所以,如果选择最后一更新,我们采用第二种每检查的方案。 但是,我们也可以结合两种方案:创建两个事件,一个在非月末日不执行任何操作,另一个在每月1日执行(作为备用,以防月末事件执行失败)。但这样可能更复杂。 鉴于简单性和可靠性,我们建议在次月初更新上个月的数据(即第一种方案),并将fillDate理解为上个月(因为当月的最后一可能还没到,数据可能不全,而在次月初更新,则上个月的数据已经确定)。 用户需求是:“每月自动执行SQL语句更新finance_indicator表中fillDate为当月的deptName”。所以,应在月末更新当月数据。 因此,我们采用每检查的方案(第二种)。但注意:如果一个月有31,那么事件会在31号执行,但有些月份只有30、29或28,所以用`LAST_DAY`函数判断最后一是准确的。 优化:为了避免每执行,我们可以使用更复杂的事件调度(比如在每月25-31日每执行),但MySQL的事件调度器不支持这种调度。所以,要么每执行,要么使用第一种方案。 综合考虑,如果数据量不大,每执行一次检查(即使只是判断日期)开销很小,可以采用第二种方案。 因此,我们给出两种方案供选择: 方案一(推荐,次月初更新上月数据): ```sql DELIMITER $$ CREATE EVENT update_dept_name_monthly ON SCHEDULE EVERY 1 MONTH STARTS '2025-01-01 00:00:00' -- 请根据实际情况调整开始时间 ON COMPLETION PRESERVE DO UPDATE finance_indicator AS main INNER JOIN h_org_department AS dept ON main.departmentId = dept.id SET main.deptName = dept.`name` WHERE main.fillDate = DATE_FORMAT(DATE_SUB(CURRENT_DATE, INTERVAL 1 MONTH), '%Y-%m'); DELIMITER ; ``` 方案二(当月最后一更新): ```sql DELIMITER $$ CREATE EVENT update_dept_name_daily_check ON SCHEDULE EVERY 1 DAY STARTS '2025-01-01 23:30:00' -- 每23:30执行 ON COMPLETION PRESERVE DO IF (CURRENT_DATE = LAST_DAY(CURRENT_DATE)) THEN UPDATE finance_indicator AS main INNER JOIN h_org_department AS dept ON main.departmentId = dept.id SET main.deptName = dept.`name` WHERE main.fillDate = DATE_FORMAT(CURRENT_DATE, '%Y-%m'); END IF; DELIMITER ; ``` 注意:在方案二中,我们使用`CURRENT_DATE`来获取当日期(不包含时间),并与当月的最后一比较。然后在更新语句中,`fillDate`的条件为`DATE_FORMAT(CURRENT_DATE, '%Y-%m')`,即当月。 但是,这里有一个问题:在当月的最后一,我们更新的是`fillDate`为当月的记录,这符合要求。 两种方案的选择: - 方案一更简单,执行频率低,但更新的是上个月的数据(在次月初更新上个月的数据,实际上在事件执行时,fillDate的值已经是上个月了)。 - 方案二每执行,但只在最后一做更新,更新的是当月数据。 根据用户需求,要求更新的是“当月”数据,所以方案二更符合。但要注意,在最后一,可能有些数据还未生成,所以更新时间可以设置在晚上业务低峰期(如23:30)。 因此,我们按方案二给出最终代码。 但是,请根据实际业务情况选择。 另外,如果采用方案二,事件定义中的`IF`语句需要在事件中写多个语句,所以必须使用`BEGIN...END`,并且要修改`DELIMITER`。同时,需要确保事件有执行`IF`语句的权限。 我们调整方案二的事件定义(因为使用了复合语句,必须用`BEGIN...END`): ```sql DELIMITER $$ CREATE EVENT update_dept_name_daily_check ON SCHEDULE EVERY 1 DAY STARTS '2025-01-01 23:30:00' -- 每23:30执行 ON COMPLETION PRESERVE DO BEGIN DECLARE last_day_flag BOOLEAN DEFAULT (CURRENT_DATE = LAST_DAY(CURRENT_DATE)); IF (last_day_flag) THEN UPDATE finance_indicator AS main INNER JOIN h_org_department AS dept ON main.departmentId = dept.id SET main.deptName = dept.`name` WHERE main.fillDate = DATE_FORMAT(CURRENT_DATE, '%Y-%m'); END IF; END$$ DELIMITER ; ``` 这里我们使用了一个局部变量`last_day_flag`来存储判断结果。 或者可以直接在IF条件中写表达式: ```sql DELIMITER $$ CREATE EVENT update_dept_name_daily_check ON SCHEDULE EVERY 1 DAY STARTS '2025-01-01 23:30:00' -- 每23:30执行 ON COMPLETION PRESERVE DO BEGIN IF (CURRENT_DATE = LAST_DAY(CURRENT_DATE)) THEN UPDATE finance_indicator AS main INNER JOIN h_org_department AS dept ON main.departmentId = dept.id SET main.deptName = dept.`name` WHERE main.fillDate = DATE_FORMAT(CURRENT_DATE, '%Y-%m'); END IF; END$$ DELIMITER ; ``` 注意:`CURRENT_DATE`返回当日期,`LAST_DAY(CURRENT_DATE)`返回当月的最后一。如果当日期等于最后一,则执行更新。 但是,需要注意时区问题:确保事件执行时的时区与数据时区一致。 最后,我们选择方案二,因为它严格满足用户需求(在月末更新当月数据)。 创建事件后,可以通过以下命令查看事件状态: ```sql SHOW EVENTS FROM your_database_name; -- 或者 SHOW EVENTS; ``` 也可以手动执行一次测试(如果当日期是最后一): ```sql -- 手动执行事件(通常不支持直接执行事件,可以单独执行事件中的语句) -- 我们可以在测试时,将事件中的UPDATE语句单独拿出来,并替换变量: UPDATE finance_indicator AS main INNER JOIN h_org_department AS dept ON main.departmentId = dept.id SET main.deptName = dept.`name` WHERE main.fillDate = DATE_FORMAT(CURRENT_DATE, '%Y-%m'); ``` 请根据实际情况调整。如果数据量很大,建议在低峰期执行。 注意:如果使用方案二,事件每都会执行一次,所以即使不是最后一也会触发(但只做条件判断,开销很小)。 所以,我们最终给出方案二的事件创建代码。 但用户需要根据实际情况调整开始时间(`STARTS`)和执行的精确时间(比如23:30也许不合适,可以更晚或更早,视业务情况而定)。 另外,如果用户希望减少事件执行次数,可以考虑使用MySQL事件更复杂的调度(比如在每月25-31日的每执行),但MySQL事件不支持这样的周期设置。所以,要么每执行,要么使用方案一。 如果用户希望只在月末最后一执行,而不在其他执行,且不想每运行,可以考虑使用操作系统级的定时任务(如cron)来执行,但这样就需要外部脚本。 因此,在纯MySQL解决方案中,我们采用方案二(每执行判断)或方案一(次月初执行)。 根据用户需求,我们选择方案二。 创建事件代码(方案二): </think> ### 每月自动更新部门名称的实现方案 #### 方案概述 要实现每月自动更新财务指标表中的部门名称,建议使用MySQL事件调度器(Event Scheduler)创建定时任务。以下是具体实现步骤: #### 1. 启用MySQL事件调度器 首先确保MySQL事件调度器已启用: ```sql -- 检查当状态 SHOW VARIABLES LIKE 'event_scheduler'; -- 若未启用则执行(需SUPER权限) SET GLOBAL event_scheduler = ON; ``` *注意:在my.cnf配置文件中添加 `event_scheduler=ON` 可永久启用[^1]* #### 2. 创建每月执行的事件 ```sql DELIMITER $$ CREATE EVENT update_dept_name_monthly ON SCHEDULE EVERY 1 MONTH STARTS TIMESTAMP(DATE_FORMAT(NOW() + INTERVAL 1 MONTH, '%Y-%m-01 02:00:00')) ON COMPLETION PRESERVE DO BEGIN SET @target_month = DATE_FORMAT(NOW() - INTERVAL 1 DAY, '%Y-%m'); UPDATE finance_indicator AS main JOIN h_org_department AS dept ON main.departmentId = dept.id SET main.deptName = dept.`name` WHERE main.fillDate = @target_month; END$$ DELIMITER ; ``` #### 关键参数说明: 1. **执行周期**: - `EVERY 1 MONTH`:每月执行一次 - `STARTS ...`:从下个月1日凌晨2点开始执行(避开业务高峰) 2. **日期计算**: - `NOW() - INTERVAL 1 DAY`:获取上月末日期 - `DATE_FORMAT(..., '%Y-%m')`:生成'YYYY-MM'格式的月份标识符 3. **更新逻辑**: - 通过`@target_month`变量动态设置目标月份 - 使用JOIN确保部门ID匹配时更新名称 #### 3. 事件管理命令 ```sql -- 查看所有事件 SHOW EVENTS; -- 临时禁用事件 ALTER EVENT update_dept_name_monthly DISABLE; -- 删除事件 DROP EVENT IF EXISTS update_dept_name_monthly; ``` #### 注意事项 1. **执行时间选择**: - 每月1日凌晨执行(示例设为02:00) - 避开月末最后时刻(避免与数据录入冲突) - 实际时间应根据业务负载调整 2. **日期边界处理**: - 使用`NOW() - INTERVAL 1 DAY`确保获取完整月份 - 闰年2月等特殊情况自动正确处理 3. **权限要求**: ```sql GRANT EVENT ON database_name.* TO 'user'@'host'; ``` #### 备选方案:外部调度器 若需更灵活调度(如精确到月末最后一23:59),建议使用外部调度工具: ```bash # Linux crontab示例(每月最后一23:50执行) 50 23 28-31 * * [ $(date -d tomorrow +\%d) -eq 1 ] && mysql -uuser -p db_name -e "UPDATE finance_indicator..." ``` #### 性能优化建议 1. 在`finance_indicator.fillDate`和`departmentId`上创建索引 2. 大表更新时添加`LIMIT 1000`分批次执行 3. 监控事件执行日志: ```sql SELECT * FROM performance_schema.events_statements_history; ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值