SQL Server 部分包含数据库的原理
原文链接:https://blog.csdn.net/zhoujunah/java/article/details/103513426
包含是针对数据库独立性而来的,非包含数据库(SQL Server 2012以前版本的所有数据库,以及SQL Server 2012及以后的数据库属性CONTAINMENT 设置为NONE的数据库)是在实例master库下进行登陆账户密码验证的;而包含数据库可以通过本身带有密码的用户直接与应用进行交互。
应用场景
部分包含数据库和非包含数据库最大的差异在于排序规则,即如果数据库的排序规则和实例排序规则不一致,并且跨库操作较少,则使用部分包含数据库能极大的减轻开发者的负担。这也是部分包含数据库的应用场景之一。
非实例级故障转移,如Always On、日志传送等如果使用包含数据库,将登录账户全部变为包含用户,就不需要额外的同步登陆账户及权限,可以极大限度的减少账户同步带来的故障恢复时间,及DBA日常维护登陆账户权限同步的额外工作及时间。这是部分包含数据库的应用场景之二。
创建部分包含数据库
可以在创建数据库时指定CONTAINMENT=PARTIAL直接创建部分包含数据库,如下:
CREATE DATABASE test3
CONTAINMENT = PARTIAL
查看数据库是否启用部分包含属性
SELECT name, containment, containment_desc
FROM sys.databases
WHERE name='test3'
从结果来看containment值为0,containment_desc值为NONE 表示数据库并未启用部分包含数据库。下面我将启用部分包含数据库。
SSMS中启用部分包含数据库
可以直接从对象资源管理器中,右击对应数据库(本文使用的test3数据库)→属性→选项→包含类型→部分,如下图:
点击确定,即可。
T-SQL 启用部分包含数据库
当然,更改数据库包含类型设置时,不能有用户连接该数据库,如果有用户连接,可以使用如下脚本查出并kill掉相关进程:
USE master
GO
SELECT 'kill '+CONVERT(varchar(3),spid)
FROM sys.sysprocesses
WHERE dbid = DB_ID('test3')
下面给出启用部分包含数据库的T-SQL:
--启用包含数据库
USE [master]
GO
EXEC sp_configure 'show advanced options', 1
RECONFIGURE WITH OVERRIDE
EXEC sp_configure 'contained database authentication', 1
RECONFIGURE WITH OVERRIDE
ALTER DATABASE [test3] SET CONTAINMENT = PARTIAL WITH NO_WAIT
GO
此时再次查看sys.databases视图,如下:
可以看到数据库test3 部分包含已经开启(contaiment值变为1,containment_desc 值变为 PARTIAL。
包含用户连接
接下来我将在部分包含数据库 test3 中创建测试包含用户。当然除包含用户可以连接外,登陆账户仍可以连接。
在部分包含数据库test3中创建包含用户Jack(带密码的 SQL 用户) 并赋予其连接数据库的权限,脚本如下:
USE test3
GO
--创建包含用户Jack
CREATE USER Jack WITH PASSWORD = 'a8ea v*(Rd##+'
--赋予用户Jack 连接数据库的权限
GRANT CONNECT TO Jack
从SSMS的资源管理器中使用用户Jack连接数据库,如下:
直接点击连接,会报如下错误:
这是因为使用包含用户连接包含数据库时,需要指定对应的包含数据库,在连接属性中,指定要连接的部分包含数据库test3,如下图:
再点击连接时,可以成功连接。从资源管理器中可以查看连接后的情况,如下图:
下面我们回过头来看一下 Jack 用户属性
带密码的 SQL 用户属性截图:
带登陆名SQL用户
从两张属性截图上来看,两者之间的主要差异在于是否有密码、是否有登陆名及默认语言。
SELECT password
FROM sys.sysusers
WHERE name = 'Jack'
有密码的包含数据库用户的密码哈希值存储在包含的数据库中。但不在系统视图中存储,如sys.sysusers、sys.database_principals均不存在密码信息。
SELECT name, type, type_desc
, authentication_type
, authentication_type_desc
FROM sys.database_principals
WHERE name = 'Jack'
从这个视图中可以看到,包含用户的授权类型是数据库级的(登陆账户授权是实例级的)。
测试与包含数据库用户同名的登陆名Jack
如果创建了一个有密码的包含数据库用户,所使用的名称与 SQL Server 登录名相同,而且在 SQL Server 登录名进行连接时将包含的数据库指定为初始目录,则 SQL Server 登录名将无法连接。该连接将被判定为包含数据库上的具有密码主体的包含数据库用户发起,而不是基于 SQL Server 登录名的用户发起。这可能导致 SQL Server 登录名遭遇到拒绝服务。
CREATE LOGIN Jack WITH PASSWORD='Password'
, CHECK_POLICY=OFF,CHECK_EXPIRATION=OFF
ALTER SERVER ROLE [sysadmin] ADD MEMBER [Jack]
GO
直接使用Jack登陆名连接实例,会报如下密码不匹配错误:
最优的方案是创建包含用户时,不要和登陆账户名重复。
迁移登陆账户为带有密码的包含用户
将现有的与登陆账户关联的数据库用户改为包含数据库用户,脚本如下:
USE [test]
GO
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;
包含数据库的跨库操作
只有包含数据库才能进行跨库操作,某个包含用户如果需要做跨库操作,需要做如下准备:
在每个数据库中创建相同的包含的数据库用户来做到这点。在创建带密码的第二个用户时,使用 SID 选项。下面的示例在两个数据库中创建两个完全相同的用户。
--返回SID,用于创建同名包含用户
USE test3
SELECT SID
FROM sys.database_principals
WHERE name = 'Jack';
USE test2
CREATE USER Jack WITH PASSWORD = 'a8ea v*(Rd##+'
,sid=0x010500000000000903000000301792D81CCF6B4093A36928EE829FF0
这里的密码和test3中包含用户Jack密码相同。
接下来使用Jack用户连接 test3,并在test3下执行如下脚本:
select * from test2.dbo.test
报如下错误:
消息 916,级别 14,状态 1,第 1 行
服务器主体 "Jack" 无法在当前安全上下文下访问数据库 "test2"。
这是因为我的test3、test2两个数据库的拥有者不同,test2的拥有者是sa,而test3的拥有者是创建该数据库的登陆账户。将test3的拥有者改为sa,脚本如下:
USE [test3]
GO
EXEC dbo.sp_changedbowner @loginame = N'sa', @map = false
GO
再在test3库下执行跨库查询的脚本,即可成功:
接下来使用Jack用户连接数据库 test2,并在数据库test2下执行如下脚本:
点赞
收藏
分享
————————————————
版权声明:本文为CSDN博主「三空道人」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/zhoujunah/java/article/details/103513426
SQL Server 部分包含数据库的原理的更多相关文章
- SQL Server 进阶 01 数据库的设计
SQL Server 进阶 01 数据库的设计 本篇目录 课程内容回顾及介绍 为什么需要规范的数据库设计 设计数据库的步骤 绘制E-R(实体-关系)图 实体-关系模型 如何将E-R图转换为表 数据规范 ...
- Sql Server系列:数据库组成及系统数据库
1. 数据库组成 数据库的存储结构分为逻辑存储结构和物理存储结构. ◊ 逻辑存储结构:说明数据库是由哪些性质的信息所组成.SQL Server的数据库不仅仅只是数据的存储,所有与数据处理操作相关的信息 ...
- sql server 脚本创建数据库邮件
sql server 脚本创建数据库邮件代码: --脚本创建数据库邮件 --1.开启数据库邮件 RECONFIGURE WITH OVERRIDE GO RECONFIGURE WITH OVERRI ...
- 第七篇 SQL Server安全跨数据库所有权链接
本篇文章是SQL Server安全系列的第七篇,详细内容请参考原文. Relational databases are used in an amazing variety of applicatio ...
- 深入解析 SQL Server 高可用镜像实现原理
作者:郭忆 本文由 网易云 发布. SQL Server 是 windows 平台 .NET 架构下标配数据库解决方案,与 Oracle.MySQL 共同构成了 DB-Engines Ranking ...
- 【译】第七篇 SQL Server安全跨数据库所有权链接
本篇文章是SQL Server安全系列的第七篇,详细内容请参考原文. Relational databases are used in an amazing variety of applicatio ...
- 深入解析SQL Server高可用镜像实现原理
本文来自网易云社区 SQL Server 是windows平台.NET架构下标配数据库解决方案,与Oracle.MySQL共同构成了DB-Engines Ranking的第一阵营,在国内外企业市场中有 ...
- 如何修改SQL Server 2008 R2数据库的内存
本篇经验将和大家介绍如何修改SQL Server 2008 R2数据库的内存,希望对大家的工作和学习有所帮助! 工具/原料 SQL Sever 2008 R2数据库已安装 方法/步骤 1 打开 ...
- 【SQL Server高可用性】数据库复制:SQL Server 2008R2中通过数据库复制,把A表的数据复制到B表
原文:[SQL Server高可用性]数据库复制:SQL Server 2008R2中通过数据库复制,把A表的数据复制到B表 经常在论坛中看到有人问数据同步的技术,如果只是同步少量的表,那么可以考虑使 ...
- sql server如何判断数据库是否存在
如何判断数据库是否存在 执行下列的SQL,获得一张表,根据表的行数来判断. select * from master..sysdatabases where name=N'所查询的数据库名 ...
随机推荐
- IE 条件注释
参考文档 IE6 IE7 IE8 IE9 IE10 Css hack及IE条件注释法 IE的有条件注释判定IE版本详解(附实例代码)
- 一次windows下使用cmake遇到的问题
背景 在windows下的cmake和mingw提供的make,在windows环境下进行了简单尝试,结果发现make的时候失败: #include <iostream> int main ...
- 如何开发 MCP 服务?保姆级教程!
最近这段时间有个 AI 相关的概念特别火,叫 MCP,全称模型上下文协议(Model Context Protocol).这是由 Anthropic 推出的一项开放标准,目标是为大型语言模型和 AI ...
- PyInstaller 常用用法
PyInstaller 常用用法 PyInstaller 是一个跨平台的 Python 应用打包工具,支持 Windows/Linux/MacOS 三大主流平台,能够把 Python 脚本及其所在的 ...
- 聊聊智商税:AI知识库
提供AI咨询+AI项目陪跑服务,有需要回复1 DeepSeek一体机是一种神奇的存在,很多公司跟风购买后发现一个尴尬的事情:用不起来,于是一体机厂家或者中间商便需要在其中叠加AI场景,这里最常见的场景 ...
- python处理ppt文件,转换成图片或者pdf文件(获取目录下所有文件信息、文件名称分割、文档操作)
把PPT每一页截图到公众号里推送可是个体力活,那就用python脚本去分解ppt,保存每一个为一张图片好了 需要用到"win32com.client"库 import win32c ...
- 什么是 Java 中的 JIT(Just-In-Time)?
Java 中的 JIT(Just-In-Time)编译器 1. JIT 的定义 JIT(Just-In-Time)编译器是一种用于 Java 虚拟机(JVM)的动态编译技术.它在 Java 程序运行时 ...
- js获取本地图片文件的原始宽高尺寸
<!-- 关键api:URL.createObjectURL(object) object:File对象或 Blob 对象 参考:https://developer.mozil ...
- git提示fatal: Authentication failed for但是不进入重新登录的流程,也死活不弹窗的解决办法,不用找证书删
问题: git提交代码输错了密码,提示 fatal: Authentication failed for xxx 但是不进入重新登录的流程,也死活不弹窗. 感觉git的这个设计真的很沙雕.网上说删证书 ...
- Rust实战系列-Rust介绍
" 学习资料:rust in action[1] 1. Rust 安装 curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | ...