在处理数据时,经常会用定时任务间隔去跑一批数据。如果一台服务器去查询执行倒也没事,如果出于负载均衡考虑,多台服务器同时去跑这个数据库的一张表的数据时,就很有可能会取到相同数据,出现执行数据重复的问题。
贴出我的做法。
--创建表定时任务取模求余表记录表 create table T_TASKMODREMAINDER ( TASKNAME varchar2(100) , MODREMAINDER number(3) , UPDATESEQ number(20) default 0, TASKIP VARCHAR2(32), UPDATETIME date ) / -- Add comments to the columns comment on column T_TASKMODREMAINDER.TASKNAME is '定时任务类名称' / comment on column T_TASKMODREMAINDER.MODREMAINDER is '定时任务执行时使用取模余数。必须从0开始,按1递增并保持连续。备注:每台机器执行定时任务时,首先要获取updatetime时间最早的该余数并对该记录上锁(如果获取失败则获取下updatetime次早的余数,直如果所有余数都获取失败,定时任务返回),然后使用该余数从数据库获取数据,获取完毕提交或失败回滚时自动释放记录锁。' / comment on column T_TASKMODREMAINDER.UPDATESEQ is '按updateseq从小到大的顺序获取取模余数。获取余数上锁后,先更新此字段,然后再获取业务数据。' / comment on column T_TASKMODREMAINDER.TASKIP is '当前使用该余数的机器IP,如:10.10.10.10。备注:1.并不是只有该IP才可以使用该余数,而是谁获取到该余数则在此登记。2.IP在使用余数时自动更新,初始化脚本不需要填写' / comment on column T_TASKMODREMAINDER.UPDATETIME is '使用该余数的机器最近执行任务的时间。' /
---初始化表插入数据,有三台服务器,则插入三条数据,MODREMAINDER从0开始 insert into T_TASKMODREMAINDER (TASKNAME, MODREMAINDER, UPDATESEQ, TASKIP, UPDATETIME) values ('BatchOperateTask', 0, 0, '', sysdate) / insert into T_TASKMODREMAINDER (TASKNAME, MODREMAINDER, UPDATESEQ, TASKIP, UPDATETIME) values ('BatchOperateTask', 1, 0, '', sysdate) / insert into T_TASKMODREMAINDER (TASKNAME, MODREMAINDER, UPDATESEQ, TASKIP, UPDATETIME) values ('BatchOperateTask', 2, 0, '', sysdate) / commit / --创建T_TASKMODREMAINDER 表的序列 create sequence seq_TASKMODREMAINDER start with 1 increment by 1 /
--创建取模函数 create or replace function f_func_gettaskmodremainder ( str_in_taskname in T_TASKMODREMAINDER.TASKNAME%type, --定时任务名称 i_o_modebase out number, --取模基数 i_o_remainder out number --取模余数 ) return integer --返回值: -- 0:异常 -- 1:成功 -- 2:取模余数全部被其他机器锁定 -- 3:取模余数记录和取模基数不匹配 -- 4:无定时任务配置数据 ------========= 注意 ================ --1、本存储过程执行过后,则会锁定某条取模余数记录(行锁), -- 调用程序在退出之前请一定要提交或回滚事务时以释放该行锁。 --2、调用方存储过程内只要一提交或回滚则会立即释放该行锁, -- 所以,调用方获取数据的模式为:获取锁、更新数据、提交,不允许出现获取锁、更新数据、提交、再获取数据的情况 --3、取数据过程中必须更新数据状态,防止多个定时任务重复获取数据或因竞争数据引发死锁 --4、调用方在所有更新相同表数据的地方都必须采用取模方式更新数据。 is --自定义异常,用于标志因资源忙导致锁定记录不成功 resource_busy exception; --将锁定记录异常和名字resource_busy绑定 pragma exception_init(resource_busy, -54); i_l_remaindercount number; i_l_locksuccess number := 0; dt_l_nowtime date := sysdate; i_l_return number; i_l_updateseq number; begin --获取取模基数(获取数据定时任务总共有几个定时任务) begin select configvalue into i_o_modebase from t_config where configname = 'portal_task_count'; --可以写死总共定时任务,为了使用方便可配置 exception when no_data_found then --无定时任务配置数据 return 4; end; --检查取模余数记录是否正常 select count(*) into i_l_remaindercount from t_taskmodremainder where taskname = str_in_taskname and modremainder >=0 and modremainder < i_o_modebase; --如果取模余数记录和取模基数不匹配,异常退出 if ( i_l_remaindercount <> i_o_modebase ) then return 3; end if; --获取获取数据序列 select SEQ_TASKMODREMAINDER.nextval into i_l_updateseq from dual; --对于序列用完又重头开始的情况,需要将大于当前序列的记录更新为1,每次仅处理一条 begin select modremainder into i_o_remainder from t_taskmodremainder where taskname = str_in_taskname and updateseq > i_l_updateseq and rownum = 1 for update nowait; --获取成功,更新 update t_taskmodremainder set updateseq = 1 where taskname = str_in_taskname and modremainder = i_o_remainder; exception --如果没有从头开始的情况,不处理 when no_data_found then null; --锁定不成功,不处理 when resource_busy then null; end; --按updateseq从小到大的顺序获取取模余数记录并上锁 for i in 1..i_o_modebase loop begin select modremainder into i_o_remainder from t_taskmodremainder where taskname = str_in_taskname and modremainder = ( select modremainder from ( select modremainder, rownum rn from ( select modremainder from t_taskmodremainder where taskname = str_in_taskname and modremainder < i_o_modebase order by updateseq ) ) where rn = i ) for update nowait; --锁定记录成功,更新 update t_taskmodremainder set updatetime = dt_l_nowtime, taskip = sys_context ('userenv', 'ip_address'), updateseq = i_l_updateseq where taskname = str_in_taskname and modremainder = i_o_remainder; --设置锁定成功标志,跳出循环 i_l_locksuccess := 1; exit; exception --锁定不成功,继续锁定updatetime次旧的一个 when resource_busy then null; end; end loop; --如果锁定取模余数记录不成功,返回2,成功返回1 return case i_l_locksuccess when 1 then 1 else 2 end; exception when others then return 0; end f_func_gettaskmodremainder; /
=========================================
--创建存储数据表 create table t_batchoperatedata ( id number primary key, username varchar2(20) , userid varchar2(20) , insertTime date default sysdate, status number , roleCode varchar2(20) , batchid number default -1, operatertime date ) / -- Add comments to the table comment on table t_batchoperatedata is '存储数据表' / comment on column t_batchoperatedata.username is '用户名' / comment on column t_batchoperatedata.userid is '用户id' / comment on column t_batchoperatedata.insertTime is '入库时间' / comment on column t_batchoperatedata.status is '当前数据状态 1.未处理;2.已处理;3已获取' / comment on column t_batchoperatedata.roleCode is '角色编号' / --获取批量执行数据 create or replace function f_getoperatedata ( str_taskname in T_TASKMODREMAINDER.taskname%type, --定时任务名称 i_o_result out integer ) return pkg_type.refcur --定义返回类型 is results pkg_type.refcur; --声明游标 get_batch_execute_maxs varchar2(20); --最大获取条数 i_o_modebase number; --模基数 i_o_remainder number; --模余数 i_funcresult integer; --函数结果输出参数 temp_id number; t_batchid number; begin --获取模基数与本次抢占到的模基数 i_funcresult := f_func_gettaskmodremainder( str_taskname, i_o_modebase, i_o_remainder ); --对返回码处理 begin case i_funcresult when 1 then i_o_result := 1; when 2 then i_o_result := 1; when 3 then i_o_result := 2; when 4 then i_o_result := 3; else i_o_result := 0; end case; exception when others then i_o_result := 0; end; if i_funcresult != 1 then rollback; open results for select * from dual where 2=1; return results; end if; --获取每次最大处理条数 select configvalue into get_batch_execute_maxs from t_config where configname = 'get_batch_execute_maxs'; select seq_batchid.nextval into t_batchid from dual; update t_batchoperatedata b set batchid = t_batchid, status = 3,operatertime=sysdate where rownum <= get_batch_execute_maxs and b.status = 1 order by b.insertTime; open results for --查询出要处理的没个号码 select b.id, --id b.username, --用户名 b.userid, --用户id b.insertTime, --入库时间 b.roleCode, --操作者角色账号 from t_batchoperatedata b where b.batchid=t_batchid; commit; return results; exception when others then return results; end f_getoperatedata; /
在类中调用f_getoperatedata函数来获取要操作的数据,每次在函数f_getoperatedata中都会调用f_func_gettaskmodremainder函数获取模基数与本次抢占到的模基数,并且锁定t_taskmodremainder
表,防止其他服务器定时任务使用,确保每台服务器定时任务每次获取的数据不是同一批。
如果有某台服务器的定时任务获取到数据后,并且以修改表t_batchoperatedata中status = 3时,服务器濡染荡掉。那么可以再加一个定时任务来定时判断如果operatertime时间大于你认为超时的时间,则去修改t_batchoperatedata中status = 3的数据,全部修改状态为1,等待下次继续执行。
或者可直接在数据库中加个job任务来执行,认为数据库job较方便些,还省去写java代码。
相关推荐
在IT行业中,数据库同步是一个关键话题,特别是在分布式系统和企业级应用中,多个数据库的同步是确保数据一致性、完整性和高可用性的重要手段。本文将深入探讨如何使用Java来实现多个数据库之间的数据同步。 首先,...
1. **Oracle服务器体系结构**:Oracle服务器是一个数据库管理系统,它包含了一个Oracle实例和一个Oracle数据库。Oracle实例是访问数据库的途径,它始终打开并仅打开一个数据库,由内存结构(系统全局区SGA)和后台...
总的来说,Oracle数据库性能优化是一个系统性的工程,需要从多个角度综合考虑,不断调整和优化,以达到最佳运行状态。这需要数据库管理员具备深厚的理论知识,实践经验,以及对整个IT环境的深入理解。
Oracle9i 是 Oracle 公司推出的一款功能强大的关系型数据库管理系统(RDBMS)。随着业务规模的增长和技术的发展,Oracle9i 的性能优化成为了提高系统响应速度、提升用户体验的关键环节。性能优化主要包括对数据库...
当多个用户同时连接同一个实例时,SGA区数据供多个用户共享,所以SGA区又称为共享全局区。用户对数据库的各种操作主要在SGA区中进行。该内存区随数据库实例的创建而分配,随实例的终止而释放。PGA区是在用户进程连接...
总的来说,Oracle照片导出工具是一个实用的辅助工具,它结合了数据库查询和文件操作,使非技术用户也能轻松处理Oracle数据库中的图像数据。同时,通过开源的方式,它为开发者提供了学习和改进的机会,进一步促进了...
在Oracle中,数据存储在表空间内,表空间由一个或多个数据文件构成。表空间是逻辑存储单元,可以设置不同的存储参数以优化性能。数据文件是物理存储单元,用于保存数据库对象的实际数据。 五、备份与恢复 Oracle...
Database Link是一种在Oracle数据库之间建立连接的技术,允许用户从一个数据库直接访问另一个数据库中的数据。这对于需要从多个数据库中获取数据的应用场景非常有用。 - **创建Database Link**: ```sql CREATE ...
以上是根据提供的文件摘要整理出的Oracle数据库实战中的核心知识点,涵盖了从数据库体系结构、安装配置、数据字典与动态性能视图到性能监控及调整等多个方面。希望这些详细的内容能帮助您更好地理解和掌握Oracle...
11.1.2 安全与数据访问控制 321 11.1.3 事务管理 322 11.1.4 文件定位 322 11.1.5 监控 322 11.1.6 版本考虑 323 11.1.7 DBA的角色 324 11.2 管理Oracle Financials软件包的特殊 准则 324 11.2.1 数据库结构 324 ...
### Oracle数据库实验操作知识点 #### 第一部分:SQL基础 ##### 基本查询语句 - **实验1:** 编写一个简单的SQL查询语句,用于查询表中的所有行和所有列。例如: ```sql SELECT * FROM 表名; ``` - **实验2:**...
Oracle18c是Oracle数据库的一个重要版本,其中18.3是这个版本的小型更新。这个版本引入了多项新特性,旨在提高性能、安全性和易用性。例如,自动索引优化(Automatic Indexing)是一项智能功能,能够自动创建、监控...
数据库则是一个存储和管理数据的系统,例如MySQL、Oracle、SQL Server等。在局域网环境中,数据库服务器通常作为中央节点,处理来自多个客户端的查询和写入请求。客户端应用程序通过特定的数据库连接协议(如TCP/IP...
客户端/服务器结构中,客户端负责提交数据库操作,而服务器端处理并发的共享数据访问。分布式处理结构是在一个计算机上拥有多个处理器,使得Oracle服务器和客户端可以分布在不同处理器上。多层结构进一步复杂化,...
Oracle数据库10g是Oracle公司推出的一个重要版本,其核心特色在于引入了网格计算的概念,旨在提高企业IT系统的效率和可扩展性。网格计算的基本理念是像使用公共设施一样使用计算资源,使得客户端可以轻松请求服务,...
在IT行业中,数据库同步是...总之,实现“远程SQL数据库定时同步到Oracle数据库”涉及多个技术层面,需要根据具体业务需求和环境条件选择合适的方法,并进行详尽的测试和监控,以确保数据的准确无误和系统的稳定运行。
可传输的表空间功能进一步简化了数据的移动和共享,可以在多个数据库之间装载只读表空间,支持跨平台操作,极大地增强了数据管理的灵活性。 Oracle Grid计算的发展趋势与硬件和行业趋势相吻合,特别是在云计算和...
- **数据缓冲区(Data Buffer Cache)**:这部分内存用来缓存数据文件中的数据块,以提高数据访问速度。 - **日志缓冲区(Redo Log Buffer)**:用于临时存储用户对数据块的操作(如DDL、DML等),在满足一定条件后会...