As we know there are two types of authentication available in SQL Server Windows authentication and SQL authentication. In Windows authentication we use Active directory authentication to connect with SQL Server which makes the most secure authentication method as it can have complexity, group policy configured at AD level applied to all domain servers while in SQL Authentication SQL users are created inside SQL and provided required permissions. The Permissions includes server wide and database wide. The logins can have certain permissions at the database level might be read or write etc.
众所周知,SQL Server Windows身份验证和SQL身份验证有两种类型的身份验证。 在Windows身份验证中,我们使用Active Directory身份验证与SQL Server连接,这是最安全的身份验证方法,因为它可能具有复杂性,在AD级别配置的组策略适用于所有域服务器,而在SQL身份验证中,SQL用户是在SQL内部创建的,并且需要权限。 权限包括服务器范围和数据库范围。 登录名可以在数据库级别具有某些权限,可以读取或写入等。
We need to understand the difference between a user and login here. A login is created at a server level while the user is created at a database level. Each having Unique SID and to work for the user, both SID should be equivalent.
我们需要了解用户和此处登录之间的区别。 在服务器级别创建登录名,而在数据库级别创建用户。 每个都有唯一的SID,并且要为用户工作,两个SID应该等效。
Usually, we have the requirement for restoring the staging or UAT databases from production or any new server. When we move or restore the database into a different environment we might come up with issues of Orphan users (where SID is not mapped for both login and user) if we have not migrated the logins with sp_help_revlogin script or by any other means, so users might have issues accessing the databases or application malfunctions. We need to fix the orphans users using system stored procedure sp_change_users_logins with appropriate parameters.
通常,我们需要从生产或任何新服务器中还原登台数据库或UAT数据库。 如果我们尚未使用sp_help_revlogin脚本或任何其他方式迁移登录名,则在将数据库移动或还原到其他环境中时,我们可能会遇到孤立用户问题(未同时为登录名和用户映射SID)。可能在访问数据库或应用程序故障时遇到问题。 我们需要使用带有适当参数的系统存储过程sp_change_users_logins修复孤儿用户。
SQL Server 2012 Onwards we have a new solution termed as contained database. Contained database is defined as a database which has the database user without logins. It includes all settings related to databases along with its metadata, thus system will be having no dependency with SQL server login. Users can easily connect to a contained database without having to go through the log in at DB engine.
从SQL Server 2012开始,我们有了一个称为包含数据库的新解决方案。 包含的数据库定义为数据库用户没有登录名的数据库。 它包括与数据库有关的所有设置及其元数据,因此系统将不依赖于SQL Server登录。 用户可以轻松地连接到包含的数据库,而无需通过DB引擎登录。
Contained database feature provides two containment modes:
包含数据库功能提供两种包含模式:
Contained databases feature is available at instance level and it is not enabled by default.
包含数据库功能在实例级别可用,默认情况下未启用。
To enable it, right click on server ➜ properties, go to Advanced, and enable the Enabled Contained Databases option
要启用它,请右键单击服务器➜属性,转到“高级”,然后启用“已启用包含的数据库”选项
Alternatively, we can use a sp_configure system stored procedure to enable contained databases on the instance, as per below query:
或者,我们可以使用sp_configure系统存储过程在实例上启用包含的数据库,如以下查询所示:
EXEC sp_configure 'show advanced', 1
GO
RECONFIGURE
GO
EXEC sp_configure 'contained database authentication', 1
GO
RECONFIGURE
GO
If we want to create a new database as a contained database, we have to make containment type as Partial in the Options page.
如果要创建一个新数据库作为包含数据库,则必须在“选项”页面中将包含类型设置为“部分”。
If we script out the create database, we can find out the query to create it using t-SQL as below:
如果我们编写创建数据库的脚本,则可以使用t-SQL查找查询以创建它,如下所示:
CREATE DATABASE [TestContainedDB]
CONTAINMENT = PARTIAL
ON PRIMARY
( NAME = N'TestContainedDB', FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\DATA\TestContainedDB.mdf' ,
SIZE = 5120KB , FILEGROWTH = 1024KB )
LOG ON
( NAME = N'TestContainedDB_log', FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\DATA\TestContainedDB_log.ldf' ,
SIZE = 2048KB , FILEGROWTH = 10%)
GO
Once the database is created, we can verify it using the sys.databases
创建数据库后,我们可以使用sys.databases进行验证
select containment,name from sys.databases where name='TestContainedDB'
If the containment is not enabled in the databases, it will return 0, else 1, so in our case it should return 1 for TestContainedDB as shown:
如果在数据库中未启用包含,它将返回0,否则返回1,因此在我们的情况下,它应为TestContainedDB返回1,如下所示:
Once the contained database is created, we need to create a new database user.
创建包含的数据库后,我们需要创建一个新的数据库用户。
For this, we need to expand contained databases and go to security -> Create new database user and create new user type as SQL user with password, provide default schema, appropriate permissions required, as shown below:
为此,我们需要扩展包含的数据库,然后转到安全性->创建新的数据库用户,并使用密码以SQL用户身份创建新的用户类型,提供默认模式和所需的适当权限,如下所示:
The script below can be used to create the user by t-sql
以下脚本可用于通过t-sql创建用户
USE [TestContainedDB]
GO
CREATE USER [TestUser] WITH PASSWORD=N'test', DEFAULT_SCHEMA=[dbo]
Go
So here we need not to create the Login before creating the user, we will directly create the user with appropriate password tagged.
因此,这里我们无需在创建用户之前创建登录名,我们将直接创建带有适当密码标记的用户。
Note: we cannot create the user in a normal database, which is not contained. If tried, we will get the below error
注意:我们无法在不包含的普通数据库中创建用户。 如果尝试过,我们将得到以下错误
Msg 33233, Level 16, State 1, Line 1 You can only create a user with a password in a contained database.
消息33233,级别16,状态1,行1您只能在包含的数据库中使用密码创建用户。
Normally, to connect with SQL database instance we used to provide instance name, authentication method (windows\SQL) and, if SQL, username and password.
通常,为了连接SQL数据库实例,我们通常提供实例名称,身份验证方法(windows \ SQL),如果提供SQL,则提供用户名和密码。
But to connect contained database we also need to specify contained DB name in the connection parameter.
但是,要连接包含的数据库,我们还需要在连接参数中指定包含的数据库名称。
If we try to connect contained database with contained user and password without specifying database name, we will get the error as:
如果我们尝试在不指定数据库名称的情况下使用所包含的用户名和密码来连接所包含的数据库,则会出现以下错误:
So, in the connection properties we need to specify contained database name as shown below:
因此,在连接属性中,我们需要指定包含的数据库名称,如下所示:
Once connected through SQL Server Management Studio, we can see the database user has access to:
通过SQL Server Management Studio连接后,我们可以看到数据库用户有权访问:
If want to convert existing database into contained database, run the command below:
如果要将现有数据库转换为包含的数据库,请运行以下命令:
ALTER DATABASE [Database_name] SET CONTAINMENT = PARTIAL WITH NO_WAIT
GO
After converting the database we need to take care of the existing logins as well. For this, we need to move the users or migrate the users using the system procedure. We need to use sp_migrate_users_to_contained with below parameters.
转换数据库后,我们还需要注意现有的登录信息。 为此,我们需要使用系统过程移动用户或迁移用户。 我们需要使用带有以下参数的sp_migrate_users_to_contained。
Suppose we have the user as TestMovecontained, so query for moving the user will be:
假设我们的用户名为TestMovecontained,因此移动用户的查询将为:
sp_migrate_user_to_contained
@username = 'TestMovecontained', --Userame to be specified here
@rename = N'keep_name',
@disablelogin = N'do_not_disable_login' ;
GO
As a contained user is created at database level, we cannot do any activity we require instance permissions like backup \ restore.
由于包含用户是在数据库级别创建的,因此我们无法执行我们需要实例权限的任何活动,例如backup \ restore。
As visible below, we are not getting option of backup \ Restore database here but we can take the database Offline.
如下所示,我们这里没有备份\ Restore database选项,但是我们可以使数据库脱机。
We can use the system view sys.database_principals view in the database to see which users are listed as contained users using the below query
我们可以使用数据库查询中的系统视图sys.database_principals视图查看哪些用户被列为包含的用户
SELECT name,type_desc,authentication_type_desc
FROM sys.database_principals WHERE authentication_type =2
Partially contained databases cannot use features like replication, change data capture, change tracking, schema-bound objects that depend on built-in functions with collation changes.
部分包含的数据库不能使用复制,更改数据捕获,更改跟踪以及依赖于带有归类更改的内置函数的架构绑定对象之类的功能。
翻译自: https://www.sqlshack.com/contained-databases-in-sql-server/