在向数据库中多个表同时插入修改数据的时候,我们1般需要使用事务来保证完整性,这段时间在维护1个银行项目,其中有较多的同时插入修改多张数据表的场景,作者使用的主键是nvarchar类型,由C# Guid.NewGuid()方法每次生成随机GUID进行填充,然后将该GUID作为主键与关链键(外键)同时插入多张数据表中。
根据我有限的数据库原理知识,这样的设计可以保证记录的唯一性,毕竟GUID重复的机率比宇宙灭亡还难见到,但这样设计会降低查询速率,因为我们知道自增长的主键,在设计的时候使用了数据结构中的顺序存储结构,即我们只需要知道0记录的地址A,第20条主键记录的位置就在A+(主键数据类型长度*20)上,查询效率可谓是数据库索引中最快的,而nvarchar主键是很慢的,不过主键应该都是簇索引的吧。
那么我们在同时向多张数据表中插入数据,并且需要维护外键的时候,该如何获得之前插入的最后1个自增长数据值呢?总不能”select top 1 * from tablename order by pkname desc”吧?其实不必这么复杂,数据库设计者们给我们提供了更简单的方法:
SQL SERVER中的三种获得自增长ID的方法
先看例子:
insert into users(Code,name) values('1111','aaaa') select SCOPE_IDENTITY() select @@IDENTITY select IDENT_CURRENT('users')
三种方法的区别:
SCOPE_IDENTITY()
返回插入到同一作用域中的 IDENTITY 列内的最后一个 IDENTITY 值。一个作用域就是一个模块――存储过程、触发器、函数或批处理。因此,如果两个语句处于同一个存储过程、函数或批处理中,则它们位于相同的作用域中。
@@IDENTITY
返回最后插入的标识值,跨表跨会话。
IDENT_CURRENT(表名)
返回为任何会话和任何作用域中的指定表最后生成的标识值。这个函数需要一个以表名为值的变量,也就是说虽然不受会话和作用域的限制,却会受到表的限制。
体会:加上事物处理,两个函数一个变量没有本质区别。不加事物处理两个函数一个变量受到其他会话、作用域的影响不一样。
MySQL中获得自增长的方法
在MySQL中,使用auto_increment类型的id字段作为表的主键。通常的做法,是通过“select max(id) from tablename”的做法,但是显然这种做法需要考虑并发的情况,需要在事务中对主表加以“X锁“,待获得max(id)的值以后,再解锁。这种做法需要的步骤比较多,有些麻烦,而且并发性也不好。有没有更简单的做法呢?答案之一是通过select LAST_INSERT_ID()这个操作。乍一看,它和select max(id)很象,但实际上它是线程安全的。也就是说它是具体于数据库连接的。下面通过实验说明:
- 在连接1中向A表插入一条记录,A表包含一个auto_increment类型的字段。
- 在连接2中向A表再插入一条记录。
- 结果:在连接1中执行select LAST_INSERT_ID()得到的结果和连接2中执行select LAST_INSERT_ID()的结果是不同的;而在两个连接中执行select max(id)的结果是相同的。
其实在MSSQL中SCOPE_IDENTITY()和IDENT_CURRENT()的区别和这里是类似的。使用SCOPE_IDENTITY()可以获得插入某个IDENTITY字段的当前会话的值,而使用IDENT_CURRENT()会获得在某个IDENTITY字段上插入的最大值,而不区分不同 的会话。
注意:使用select last_insert_id()时要注意,当一次插入多条记录时,只是获得第一次插入的id值。