SQL Server 2012引入了包含数据库(Contained Database),解决了与当前(非包含)数据库关联的某些问题和复杂性。包含的数据库不依赖于其所属服务器相关的配置、管理、排序规则和安全认证信息,因此可以在数据库实例间方便的移动和部署,使数据库的应用和实例分离开来,也使研发能够更好的集中在应用和功能本身。下面将从什么是包含数据库,如何创建包含数据库,如何将数据库转换为部分包含的数据库,如何将用户迁移为包含的数据库用户,以及如何备份和还原包含数据库等几个方面来熟悉一下2012的这个新特性。
- 当前(非包含)的数据库所面临的问题
在描述什么是包含数据库之前,先了解一下为什么会出现包含数据库。当前的数据库有一些问题,如下:
1、在数据库迁移或部署的过程中一些信息会丢失
当我们将数据库从一个SQL Server实例迁移到另一个实例是,诸如登陆、工作代理等信息将不能一起被迁移。因为这些信息有特殊用途,自创建后就常驻SQL Server实例。在新的SQL Server实例上重新创建这些任务将是一个耗时、易出错的过程。
2、从应用开发转向部署
在Server上部署应用时或许会遇到一些障碍,因为很有可能环境不匹配。例如,创建login时可能没权限,命令行实用工具(如“xp_cmdshell”)或许是禁用的,应用里用到的数据库排序规则或许和Server初始指定的(也可能是默认的)排序规则不同。
3、应用管理的安全考量
管理和维护单个数据库比较困难,因为login、job agent等信息是跨数据库实例访问的,因此,允许用户对整个实例授权将引起对其他数据库的不必要访问,进而导致安全隐患。 - 什么是包含的数据库
义如其名,它是一种自我包含的数据库。例如,它自带所有创建数据库时所需要的数据库设置及元数据信息。它独立于SQL Server实例,没有外部依赖关系,自带授权用户的自我包含机制。由于它独立于数据库实例,就使得在部署到不同服务器时数据库的排序规则不再是一个问题。
一个包含的数据库,保留了所有数据库里必要信息和对象,如表、函数、限制、架构、类型等。它也存有所有数据库里的应用级对象,如登陆、代理作业、系统设置、链接服务器信息等。
这种数据库带给我们的好处是,可以轻松地从一台Server搬移到另一台,并且不需要做任何额外配置就可以立即使用它,因为他们没有任何外部的依赖。 - 4步创建包含的数据库
步骤1、启用包含的数据库
方法1: 使用 Management Studio 启用包含的数据库
1.在对象资源管理器中,右击服务器名称,然后单击“属性”
2.在“高级”页面上的“包含”部分中,将“启用包含的数据库”选项设置为“True”(默认为“False”)。
3.单击“确定”。
方法2: 使用T-SQL启用包含的数据库
--Enabled Advanced options sp_configure 'show advanced', 1; RECONFIGURE WITH OVERRIDE; go --Enabled Database Containment sp_configure 'contained database authentication', 1; RECONFIGURE WITH OVERRIDE; go
步骤2、创建一个数据库,并将它的包含类型设置为“部分”
1. 创建一个名为“TestContainedDB”的数据库,然后右击该数据库并单击其属性
2. 在“选项”一栏,将包含类型选择为“部分”,最后单击“确认”。
步骤2也可以通过T-SQL实现:
USE [master] GO /****** Object: Database [TestContainedDB] Script Date: 2012/4/18 16:31:14 ******/ CREATE DATABASE [TestContainedDB] CONTAINMENT = PARTIAL ON PRIMARY ( NAME = N'TestContainedDB', FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\TestContainedDB.mdf' , SIZE = 5120KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB ) LOG ON ( NAME = N'TestContainedDB_log', FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\TestContainedDB_log.ldf' , SIZE = 1024KB , MAXSIZE = 2048GB , FILEGROWTH = 10%) GO ALTER DATABASE [TestContainedDB] SET COMPATIBILITY_LEVEL = 110 GO IF (1 = FULLTEXTSERVICEPROPERTY('IsFullTextInstalled')) begin EXEC [TestContainedDB].[dbo].[sp_fulltext_database] @action = 'enable' end GO ALTER DATABASE [TestContainedDB] SET ANSI_NULL_DEFAULT OFF GO ALTER DATABASE [TestContainedDB] SET ANSI_NULLS OFF GO ALTER DATABASE [TestContainedDB] SET ANSI_PADDING OFF GO ALTER DATABASE [TestContainedDB] SET ANSI_WARNINGS OFF GO ALTER DATABASE [TestContainedDB] SET ARITHABORT OFF GO ALTER DATABASE [TestContainedDB] SET AUTO_CLOSE OFF GO ALTER DATABASE [TestContainedDB] SET AUTO_CREATE_STATISTICS ON GO ALTER DATABASE [TestContainedDB] SET AUTO_SHRINK OFF GO ALTER DATABASE [TestContainedDB] SET AUTO_UPDATE_STATISTICS ON GO ALTER DATABASE [TestContainedDB] SET CURSOR_CLOSE_ON_COMMIT OFF GO ALTER DATABASE [TestContainedDB] SET CURSOR_DEFAULT GLOBAL GO ALTER DATABASE [TestContainedDB] SET CONCAT_NULL_YIELDS_NULL OFF GO ALTER DATABASE [TestContainedDB] SET NUMERIC_ROUNDABORT OFF GO ALTER DATABASE [TestContainedDB] SET QUOTED_IDENTIFIER OFF GO ALTER DATABASE [TestContainedDB] SET RECURSIVE_TRIGGERS OFF GO ALTER DATABASE [TestContainedDB] SET DISABLE_BROKER GO ALTER DATABASE [TestContainedDB] SET AUTO_UPDATE_STATISTICS_ASYNC OFF GO ALTER DATABASE [TestContainedDB] SET DATE_CORRELATION_OPTIMIZATION OFF GO ALTER DATABASE [TestContainedDB] SET TRUSTWORTHY OFF GO ALTER DATABASE [TestContainedDB] SET ALLOW_SNAPSHOT_ISOLATION OFF GO ALTER DATABASE [TestContainedDB] SET PARAMETERIZATION SIMPLE GO ALTER DATABASE [TestContainedDB] SET READ_COMMITTED_SNAPSHOT OFF GO ALTER DATABASE [TestContainedDB] SET HONOR_BROKER_PRIORITY OFF GO ALTER DATABASE [TestContainedDB] SET RECOVERY FULL GO ALTER DATABASE [TestContainedDB] SET MULTI_USER GO ALTER DATABASE [TestContainedDB] SET PAGE_VERIFY CHECKSUM GO ALTER DATABASE [TestContainedDB] SET DB_CHAINING OFF GO ALTER DATABASE [TestContainedDB] SET DEFAULT_FULLTEXT_LANGUAGE = 2052 GO ALTER DATABASE [TestContainedDB] SET DEFAULT_LANGUAGE = 2052 GO ALTER DATABASE [TestContainedDB] SET NESTED_TRIGGERS = ON GO ALTER DATABASE [TestContainedDB] SET TRANSFORM_NOISE_WORDS = OFF GO ALTER DATABASE [TestContainedDB] SET TWO_DIGIT_YEAR_CUTOFF = 2049 GO ALTER DATABASE [TestContainedDB] SET FILESTREAM( NON_TRANSACTED_ACCESS = OFF ) GO ALTER DATABASE [TestContainedDB] SET TARGET_RECOVERY_TIME = 0 SECONDS GO ALTER DATABASE [TestContainedDB] SET READ_WRITE GO --------附:使用T_SQL将数据库转换为部分包含的数据库 USE [master] GO ALTER DATABASE [TestContainedDB] SET CONTAINMENT = PARTIAL GO
- 步骤3、创建一个包含的用户
1. 新建用户
2.创建用户名和密码,这里的用户名为TestUser,密码是Test@PWD1
注意:密码需要达到复杂度要求,如英文字母、数字、特殊符号等,否则在创建时可能会遇到报错
3. 成员身份选择“db_owner”
通过T-SQL创建:
创建好后,就可以在数据库的用户里看到:USE [TestContainedDB] GO CREATE USER [TestUser] WITH PASSWORD='Test@PWD1', DEFAULT_SCHEMA=[dbo] GO
步骤4、 用包含的用户登录包含的数据库
1. 在登录栏输入登录名(这里用的是TestUser)和密码(这里用的是Test@PWD1)
2. 在连接属性栏(点击登陆界面的“选项”,展开后就可以看到)输入要连接的数据库名称(这里是TestContainedDB)
3. 点击“连接”,即可登陆成功
- 将非包含的数据库转换为包含的数据库
这里,我先创建一个非包含的数据库(命名为:TestNonContainedDB),并建一张表和一个存储过程(如下截图),即为非包含数据库创建连个常见的对象。
USE [master] GO /****** Object: Database [TestNonContainedDB] Script Date: 2012/4/19 10:27:16 ******/ CREATE DATABASE [TestNonContainedDB] CONTAINMENT = NONE ON PRIMARY ( NAME = N'TestNonContainedDB', FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\TestNonContainedDB.mdf' , SIZE = 5120KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB ) LOG ON ( NAME = N'TestNonContainedDB_log', FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\TestNonContainedDB_log.ldf' , SIZE = 1024KB , MAXSIZE = 2048GB , FILEGROWTH = 10%) GO
下面开始一步步将非包含的数据库转换成包含的数据库:
1. 创建一个登录名和一个用户
2. 先看看当前DB有哪些非包含的对象。由下图可见,忽略ROUTE,当前有1个非包含的数据库对象--Create a login on the server use master CREATE LOGIN NonContainedUser WITH PASSWORD = 'PWD+12345' --Create a "non-contained" users for the login on the server USE TestNonContainedDB GO CREATE USER NonContainedUser FOR LOGIN NonContainedUser GO
SELECT class_desc,feature_name,feature_type_name FROM sys.dm_db_uncontained_entities
对于非包含的用户,我们从下面可以看到只有1个:
USE TestNonContainedDB GO SELECT dp.name FROM sys.database_principals dp JOIN sys.server_principals sp ON dp.sid = sp.sid WHERE dp.authentication_type = 1 AND sp.is_disabled = 0
3. 将数据库转换为部分包含的数据库
在对象资源管理器中,展开“数据库”,右键单击要转换的数据库(这里是TestNonContainedDB),然后单击“属性”,在“选项”页面上,将“包含类型”选项更改为“部分”,最后单击“确定”。或者使用如下T-SQL:
4. 将用户迁移为包含的数据库用户USE [master] GO ALTER DATABASE TestNonContainedDB SET CONTAINMENT = PARTIAL GO
迁移之前先看看当前的用户属性:
现在执行下面的命令进行迁移:
执行之后再看看用户的属性,这是用户类型变成了带密码的SQL用户:USE TestNonContainedDB GO EXEC sp_migrate_user_to_contained @username = N'NonContainedUser', @rename = N'keep_name', @disable_login = N'disable_login'
再验证一下非包含的用户,由下图可见,将用户迁移为包含的数据库用户之后,对应的非包含用户就消失了;同时,对应的登录名也是被禁用状态。
如果要将所有基于 SQL Server 登录名(启用的)的用户迁移到具有密码的包含的数据库用户,可在包含的数据库中执行下面命令:
5. 用迁移的用户登录DECLARE @username sysname ; DECLARE user_cursor CURSOR FOR SELECT dp.name FROM sys.database_principals AS dp JOIN sys.server_principals AS sp ON dp.sid = sp.sid WHERE dp.authentication_type = 1 AND sp.is_disabled = 0; OPEN user_cursor FETCH NEXT FROM user_cursor INTO @username WHILE @@FETCH_STATUS = 0 BEGIN EXECUTE sp_migrate_user_to_contained @username = @username, @rename = N'keep_name', @disablelogin = N'disable_login'; FETCH NEXT FROM user_cursor INTO @username END CLOSE user_cursor ; DEALLOCATE user_cursor ;
- 备份包含的数据库
备份包含的数据库可以以备份非包含的数据库的方式(通过SSMS或T-SQL)来实现。唯一要注意的是,如果是通过包含的用户登录,则通过SSMS备份在右击数据库名称时会遇到如下问题(通过带登录名的SQL用户登录,就不会有此问题,当然也要有备份包含的数据库的权限):
不过没关系,你可以通过T_SQL实现:
- 还原包含的数据库
以上比较详细的介绍了包含的数据库的概念、创建、迁移、备份及还原等,其他相关信息,可以再参考MSDN:http://msdn.microsoft.com/zh-cn/library/ff929071.aspx