四类 DML
-- 单行插入
INSERT INTO departments (department_id, department_name, location_id)
VALUES (300, 'Research', 1700);
-- 从查询结果批量插入(先建一张结构相同的备用表)
CREATE TABLE dept_backup AS
SELECT department_id, department_name FROM departments WHERE 1 = 0;
INSERT INTO dept_backup (department_id, department_name)
SELECT department_id, department_name FROM departments WHERE location_id = 1700;
-- 条件更新(执行前先用同样的 WHERE 写 SELECT COUNT(*) 确认影响行数)
UPDATE employees SET salary = salary * 1.1 WHERE department_id = 60;
-- 删除
DELETE FROM job_history WHERE employee_id = 176;只作示例阅读:5 行写入限制下只开放单独创建普通空表;CTAS、删表、清空表、改结构、触发器和存储程序不允许执行。请在独立学习数据库中练习。
-- 先准备好源表与目标表(真实项目里它们通常已经存在)
CREATE TABLE dept_target AS
SELECT department_id, department_name FROM departments;
CREATE TABLE dept_source AS
SELECT department_id, department_name FROM departments WHERE department_id <= 30;
MERGE INTO dept_target t
USING (SELECT department_id, department_name FROM dept_source) s
ON (t.department_id = s.department_id)
WHEN MATCHED THEN
UPDATE SET t.department_name = s.department_name
WHEN NOT MATCHED THEN
INSERT (department_id, department_name)
VALUES (s.department_id, s.department_name);MERGE 是数据同步场景的标准写法,比「先 UPDATE 再 INSERT」更安全且只扫一遍源表。
只作示例阅读:5 行写入限制下只开放单独创建普通空表;CTAS、删表、清空表、改结构、触发器和存储程序不允许执行。请在独立学习数据库中练习。
事务与提交
Oracle 没有 BEGIN TRANSACTION。事务在你执行第一条 DML 时自动开始,到 COMMIT 或 ROLLBACK 结束。在此之前,你的修改只有你自己能看到,别人看不到(读一致性)。
- COMMIT:确认事务,修改永久生效,释放锁
- ROLLBACK:撤销整个事务,回到事务开始前
- SAVEPOINT:设置中间点,可以只回滚到某一点
- DDL 语句(CREATE/ALTER/DROP/TRUNCATE)会隐式提交,且不可回滚
- AUTOCOMMIT 默认是 OFF,即每条 DML 后不会自动提交,需要你显式 COMMIT
- 但 EXITCOMMIT 默认是 ON:正常退出 SQL*Plus 时会提交未完成的事务。想避免误提交,要显式 SET EXITCOMMIT OFF
UPDATE employees SET salary = salary + 100 WHERE employee_id = 100;
SAVEPOINT after_first;
UPDATE employees SET salary = salary + 500 WHERE employee_id = 101;
-- 只撤销第二条更新
ROLLBACK TO SAVEPOINT after_first;
-- 此时第一条仍在事务中,确认无误后提交
COMMIT;只作示例阅读:请使用提交/回滚按钮;不支持自定义保存点或中间提交。请在独立学习数据库中练习。
锁与并发
- Oracle 默认行级锁,UPDATE 时自动加,COMMIT/ROLLBACK 时释放
- 读操作不会被写操作阻塞(多版本读一致性),这是 Oracle 的重要优势
- 忘记提交会长期占用锁,导致别人被阻塞——这在开发环境很常见
- SELECT FOR UPDATE 用于「先读后改」的业务逻辑,防止丢失更新
-- 锁定这两行,直到本事务提交,其他会话无法修改
SELECT employee_id, salary
FROM employees
WHERE department_id = 60
FOR UPDATE NOWAIT;
-- NOWAIT:拿不到锁立即报错,不等待
-- 查看当前阻塞情况
SELECT blocking_session, sid, serial#, wait_class, seconds_in_wait
FROM v$session
WHERE blocking_session IS NOT NULL;只作示例阅读:读取全库字典或会话(沙箱只开放自身对象)。请在独立学习数据库中练习。