SQL数据库基础笔记(一)

SQL Server数据库基础笔记(一)

数据库隔离级别

首先了解几个基本概念:

脏读:一个事务读取了另一个事务还未提交的数据
不可重复读:指在一个事务内读取表中的某一行数据,多次读取结果不同

比如:如果不考虑脏读的情况,假设事务A,事务B,事务C同时执行,事务A在整个执行阶段,将某个数据项 的值由1加到10,然后进行事务提交。在此过程中,事务B进行读取,只可能读取到1和最终值10。之 后事务B并没有结束,事务C再次将该项的值由10加到20,然后进行事务提交。在此过程中,事务B再 次进行读取,只可能读取到10和最终值20。因此事务B在执行过程中有可能两次读取结果不同。

幻读:指在一个事务内读取到了别的事务插入的数据,导致前后读取不一致

比如:如果不考虑脏读和不可重复读的情况,假设事务A对一个表中的某个数据项设置为1,这种修改涉及到 表中的全部数据行,与此同时,事务B向表中插入一条新的数据且该数据项为2,那么此时操作事务A 的用户就会发现表中有一条数据的该数据项居然不是1,好像发生了幻觉。

不可重复读和幻读的区别在于:

  • 不可重复读:在同一事物中,两次读取同一数据,得到内容不同
  • 幻读:同一事物中,用同样的操作读取两次,得到的记录数不同

为了解决以上这些问题,保证事务与事务之间的隔离性,数据库中对事务的隔离级别做出了限制,分别在一定程度上对以上问题进行了解决。

在标准SQL规范中,定义了四个事务隔离级别。
  1. 读未提交。最低级别,以上问题均无法解决。
  2. 读已提交。可避免脏读情况发生。
  3. 可重复读取。可避免脏读、不可重复读情况的发生。保证在事务的处理过程中,多次读取同一个数据的时候,其值都和事务开始的时候是一致的。这也是为何下图中只能读取到1的原因。
  4. 串行化。最严格的事务隔离级别,要求所有事务被串行执行,不能并发执行,可避免脏读、不可重复读、幻读情况的发生。

在这里插入图片描述

数据库锁

在SQL Server中,每一个查询都会找到最短路径实现自己的目标。如果数据库只接受一个连接一次只执行一个查询。那么查询当然是要多快好省的完成工作。但对于大多数数据库来说是需要同时处理多个查询的。这些查询并不会像绅士那样排队等待执行,而是会找最短的路径执行。因此,就像十字路口需要一个红绿灯那样,SQL Server也需要一个红绿灯来告诉查询:什么时候走,什么时候不可以走。这个红绿灯就是锁。

在这里插入图片描述
SQL Server通过锁,就像十字路口的红绿灯那样,告诉所有并发的连接,在同一时刻上,哪些资源可以读取,哪些资源可以修改。前面说到,查询本身可不是什么绅士,所以需要被监管。当一个事务需要访问的资源加了其所不兼容的锁,SQL Server会阻塞当前的事务来达成所谓的隔离性。直到其所请求资源上的锁被释放

死锁:当两个进程都持有一个或一组锁时,而另一个进程持有的锁和另一个进程视图获得的锁不兼容时。就会发生死锁。这个概念如图所示

在这里插入图片描述

锁的分类:

  • 从数据库系统的角度来看:分为独占锁(即排他锁)、共享锁、更新锁

  • 从程序员的角度看:分为乐观锁、悲观锁

数据类型转换(cast 和 convert函数)

CAST() 函数语法:CAST ( AS <data_ type>[ length ])

CONVERT() 函数语法:CONVERT (<data_ type>[ length ], [, style])

  • data_type为SQL Server系统定义的数据类型,用户自定义的数据类型不能在此使用
  • length用于指定数据的长度,缺省值为30
  • 把char或varchar类型转换为诸如int或samllint这样的integer类型、结果必须是带正号(+)或负号(-)的数值
  • text类型到char或varchar类型转换最多为8000个字符,即char或varchar数据类型是最大长度
  • image类型存储的数据转换到binary或barbinary类型,最多为8000个字符
  • 把整数值转换为money或smallmoney类型,按定义的国家的货币单位来处理,如人民币、美元、英镑等
  • bit类型的转换把非零值转换为1,并仍以BIT类型存储
  • 试图转换到不同长度的数据类型,会截短转换值并在转换值后显示“+”,以标识发生了这种截断
  • 用convert()函数的style 选项能以不同的格式显示日期和时间。style 是将datetime 和smalldatetime 数据转换为字符串时所选用的由SQL Server 系统提供的转换样式编号,不同的样式编号有不同的输出格式

字符串函数stuff()

说明:STUFF 函数将字符串插入到另一个字符串中。 它从第一个字符串的开始位置删除指定长度的字符;然后将 第二个字符串插入到第一个字符串的开始位置。

语法:STUFF ( character_expression , start , length , replaceWith_expression )

参数:

  • character_expression:字符数据的表达式。 character_expression 可以是常量、变量,也可以是字符列或二进制数据列。
  • start:一个整数值(从1开始),指定删除和插入的开始位置。start 的类型可以是 bigint。(如果 start 为负或为零,则返回空字符串;如果 start 的长度大于第一个 character_expression,则返回空字符串。 )
  • length:一个整数,指定要删除的字符数。 length 的类型可以是 bigint。(如果 length 为负,则返回空字符串;如果 length 的长度大于character_expression,则最多可以删除到character_expression 中的最后一个字符;如果 length 为零,则不删除字符直接在指定位置插入内容。 )
  • replaceWith_expression:字符数据的表达式。 replaceWith_expression 可以是常量、变量,也可以是字符列或二进制数据列。 此表达式从 start 开始替换 length 个字符的 character_expression。(如果 replaceWith_expression 为 NULL,则在不插入任何内容的情况下删除字符。)
  • 返回类型:如果 character_expression 是支持的字符数据类型之一,则返回字符数据。 如果 character_expression 是支持的二进制数据类型之一,则返回二进制数据。

