一、先说问题
在开发过程中,遇到了Oracle DDL语句和DML语句需要在一个事务中一块处理的情况,该方法要么成功,要么失败。对于这个问题,sql server等数据库是可以解决的,因为其能对DDL语句做回滚,而oracle在执行ddl语句时会先执行commit,所以就不能对DDL语句回滚了。
二、事务相关概念
1、 首先,说说数据库对事务的相关定义:
在数据库中事务是工作的逻辑单元 , 一个事务是由一个或多个完成一组的相关行为的 SQL 语句组成 , 通过事务机制确保这一组 SQL 语句所作的操作要么完全成功执行 , 完成整个工作单元操作 , 要么一点也不执行。 事务具有ACID特性(即:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation,又称独立性)、持久性(Durability)),ACID的概念在ISO/IEC 10026-1:1992文件的第四段內有所说明(我找了半天也没下载到这个标准,谁有的送我一份啊,呵呵)。
2、我机器的oracle版本为10g,10g对应的jdbc版本为3。看一下JDBC3有关事务概念:
JDBC3提到了事务和分布式事务。对于大家经常说的嵌套事务,没有提及。数据库本质上从来没有过嵌套事务的概念,只是应用程序为了不同的目的将对事务的操作过程嵌套起来,即使是Oracle的自治事务也可划为应用程序(存储过程或是触发器什么的), 从应用角度讲,嵌套事务处理就是应用程序如何将应用层面的嵌套转变为数据库层面的单事务操作, 这方面Java领域的EJB,Spring提供了解决方案,另外提一下JTA,它提供了事务的suspend,resume功能,实质上其实数据库事务那里有什么挂起什么的概念,其仅仅是换了一个数据库连接,这样新的数据库事务开始了,老的数据库事务便不再操作,直接其被resume。)。
那么接下来我们看看JDBC3中对事务的定义:
Transactions are used to provide data integrity, correct application semantics, and a consistent view of data during concurrent access. All JDBC compliant drivers are required to provide transaction support. Transaction management in the JDBC API mirrors the SQL99 specification and includes these concepts:
Auto-commit mode
Transaction isolation levels
Savepoints
三、解决方法
要想解决一个问题,找到问题的关键所在,就等于成功了一半。如上所述,该问题的关键所在又是什么呢?
oracle在执行ddl语句时会先执行commit,所以就不能对DDL语句进行回滚。jdbc事务也不提供相关方法来进行回滚(spring、ejb或许可以,但没测试过,不好说)。
既然应用的一些框架不能提供该功能,就只能自己想办法解决了,怎么解决?反向操作!或许感觉有些麻烦,但不这么做又如何呢,在操作SQL语句成功后,后边跟着反向操作的定义(内部类派上用场了),在一个大的事务中,如果出现异常,在异常的地方把反向操作执行一把即可。再进一步,如果让所有的DDL语句能和DML语句用不同的数据库连接,那么DML语句就不用反向操作了,节省了很多工作量,DML语句用事务的回滚多好啊!当然这样做的前提是,在DDL执行时,不能和DML操作的资源引起冲突,即锁的问题。