【问题标题】:SQL stored procedure parameters - approachSQL 存储过程参数 - 方法
【发布时间】:2018-11-20 22:56:48
【问题描述】:

我正在开发相对简单的数据库,用于管理生产工厂的用户、硬件和软件。

我不是数据库主题的专家。下面附上数据库片段:

https://i.stack.imgur.com/I0BD7.png

我决定始终使用整数代理键,即使登录或权限等字段是唯一的。

这个数据库将被许多类型的软件使用,它们并不总是有像样的 ORM,我决定使用 StoredProcedures 与 DB 交互

我的问题是关于存储过程及其参数。例如 usp_AddUserRole 可以定义如下:

IF NOT EXISTS (select * from dbo.sysobjects where id = object_id(N'[User].[usp_AddUserRole]') and OBJECTPROPERTY(id, N'IsProcedure') = 1)
EXEC
('CREATE PROCEDURE [User].[usp_AddUserRole] AS SET NOCOUNT ON')
GO

GRANT EXECUTE ON [User].[usp_AddUserRole] TO sp_executor
GO

ALTER PROCEDURE [User].[usp_AddUserRole]
    @UserID numeric(18,0), 
    @RoleID numeric(18,0) AS
SET XACT_ABORT, NOCOUNT ON

BEGIN TRY
BEGIN TRANSACTION

    INSERT INTO [User].[User_Role] (
        [UserID]
        ,[RoleID]
        )
    VALUES (
        @UserID
        ,@RoleID
        )

COMMIT TRANSACTION
END TRY

BEGIN CATCH
    IF @@trancount > 0 ROLLBACK TRANSACTION
    ;THROW
    RETURN -1
END CATCH
GO

但这在我看来不是用户友好的。 我也可以通过 Login 和 Role 值直接执行此操作,并在存储过程中解析 ID:

ALTER PROCEDURE [User].[usp_AddUserRole]
    @Login varchar(30), 
    @Role varchar(50) AS
SET XACT_ABORT, NOCOUNT ON

BEGIN TRY
BEGIN TRANSACTION

    DECLARE @UserID numeric = (SELECT UserID FROM [User].[User] WHERE [Login] = @Login)
    DECLARE @RoleID numeric = (SELECT RoleID FROM [User].[Role] WHERE [Name] = @Role)

    INSERT INTO [User].[User_Role] (
        [UserID]
        ,[RoleID]
        )
    VALUES (
        @UserID
        ,@RoleID
        )

COMMIT TRANSACTION
END TRY

BEGIN CATCH
    IF @@trancount > 0 ROLLBACK TRANSACTION
    ;THROW
    RETURN -1
END CATCH
GO

这个存储过程以后会被一些网络服务调用。 你知道应该使用什么方法以及为什么?

谢谢!

【问题讨论】:

  • 这是基于选项的,两种方法都可以。如果你手头总是有Id's,那么第一个会快一点。我确实想知道RETURN -1 语句是否仍会在;THROW 之后被调用

标签: sql sql-server web-services stored-procedures architecture


【解决方案1】:

这两种方法都可以接受。最好有两个重构的存储过程:usp_AddUserRoleByNames 读取 ID,然后调用 usp_AddUserRoleByIDs

在存储过程中通过名称解析 ID 时:

  • 至少应将事务隔离设置为 REPEATABLE READ 以防止修改/删除已读取的数据
  • 检查 ID 的 NULL 值
  • 检查用户角色链接是否不存在(需要SERIALISABLE 级别)
  • 不要混用返回错误码和抛出异常的方法

【讨论】:

  • 您能否详细说明您的第一点,事务隔离,请
  • 例如,SELECT中读取的@UserID可能在INSERT之前被另一个事务(进程)修改甚至删除。 DBMS 支持不同的标准事务隔离级别。在"Transaction, isolation and locks"章节中查看更多细节和示例
  • 是的,我知道,我只是认为这个解释应该在你的回答中
  • 感谢您的宝贵意见。如果有人决定在插入语句发生之前删除@UserID,则会在此 SP 中引发 FK 约束错误,因此不存在无效数据的风险。如果我对隔离级别的理解正确,我可以例如对选定的行强制“锁定”,直到此事务结束?
  • @pawhan11 您也可以手动锁定数据,即使用HOLDLOCK 提示,但与 SQL Server 引擎根据当前隔离级别设置的锁定相比,它的效率可能较低。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多