实例:

从第一个字符串 ABCDEFG的第 2 个位置 (B) 开始删除3个字符,然后在删除位置插入第二个字符串,从而创建并返回一个字符串

在这里插入图片描述

如果 start 为负或为零,则返回空字符串

在这里插入图片描述

如果 start 的长度大于第一个 character_expression,则返回空字符串。

在这里插入图片描述

如果 length 为负,则返回空字符串

在这里插入图片描述

如果 length 的长度大于character_expression,则最多可以删除到character_expression 中的最后一个字符。

在这里插入图片描述

如果 length 为零,则不删除字符直接在指定位置插入内容

在这里插入图片描述

如果 replaceWith_expression 为 NULL,则在不插入任何内容的情况下删除字符。

在这里插入图片描述

临时表

临时表与永久表相似,但临时表存储在tempdb中,当关闭sql连接的时候,临时表就会自动删除,普通表不会。临时表有两种类型:本地和全局。它们在名称、可见性以及可用性上有区别。

  • 本地临时表就是用户在创建表的时候添加了“#”前缀的表,其特点是根据数据库连接独立。只有创建本地临时表的数据库连接有表的访问权限,其它连接不能访问该表;
  • 不同的数据库连接中,创建的本地临时表虽然“名字”相同,但是这些表之间相互并不存在任何关系;在SQLSERVER中,通过特别的命名机制保证本地临时表在数据库连接上的独立性。
  • 真正的临时表利用了数据库临时表空间,由数据库系统自动进行维护,因此节省了表空间。并且由于临时表空间一般利用虚拟内存,大大减少了硬盘的I/O次数,因此也提高了系统效率。
  • 临时表在事务完毕或会话完毕数据自动清空,不必记得用完后删除数据。
本地临时表

本地临时表的名称以单个数字符号 (#) 打头;它们仅对当前的用户连接(也就是创建本地临时表的connection)是可见的;当用户从 SQL Server 实例断开连接时被删除

举个栗子:

--在一个数据库连接中用如下语句创建本地临时表#Temp
--数据库连接1
CREATE TABLE #Temp
(
    id int,
    customer_name nvarchar(50),
    age int
)
--然后同时启动数据库连接2,执行查询#Temp的操作
--数据库连接2
select * from #temp

结果显示,数据库连接2找不到表#Temp。这说明#Temp这张临时表,只是对创建它的数据库连接1可见,而对于数据库连接2来说是不可见的

数据库连接2:

在这里插入图片描述

全局临时表

全局临时表的名称以两个数字符号 (##) 打头,创建后对任何数据库连接都是可见的,当所有引用该表的数据库连接从 SQL Server 断开时被删除。

--数据库连接1
CREATE TABLE ##Temp
(
    id int,
    customer_name nvarchar(50),
    age int
)

INSERT INTO ##Temp VALUES(1,'老王',20),(2,'老张',30),(3,'老李',25)
--接着我们在数据库连接2中,查询##Temp的数据
--数据库连接2
select * from ##Temp

数据库连接2结果:可以成功访问到数据库连接1创建的全局临时表##Temp

在这里插入图片描述

但是如果我们现在关闭数据连接1,然后再执行数据库连接2的##Temp查询语句:

关闭数据库连接1,然后数据库连接2再次执行:

select * from ##Temp

在这里插入图片描述

我们发现关闭数据库连接1后,数据库连接2就找不到全局临时表##Temp了。这是因为数据库连接1被关闭后,数据库连接2此时也没有语句正在使用临时表##Temp,所以Sqlserver认为此时已经没有数据库连接在引用全局临时表##Temp了,就将##Temp释放掉了


接下来,我们尝试在数据库连接2中对全局临时表##Temp持有事务中的排他锁(X锁)后,然后关闭数据库连接1.

--数据库连接1
CREATE TABLE ##Temp
(
    id int,
    customer_name nvarchar(50),
    age int
)

INSERT INTO ##Temp VALUES(1,'老王',20),(2,'老张',30),(3,'老李',25)
--数据库连接2
BEGIN TRAN
select * from ##Temp with(xlock)
--关闭数据库连接1,然后数据库连接2执行
select * from ##temp

在这里插入图片描述

O ##Temp VALUES(1,‘老王’,20),(2,‘老张’,30),(3,‘老李’,25)
–数据库连接2
BEGIN TRAN
select * from ##Temp with(xlock)
–关闭数据库连接1,然后数据库连接2执行
select * from ##temp


[外链图片转存中...(img-RBXE7ORc-1607670582074)]

结果显示我们尽管关闭了数据库连接1,但是由于数据库连接2在事务中一直持有全局临时表##Temp的排他锁(X锁),所以临时表##Temp并没有随着数据库连接1的关闭而被释放掉,只要数据库连接2中启动的事务没有被回滚或提交,那么数据库连接2会一直持有临时表##Temp的排他锁,这时Sqlserver会认为还有数据库连接正在引用全局临时表##Temp,所以##Temp不会被释放掉

猜你喜欢

转载自blog.csdn.net/weixin_44337241/article/details/111035889