只有在autocommit关闭且事务含dml时才需显式commit;pl/sql块不自动提交,过程成功退出也不提交;ddl会隐式提交且不可逆;sql*plus退出默认自动commit。

PL/SQL里什么时候必须显式写COMMIT?
只有在AUTOCOMMIT关闭(默认)且事务包含DML语句时,才需要手动COMMIT。PL/SQL块本身不自动提交——哪怕过程执行成功、正常退出,只要没执行COMMIT,所有DML改动仍处于未提交状态。
常见误判场景:
- 以为存储过程结束 = 自动提交 → 实际上会话断开前未提交,数据仍可被
ROLLBACK撤销(但SQL*Plus等客户端退出时可能隐式提交,见后文) - 在循环中每条
INSERT后都COMMIT→ 日志刷盘频繁,性能骤降,还可能破坏原子性 - 调用多个含DML的子过程,只在最外层
COMMIT→ 可行,但需确保所有子过程都不提前COMMIT或ROLLBACK
ROLLBACK放在EXCEPTION里就够了吗?
够,但不够稳。显式ROLLBACK在异常分支里是底线,但要注意三点:
-
ROLLBACK必须在RAISE或RAISE_APPLICATION_ERROR之前执行,否则异常抛出后控制流跳出,回滚失效 - 如果过程中用了
SAVEPOINT,应优先ROLLBACK TO SAVEPOINT而非全事务回滚,避免撤掉前面已确认的逻辑 - 某些场景(如自治事务)中
ROLLBACK只影响当前事务上下文,不影响父事务 —— 这类情况必须单独设计回滚逻辑
DDL语句(比如CREATE TABLE)会偷偷提交吗?
会,而且不可逆。Oracle在执行任何DDL(CREATE、ALTER、DROP、TRUNCATE)或DCL(GRANT、REVOKE)时,会触发隐式COMMIT,并立即结束当前事务。
这意味着:
- DDL前的DML操作会被一并提交,无法再用
ROLLBACK撤销 - DDL后的DML属于新事务,和之前完全隔离
- 若想保留事务完整性,应把DDL操作拆到事务外,或改用
EXECUTE IMMEDIATE动态执行并接受其副作用
SQL*Plus退出时到底提交还是回滚?
默认行为是提交,不是回滚。SQL*Plus在用户正常EXIT或QUIT时,会把当前会话中所有未提交的DML全部COMMIT——哪怕你全程没写过COMMIT,也没设AUTOCOMMIT ON。
这个行为容易引发线上事故:
- 开发在SQL*Plus里测试DML后直接退出 → 数据意外落库
- 误以为
AUTOCOMMIT OFF就能“安全试跑”,结果退出即生效 - 解决办法:退出前手动
ROLLBACK;或启动时加-L参数禁用登录脚本干扰;更稳妥的是用SET AUTOCOMMIT OFF配合明确的COMMIT/ROLLBACK习惯
真正难处理的从来不是语法,而是事务边界与业务逻辑的咬合点——比如转账要跨账户、跨币种、还要记流水日志,哪一步该设SAVEPOINT,哪一步必须全盘回退,得看锁竞争、补偿成本和幂等设计,而不是看COMMIT写在哪一行。











