Oracle数据中表值插不进去问题

本文讨论了Oracle数据库中遇到表值无法插入的问题,分析了三种死锁情况及其原因,提供了相应的解决方法,包括调整程序逻辑、使用乐观锁和悲观锁控制并发,并给出了在数据库表被锁住后的解决步骤。

相信我们在进行测试的时候,有的时候会遇上数据库表的值插不进去的情况,在执行SQL语句的时候,好像卡住一样,没有反应。但是当你把SQL语句copy下来放在PL/SQL中执行的时候,在语法没有任何的错误,但是执行会很慢,此时我们就应该要想到应该表被锁了,尤其是当多条语句不停的提交,不停的执行的时候,这个时候就会由于语句执行不完整,而容易引起锁表。

下面先介绍一下表的锁已经在设计是应该注意的问题。

在数据库中有两种基本的锁类型:排它锁(Exclusive Locks,即X锁)和共享锁(Share Locks,即S锁)。当数据对象被加上排它锁时,其他的事务不能对它读取和修改。加了共享锁的数据对象可以被其他事务读取,但不能修改。数据库利用这两种基本的锁类型来对数据库的事务进行并发控制。 
死锁的第一种情况: 
一个用户A 访问表A(锁住了表A),然后又访问表B;另一个用户B 访问表B(锁住了表B),然后企图访问表A;这时用户A由于用户B已经锁住表B,它必须等待用户B释放表B才能继续,同样用户B要等用户A释放表A才能继续,这就死锁就产生了。 

### Oracle 数据库中获取数据后返回的 ID 方法 在 Oracle 数据库中,可以通过 `SELECT` 查询序列(Sequence)并结合虚拟 `DUAL` 来实现数据后返回生成的主键 ID 。以下是具体方法: #### 使用 `<selectKey>` 标签 在 MyBatis 的 XML 配置文件中,可以利用 `<selectKey>` 标签来提前生成主键,并将其赋给待入的对象属性。 ```xml <insert id="insertEntity" parameterType="com.example.Entity"> <selectKey keyProperty="id" order="BEFORE" resultType="java.lang.Long"> SELECT SEQ_TEST.NEXTVAL AS ID FROM DUAL </selectKey> INSERT INTO TEST_TABLE ( ID, CODE, NAME, ADD_DATE ) VALUES ( #{id}, #{code}, #{name}, SYSDATE ) </insert> ``` 上述代码通过 `order="BEFORE"` 设置,在执行 `INSERT` 语句之前生成主键[^1]。这样可以在入操作完成之后直接访问对象中的 `id` 属性以获得新生成的主键。 --- #### 利用触发器和序列 另一种方式是创建一个基于的触发器(Trigger),当有新的记录入时自动为其分配唯一的主键。 ##### 创建序列 首先定义一个用于生成唯一编号的序列: ```sql CREATE SEQUENCE SEQ_TEST START WITH 1 INCREMENT BY 1 NOCACHE; ``` ##### 定义触发器 接着编写触发器逻辑,确保每次入都会调用该序列更新目标列: ```sql CREATE OR REPLACE TRIGGER TRG_TEST BEFORE INSERT ON TEST_TABLE FOR EACH ROW BEGIN IF :NEW.ID IS NULL THEN SELECT SEQ_TEST.NEXTVAL INTO :NEW.ID FROM DUAL; END IF; END; / ``` 此时无需手动指定主键即可完成入动作,而实际产生的主键可通过查询最新的一行或者特定条件下的某一行取得。 --- #### 结合 CURRVAL 获取刚入的数据 ID 对于某些场景下可能需要立即知道刚刚入那条记录的具体位置,则可借助于 `.CURRVAL` 函数读取最近由同一会话所使用的下一个数实例。 注意此方法仅适用于单线程环境以及确认没有其他并发写入干扰的情况下有效。 示例 SQL 如下所示: ```sql -- 入一条测试数据 DECLARE v_id NUMBER; BEGIN -- 调用序列得到一个新的ID SELECT SEQ_TEST.NEXTVAL INTO v_id FROM DUAL; -- 执行入命令 INSERT INTO TEST_TABLE(ID, CODE, NAME, ADD_DATE) VALUES(v_id,'TEST_CODE','Test Name',SYSDATE); COMMIT; DBMS_OUTPUT.PUT_LINE('Inserted Record with ID:' || TO_CHAR(v_id)); -- 如果想验证当前session内的currval是否一致也可以打印出来看看 DBMS_OUTPUT.PUT_LINE('Current Value of Sequence is '||TO_CHAR(SEQ_TEST.CURRVAL)); END; / ``` 以上脚本展示了如何在一个事务内部安全地控制整个流程,并最终输出本次新增加进去的那个实体标识符[^2]。 --- ### 总结 综上所述,针对同需求可以选择合适的技术手段达成目的:如果是框架层面推荐采用MyBatis内置机制;要是更倾向于纯SQL解决方案的话则考虑运用存储过程配合PL/SQL块处理业务逻辑更为灵活高效一些。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值