你了解每种数据库的事务性DDL吗?| SQL全面教程六:事务(2)事务性DDL、保留点的使用,及Oracle中如何实现在一个单一事务中创建多个表「建议收藏」

你了解每种数据库的事务性DDL吗?| SQL全面教程六:事务(2)事务性DDL、保留点的使用,及Oracle中如何实现在一个单一事务中创建多个表「建议收藏」DDL(数据定义语言)用于定义数据库结构(包括对数据库、表、列、索引、视图、存储过程、约束的操作)。从概念上,DDL语句自身也可以通过事务,实现一定程度的一致性和安全性。

本文已参与好文召集令活动,点击查看:后端、大前端双赛道投稿,2万元奖池等你挑战!

DDL语句的事务支持(事务性DDL)

事务用于保持数据库完整性,事务中的所有命令单线执行可以保持完整性约束,并且不会使数据库处于过渡的、不一致的状态。

DDL(数据定义语言)用于定义数据库结构(包括对数据库、表、列、索引、视图、存储过程、约束的操作)。因为DDL是关于数据库结构的定义,应该确保在DDL之前和之后提交,以保证数据操作。但从概念上,DDL语句自身也可以通过事务,实现一定程度的一致性和安全性。

大多数RDBMS对DDL命令支持一定的”事务性”操作,但不是所有的命令。通常,用于创建和删除数据库中存储的文件系统对象(file system objects)的大多数全局命令都不支持回滚。对于不引起文件系统结构变化的次要命令回滚是支持的。

事务在所有的RDBMS中,仅仅在一般情况下相似。实际上,每个数据库管理系统都具有独特的事务控制命令语法和自己独特的事务控制机制。可以称其为某个RDBMS的“事务模型”(transaction model)。

下面是常见数据库的事务性DDL支持情况:

事务性DDL在数据库迁移中,作用是非常大的。因为数据库迁移本身工作量大、冲突和问题也非常多,涉及到表结构大量的更改和数据的转移。如果能做到事务性的操作,在遇到问题或错误时,可以很方便很快的回退到之前的状态。否则只能还原数据库,然后重新开始所有的操作。

PostgreSQL

PostgreSQL支持事务性DDL:支持除了创建和删除DATABASE、TABLESPACE、CLUSTER等对象的“高级(high-caliber)”操作之外的所有DDL命令。

PostgreSQL在保存点级别上支持多级事务(multi-level transactions)。与标准SQL不同,PostgreSQL支持同名保存点(save points)。这意味着如果有新的点,存在的旧的点就不可用。

如果事务内部发生错误,PostgreSQL会回滚整个事务,但必须要有一个命令来完成当前事务(COMMIT、ROLLBACK、ABORT)。 PostgreSQL在多语句开始时启动隐式事务,并在多语句中存在BEGIN(或 BEGIN TRANSACTION)命令时将事务转换为显式事务(该事务被视为从多语句开始处开始)。

BEGIN命令作为显式事务作用与多语句的开始。条件必须为多语句(multistatement),而不是多条语句。如果多条语句执行,BEGIN之前的语句就已经作为隐式事务自动提交了,而不会起到作用。通常作为事务处理时,肯定会把BEGIN放在开头书写。

如下,多语句中放入BEGIN,作为整体执行并确认回滚效果。

select * from productcopy;
delete from productcopy where product_id='0007';
BEGIN;
select * from productcopy;
ROLLBACK;
select * from productcopy;

你了解每种数据库的事务性DDL吗?| SQL全面教程六:事务(2)事务性DDL、保留点的使用,及Oracle中如何实现在一个单一事务中创建多个表「建议收藏」

MySQL、MariaDB

MySQL/MariaDB不支持事务性DDL。

MyISAM引擎根本不支持事务。对于InnoDB,DDL命令会导致当前事务的隐式提交。

SQL Server

SQL Server和PostgreSQL类似,除了CREATE/ALTER/DROP DATABASE等”高级别”对象外,支持大多数事务性DDL

MSSQL中对多级事务的支持体现在对保存点的支持上。—— The support of multi-level transactions in MS SQL is expressed in the support of save points.

在SQL Server中,所谓的嵌套事务仅仅是BEGIN TRANSACTION调用的计数器。要确认事务,需要调用一定数量的COMMIT TRANSACTIONROLLBACK命令回滚整个事务而不管嵌套级别。第一个BEGIN TRANSACTION始终被视为事务的开始,同时通过保存点启用多级事务的完整功能。保存点可以通过SAVE TRANSACTIONROLLBACK TRANSACTION命令使用。

似乎SQL Server中对DDL事务的隔离(快照隔离)有着很大的限制,而且没提交前,事务内DDL的改变也是可以被其他用户看到的。具体要看实际的MSSQL版本和真实测试。

PostgreSQL的实现则比较完善,对事务性DDL做到了很好的支持。

SQL Server中CREATE VIEW必须是一个查询批中的第一个语句。并且必须是批中唯一的语句。

Msg 111, Level 15, State 1, Line 2
'CREATE VIEW' must be the first statement in a query batch.

'CREATE VIEW' must be the only statement in the batch.

