zoukankan      html  css  js  c++  java
  • (Coding for Concurrency).sql

    ---------------------------------------------------------------------------------------------
    -- Query Optimization Basics
    ---------------------------------------------------------------------------------------------

    SELECT  productModel.name as productModel,
            product.name as productName
    FROM    AdventureWorks2008.production.product as product
              join AdventureWorks2008.production.productModel as productModel
                     on productModel.productModelId = product.productModelId
    WHERE   product.name like '%glove%'


    ---------------------------------------------------------------------------------------------
    -- Transactions; Transaction Syntax; Basic Transactions
    ---------------------------------------------------------------------------------------------

    BEGIN TRANSACTION one
    ROLLBACK TRANSACTION one
    GO
    BEGIN TRANSACTION one
    BEGIN TRANSACTION two
    ROLLBACK TRANSACTION two
    GO
    ROLLBACK
    GO

    SELECT  recovery_model_desc
    FROM    sys.databases
    WHERE   name = 'AdventureWorks2008'
    GO

    USE Master
    GO

    ALTER DATABASE AdventureWorks2008
          SET RECOVERY FULL
    GO
    EXEC sp_addumpdevice 'disk', 'TestAdventureWorks2008', 'C:\Temp\AdventureWorks2008.bak'
    EXEC sp_addumpdevice 'disk', 'TestAdventureWorks2008Log',
                                  'C:\Temp\AdventureWorks2008Log.bak'
    GO
    BACKUP DATABASE AdventureWorks2008 TO TestAdventureWorks2008
    GO

    USE AdventureWorks2008
    GO
    SELECT count(*)
    FROM   SALES.SalesTaxRate

    BEGIN TRANSACTION Test WITH MARK 'Test'
    DELETE SALES.SalesTaxRate
    COMMIT TRANSACTION
    GP
    BACKUP LOG AdventureWorks2008  to TestAdventureWorks2008Log
    GO

    USE Master
    GO
    RESTORE DATABASE AdventureWorks2008 FROM TestAdventureWorks2008
                                                       WITH REPLACE, NORECOVERY
    go
    RESTORE LOG AdventureWorks2008 FROM TestAdventureWorks2008Log
                                                       WITH STOPBEFOREMARK = 'Test'
    GO
    USE AdventureWorks2008
    GO
    SELECT count(*)
    FROM   SALES.SalesTaxRate

    ---------------------------------------------------------------------------------------------
    -- Transactions; Transaction Syntax; Basic Transactions
    ---------------------------------------------------------------------------------------------
    Use tempdb
    go
    SELECT @@TRANCOUNT AS zeroDeep
    BEGIN TRANSACTION
    SELECT @@TRANCOUNT AS oneDeep
    GO

    BEGIN TRANSACTION
    SELECT @@TRANCOUNT AS twoDeep
    COMMIT TRANSACTION --commits very last transaction started with BEGIN TRANSACTION
    SELECT @@TRANCOUNT AS oneDeep
    GO

    COMMIT TRANSACTION
    SELECT @@TRANCOUNT AS zeroDeep

    GO


    BEGIN TRANSACTION
    BEGIN TRANSACTION
    BEGIN TRANSACTION
    BEGIN TRANSACTION
    BEGIN TRANSACTION
    BEGIN TRANSACTION
    BEGIN TRANSACTION
    SELECT @@trancount as InTran
    ROLLBACK TRANSACTION
    SELECT @@trancount as OutTran

    GO

    COMMIT TRANSACTION
    GO

    ---------------------------------------------------------------------------------------------
    -- Transactions; Transaction Syntax; savepoints
    ---------------------------------------------------------------------------------------------
    GO
    CREATE SCHEMA arts
    CREATE TABLE arts.performer
    (
        performerId int identity,
        name varchar(100)
     )
    GO
    BEGIN TRANSACTION
    INSERT INTO arts.performer(name) VALUES ('Elvis Costello')

    SAVE TRANSACTION savePoint

    INSERT INTO arts.performer(name) VALUES ('Air Supply')

    --don't insert Air Supply, yuck! ...
    ROLLBACK TRANSACTION savePoint

    COMMIT TRANSACTION

    SELECT *
    FROM arts.performer
    GO

    ---------------------------------------------------------------------------------------------
    -- Transactions; Compiled SQL Server Code; Stored Procedures
    ---------------------------------------------------------------------------------------------
    CREATE PROCEDURE tranTest
    AS
    BEGIN
      SELECT @@TRANCOUNT AS trancount

      BEGIN TRANSACTION
      ROLLBACK TRANSACTION
    END
    GO
    BEGIN TRANSACTION
    EXECUTE tranTest
    COMMIT TRANSACTION
    GO

    ALTER PROCEDURE tranTest
    AS
    BEGIN
      --gives us a unique savepoint name, trim it to 125 characters if the
      --user named the procedure really really large, to allow for nestlevel
      DECLARE @savepoint nvarchar(128) =
          cast(object_name(@@procid) AS nvarchar(125)) +
                             cast(@@nestlevel AS nvarchar(3))

      BEGIN TRANSACTION
      SAVE TRANSACTION @savepoint
        --do something here
      ROLLBACK TRANSACTION @savepoint
      COMMIT TRANSACTION
    END
    GO

    BEGIN TRANSACTION
    EXECUTE tranTest
    COMMIT TRANSACTION
    GO


    ALTER PROCEDURE tranTest
    AS
    BEGIN
      --gives us a unique savepoint name, trim it to 125
      --characters if the user named it really large
      DECLARE @savepoint nvarchar(128) =
                   cast(object_name(@@procid) AS nvarchar(125)) +
                                          cast(@@nestlevel AS nvarchar(3))
      --get initial entry level, so we can do a rollback on a doomed transaction
      DECLARE @entryTrancount int = @@trancount

      BEGIN TRY
        BEGIN TRANSACTION
        SAVE TRANSACTION @savepoint

        --do something here
        RAISERROR ('Invalid Operation',16,1)

        COMMIT TRANSACTION
      END TRY
      BEGIN CATCH

       --if the tran is doomed, and the entryTrancount was 0
       --we have to rollback   
        IF xact_state()= -1 and @entryTrancount = 0
            rollback transaction
        --otherwise, we can still save the other activities in the
        --transaction.
        ELSE IF xact_state() = 1 --transaction not doomed, but open
           BEGIN
             ROLLBACK TRANSACTION @savepoint
             COMMIT TRANSACTION
           END

        DECLARE @ERRORmessage nvarchar(4000)
        SET @ERRORmessage = 'Error occurred in procedure ''' + object_name(@@procid)
                            + ''', Original Message: ''' + ERROR_MESSAGE() + ''''
        RAISERROR (@ERRORmessage,16,1)
        RETURN -100
      END CATCH
    END
    GO

    CREATE SCHEMA menu
    CREATE TABLE menu.foodItem
    (
        foodItemId int not null IDENTITY(1,1)
            CONSTRAINT PKmenu_foodItem PRIMARY KEY,
        name varchar(30) not null
            CONSTRAINT AKmenu_foodItem_name UNIQUE,
        description varchar(60) not null,
            CONSTRAINT CHKmenu_foodItem_name CHECK (name <> ''),
            CONSTRAINT CHKmenu_foodItem_description CHECK (description <> '')
    )
    GO

    CREATE PROCEDURE menu.foodItem$insert
    (
        @name   varchar(30),
        @description varchar(60),
        @newFoodItemId int = null output --we will send back the new id here
    )
    AS
    BEGIN
      SET NOCOUNT ON

      --gives us a unique savepoint name, trim it to 125
      --characters if the user named it really large
      DECLARE @savepoint nvarchar(128) =
                   cast(object_name(@@procid) AS nvarchar(125)) +
                                          cast(@@nestlevel AS nvarchar(3))
      --get initial entry level, so we can do a rollback on a doomed transaction
      DECLARE @entryTrancount int = @@trancount

      BEGIN TRY
        BEGIN TRANSACTION
        SAVE TRANSACTION @savepoint

        INSERT INTO menu.foodItem(name, description)
        VALUES (@name, @description)

        SET @newFoodItemId = scope_identity() --if you use an instead of trigger
                                              --you will have to use name as a key
                                              --to do the identity "grab" in a SELECT
                                              --query

        COMMIT TRANSACTION
      END TRY
      BEGIN CATCH

       --if the tran is doomed, and the entryTrancount was 0
       --we have to rollback   
        IF xact_state()= -1 and @entryTrancount = 0
            rollback transaction
        --otherwise, we can still save the other activities in the
        --transaction.
        ELSE IF xact_state() = 1 --transaction not doomed, but open
           BEGIN
             ROLLBACK TRANSACTION @savepoint
             COMMIT TRANSACTION
           END

        DECLARE @ERRORmessage nvarchar(4000)
        SET @ERRORmessage = 'Error 0ccurred in procedure ''' + object_name(@@procid)
                            + ''', Original Message: ''' + ERROR_MESSAGE() + ''''
        RAISERROR (@ERRORmessage,16,1)
        RETURN -100
      END CATCH
    END
    GO

    DECLARE @foodItemId int, @retval int
    EXECUTE @retval = menu.foodItem$insert  @name ='Burger',
                                            @description = 'Mmmm Burger',
                                            @newFoodItemId = @foodItemId output
    SELECT  @retval as returnValue
    IF @retval >= 0
        SELECT  foodItemId, name, description
        FROM    menu.foodItem
        where   foodItemId = @foodItemId
    GO

    DECLARE @foodItemId int, @retval int
    EXECUTE @retval = menu.foodItem$insert  @name ='Big Burger',
                                            @description = '',
                                            @newFoodItemId = @foodItemId output
    SELECT  @retval as returnValue
    IF @retval >= 0
        SELECT  foodItemId, name, description
        FROM    menu.foodItem
        where   foodItemId = @foodItemId
    GO


    ---------------------------------------------------------------------------------------------
    -- Transactions; Compiled SQL Server Code; Triggers
    ---------------------------------------------------------------------------------------------

    CREATE TRIGGER menu.foodItem$InsertTrigger
    ON menu.foodItem
    AFTER INSERT
    AS
    BEGIN
       DECLARE @rowsAffected int,    --stores the number of rows affected
               @msg varchar(2000)    --used to hold the error message

       SET @rowsAffected = @@rowcount

       --no need to continue on if no rows affected
       IF @rowsAffected = 0 return
     
       SET NOCOUNT ON --to avoid the rowcount messages
       SET ROWCOUNT 0 --in case the client has modified the rowcount

       BEGIN TRY
            --[validation blocks][validation section]
            RAISERROR ('FoodItem''s cannot be done that way',16,1)
           --[modification blocks][modification section]
       END TRY
       BEGIN CATCH
                  IF @@trancount > 0
                      ROLLBACK TRANSACTION

                  DECLARE @ERROR_MESSAGE nvarchar(4000)
                  SET @ERROR_MESSAGE = ERROR_MESSAGE()
                  RAISERROR (@ERROR_MESSAGE,16,1)

         END CATCH
    END

    GO

    ALTER PROCEDURE menu.foodItem$insert --modded error handler to return positional output
    (
        @name   varchar(30),
        @description varchar(60),
        @newFoodItemId int = null output --we will send back the new id here
    )
    AS
    BEGIN
      SET NOCOUNT ON

      --gives us a unique savepoint name, trim it to 125
      --characters if the user named it really large
      DECLARE @savepoint nvarchar(128) =
                   cast(object_name(@@procid) AS nvarchar(125)) +
                                          cast(@@nestlevel AS nvarchar(3))
      --get initial entry level, so we can do a rollback on a doomed transaction
      DECLARE @entryTrancount int = @@trancount

      BEGIN TRY
        BEGIN TRANSACTION
        SAVE TRANSACTION @savepoint

        INSERT INTO menu.foodItem(name, description)
        VALUES (@name, @description)

        SET @newFoodItemId = scope_identity() --if you use an instead of trigger
                                              --you will have to use name as a key
                                              --to do the identity "grab" in a SELECT
                                              --query

        COMMIT TRANSACTION
      END TRY
      BEGIN CATCH
       SELECT 'In error handler'

       --if the tran is doomed, and the entryTrancount was 0
       --we have to rollback   
        IF xact_state()= -1 and @entryTrancount = 0
         begin 
            SELECT 'Transaction Doomed'
            ROLLBACK TRANSACTION
         end
        --otherwise, we can still save the other activities in the
        --transaction.
        ELSE IF xact_state() = 1 --transaction not doomed, but open
           BEGIN
             SELECT 'Savepoint Rollback'
             ROLLBACK TRANSACTION @savepoint
             COMMIT TRANSACTION
           END


        DECLARE @ERRORmessage nvarchar(4000)
        SET @ERRORmessage = 'Error 0ccurred in procedure ''' + object_name(@@procid)
                            + ''', Original Message: ''' + ERROR_MESSAGE() + ''''
        RAISERROR (@ERRORmessage,16,1)
        RETURN -100
      END CATCH
    END
    GO

    DECLARE @foodItemId int, @retval int
    EXECUTE @retval = menu.foodItem$insert  @name ='Big Burger',
                                            @description = '',
                                            @newFoodItemId = @foodItemId output
    SELECT @retval
    GO

    DECLARE @foodItemId int, @retval int
    EXECUTE @retval = menu.foodItem$insert  @name ='Big Burger',
                                            @description = 'Yummy Big Burger',
                                            @newFoodItemId = @foodItemId output
    SELECT @retval
    GO

    ALTER TRIGGER menu.foodItem$InsertTrigger
    ON menu.foodItem
    AFTER INSERT
    AS
    BEGIN
       DECLARE @rowsAffected int,    --stores the number of rows affected
               @msg varchar(2000)    --used to hold the error message

       SET @rowsAffected = @@rowcount

       --no need to continue on if no rows affected
       IF @rowsAffected = 0 return
     
       SET NOCOUNT ON --to avoid the rowcount messages
       SET ROWCOUNT 0 --in case the client has modified the rowcount

       RAISERROR ('FoodItem''s cannot be done that way',16,1)
     
    END
    GO

    DECLARE @foodItemId int, @retval int
    EXECUTE @retval = menu.foodItem$insert  @name ='Big Burger',
                                            @description = 'Yummy Big Burger',
                                            @newFoodItemId = @foodItemId output
    SELECT @retval
    GO

    ----------------------------------------------------------------------------------
    --SQL Server Concurrency Controls; Isolation Levels
    ----------------------------------------------------------------------------------
    GO
    CREATE TABLE dbo.testIsolationLevel
    (
       testIsolationLevelId int identity(1,1)
                    CONSTRAINT PKtestIsolationLevel PRIMARY KEY,
       value varchar(10)
    )

    INSERT dbo.testIsolationLevel(value)
    VALUES ('Value1'),
           ('Value2')
    GO

    SELECT  case transaction_isolation_level
                when 1 then 'Read Uncomitted'      when 2 then 'Read Committed'
                when 3 then 'Repeatable Read'      when 4 then 'Serializable'
                when 5 then 'Snapshot'             else 'Unspecified'
             end
    FROM    sys.dm_exec_sessions
    WHERE  session_id = @@spid
    GO
    ----------------------------------------------------------------------------------
    --SQL Server Concurrency Controls; Isolation Levels; READ UNCOMMITTED
    ----------------------------------------------------------------------------------

    --CONNECTION A
    SET TRANSACTION ISOLATION LEVEL READ COMMITTED --this is the default, just
                                                   --setting for emphasis
    BEGIN TRANSACTION
    INSERT INTO dbo.testIsolationLevel(value)
    VALUES('Value3')
    GO

    --CONNECTION B
    SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
    SELECT *
    FROM dbo.testIsolationLevel
    GO
    --CONNECTION A

    COMMIT TRANSACTION
    GO

    ----------------------------------------------------------------------------------
    --SQL Server Concurrency Controls; Isolation Levels; READ COMMITTED
    ----------------------------------------------------------------------------------

    --CONNECTION A

    SET TRANSACTION ISOLATION LEVEL READ COMMITTED

    BEGIN TRANSACTION
    SELECT * FROM dbo.testIsolationLevel
    GO
    --CONNECTION B

    DELETE FROM dbo.testIsolationLevel
    WHERE testIsolationLevelId = 1
    GO

    --CONNECTION A
    SELECT *
    FROM dbo.testIsolationLevel
    COMMIT TRANSACTION

    GO
    ----------------------------------------------------------------------------------
    --SQL Server Concurrency Controls; Isolation Levels; REPEATABLE READ
    ----------------------------------------------------------------------------------
    --CONNECTION A

    SET TRANSACTION ISOLATION LEVEL REPEATABLE READ

    BEGIN TRANSACTION
    SELECT * FROM dbo.testIsolationLevel
    GO
    --CONNECTION B

    INSERT INTO dbo.testIsolationLevel(value)
    VALUES ('Value4')
    GO
    --CONNECTION B
    DELETE FROM dbo.testIsolationLevel
    WHERE value = 'Value3'

    GO
    --CONNECTION A

    SELECT * FROM dbo.testIsolationLevel
    COMMIT TRANSACTION

    GO

    ----------------------------------------------------------------------------------
    --SQL Server Concurrency Controls; Isolation Levels; SERIALIZABLE
    ----------------------------------------------------------------------------------
    --CONNECTION A

    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

    BEGIN TRANSACTION
    SELECT * FROM dbo.testIsolationLevel
    GO
    --CONNECTION B

    INSERT INTO dbo.testIsolationLevel(value)
    VALUES ('Value5')
    GO
    --CONNECTION A

    SELECT * FROM dbo.testIsolationLevel
    COMMIT TRANSACTION
    GO
    ----------------------------------------------------------------------------------
    --SQL Server Concurrency Controls; Isolation Levels; SNAPSHOT
    ----------------------------------------------------------------------------------
    ALTER DATABASE tempDb
    SET ALLOW_SNAPSHOT_ISOLATION ON
    GO
    --CONNECTION A

    SET TRANSACTION ISOLATION LEVEL SNAPSHOT
    BEGIN TRANSACTION
    SELECT * from dbo.testIsolationLevel
    GO
    --CONNECTION B

    SET TRANSACTION ISOLATION LEVEL READ COMMITTED
    INSERT INTO dbo.testIsolationLevel(value)
    VALUES ('Value6')

    GO

    --CONNECTION B

    DELETE FROM dbo.testIsolationLevel
    WHERE  value = 'Value4'
    GO

    --CONNECTION A

    UPDATE  dbo.testIsolationLevel
    SET     value = 'Value2-mod'
    WHERE   testIsolationLevelId = 2
    GO

    --CONNECTION A

    COMMIT TRANSACTION
    SELECT * from dbo.testIsolationLevel
    GO

    --CONNECTION A
    SET TRANSACTION ISOLATION LEVEL SNAPSHOT
    BEGIN TRANSACTION

    --touch the data
    SELECT * FROM dbo.testIsolationLevel

    GO
    --CONNECTION B
    SET TRANSACTION ISOLATION LEVEL READ COMMITTED --any will do

    UPDATE dbo.testIsolationLevel
    SET    value = 'Value5-mod'
    WHERE  testIsolationLevelId = 5 --might be different in yours
    GO

    --CONNECTION A
    UPDATE dbo.testIsolationLevel
    SET   value = 'Value5-mod'
    WHERE testIsolationLevelId = 5 --might be different in yours
    GO

    ----------------------------------------------------------------------------------
    --Coding for Integrity and Concurrency; Pessimistic Locking
    ----------------------------------------------------------------------------------

    --CONNECTION A

    BEGIN TRANSACTION
       DECLARE @result int
       EXEC @result = sp_getapplock @Resource = 'invoiceId=1', @LockMode = 'Exclusive'
       SELECT @result
    GO

    --CONNECTION B
    BEGIN TRANSACTION
       DECLARE @result int
       EXEC @result = sp_getapplock @Resource = 'invoiceId=1', @LockMode = 'Exclusive'
       PRINT @result
    GO

    --CONNECTION B

    BEGIN TRANSACTION
    SELECT  APPLOCK_TEST('public','invoiceId=1','Exclusive','Transaction')
                                                            as CanTakeLock
    ROLLBACK TRANSACTION
    GO

    --CLEANUP on Connection A
    ROLLBACK TRANSACTION
    GO

    create table applock
    (
        applockId int primary key,  --the value that we will be generating
                                    --with the procedure
        connectionId int,           --holds the spid of the connection so you can
                                    --who creates the row
        insertTime datetime default (getdate()) --the time the row was created, so
                                                 --you can see the progression
    )

    GO

    create procedure applock$test
    (
        @connectionId int,
        @useApplockFlag bit = 1,
        @stepDelay varchar(10) = '00:00:00'
    ) as
    set nocount on
    begin try
        begin transaction
            declare @retval int = 1
            if @useApplockFlag = 1 --turns on and off the applock for testing
                begin
                    exec @retval = sp_getapplock @Resource = 'applock$test',
                                                        @LockMode = 'exclusive';
                    if @retval < 0
                        begin
                            declare @errorMessage nvarchar(200)
                            set @errorMessage = case @retval
                                        when -1 then 'Applock request timed out.'
                                        when -2 then 'Applock request canceled.'
                                        when -3 then 'Applock involved in deadlock'
                                    else 'Parameter validation or other call error.'
                                                 end
                            raiserror (@errorMessage,16,1)
                        end
                end

        --get the next primary key value
        declare @applockId int   
        set @applockId = coalesce((select max(applockId) from applock),0) + 1

        --delay for parameterized amount of time to slow down operations
        --and guarantee concurrency problems
        waitfor delay @stepDelay

        --insert the next value
        insert into applock(applockId, connectionId)
        values (@applockId, @connectionId)

        --won't have much effect on this code, since the row will now be
        --exclusively locked, and the max will need to see the new row to
        --be of any effect.
        exec @retval = sp_releaseapplock @Resource = 'applock$test'

        --this releases the applock too
        commit transaction
    end try
    begin catch
        --if there is an error, rollback and display it.
        if @@trancount > 0
            rollback transaction
            select cast(error_number() as varchar(10)) + ':' + error_message()
    end catch

    GO
    waitfor time '23:46' --set for a time to run so multiple batches
                                --can simultaneously execute
    go
    exec applock$test @@spid, 1 -- <1=use applock, 0 = don't use applock>,
                ,'00:00:00.001'--'delay in hours:minutes:seconds.parts of seconds'
    go 10000 --runs the batch 10000 times in SSMS
    GO


    ----------------------------------------------------------------------------------
    --Coding for Integrity and Concurrency; Optimistic Locking; Adding Optimistic Lock Columns
    ----------------------------------------------------------------------------------
    GO
    CREATE SCHEMA hr
    CREATE TABLE hr.person
    (
         personId int IDENTITY(1,1) CONSTRAINT PKperson primary key,
         firstName varchar(60) NOT NULL,
         middleName varchar(60) NOT NULL,
         lastName varchar(60) NOT NULL,

         dateOfBirth date NOT NULL,
         rowLastModifyTime datetime NOT NULL
             CONSTRAINT DFLTperson_rowLastModifyTime default getdate(),
         rowModifiedByUserIdentifier nvarchar(128) NOT NULL
             CONSTRAINT DFLTperson_rowModifiedByUserIdentifier default suser_sname()

    )
    GO

    CREATE TRIGGER hr.person$InsteadOfUpdate
    ON hr.person
    INSTEAD OF UPDATE AS
    BEGIN

        --stores the number of rows affected
       DECLARE @rowsAffected int = @@rowcount,
               @msg varchar(2000) = ''    --used to hold the error message

          --no need to continue on if no rows affected
       IF @rowsAffected = 0 return

       SET NOCOUNT ON --to avoid the rowcount messages
       SET ROWCOUNT 0 --in case the client has modified the rowcount

       BEGIN TRY
              --[validation blocks]
              --[modification blocks]
              --remember to update ALL columns when building instead of triggers
              UPDATE hr.person
              SET    firstName = inserted.firstName,
                     middleName = inserted.middleName,
                     lastName = inserted.lastName,
                     dateOfBirth = inserted.dateOfBirth,
                     rowLastModifyTime = default, -- set the value to the default
                     rowModifiedByUserIdentifier = default
              FROM   hr.person                             
                         JOIN inserted
                                 on hr.person.personId = inserted.personId
       END TRY
       BEGIN CATCH
                  IF @@trancount > 0
                     ROLLBACK TRANSACTION

                  --EXECUTE dbo.errorLog$insert

                  DECLARE @ERROR_MESSAGE varchar(8000)
                  SET @ERROR_MESSAGE = ERROR_MESSAGE()
                  RAISERROR (@ERROR_MESSAGE,16,1)

         END CATCH
    END

    GO

    INSERT INTO hr.person (firstName, middleName, lastName, dateOfBirth)
    VALUES ('Paige','O','Anxtent','19391212')

    SELECT *
    FROM   hr.person
    GO

    UPDATE hr.person
    SET     middleName = 'Ona'
    WHERE   personId = 1

    SELECT rowLastModifyTime
    FROM   hr.person

    GO

    ALTER TABLE hr.person
      ADD rowversion rowversion
    GO
    SELECT personId, rowversion
    FROM   hr.person
    GO
    UPDATE  hr.person
    SET     firstName = 'Paige' --no actual change occurs
    WHERE   personId = 1
    Go
    SELECT personId, rowversion
    FROM   hr.person
    GO

    ----------------------------------------------------------------------------------
    --Coding for Integrity and Concurrency; Optimistic Locking; Coding for Row-Level Optimistic Locking
    ----------------------------------------------------------------------------------
    GO
    UPDATE  hr.person
    SET     firstName = 'Headley'
    WHERE   personId = 1  --include the key
      and   firstName = 'Paige'
      and   middleName = 'ona'
      and   lastName = 'Anxtent'
      and   dateOfBirth = '19391212'
    GO
    UPDATE  hr.person
    SET     firstName = 'Fred'
    WHERE   personId = 1  --include the key
      and   rowLastModifyTime = '2005-07-30 00:28:28.397'
    GO
    UPDATE  hr.person
    SET     firstName = 'Fred'
    WHERE   personId = 1
      and   rowversion = 0x00000000000007D3
    GO
    DELETE FROM hr.person
    WHERE   personId = 1
      And   rowversion = 0x00000000000007D3
    GO
    ----------------------------------------------------------------------------------
    --Coding for Integrity and Concurrency; Optimistic Locking; Logical Unit of Work
    ----------------------------------------------------------------------------------

    CREATE SCHEMA invoicing
    go
    --leaving off who invoice is for
    CREATE TABLE invoicing.invoice
    (
         invoiceId int IDENTITY(1,1),
         number varchar(20) NOT NULL,
         objectVersion rowversion not null,
         constraint PKinvoicing_invoice primary key (invoiceId)
    )
    --also forgetting what product that the line item is for
    CREATE TABLE invoicing.invoiceLineItem

    (
         invoiceLineItemId int NOT NULL,
         invoiceId int NULL,
         itemCount int NOT NULL,
         cost int NOT NULL,
          constraint PKinvoicing_invoiceLineItem primary key (invoiceLineItemId),
          constraint FKinvoicing_invoiceLineItem$references$invoicing_invoice
                foreign key (invoiceId) references invoicing.invoice(invoiceId)
    )
    GO

    CREATE PROCEDURE invoiceLineItem$del
    (
        @invoiceId int, --we pass this because the client should have it
                        --with the invoiceLineItem row
        @invoiceLineItemId int,
        @objectVersion rowversion
    ) as
      BEGIN
        --gives us a unique savepoint name, trim it to 125
        --characters if the user named it really large
        DECLARE @savepoint nvarchar(128) =
                              cast(object_name(@@procid) AS nvarchar(125)) +
                                             cast(@@nestlevel AS nvarchar(3))
        --get initial entry level, so we can do a rollback on a doomed transaction
        DECLARE @entryTrancount int = @@trancount

        BEGIN TRY
            BEGIN TRANSACTION
            SAVE TRANSACTION @savepoint

            UPDATE  invoice
            SET     number = number
            WHERE   invoiceId = @invoiceId
              And   objectVersion = @objectVersion

            DELETE  invoiceLineItem
            FROM    invoiceLineItem
            WHERE   invoiceLineItemId = @invoiceLineItemId

            COMMIT TRANSACTION

        END TRY
        BEGIN CATCH

            --if the tran is doomed, and the entryTrancount was 0
            --we have to rollback   
            IF xact_state()= -1 and @entryTrancount = 0
                rollback transaction
            --otherwise, we can still save the other activities in the
           --transaction.
           ELSE IF xact_state() = 1 --transaction not doomed, but open
             BEGIN
                 ROLLBACK TRANSACTION @savepoint
                 COMMIT TRANSACTION
             END

        DECLARE @ERRORmessage nvarchar(4000)
        SET @ERRORmessage = 'Error occurred in procedure ''' +
              object_name(@@procid) + ''', Original Message: '''
              + ERROR_MESSAGE() + ''''
        RAISERROR (@ERRORmessage,16,1)
        RETURN -100

         END CATCH
     END

  • 相关阅读:
    C# 文件夹的常用操作
    c语言学习笔记---预编译
    linux学习笔记
    c语言学习笔记---符号
    vim 编辑基础使用-----linux编程
    用pywinauto进行win32应用程序的测试
    Python中下划线的使用方法
    创建可维护的自动化验收测试
    Appium+Robotframework实现Android应用的自动化测试-1:Appium在Windows中的安装
    在中文windows下使用pywinauto进行窗口操作
  • 原文地址:https://www.cnblogs.com/dushu/p/2509034.html
Copyright © 2011-2022 走看看