我正在尝试验证注册表单,以检查用户名/姓名+姓氏是否已经存在。
这是我尝试过的:
Dim conn As New SqlConnection("Data Source=BRIAN-PC\SQLEXPRESS;Initial Catalog=master_db;Integrated Security=True")
Dim registerSQL As SqlCommand
Dim checkCredentialsSQL As SqlCommand
Dim sqlComm As String
Dim sqlCommName As String
Dim sqlCommUsername As String
sqlComm = "INSERT INTO users(Username, Password, Name, Surname, Address1, Address2, " +
"City, Country, date_of_birth, age, Occupation, department, work_location, " +
"project_manager,team_leader, team_leader_id, project_manager_id, " +
"date_registration, contract_type, contract_duration) " +
"VALUES(@p1, @p2,@p3,@p4,@p5,@p6,@p7,@p8,@p9,@p10,@p11,@p12,@p13,@p14,@p15," +
"@p16,@p17,@p18,@p19,@p20)"
sqlCommName = "SELECT name, surname FROM users WHERE name='" + txtName.Text + "' and surname='" + txtSurname.Text + "'"
sqlCommUsername = "SELECT username FROM users WHERE username='" + txtUsername.Text + "'"
conn.Open()
checkCredentialsSQL = New SqlCommand(sqlCommName, conn)
If checkCredentialsSQL.ExecuteScalar IsNot Nothing Then
lblName.Text = txtName.Text + " " + txtSurname.Text + "is already registered."
lblName.Visible = True
Else
checkCredentialsSQL = New SqlCommand(sqlCommUsername, conn)
If checkCredentialsSQL.ExecuteScalar IsNot Nothing Then
lblUsername.Text = "'" + txtUsername.Text + "' is already taken."
Else
registerSQL = New SqlCommand(sqlComm, conn)
registerSQL.Parameters.AddWithValue("@p1", Username)
registerSQL.Parameters.AddWithValue("@p2", Password)
registerSQL.Parameters.AddWithValue("@p3", Name)
registerSQL.Parameters.AddWithValue("@p4", Surname)
registerSQL.Parameters.AddWithValue("@p5", Address1)
registerSQL.Parameters.AddWithValue("@p6", Address2)
registerSQL.Parameters.AddWithValue("@p7", City)
registerSQL.Parameters.AddWithValue("@p8", Country)
registerSQL.Parameters.AddWithValue("@p9", DOB)
registerSQL.Parameters.AddWithValue("@p10", Age)
registerSQL.Parameters.AddWithValue("@p11", Occupation)
registerSQL.Parameters.AddWithValue("@p12", Department)
registerSQL.Parameters.AddWithValue("@p13", WorkLocation)
registerSQL.Parameters.AddWithValue("@p14", ProjectManager)
registerSQL.Parameters.AddWithValue("@p15", TeamLeader)
registerSQL.Parameters.AddWithValue("@p16", TeamLeaderID)
registerSQL.Parameters.AddWithValue("@p17", ProjectManagerID)
registerSQL.Parameters.AddWithValue("@p18", RegistrationDate)
registerSQL.Parameters.AddWithValue("@p19", ContractType)
registerSQL.Parameters.AddWithValue("@p20", ContractDuration)
registerSQL.ExecuteNonQuery()
End If
End If
conn.Close()
这样做可行/安全/推荐吗?
发布于 2013-03-30 19:17:31
下面是一个简单的存储过程,它检查您想要检查的两个条件(下面将详细介绍):
CREATE PROCEDURE dbo.CreateUser
@username NVARCHAR(255),
@name NVARCHAR(64),
@surname NVARCHAR(64)
/* ... other params ... */
AS
BEGIN
SET NOCOUNT ON;
IF EXISTS (SELECT 1 FROM dbo.users WHERE username = @username)
BEGIN
RAISERROR('Username %s is already registered.', 11, 1, @username);
RETURN -1;
END
IF EXISTS (SELECT 1 FROM dbo.users WHERE name = @name AND surname = @surname)
BEGIN
RAISERROR('Name %s %s is already registered.', 11, 1, @name, @surname);
RETURN -2;
END
BEGIN TRY
INSERT dbo.Users(username, name, surname, ...other columns...)
SELECT @username, @name, @suername, ...other params...;
END TRY
BEGIN CATCH
DECLARE @msg NVARCHAR(255) = ERROR_MESSAGE();
RAISERROR(@msg, 11, 1);
RETURN -3;
END CATCH
END
现在,您的VB.Net代码就简单多了:
Dim conn As New SqlConnection("...conn string...")
conn.Open()
Dim sql As New SqlCommand("dbo.CreateUser", conn)
sql.CommandType = CommandType.StoredProcedure
rv = sql.Parameters.Add("@rv", SqlDbType.Int)
rv.Direction = ParameterDirection.ReturnValue
sql.Parameters.AddWithValue("@username", Username)
sql.Parameters.AddWithValue("@name", Name)
sql.Parameters.AddWithValue("@surname", Surname)
... other params ...
sql.ExecuteNonQuery()
Debug.Print "Return value: " & rv.ToString
...act accordingly depending on error raised and/or return value
...maybe you want TRY/CATCH here?
conn.Close()
虽然尝试插入(使用WHERE
子句,或者只是让约束引发错误)在技术上可能是一种可行的方法,但我不认为这是一个好主意。第一个原因是您的代码不能告诉您是哪种情况导致了问题,第二个原因是让SQL Server为您引发异常的代价非常高:
http://www.sqlperformance.com/2012/08/t-sql-queries/error-handling
当然,这并不意味着你不应该有潜在的约束。它们应该在用户不通过存储过程、应用层等的情况下使用。
哦,我同意其他人的观点。你真的认为只有一个约翰·史密斯会注册吗?与他人同名并不是阻止某人注册IMHO的一个非常有效的理由。
另外,如果我的VB.Net代码远不完美,我向您道歉。我不是用VB写的,其中一些是有根据的猜测……
发布于 2013-03-30 18:05:04
sqlCommName
命令不受SQL注入的保护。如果txtName.Text
包含existing_username AND 1 = 0
,则用户可以注册两次。
发布于 2013-03-30 18:51:59
尽管我不同意您使用的标准(因为name+surname几乎肯定不是一个人的惟一标识符),但一般形式应该是一个尝试的INSERT
INSERT INTO TabA (Val1,Val2,Val3)
SELECT @Val1,@Val2,@Val3
WHERE NOT EXISTS (SELECT * FROM TabA where Val1 = @Val1 or (Val2 = @Val2 and Val3 = @Val3)
否则,您仍然将自己暴露在竞争条件下。
而且,根据您正在运行的并发设置,您可能仍然需要处理违反约束的情况(我假设您也在数据库级别强制执行任何唯一性约束)。
https://stackoverflow.com/questions/15721596
复制相似问题