행 선택과 업데이트를 동시에 할 수 있는 방법이 있습니까?
간단한 기준으로 일련의 행을 업데이트하고 변경된 PK 목록을 받고 싶습니다.저는 이와 같은 작업을 할 수 있다고 생각했지만 동시성 문제가 발생할 수 있어 걱정입니다.
SELECT Id FROM Table1 WHERE AlertDate IS NULL;
UPDATE Table1 SET AlertDate = getutcdate() WHERE AlertDate IS NULL;
만약 그것이 거래로 포장된다면 동시성 문제가 발생할 수 있습니까?아니면 더 나은 방법이 있을까요?
OUTPUT 조항을 보는 것을 고려해 보십시오.
USE AdventureWorks2012;
GO
DECLARE @MyTableVar table(
EmpID int NOT NULL,
OldVacationHours int,
NewVacationHours int,
ModifiedDate datetime);
UPDATE TOP (10) HumanResources.Employee
SET VacationHours = VacationHours * 1.25,
ModifiedDate = GETDATE()
OUTPUT inserted.BusinessEntityID,
deleted.VacationHours,
inserted.VacationHours,
inserted.ModifiedDate
INTO @MyTableVar;
--Display the result set of the table variable.
SELECT EmpID, OldVacationHours, NewVacationHours, ModifiedDate
FROM @MyTableVar;
GO
--Display the result set of the table.
SELECT TOP (10) BusinessEntityID, VacationHours, ModifiedDate
FROM HumanResources.Employee;
GO
몇 년 후에...
OUTPUT 절을 사용하는 것에 대한 인정된 답변은 좋습니다.실제 구문을 조사해야 했기 때문에, 여기 있습니다.
DECLARE @UpdatedIDs table (ID int)
UPDATE
Table1
SET
AlertDate = getutcdate()
OUTPUT
inserted.Id
INTO
@UpdatedIDs
WHERE
AlertDate IS NULL;
2015년 9월 14일 추가:
"표 변수 대신 스칼라 변수를 사용할 수 있나요?"라고 물을 수도 있습니다.미안하지만, 안돼요.당신이 해야 할 것입니다.SELECT @SomeID = ID from @UpdatedIDs신분증이 필요하시면요
이를 처리하는 한 가지 방법은 트랜잭션에서 이를 수행하고, 트랜잭션이 완료될 때까지 선택한 행에 대해 SELECT 쿼리가 업데이트 잠금을 취하도록 하는 것입니다.
BEGIN TRAN
SELECT Id FROM Table1 WITH (UPDLOCK)
WHERE AlertDate IS NULL;
UPDATE Table1 SET AlertDate = getutcdate()
WHERE AlertDate IS NULL;
COMMIT TRAN
이렇게 하면 동시 클라이언트가 SELECT와 UPDATE 사이의 순간에 선택한 행을 업데이트할 가능성이 사라집니다.
트랜잭션을 커밋하면 업데이트 잠금이 해제됩니다.
이 문제를 해결하는 또 다른 방법은 FOR UPDATE 옵션을 사용하여 SELECT에 대한 커서를 선언하는 것입니다.그런 다음 커서의 전류 위치를 업데이트합니다.다음은 테스트되지 않았지만 기본적인 아이디어를 제공해야 합니다.
DECLARE cur1 CURSOR FOR
SELECT AlertDate FROM Table1
WHERE AlertDate IS NULL
FOR UPDATE;
DECLARE @UpdateTime DATETIME
SET @UpdateTime = GETUTCDATE()
OPEN cur1;
FETCH NEXT FROM cur1;
WHILE @@FETCH_STATUS = 0
BEGIN
UPDATE Table1
SET AlertDate = @UpdateTime --set value
WHERE CURRENT OF cur1;
FETCH NEXT FROM cur1;
END
업데이트를 먼저 한 후 'SELECT ID FROM INTERVE'를 실행하는 것이 더 쉽습니다.
이런 거라도?
declare @UpdateTime datetime
set @UpdateTime = getutcdate()
update Table1 set AlertDate = @UpdateTime where AlertDate is null
select ID from Table1 where AlertDate = @UpdateTime
저도 같은 문제가 생겼습니다. 신용금액을 업데이트해야 하고, DB에서 신용정보와 함께 수정된 시간을 받아야 합니다.그것은 기본적으로
MYSQL에서 동기적/원자적으로 수행(업데이트 후 GET)
저는 여러 가지 방법을 시도해보았고, 제 문제를 해결해주는 방법을 발견했습니다.
1) OPTION_1 업데이트를 위해 선택
이것은 업데이트까지 잠금을 유지하는 것이지만(SYNC는 GET에서 UPDATE로), 업데이트 후 GET까지 잠금이 필요합니다.
2) OPTION_2 저장 프로시저
저장 프로시저는 redislua처럼 동기적으로 실행되지 않기 때문에 이를 수행하기 위해서는 동기 코드가 필요합니다.
3) OPTION_3 트랜잭션
아래와 같이 JPA entityManager를 사용하였는데 커밋 전에는 아무도 업데이트를 할 수 없고 커밋 전에는 (DB에서) 수정된 시간과 함께 업데이트된 객체를 받을 것이라고 생각했습니다.하지만 저는 최신 물건을 받지 못했습니다.가장 최근에 받은 것은 커밋 뿐입니다.
try {
entityManager.getTransaction().begin();
//entityManager.persist(object);
int upsert = entityManager.createNativeQuery(
"update com.bill.Credit c set c.balance = c.balance - ?1
where c.accountId = ?2 and c.balance >= ?1").executeUpdate();
//c.balance >= ? for limit check
Credit newCredit = entityManager.find(Credit.class, "id");
entityManager.refresh(newCredit); //SHOULD GET LATEST BUT NOT
entityManager.getTransaction().commit();
} finally {
entityManager.unwrap(Session.class).close();
}
4) OPTION_4 LOCK으로 문제가 해결되어 업데이트 전에 잠금을 획득했고 GET 후에는 잠금을 해제했습니다.
private Object getLock(final EntityManager entityManager, final String Id){
entityManager.getTransaction().begin();
Object obj_acquire = entityManager.createNativeQuery("SELECT GET_LOCK('" + Id + "', 10)").getSingleResult();
entityManager.getTransaction().commit();
return obj_acquire;
}
private Object releaseLock(final EntityManager entityManager, final String Id){
entityManager.getTransaction().begin();
Object obj_release = entityManager.createNativeQuery("SELECT RELEASE_LOCK('" + Id + "')").getSingleResult();
entityManager.getTransaction().commit();
return obj_release;
}
편집: 죄송합니다. 선택 항목에서 업데이트가 아니라 업데이트 후 결과를 표시하도록 했습니다.
하위 선택을 해보셨습니까?
update mytable set mydate = sysdate
where mydate in (select mydate from mytable where mydate is null);
트랜잭션 내부에 있으면 데이터베이스 잠금 시스템이 동시성 문제를 처리합니다.물론 하나를 사용하는 경우(mssql 기본값은 잠금을 사용하므로 재정의하지 않으면 표시됨)
SQL 2008에서는 소스 테이블과의 조인 결과를 기반으로 대상 테이블에 대한 삽입, 업데이트 또는 삭제 작업을 수행하는 새로운 TSQL 문 "MERGE"가 도입됩니다.다른 테이블에 있는 차이점을 기준으로 한 테이블의 행을 삽입, 업데이트 또는 삭제하여 두 테이블을 동기화할 수 있습니다.
http://blogs.msdn.com/ajaiman/archive/2008/06/25/tsql-merge-statement-sql-2008.aspx http://msdn.microsoft.com/en-us/library/bb510625.aspx
언급URL : https://stackoverflow.com/questions/497464/is-there-a-way-to-select-and-update-rows-at-the-same-time
'programing' 카테고리의 다른 글
| 하위 디바 표시 상위 디바 반응 js에서 하위 디바 호버링 (0) | 2023.11.07 |
|---|---|
| angular $resource delete가 express.js 서버로 본문을 전송하지 않습니다. (0) | 2023.11.07 |
| PowerShell의 변수에 null 값을 할당하려면 어떻게 해야 합니까? (0) | 2023.11.07 |
| sql 주입 공격에서 게시물의 스크립트를 제거하는 방법? (0) | 2023.11.02 |
| WordPress의 외부 DB에서 SQL 쿼리 (0) | 2023.11.02 |