因此,在SSMS中要想对’CREATE VIEW’实现事务控制,可以通过go分割实现:

begin transaction;
go
create view myview as select * from productcopy;
go
rollback; -- commit;

因此在pg和MSSQL中可以回滚truncate语句

Oracle

Oracle不支持事务性DDL。当执行CREATE、DROP、RENAME或ALTER命令时,事务将会关闭。

Oracle默认从第一个(DML)SQL语句开始开启一个隐式事务。如果包含DDL命令,则Oracle将DDL命令之前的SQL语句作为一个事务整体提交,然后将DDL命令作为单独的事务提交。

也就是,DDL命令会发生两次提交,一次是DDL执行之前,另一次是DDL执行之后

Oracle查看当前是否有活动的事务

SELECT * FROM V$TRANSACTION WHERE STATUS='ACTIVE';

Oracle中如何实现在一个单一事务中创建多个表?

此部分参考自DDL commands in Transactions in SQL Server versus Oracle

既然Oracle不支持DDL,但是有时确实需要在单个事务中创建多个表。即一次创建多个表,要么成功,要么失败。

Oracle中可以使用CREATE SCHEMA语句,包含多个CREATE TABLECREATE VIEWGRANT语句在schema的一个事务中。CREATE SCHEMA中的所有语句执行成功,则事务会提交;如果发生错误,包括CREATE SCHEMA的所有语句都会回滚。

CREATE SCHEMA语句不会创建一个方案(schema),它用于在一个事务中,创建tables、views或授权(grant privileges)。

CREATE SCHEMA AUTHORIZATION MyUser
CREATE TABLE TableC (Value INT)
CREATE TABLE TableD (Value INT);

DB2

DB2支持嵌套事务级别和保存点级别的多级别事务。保存点在每个嵌套级别上提供独立的命名空间。


本部分主要参考翻译自How Popular Databases Deal with DDL Commands in Transactions,及相关数据库的官方文档。

savepoint保留点的使用

savepoint保留点允许回滚事务到一个特定的点。也就是回滚事务的某一部分而不是整个事务

回滚保留点,则从保留点到rollback命令之间的语句将会被放弃。

对于保留点语句的实现,各DBMS的语法都有所不同

PostgreSQL、MySQL/MariaDB中的保留点

PostgreSQL、MySQL/MariaDB中使用、回滚和销毁(释放)保留点的语法是相同的:

SAVEPOINT savepoint_name;

-- 回滚保留点
ROLLBACK TO SAVEPOINT savepoint_name;
-- 或
ROLLBACK TO savepoint_name;

-- 销毁保留点
RELEASE SAVEPOINT savepoint_name;
begin transaction;
	INSERT INTO Productcopy VALUES ('0016', 'T恤' ,'衣服', 1000, 500, '2009-09-20');
	-- 新建保留点
	SAVEPOINT secondInsert;
	INSERT INTO Productcopy VALUES ('0017', 'T恤' ,'衣服', 1000, 500, '2009-09-20');
  SAVEPOINT secondInsert;
	INSERT INTO Productcopy VALUES ('0018', 'T恤' ,'衣服', 1000, 500, '2009-09-20');
	-- 回滚到保留点
	ROLLBACK TO SAVEPOINT secondInsert;
commit;

select * from Productcopy;

执行结果如下,可以看到,第二行’0015’的插入被回滚。

 product_id | product_name | product_type | sale_price | purchase_price | regist_date
------------+--------------+--------------+------------+----------------+-------------
 0011       | T恤          | 衣服         |       1000 |            500 | 2009-09-20
 0012       | T恤          | 衣服         |       1000 |            500 | 2009-09-20
 0014       | T恤          | 衣服         |       1000 |            500 | 2009-09-20

存在相同保留点名时,回滚只会回滚到最新的保留点。

Oracle中保留点的用法也和MySQL一样。

SQL Server中的保留点

begin transaction;
	INSERT INTO Productcopy VALUES ('0014', 'T恤' ,'衣服', 1000, 500, '2009-09-20',null);
	-- 新建保留点
	save transaction secondInsert;
	INSERT INTO Productcopy VALUES ('0015', 'T恤' ,'衣服', 1000, 500, '2009-09-20',null);
	-- 回滚到保留点
	rollback transaction secondInsert;
commit;

select * from Productcopy;

执行结果如下,第二个插入被回滚。

product_id	product_name	product_type	sale_price	purchase_price	regist_date	test_col
0011	T恤	衣服	2120	500	2009-09-20	NULL
0012	T恤	衣服	1000	500	2009-09-20	NULL
0013	T恤	衣服	1000	500	2009-09-20	NULL
0014	T恤	衣服	1000	500	2009-09-20	NULL

SQL Server中的保留点名还可以使用变量。但是保留点名的最大大小为32个字符。

存在相同保留点名时,回滚只会回滚到最新的保留点。

@@TRANCOUNT表示当前执行开启的事务数,在回滚或提交一个事务时,@@TRANCOUNT-1@@TRANCOUNT=0表示没有正在运行的事务。

回滚到保留点,不影响@@TRANCOUNT

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
转载请注明出处: https://daima100.com/13370.html

(0)

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注