programing

행 선택과 업데이트를 동시에 할 수 있는 방법이 있습니까?

mailnote 2023. 11. 7. 21:02
반응형

행 선택과 업데이트를 동시에 할 수 있는 방법이 있습니까?

간단한 기준으로 일련의 행을 업데이트하고 변경된 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'를 실행하는 것이 더 쉽습니다.

SQL 팁에서 자세한 정보와 예를 확인해 보십시오.

이런 거라도?

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

반응형