阻止同一表中,两个并发会话插入相同记录的解决方案
背景
两个并发会话,要并发访问一张表,并向表中插入记录,主键
ID
为自增长的序号,所以两个会话肯定会得到不同的主键
Id
,靠这个
ID
主键约束不能解决阻止插入重复记录的问题。
举例
系统存在如下一张表
create
table
test (
id
integer
,
value
varchar
(
20
),
primary
key
(
id
)
);
表中
ID
值来自业务需求上的自增长序列。
方案
方案一
在
test
表的
value
字段上建立一个唯一约束(如果表中的字段为多个,则表这些字段全部加到唯一约束上去即可)。
alter
table
test
add
constraints
test_001
unique
(
value
);
优缺点
优点:此种方案最简单,几乎接触过数据库的人都可以做,而且省时省力。
缺点:影响性能,如果大批量的数据通过多个会话并发插入的话,数据库会成为性能瓶颈,因为每插入一条数据,数据库都要去检查唯一约束。
方案二
步骤
1
,分配权限
为用数据库用户分配权限,因为下面的
trigger
,使用到了
dbms_lock
和
dbms_utility
包。
否则将报错误。(图片没法显示,错误码信息是:ORA-04098:触发器XXX无效且未通过重新验证)
以
sysdba
身份登陆数据库,为
imeg
用户(本人的数据库用户名为
imeg
)分配权限,命令如下:
huawei:~ # su - oracle
oracle@huawei:~>
sqlplus '/as sysdba';
SQL> grant execute on
dbms_lock to imeg;
Grant succeeded.
SQL> grant execute on
dbms_utility to imeg;
Grant succeeded.
--
可能上面的
grant
是多余的(没测试),只要下面这句就可以了。在此有点脱裤子放屁的感觉。
SQL> grant execute any
procedure to imeg;
Grant succeeded.
注意:权限分配了以后,可能要过一段时间才会生效,我操作上就是这样,分配完直接操作会报错。不知是
Oracle
的什么原因所至。作为一个疑问,希否定知道的可以告知。在此留下答题卡:
答:
____________________________________________________________________________
步骤
2
,建立触发器
使用
trigger
,在
test
表上建立如下的
trigger
create
or
replace
trigger
test_trigger
before
insert
on
test
for
each
row
declare
l_lock_id
number
;
resource_busy
exception
;
pragma
exception_init
( resource_busy, -
54
);
begin
l_lock_id :=
dbms_utility.get_hash_value(
:new.value,
0
,
1024
);
if
( dbms_lock.request
(
id
=> l_lock_id,
lockmode
=> dbms_lock.x_mode,
--timeout
=> 0,
--
此处的
timeout
是为了让第二个会话如果存在唯一值冲突时,是否立即返回,默认为
oracle
的最大时间,等第一个会话提交时返回。如果为
0
,则表示如果有冲突,不等第一个会话提交,直接返回错误信息。
release_on_commit
=>
TRUE
) <>
0
)
then
raise
resource_busy;
end
if
;
end
;
步骤
3
,将应中的
SQL
语句改为
merge
会话
1
:
merge
into
test_meger t1
using
(
select
'value'
value
from
dual) t2
on
(t1.value=t2.value)
--when matched then
--
dbms_output.put_line('null')
when
not
matched
then
insert
(t1.id,t1.value)
values
(
2
,
'value'
);
会话
2
:
merge
into
test_meger t1
using
(
select
'value'
value
from
dual) t2
on
(t1.value=t2.value)
--when matched then
--
dbms_output.put_line('null')
when
not
matched
then
insert
(t1.id,t1.value)
values
(
3
,
'value'
);
会话执行描述
1、
会话
1
提交后,会话
2
执行:
由于会话
2
的
merge
的
on
条件,
t1.value=t2.value
此时可以看到会话
1
提交的数据,所以会话
2
什么也不错。
可以消除
ID
不同的重复记录。
2、
会话
1
执行,但未提交,会话
2
执行:
由于会话
1
没有提交,会话
2
的
merge
的
on
条件,
t1.value=t2.value
此时可以看不到会话
1
提交的数据,但是由于步骤
2
的触发器,使会话
2
处于阻塞状态,得不到执行。如果此时去掉触发器关于
timeout
的注释,会话
2
将直接报错返回,而不会阻塞。
3、
优缺点
优点:将
timeout=> 0
加上,可以让会话
2
不用等待会话
1
提交,如果存在相同的值,则直接返回。减少了会话
2
的等待时间。
缺点:如果会话
1
没提交,而会话
2
由于
timeout=> 0
而报错返回了,则会丢失本来应该插入的记录。另外,这个同样存在效率问题,如果电信级的应用,不推荐用这种做法,可能需要在应用层进行序列化控制,应用层同样有缺点,比如:怎么解决应用层集群并发写入的问题。有好的解决方案,还请不吝赐教啊。
总结
上述的解决方案二,仅适合于
oracle
的数据库,对其它的数据库,可能要从数据库隔离级别入手去解决了,比如:将隔离级别设为序列化的,在事务开始时,先去查询一下是否有同值记录存在,存在则退出,否则插入,序列化的隔离级别是性能大忌。
以上仅是本个的一些浅建,如有更好的解决方案可以说出来,大家探讨啊。
分享到:
相关推荐
### MySQL 死锁产生原因与解决方案详解 #### 一、MySQL锁类型介绍 MySQL支持多种锁机制来确保数据的一致性和事务的隔离性。锁的主要目的是控制并发操作时的资源访问,防止数据不一致的问题。根据锁的作用范围不同...
- **描述**: 当两个或多个会话设置了不同的DML_LOCKS时触发。 - **解决方法**: 确认所有会话设置相同的DML_LOCKS。 #### 36. ORA-00062: 无法获得DML全表锁定;DML_LOCKS为0 - **描述**: 当尝试获取全表锁时发现`...
简单来说,锁的作用是防止两个或多个进程同时更新相同的SGA区域,从而避免数据损坏或不一致的问题。 Oracle会话在执行几乎所有的数据库操作时都需要访问或修改SGA中的数据。例如: - 当一个会话从磁盘读取数据块时...
Redis提供了更优的解决方案,如SETNX指令,可以原子性地设置一个键,如果键不存在。配合EXPIRE指令设置过期时间,可以解决锁的自动释放问题。RedLock算法进一步增强了分布式锁的可靠性,通过在多个Redis实例之间获取...
解决方案包括分批插入、优化事务大小、增加内存或磁盘空间,以及调整数据库参数以支持更大并发。 9. 数据去重:在有主键和外键约束的数据库中,不能有重复数据。可以通过添加自增ID字段,然后删除重复行,或者使用...
通过以上内容,我们可以看出HSQLDB不仅具备现代关系型数据库管理系统的核心功能,而且还提供了一系列高级特性,使其成为一个强大且灵活的数据库解决方案。无论是用于开发应用程序还是作为教学工具,HSQLDB都能满足...
这通常是因为临时表的生命周期与函数调用不匹配,或是在不同的会话中尝试访问同一临时表。正确处理临时表的生命周期和作用域可以解决这类问题。 #### 48. 目前有哪些数据复制方案可用? PostgreSQL支持多种复制...
- **幻读**:在可重复读隔离级别下,可能导致同一事务两次读取到不同数量的数据,因为有新的插入。 - **间隙锁(Next-Key Locks)**:防止幻读,锁定索引记录及其之间的间隙,只有在可重复读隔离级别下有效。 11....
【基于C#和SQL的网上选课系统】是一种利用现代技术改造传统选课流程的解决方案。C#,作为微软.NET框架的主要编程语言,以其高效、安全和面向对象的特性,常用于开发Web应用程序。SQL(Structured Query Language)是...
- **SGA (System Global Area)** 和 **PGA (Program Global Area)** 是Oracle数据库中的两个主要内存区域。SGA由多个组成部分组成,如数据缓冲区、共享池、redo日志缓冲区等。PGA则包含每个用户会话的私有内存。 -...
8. **海量数据插入**:大量数据插入可能导致数据库性能瓶颈,解决方案包括批量插入、分批处理、使用存储过程、优化索引、调整数据库配置(如缓存大小、日志文件等)以及利用数据库的批量导入功能(如BULK INSERT)。...
- **内连接(INNER JOIN)**:仅返回两个表中匹配的行。 - **外连接(LEFT JOIN/RIGHT JOIN)**:返回左表或右表的所有行,即使在另一表中没有匹配。 - **交叉连接(CROSS JOIN)**:返回所有可能的组合,即笛卡尔积...
1. **数据交换**:在不使用第三方变量的情况下,可以通过加减运算或异或操作来交换两个变量的值。如`a=a+b; b=a-b; a=a-b;`或者使用异或操作`a^=b^(b^=a^b);`,异或操作交换变量的原理是异或两次同一个数等于零。 2...
以Ehcache为例,它是Hibernate常用的一种二级缓存解决方案,提供了内存和磁盘两层缓存,支持自动过期策略,确保数据的实时性。 配置二级缓存主要包括以下几个步骤: 1. 引入依赖:在项目的pom.xml或build.gradle...
Oracle提供了多种高可用性解决方案,如Real Application Clusters (RAC)、Data Guard等,确保数据库的连续运行。 #### 第18章 分区表及分区索引 分区是一种将大表分割成较小、更易于管理的部分的技术。本章介绍了...
- **解决方案**:使用数组模拟大数的存储与运算。 - **实现细节**: - 定义数组,每个元素表示一位数字。 - 实现加法、乘法等基本运算规则。 - 通过模拟进位机制处理大数运算。 ### 6. 进程与线程的区别 - **...
当发生冲突时,即两个不同的键具有相同的哈希值时,新的键值对将被添加到对应的链表末尾。这样可以保证每个键值对都有唯一的存储位置,即使它们的哈希值相同。 以上是对Java程序猿在面试过程中可能会遇到的一些核心...
Dubbo是一个高性能、轻量级的开源服务框架,它提供了一整套解决方案,包括服务发布、发现、调用、负载均衡、容错、限流等。Dubbo支持多种服务注册与发现方式,其中Zookeeper是最常用的一种。 **1.2 Dubbo工作原理**...
#### 四、并发事务带来的问题及解决方案 在多用户环境中,多个事务并发执行可能会带来一系列问题,如脏读、不可重复读、幻读等。 1. **脏读**:一个事务读取了另一个事务未提交的数据。 2. **不可重复读**:在一个...
**DBA的挑战与解决方案** Oracle Database 12c 的多租户架构解决了DBA在传统环境中面临的挑战,如频繁的修补和升级、供应压力、性能和可扩展性的需求。通过标准化服务和自助服务,DBA可以更轻松地管理大量的数据库...