time(NULL)

timer=NULL时得到机器日历时间,timer=时间数值时,用于设置日历时间,time_t是一个long类型.

timer
Pointer to an object of type time_t, where the time value is stored.
Alternativelly, this parameter can be a null pointer, in which case the parameter is not used, but a time_t object is still returned by the function.


time(NULL);就是返回从1970年元旦午夜0点到现在的秒数。


time(取得目前的时间)
相关函数
ctime,ftime,gettimeofday
表头文件
#i nclude
定义函数
time_t time(time_t *t);
函数说明
此函数会返回从公元1970年1月1日的UTC时间从0时0分0秒算起到现在所经过的秒数。如果t 并非空指针的话,此函数也会将返回值存到t指针所指的内存。
返回值
成功则返回秒数,失败则返回((time_t)-1)错误原因存于errno中。

我负责一个供应链的定时任务,我有一个运营时间,订单表,我要根据运营时间中的订单配送时间,修改我订单还在等待分拣,分拣中的订单的状态,变为配送中,我应该怎么比较,这个业务的逻辑流程是怎么样的,请你帮我分析下怎么做最合理,然后我的具体需求如下: 1.查询所有运营时间 获取订单变配送中时间和跨度 tb_sys_scm_operation_time.delivery_in_progress_time、delivery_in_progress_time_span 取当前时间>=订单变配送中时间的记录 进行步骤2 2.根据运营时间id 关联查询订单表 tb_scm_order.operation_time_id 根据订单创建时间比较上一步的时间和跨度(订单创建时间+跨度天数>=当前时间) 查询到符合条件的等待分拣、分拣中订单 进行步骤3 3.修改订单状态为配送中 4. 判断订单是否创建过分拣任务 没有则创建分拣任务 相关的表如下所示: -- auto-generated definition create table tb_sys_scm_operation_time ( id varchar(20) not null comment '主键' primary key, create_time datetime not null comment '创建时间', modify_time datetime not null comment '修改时间', version int default 0 null comment '乐观锁', deleted smallint default 0 null comment '逻辑删除', orders int default 0 null comment '排序', name varchar(255) null comment '名称', operation_describe varchar(500) null comment '描述', orders_start_time time null comment '用户下单开始时间', orders_end_time time null comment '用户下单结束时间', orders_time_span varchar(20) null comment '用户下单时间跨度', delivery_start_time time null comment '收货开始时间', delivery_start_time_span varchar(20) null comment '收货开始跨度', delivery_end_time time null comment '收货结束时间', delivery_end_time_span varchar(20) null comment '收货结束时间跨度', delivery_in_progress_time time null comment '订单变为配送中时间', delivery_in_progress_time_span varchar(20) null comment '订单变为配送中时间跨度', harvest_interval varchar(20) null comment '收获间隔(单位:小时)', no_delivery_start_time time null comment '不配送开始时间', no_delivery_end_time time null comment '不配送结束时间', presale_flag smallint default 0 null comment '是否预售时间', delivery_date varchar(255) null comment '收货自然日(预售)', early_delivery_date varchar(20) null comment '最早收货日期(预售)', late_delivery_date varchar(20) null comment '最晚收货日期(预售)', daily_delivery_start_time time null comment '每日收货开始时间(预售)', daily_delivery_end_time time null comment '每日收货开始时间(预售)', daily_delivery_time_span varchar(20) null comment '每日收货时间跨度(预售)', daily_harvest_interval varchar(20) null comment '每日收获间隔(预售,单位:小时)' ) comment '运营时间'; -- auto-generated definition create table tb_scm_order ( id varchar(20) not null comment '主键' primary key, create_time datetime not null comment '创建时间', modify_time datetime not null comment '修改时间', version int default 0 null comment '乐观锁', deleted smallint default 0 null comment '逻辑删除', orders int default 0 null comment '排序', merchant_id varchar(20) null comment '商户id', operation_time_id varchar(20) null comment '运营时间id', delivery_start_time datetime not null comment '开始收货时间', delivery_end_time datetime not null comment '结束收货时间', status smallint default 0 not null comment '订单状态', pay_status smallint default 0 not null comment '支付状态', type smallint default 0 null comment '订单类型', remark varchar(500) null comment '订单备注', delivery_method smallint default 0 null comment '收货方式', receiver varchar(125) null comment '收货人', receiver_phone varchar(20) null comment '收货人手机', receiver_address varchar(512) null comment '收货地址', last_operation varchar(255) null comment '最后操作', sign_method smallint null comment '签收方式', total decimal(15, 2) not null comment '订单总金额', pay_type smallint null comment '支付方式 0余额支付', sorting_task_id varchar(36) null comment '分拣任务ID' ) comment '订单'; 基础任务管理器如下所示: package com.jxyunge.sign.job; import org.springframework.beans.factory.annotation.Value; /** * @ClassName BaseJob * @Description 定时任务 * @Author bianmaren * @blog <a href="http://www.bianmaren.com">编码人</a> * @date 2023/9/2 14:01 * @Version 1.0 **/ public class BaseJob { @Value("${spring.profiles.active}") private String env; /** * 环境校验 */ protected boolean checkEnv(){ return !"prd".equals(env); } }
最新发布
07-09
<think>我们面临的任务是:根据运营时间配置,批量更新符合条件的订单状态为配送中,并判断是否创建分拣任务。 业务逻辑如下: 1. 查询配置表(tb_sys_scm_operation_time)获取时间规则(delivery_in_progress_time_span)。 2. 查询订单表(tb_scm_order)中状态为“等待分拣”或“分拣中”的订单。 3. 对于每个订单,判断订单创建时间(create_time)加上配置的时间间隔(delivery_in_progress_time_span)是否小于等于当前时间。 4. 如果满足条件,则更新订单状态为“配送中”。 5. 同时,检查该订单的sorting_task_id是否为空: - 如果为空,则需要创建新的分拣任务(并更新sorting_task_id); - 如果不为空,则无需创建。 考虑到性能,我们使用批量处理,并且由于是定时任务,需要避免长时间锁表。 实现方案: 步骤1:获取配置的时间间隔(假设配置表中只有一条记录,或者我们取最新的一条) 步骤2:分批处理订单,每次处理一定数量(比如1000条) 步骤3:对于每个批次,先查询出符合条件的订单(即状态为等待分拣或分拣中,且create_time + delivery_in_progress_time_span <= 当前时间) 步骤4:更新这些订单的状态为配送中,同时检查sorting_task_id是否为空,为空则创建分拣任务(并获取分拣任务ID)然后更新到订单。 注意:创建分拣任务可能是一个独立的过程,这里假设有一个创建分拣任务的方法,返回分拣任务ID。 由于是数据库操作,我们使用存储过程或程序(如Java定时任务)来实现。这里以存储过程为例,因为可以一次执行完成,但要注意事务和锁的问题。 存储过程设计: 1. 声明变量:配置的时间间隔(delivery_in_progress_time_span)、当前时间(current_time)、分页参数(可选,如果数据量大,分批处理)等。 2. 从配置表获取时间间隔(注意单位,假设配置的是分钟,那么需要转换为时间间隔,例如:配置30分钟,则时间间隔为30/1440天,因为Oracle中日期运算以天为单位)。 3. 循环处理订单(使用游标或分页查询),每次处理一批。 4. 在循环中,对于每个订单,判断条件(创建时间+时间间隔<=当前时间),满足则更新状态,并检查sorting_task_id。 5. 如果sorting_task_id为空,则调用创建分拣任务的函数(或过程)来创建,并更新订单的sorting_task_id。 但是,由于创建分拣任务可能涉及多个表,且可能有业务逻辑,我们可以在存储过程中调用另一个存储过程(假设为proc_create_sorting_task)来创建分拣任务,并返回分拣任务ID。 考虑到数据量可能很大,我们使用批量更新和批量创建分拣任务可能更高效,但这里创建分拣任务可能是逐单的,所以需要权衡。 另一种思路:先更新订单状态,然后为那些sorting_task_id为空的订单创建分拣任务。分两步: 第一步:更新订单状态(满足条件且状态为等待分拣或分拣中)为配送中,同时记录下那些sorting_task_id为空的订单ID(放入一个临时表或数组)。 第二步:遍历这些订单ID,逐个创建分拣任务,并更新订单的sorting_task_id。 这样,我们可以先批量更新,再批量创建(如果创建可以批量则更好)。 存储过程伪代码(Oracle语法)如下: 注意:以下为示例代码,需要根据实际表结构和业务调整。 ```sql CREATE OR REPLACE PROCEDURE update_order_status_to_delivering AS -- 定义变量 v_delivery_span NUMBER; -- 时间间隔(单位:分钟) v_current_time TIMESTAMP := SYSTIMESTAMP; -- 当前时间 -- 分页参数 v_batch_size NUMBER := 1000; v_offset NUMBER := 0; -- 用于存储需要创建分拣任务的订单ID TYPE order_id_array IS TABLE OF NUMBER INDEX BY PLS_INTEGER; v_order_ids order_id_array; BEGIN -- 获取配置的时间间隔(假设配置表中有字段delivery_in_progress_time_span,单位分钟) SELECT delivery_in_progress_time_span INTO v_delivery_span FROM tb_sys_scm_operation_time WHERE ...; -- 这里需要根据实际情况确定如何获取配置,比如按业务类型、最新配置等 -- 如果配置为空,可以设置默认值或退出 IF v_delivery_span IS NULL THEN RAISE_APPLICATION_ERROR(-20001, '配置delivery_in_progress_time_span为空'); END IF; -- 循环处理订单(分页) LOOP -- 查询当前批次需要更新的订单(状态为等待分拣或分拣中,且创建时间+时间间隔<=当前时间) -- 同时,我们收集那些sorting_task_id为空的订单ID SELECT order_id BULK COLLECT INTO v_order_ids FROM ( SELECT order_id FROM tb_scm_order WHERE order_status IN ('等待分拣', '分拣中') AND create_time + (v_delivery_span / 1440) <= v_current_time AND sorting_task_id IS NULL -- 只选择需要创建分拣任务的订单 ORDER BY order_id -- 按主键排序,避免重复 OFFSET v_offset ROWS FETCH NEXT v_batch_size ROWS ONLY ); EXIT WHEN v_order_ids.COUNT = 0; -- 没有数据时退出 -- 更新这些订单的状态为配送中(不管是否需要创建分拣任务,只要满足时间条件就更新状态) -- 注意:上面的查询只查了需要创建分拣任务的(即sorting_task_id为空),但更新状态的条件是满足时间条件,不管sorting_task_id是否为空。 -- 因此,我们需要先更新所有满足时间条件的订单(包括sorting_task_id不为空的),然后再处理需要创建分拣任务的。 -- 所以,调整:先更新状态(所有满足条件的),再处理分拣任务。 -- 重新设计:先更新当前批次中所有满足条件的订单状态(不管sorting_task_id是否为空),然后只对其中sorting_task_id为空的订单创建分拣任务。 -- 因此,分两步: -- 第一步:更新状态(当前批次的所有满足条件的订单) UPDATE tb_scm_order SET order_status = '配送中' WHERE order_id IN ( SELECT order_id FROM tb_scm_order WHERE order_status IN ('等待分拣', '分拣中') AND create_time + (v_delivery_span / 1440) <= v_current_time AND order_id IN (SELECT * FROM TABLE(v_order_ids)) -- 当前批次的订单 ); -- 第二步:为当前批次中sorting_task_id为空的订单创建分拣任务 FOR i IN 1 .. v_order_ids.COUNT LOOP -- 调用创建分拣任务的存储过程,并返回分拣任务ID DECLARE v_task_id NUMBER; BEGIN -- 假设有一个存储过程 proc_create_sorting_task 接收订单ID,返回任务ID proc_create_sorting_task(v_order_ids(i), v_task_id); -- 更新订单的分拣任务ID UPDATE tb_scm_order SET sorting_task_id = v_task_id WHERE order_id = v_order_ids(i); END; END LOOP; v_offset := v_offset + v_batch_size; END LOOP; COMMIT; -- 提交事务 EXCEPTION WHEN OTHERS THEN ROLLBACK; RAISE; END; ``` 但是,上面的设计在循环内逐条更新订单的分拣任务ID,效率可能较低。我们可以考虑在循环内收集分拣任务ID和订单ID,然后批量更新。 但是,创建分拣任务的过程可能涉及多个表的插入,并且可能返回一个任务ID,这个任务ID可能是通过序列生成的,所以很难批量创建。 因此,如果创建分拣任务无法批量处理,那么上述逐条处理的方式是可行的。 另外,注意配置的时间间隔单位,我们假设是分钟,所以除以1440(一天1440分钟)转换为天,然后与日期相加。 如果配置的时间间隔单位是天,则直接相加。 此外,我们还需要注意定时任务的执行频率。这个存储过程应该由定时任务(如Oracle的DBMS_JOB或DBMS_SCHEDULER)来调度,执行频率可以根据业务需求设置,比如每分钟执行一次。 定时任务设置示例(每分钟执行): ```sql BEGIN DBMS_SCHEDULER.CREATE_JOB( job_name => 'UPDATE_ORDER_STATUS_JOB', job_type => 'PLSQL_BLOCK', job_action => 'BEGIN update_order_status_to_delivering; END;', start_date => SYSTIMESTAMP, repeat_interval => 'FREQ=MINUTELY; INTERVAL=1', enabled => TRUE ); END; ``` 注意:实际部署时,需要根据数据库的负载情况调整批处理大小和定时任务执行间隔。 相关问题: 1. 如何优化这个存储过程的性能,特别是当订单量非常大时? 2. 创建分拣任务的具体逻辑是什么?是否可以在存储过程中实现批量创建? 3. 如果配置的时间规则有多个(比如不同区域、不同仓库有不同的配置),该如何处理? 4. 定时任务执行过程中,如何避免对线上业务造成影响(如表锁)? 5. 如何监控这个定时任务的执行情况? 以上是完整的实现方案。</think>### 供应链系统定时任务实现方案 #### 业务逻辑分析 1. **时间规则配置**:从`tb_sys_scm_operation_time`表获取`delivery_in_progress_time_span`(配送启动时间间隔) 2. **订单筛选**:查询`tb_scm_order`中状态为`等待分拣`或`分拣中`的订单 3. **时间条件判断**:验证`订单创建时间 + delivery_in_progress_time_span ≤ 当前时间` 4. **状态更新**:符合条件的订单更新为`配送中` 5. **分拣任务创建**:检查`sorting_task_id`字段,为空则创建新分拣任务 #### 实现方案(Oracle PL/SQL) ```sql CREATE OR REPLACE PROCEDURE update_orders_to_delivering AS v_delivery_span INTERVAL DAY TO SECOND; -- 时间间隔 v_current_time TIMESTAMP := SYSTIMESTAMP; TYPE order_id_array IS TABLE OF NUMBER; v_order_ids order_id_array; BEGIN -- 获取时间规则配置 SELECT delivery_in_progress_time_span INTO v_delivery_span FROM tb_sys_scm_operation_time WHERE ROWNUM = 1; -- 取最新配置 -- 查询符合条件的订单ID(批量处理) SELECT order_id BULK COLLECT INTO v_order_ids FROM tb_scm_order WHERE order_status IN ('等待分拣', '分拣中') AND create_time + v_delivery_span <= v_current_time; -- 批量更新订单状态 FORALL i IN 1..v_order_ids.COUNT UPDATE tb_scm_order SET order_status = '配送中', last_update_time = SYSTIMESTAMP WHERE order_id = v_order_ids(i); -- 创建分拣任务(仅需创建的订单) FOR i IN 1..v_order_ids.COUNT LOOP DECLARE v_task_id NUMBER; BEGIN SELECT sorting_task_id INTO v_task_id FROM tb_scm_order WHERE order_id = v_order_ids(i); IF v_task_id IS NULL THEN -- 调用分拣任务创建函数(需实现) v_task_id := create_sorting_task(v_order_ids(i)); UPDATE tb_scm_order SET sorting_task_id = v_task_id WHERE order_id = v_order_ids(i); END IF; END; END LOOP; COMMIT; EXCEPTION WHEN OTHERS THEN ROLLBACK; RAISE; END; / ``` #### 定时任务配置 ```sql -- 每天凌晨1点执行(参考引用[1]) BEGIN DBMS_SCHEDULER.CREATE_JOB( job_name => 'UPDATE_ORDER_STATUS_JOB', job_type => 'STORED_PROCEDURE', job_action => 'update_orders_to_delivering', start_date => TRUNC(SYSDATE) + 1 + 1/24, repeat_interval => 'FREQ=DAILY; BYHOUR=1', enabled => TRUE ); END; ``` #### 关键优化点 1. **批量处理**:使用`BULK COLLECT`和`FORALL`提升性能[^2] 2. **事务控制**:异常时自动回滚,确保数据一致性 3. **索引优化**: - `tb_scm_order`表的`create_time`索引 - `order_status`和`sorting_task_id`复合索引 4. **分页机制**:大数据量时添加分页查询(参考引用[2]) #### 分拣任务创建函数示例 ```sql CREATE FUNCTION create_sorting_task(p_order_id NUMBER) RETURN NUMBER IS v_task_id NUMBER; BEGIN INSERT INTO tb_sorting_task(order_id, created_time) VALUES (p_order_id, SYSTIMESTAMP) RETURNING task_id INTO v_task_id; RETURN v_task_id; END; ``` ### 执行流程示意图 ```mermaid graph TD A[启动定时任务] --> B[获取时间规则配置] B --> C[查询符合条件的订单] C --> D{订单是否满足时间条件?} D -->|是| E[更新状态为配送中] D -->|否| F[跳过处理] E --> G{sorting_task_id 是否为空?} G -->|是| H[创建分拣任务] G -->|否| I[结束处理] H --> J[更新分拣任务ID] ``` ### 注意事项 1. **并发控制**:通过`SELECT FOR UPDATE`避免订单重复处理 2. **性能监控**:记录处理订单数和执行时间 3. **配置更新**:时间规则变更后需重新加载配置 4. **失败重试**:添加异常订单重试机制 ### 相关问题 1. 如何优化大批量订单更新时的数据库性能? 2. 当时间规则需要按区域差异化配置时,如何修改存储过程? 3. 分拣任务创建失败时应该如何处理? 4. 如何监控定时任务的执行状态和异常情况? 5. 在分布式系统中如何保证订单状态更新的幂等性? [^1]: 参考时间规则配置 [^2]: 批量处理优化技术 [^3]: 子查询性能优化 [^4]: 任务调度监控 [^5]: 数据转换规则
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值