我正在做一个论坛,遇到很大的迷惑,谷歌找不到 我想要的,所以在这里求助。
问题如下:
论坛发帖后要向论坛更新最后有动态的帖子,所以发表帖子以后需要获取刚刚发表的帖子的帖子ID,因为帖子ID我设置为自动增长,所以使用SQL中的全局变量@@identity来获取刚刚发表的帖子ID,C#代码如下:
            //向帖子表添加一条数据
            string sql = string.Format("insert lt_topics values({0},'{1}','{2}','{3}',{4},'{5}',0,0,'{6}',default,default)  select @@identity", fid, postTitle, postUserName, postText, postUserID, time, postUserName);
            //执行添加帖子的Sql语句,同时获取刚刚添加的帖子的帖子id
            int topicId = Convert.ToInt32(SqlHelper.ExecuteScalar(sql, null));
我的疑问是:如果用多个用户同时发帖,会出现什么情况?insert lt_topics values({0},'{1}','{2}','{3}',{4},'{5}',0,0,'{6}',default,default)  select @@identity  这个语句是不是算一个事务,多个用户同时发帖会一个个的执行所以这个Sql语句不会出现Bug,还是在执行这个语句的同时有其他语句同时执行(其他的表也有自动增长列),那样的话取到的@@Identity就不对了。
那么到底会出现哪一种情况呢?在底层,Sql Server是怎样处理对数据库的操作?
这些知识我在网上搜不到(可能是我知道搜索关键字),如果有关于这方面的好文也希望大家推荐一下,谢谢大家了。

