MS SQL Server에서 전체 테이블을 잠그지 않도록 SQL 삽입 및 / 또는 업데이트를 얻는 방법


13

DB 작업에 대한 초보자가 많으므로 기본적인 질문으로 인내심을 가져 주셔서 감사합니다. 로컬 컴퓨터에서 SQL Server 2014를 실행하고 있으며 작은 테이블과 기본 클라이언트 응용 프로그램으로 다양한 접근 방식을 테스트 할 수 있습니다. INSERT INTOUPDATE문 모두에서 테이블 잠금으로 보이는 것을 얻고 있습니다 . 클라이언트는 다음 코드를 가진 ASP.NET 응용 프로그램입니다.

OleDbConnection cn = new OleDbConnection("Provider=SQLNCLI11; server=localhost\\SQLEXPRESS; Database=<my db>; user id=<my uid>; password=<my pwd>");
cn.Open();
OleDbTransaction tn = cn.BeginTransaction();
OleDbCommand cmd = new OleDbCommand("INSERT INTO LAYOUTSv2 (LAYOUTS_name_t, LAYOUTS_enabled_b, LAYOUTS_data_m) VALUES ('name', '-1', 'data')", cn, tn);
cmd.ExecuteNonQuery();
cmd.CommandText = "SELECT SCOPE_IDENTITY()";
int newkey = Decimal.ToInt32((decimal)cmd.ExecuteScalar());
Console.WriteLine("Created index " + newkey);
Thread.Sleep(15000);
tn.Commit();
tn = cn.BeginTransaction();
cmd.CommandText = "UDPATE LAYOUTSv2 SET LAYOUTS_enabled_b='-3' WHERE LAYOUTS_key='" + newkey + "'";
cmd.Transaction = tn;
cmd.ExecuteNonQuery();
Console.WriteLine("updated row");
Thread.Sleep(15000);
tn.Rollback();
cn.Close();

이 코드를 실행 한 다음 관리 스튜디오에서 실행 SELECT * FROM LAYOUTSv2합니다. 클라이언트 스레드가 일시 정지 된 (즉, 커미트 / 롤백 이전) 두 경우 모두 커밋 / 롤백이 발생할 때까지 SELECT 쿼리가 정지됩니다.

테이블에는 기본 키로 지정된 LAYOUTS_key 필드가 있습니다. 속성 창에서 페이지 잠금과 행 잠금이 모두 허용 된 고유하고 클러스터 된 것으로 표시됩니다. 테이블의 잠금 에스컬레이션 설정은 비활성화입니다 ... 테이블과 AUTO의 다른 사용 가능한 설정을 변경하지 않고 시도했습니다. 나는 시도 SELECT ... WITH (NOLOCK)하고 결과를 즉시 반환하지만 여기 와 다른 곳에서 주의를 기울 이면 내가해야 할 일이 아닙니다. 와 진술 ROWLOCK에 힌트를 주려고 했지만 아무것도 바뀌지 않았습니다. INSERTUPDATE

내가 찾고있는 행동은 이것입니다 :의 커밋하기 전에 INSERT다른 스레드의 쿼리는 에딩중인 행을 제외한 모든 행을 읽습니다 INSERT. UPDATE다른 스레드에서 쿼리 를 커밋하기 전에 시작중인 버전의 행을 읽습니다 UPDATE. 내가 할 수있는 방법이 있습니까? 사용 사례를 명확히하기 위해 다른 정보를 제공해야하는 경우 알려주십시오. 감사.


3
그건 그렇고 WHERE LAYOUTS_key='" + newkey + "'SQL 주입을 포함하여 다양한 이유로 완전한 아니오입니다, 당신은 매개 변수 쿼리를 사용해야합니다.
Martin Smith

1
@MartinSmith이 문제에 대해 진심으로 감사드립니다 ... 매개 변수화 된 쿼리 나 SQL 인젝션 공격에 대해 들어 본 적이 없습니다.
John Riehl

@JohnRiehl, re : 주입 공격, 사용자 newkey가 " something';DELETE FROM LAYOUTSv2 --"로 설정 되어 있다고 상상해보십시오 . 사용자가 아포스트로피를 삽입하여 쿼리를 조작했기 때문에 업데이트가 성공적으로 완료된 후 테이블을 비 웁니다. 일반적으로 매개 변수화 된 쿼리는 다음과 유사 UDPATE LAYOUTSv2 SET LAYOUTS_enabled_b='-3' WHERE LAYOUTS_key=?하며 ?코드 의 (매개 변수)에 값을 별도로 할당합니다 .
Daniel Hutmacher

답변:


10

"전체 테이블"을 잠그지 않을 수 있습니다.

테이블의 행을 잠그고 있지만 SELECT * FROM LAYOUTSv2전체 테이블을 읽으려고하면 잠금에 의해 반드시 차단됩니다.

삽입 사례의 경우 READPAST잠긴 행을 건너 뛸 힌트를 지정할 수는 있지만 원하는 경우 결과를 제공하지 않습니다 UPDATE(행의 시작 버전을 읽지 않고 행을 다시 건너 뜁니다).

당신에 대한 데이터베이스 구성하면 읽기 커밋 스냅 숏 격리를 이 (더 큰 사용의 비용으로 두 가지 경우에 원하는 효과를 줄 것이다 tempdb)


"읽기 커밋 된 스냅 샷 켜기"를 True로 변경 한 후 힌트없이 완벽하게 작동합니다. 감사! 후속 조치 ... "스냅 샷 격리 허용"을 False로 설정 한 상태로 두었습니다 ... 괜찮습니까? 감사.
John Riehl

@JohnRiehl-예. SNAPSHOT격리를 사용하지 않고 명시 적으로 사용하지 않는 경우 예 를 들어 나중에 유용하다고 판단되면 사용하도록 설정하십시오.
Martin Smith

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.