2012-01-27 4 views
0

Sequences 테이블에 시퀀스 번호가 증가하는 기존의 코드가 나타났습니다. 이 시퀀스 번호는 다른 테이블 (Orders 테이블)의 새 레코드에 대한 ID로 사용됩니다.데이터베이스 행을 잠그는 간단한 방법

내가이 일을 할 예정이다 생각하는 것은 :

  1. 이 순서의 레코드가 해당 번호를 값을 얻을 반환이 있으면 + 1
  2. 대한 기록, 검사가없는 경우 실제 테이블을 현재 최대 값을 찾고 가장 가까운 1000으로 반올림하고 Sequences 테이블에 최대 값을 기록하십시오.

여기서 코드이다 :

private static final long SEQUENCE_BLOCK_SIZE = 1000; 
private static final String ID_FIELD_NAME = "Order_ID"; 
private static final String TABLE_NAME = "Orders"; 
private static long lastID = 0; 
String init = null; 

public long newID() throws Exception { 
    Connection c = null; 
    long id = 0; 

    try { 
    c = Connections.getConnection(init); 
    id = nextID(c); 
    } catch(Exception e) { 
    try { 
     c.close(); 
    } catch(Exception ignore) { 
    } 
    throw e; 
    } finally { 
    if (c != null) { 
     Connections.putConnection(c); 
    } 
    } 

    return id; 
} 

/** 
* Returns a new unique id for the account. 
*/ 
protected static synchronized long nextID(Connection c) throws Exception { 
    // Only update the table occasionally. 
    if(lastID % SEQUENCE_BLOCK_SIZE == 0) { 
    Statement s = null; 
    ResultSet r = null; 

    try { 
     lastID = 0; 

     s = c.createStatement(); 

     // Lock the row. +++ EH??? +++ 
     s.executeUpdate("UPDATE sequences SET sequence_value=sequence_value WHERE sequence_name='" + ID_FIELD_NAME + "'"); 

     // Get the current value. 
     r = s.executeQuery("SELECT sequence_value FROM sequences WHERE sequence_name='" + ID_FIELD_NAME + "'"); 
     if(r.next()) { 
     lastID = r.getLong(1); 
     } 
     r.close(); 

     s.close(); 

     if(lastID == 0) { 
     // Get the current max value from the table. 
     s = c.createStatement(); 
     r = s.executeQuery("SELECT MAX(" + ID_FIELD_NAME + ") FROM " + TABLE_NAME + ""); 
     if(r.next()) { 
      lastID = ((r.getLong(1) + SEQUENCE_BLOCK_SIZE)/SEQUENCE_BLOCK_SIZE) * SEQUENCE_BLOCK_SIZE; 
     } 
     r.close(); 
     s.close(); 

     // Insert the new row. 
     s = c.createStatement(); 
     s.executeUpdate("INSERT INTO sequences(sequence_value,sequence_name) VALUES(" + (lastID + SEQUENCE_BLOCK_SIZE) + ",'" + ID_FIELD_NAME + "')"); 
     s.close(); 
     }else { 
     // Update the row. 
     s = c.createStatement(); 
     s.executeUpdate("UPDATE sequences SET sequence_value=" + (lastID + SEQUENCE_BLOCK_SIZE) + " WHERE sequence_name='" + ID_FIELD_NAME + "'"); 
     s.close(); 
     } 
    } catch(Exception e) { 
     throw e; 
    } finally { 
     try { 
     r.close(); 
     } catch(Exception e) { 
     } 
     try { 
     s.close(); 
     } catch(Exception e) { 
     } 
    } 
    } 

    return lastID++; 
} 

내 문제는 그것이 새로운 레코드를 추가하지 않는 Sequences 테이블에 레코드가없는 경우는 INSERT을 실행되지만이다. 별도로 INSERT을 테스트했으며 정상적으로 작동하는 것 같습니다. 나는 이것이 //Lock the row 진술과 관련이 있다고 생각합니다. 진술서가 실제로 그 행을 잠 그거나 어떤 영향을 미치는지를 암시하는 문서는 찾을 수 없습니다.

SQL Server 2008에 대해 테스트 중이지만 동일한 메커니즘이 2000+와 Oracle에 대해 작동해야합니다.

덧글에 대한 응답.

고유 한 시퀀스 번호에 대해 기본 데이터베이스 메커니즘을 사용하는 것이 더 좋거나 더 효율적일 것이라는 점을 인정합니다. 슬프게도이 응용 프로그램은 약 6 개의 다른 데이터베이스 시스템 중 하나를 구동하도록 설계되었으며 확실하게 OracleMS SQL을 모두 지원하므로이 기술을 고수하는 것이 바람직합니다.

세션을 자동 커밋 모드로 실행합니다. INSERT이 새 레코드를 만들지 않는 이유는 무엇입니까? 잠금 시도와 관련이 있습니까?

+1

Oracle에서 update 문은 다른 세션의 업데이트 레코드를 잠그지 만 값을 쿼리하려고 시도하는 모든 세션은 업데이트 전에 있던 정보를 검색합니다. –

+1

코드를 제거하고 네이티브 시퀀서를 사용하십시오. 데이터베이스가 제공하는 이유가 있습니다. – millimoose

+0

@Inerdial 나에게 참고 자료를 제공해 주시겠습니까? Oracle과 SQL 모두 동일한 코드를 사용할 수 있습니까? – OldCurmudgeon

답변

0

문제는 제가 거래를 성사시키지 않은 것이 었습니다. autocommit 모드에서 세션을 실행하는 것에 대해 잘못된 것이 었습니다.

레코드 잠금은 @ Sérgio가 그의 코멘트에서 말한대로 작동합니다.

0

왜 사용하지 않았습니까 SELECT ... FOR UPDATE * struct?

+0

내 질문에 대한 대답으로 그 뜻이 실제로 있습니까? OldCurmudgeon

관련 문제