解决方案 »

  1.   

    @@identity是返回最后插入的ID同时操作的话应该是并发问题,加锁吧
      

  2.   

    http://blog.csdn.net/misterliwei/archive/2010/01/05/5134043.aspx
    @@IDENTITY返回当前会话生成的最后的一个标识值。
      

  3.   

    本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/ws_hgo/archive/2009/04/26/4125239.aspxSQL标识列初探
    一、标识列的定义以及特点SQL Server中的标识列又称标识符列,习惯上又叫自增列。
    该种列具有以下三种特点:1、列的数据类型为不带小数的数值类型
    2、在进行插入(Insert)操作时,该列的值是由系统按一定规律生成,不允许空值
    3、列值不重复,具有标识表中每一行的作用,每个表只能有一个标识列。由于以上特点,使得标识列在数据库的设计中得到广泛的使用。二、标识列的组成
    创建一个标识列,通常要指定三个内容:
    1、类型(type)
    在SQL Server 2000中,标识列类型必须是数值类型,如下:
    decimal、int、numeric、smallint、bigint 、tinyint 
    其中要注意的是,当选择decimal和numeric时,小数位数必须为零
    另外还要注意每种数据类型所有表示的数值范围2、种子(seed)
    是指派给表中第一行的值,默认为13、递增量(increment)
    相邻两个标识值之间的增量,默认为1。三、标识列的创建与修改
    标识列的创建与修改,通常在企业管理器和用Transact-SQL语句都可实现,使用企业管理管理器比较简单,请参考SQL Server的联机帮助,这里只讨论使用Transact-SQL的方法1、创建表时指定标识列
    标识列可用 IDENTITY 属性建立,因此在SQL Server中,又称标识列为具有IDENTITY属性的列或IDENTITY列。
    下面的例子创建一个包含名为ID,类型为int,种子为1,递增量为1的标识列
    CREATE TABLE T_test
    (ID int IDENTITY(1,1),
    Name varchar(50)
    )2、在现有表中添加标识列
    下面的例子向表T_test中添加一个名为ID,类型为int,种子为1,递增量为1的标识列
    --创建表
    CREATE TABLE T_test
    (Name varchar(50)
    )--插入数据
    INSERT T_test(Name) VALUES('张三')--增加标识列
    ALTER TABLE T_test
    ADD ID int IDENTITY(1,1)3、判段一个表是否具有标识列可以使用 OBJECTPROPERTY 函数确定一个表是否具有 IDENTITY(标识)列,用法:
    Select OBJECTPROPERTY(OBJECT_ID('表名'),'TableHasIdentity')
    如果有,则返回1,否则返回04、判断某列是否是标识列可使用 COLUMNPROPERTY 函数确定 某列是否具有IDENTITY 属性,用法
    SELECT COLUMNPROPERTY( OBJECT_ID('表名'),'列名','IsIdentity')
    如果该列为标识列,则返回1,否则返回04、查询某表标识列的列名
    SQL Server中没有现成的函数实现此功能,实现的SQL语句如下
    SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.columns
       WHERE TABLE_NAME='表名' AND COLUMNPROPERTY(      
          OBJECT_ID('表名'),COLUMN_NAME,'IsIdentity')=15、标识列的引用如果在SQL语句中引用标识列,可用关键字IDENTITYCOL代替
    例如,若要查询上例中ID等于1的行,
    以下两条查询语句是等价的
    SELECT * FROM T_test WHERE IDENTITYCOL=1
    SELECT * FROM T_test WHERE ID=16、获取标识列的种子值可使用函数IDENT_SEED,用法:
    SELECT IDENT_SEED ('表名')7、获取标识列的递增量可使用函数IDENT_INCR ,用法:
    SELECT IDENT_INCR('表名')8、获取指定表中最后生成的标识值可使用函数IDENT_CURRENT,用法:
    SELECT IDENT_CURRENT('表名') 
    注意事项:当包含标识列的表刚刚创建,为经过任何插入操作时,使用IDENT_CURRENT函数得到的值为标识列的种子值,这一点在开发数据库应用程序的时候尤其应该注意。
      

  4.   


    CREATE TABLE T_test
    (ID int IDENTITY(1,1),
    Name varchar(50)
    )
    INSERT T_test(Name) VALUES('张三')select @@identity--这个就是当前会话(你向T_test表中插入信息)
      

  5.   

    楼主请参考:
    1.@@identity--全局
    2.@@scope_identity--当前语句执行后,该行返回的自增值
    3.@@ident_current('tableName')--指定表的最大自增值
      

  6.   

    你这种情况应该用 ident_current('tableName')。
    下面是MSDN上对@@identity, scope_identity和ident_current这三个函数的解释:
    ********************************************************************
    IDENT_CURRENT (Transact-SQL)返回为指定的表或视图生成的最后一个标识值。所生成的最后一个标识值可以针对任何会话和任何作用域。 Transact-SQL 语法约定  语法 IDENT_CURRENT( 'table_name' )
      参数 
    table_name 
    其标识值被返回的表的名称。table_name 的数据类型为 varchar,无默认值。  返回类型 
    numeric(38,0)   异常 
    出现错误时或调用方没有权限查看对象时,将返回 NULL。在 SQL Server 中,用户只能查看其拥有的安全对象的元数据,或者已对其授予权限的安全对象的元数据。这意味着,如果用户对对象没有任何权限,则元数据生成的内置函数(如 IDENT_CURRENT)可能返回 NULL。有关详细信息,请参阅元数据可见性配置和元数据可见性故障排除。  注释 
    IDENT_CURRENT 类似于 SQL Server 2000 标识函数 SCOPE_IDENTITY 和 @@IDENTITY。这三个函数都返回最后生成的标识值。但是,上述每个函数中定义的“最后”的作用域和会话有所不同。IDENT_CURRENT 返回为某个会话和用域中的指定表生成的最新标识值。@@IDENTITY 返回为跨所有作用域的当前会话中的某个表生成的最新标识值。SCOPE_IDENTITY 返回为当前会话和当前作用域中的某个表生成的最新标识值。
    如果 IDENT_CURRENT 值为 NULL(因为表从未包含行或已被截断),IDENT_CURRENT 函数将返回种子值。如果语句和事务失败,它们会更改表的当前标识,从而使标识列中的值出现不连贯现象。即使未提交试图向表中插入值的事务,也永远无法回滚标识值。例如,如果因 IGNORE_DUP_KEY 冲突而导致 INSERT 语句失败,表的当前标识值仍然会增加。请谨慎使用 IDENT_CURRENT 来预报下一个生成的标识值。由于其他会话执行的插入,实际生成的值可能与 IDENT_CURRENT 加上 IDENTITY_INCR 不同。  示例 
    A. 返回为指定表生成的最后一个标识值
    以下示例返回为 AdventureWorks 数据库中的 Person.Address 表生成的最后一个标识值。复制代码 
    USE AdventureWorks;
    GO
    SELECT IDENT_CURRENT ('Person.Address') AS Current_Identity;
    GO
    B. 比较 IDENT_CURRENT、@@IDENTITY 和 SCOPE_IDENTITY 返回的标识值
    以下示例将显示由 IDENT_CURRENT、@@IDENTITY 和 SCOPE_IDENTITY 返回的不同标识值。复制代码 
    USE AdventureWorks;
    GO
    IF OBJECT_ID(N't6', N'U') IS NOT NULL 
        DROP TABLE t6;
    GO
    IF OBJECT_ID(N't7', N'U') IS NOT NULL 
        DROP TABLE t7;
    GO
    CREATE TABLE t6(id int IDENTITY);
    CREATE TABLE t7(id int IDENTITY(100,1));
    GO
    CREATE TRIGGER t6ins ON t6 FOR INSERT 
    AS
    BEGIN
       INSERT t7 DEFAULT VALUES
    END;
    GO
    --End of trigger definitionSELECT id FROM t6;
    --id is empty.SELECT id FROM t7;
    --ID is empty.--Do the following in Session 1
    INSERT t6 DEFAULT VALUES;
    SELECT @@IDENTITY;
    /*Returns the value 100. This was inserted by the trigger.*/SELECT SCOPE_IDENTITY();
    /* Returns the value 1. This was inserted by the 
    INSERT statement two statements before this query.*/SELECT IDENT_CURRENT('t7');
    /* Returns value inserted into t7, that is in the trigger.*/SELECT IDENT_CURRENT('t6');
    /* Returns value inserted into t6. This was the INSERT statement four statements before this query.*/-- Do the following in Session 2.
    SELECT @@IDENTITY;
    /* Returns NULL because there has been no INSERT action 
    up to this point in this session.*/SELECT SCOPE_IDENTITY();
    /* Returns NULL because there has been no INSERT action 
    up to this point in this scope in this session.*/SELECT IDENT_CURRENT('t7');
    /* Returns the last value inserted into t7.*/