课程章节介绍
同学,我们今天来讲一个很实用的知识点——Apex 里面的“保存点”,也就是 Savepoint。
你可以把保存点想象成游戏里的存档。在程序运行到某个时刻,你对数据库说:“嘿,记住现在数据库的状态。” 之后,如果你发现操作出了问题,或者需要撤销刚才的改动,就可以直接“读档”,让数据库恢复到那个存档的状态。而且不用重启,也不用整个回滚,非常方便。
那在 Apex 里怎么实现呢?很简单,用 `Database.setSavepoint()` 这个方法就能生成一个保存点。如果你后面想回滚,也就是把数据库恢复到保存点那一刻的样子,就可以调用 `Database.rollback(savepoint)`。这样,从保存点之后所有还没来得及提交的 DML 操作(也就是增删改)都会被丢弃。同时,回滚的时候,所有从保存点之后拿到的表锁、行锁也都会被释放掉,不影响其他操作。
当然,保存点好用,但也有一些限制,这个要注意:
第一,如果你有好几个保存点,比如先设了保存点 A,又设了保存点 B。如果你回滚到 A,那 B 就会失效,不能再用 B 回滚了,因为 B 是建立在 A 之后的状态上的。这就像游戏里你如果读了一个更早的存档,后面存的进度自然就没了。
第二,保存点不能跨触发器调用。也就是说,你不能在一个触发器里设个保存点,然后指望在另一个触发器中回滚它。保存点的作用范围只在同一个触发器上下文或者同一个执行块里。
第三,保存点只恢复数据库状态,但不会恢复静态变量的值。也就是说,如果你在保存点之后改了一个静态变量,然后回滚,那个静态变量还是改后的值,不会变回去。这一点一定要记清楚,因为它可能会引起逻辑上的小麻烦。
最后还有个小细节,回滚的时候,虽然数据复原了,但如果你在插入记录时生成的 sObject ID 并不会被回收。意思就是说,你本来插入了一条记录拿到了一个 ID,回滚后那条记录没了,但这个 ID 已经被消耗掉了,不会重复使用。这是 Salesforce 平台的一种设计,避免 ID 冲突。
最后,当你用完了保存点,确定不再需要它了,记得调用 `Database.releaseSavepoint()` 来释放这个保存点,这样可以节省资源,也不会在后续误操作时意外回滚。
简单总结一下:用 `setSavepoint` 存档,`rollback` 读档,`releaseSavepoint` 删档。注意限制:早期回滚让后期失效、不能跨触发器、静态变量不恢复、ID 永久消耗。
好,咱们这节课就讲到这里,下次遇到需要局部回滚的场景,你就可以放心地用保存点了。
关键词
Apex
Salesforce
Developer Guide