2010-02-18 5 views
1

SubSonic 및 SQLite와 트랜잭션을 사용할 때 잠금 예외가 발생합니다. 나는이 스레드를 단일 스레드에서 사용하고 있으며 다른 프로세스가 db에 액세스하지 않으므로 이러한 문제는 실제로 예상하지 못했습니다.단일 스레드에서 트랜잭션을 사용할 때 sqlite 및 SubSonic 잠금 문제

아래 코드를 작성하면 루프 내에서 Save() 호출에 대한 예외가 발생하므로 Save()를 세 번 호출하면 예외가 발생합니다.

 using (TransactionScope ts = new TransactionScope()) 
     { 
      using (SharedDbConnectionScope sharedConnectinScope = new SharedDbConnectionScope()) 
      { 
       SomeDALObject x = new SomeDALObject() 
       x.Property1 = "blah"; 
       x.Property2 = "blah blah"; 
       x.Save(); 

       foreach (KeyValuePair<string, string> attribute in attributes) 
       { 
        AnotherDALObject y = new AnotherDALObject() 
        y.Property1 = attribute.Key 
        y.Property2 = attribute.Value 

        y.Save(); // this is where the exception is raised, on the 2nd time through this loop 
       } 
      } 
     } 

나는 위와 같이 문) (사용하거나 그냥 다음 using (TransactionScope ts = new TransactionScope())이있는 경우 나 데이터베이스 파일은 데이터베이스가

잠긴

잠겨

메시지와 System.Data.SQLite.SQLiteException를 얻을 수있는 경우

스택 추적은 다음과 같습니다.

at System.Data.SQLite.SQLite3.Step(SQLiteStatement stmt) 
    at System.Data.SQLite.SQLiteDataReader.NextResult() 
    at System.Data.SQLite.SQLiteDataReader..ctor(SQLiteCommand cmd, CommandBehavior behave) 
    at System.Data.SQLite.SQLiteCommand.ExecuteReader(CommandBehavior behavior) 
    at System.Data.SQLite.SQLiteCommand.ExecuteNonQuery() 
    at System.Data.SQLite.SQLiteTransaction..ctor(SQLiteConnection connection, Boolean deferredLock) 
    at System.Data.SQLite.SQLiteConnection.BeginDbTransaction(IsolationLevel isolationLevel) 
    at System.Data.SQLite.SQLiteConnection.BeginTransaction() 
    at System.Data.SQLite.SQLiteEnlistment..ctor(SQLiteConnection cnn, Transaction scope) 
    at System.Data.SQLite.SQLiteConnection.EnlistTransaction(Transaction transaction) 
    at System.Data.SQLite.SQLiteConnection.Open() 
    at SubSonic.SQLiteDataProvider.CreateConnection(String newConnectionString) 
    at SubSonic.SQLiteDataProvider.CreateConnection() 
    at SubSonic.SQLiteDataProvider.ExecuteScalar(QueryCommand qry) 
    at SubSonic.DataService.ExecuteScalar(QueryCommand cmd) 
    at SubSonic.ActiveRecord`1.Save(String userName) 
    at SubSonic.ActiveRecord`1.Save() 
    at (my line of code above). 

외부에서 SharedDbConnectionScope를 사용하여 다른 문장으로 중첩 된 구문을 사용하는 경우 "작업이 트랜잭션 상태에 유효하지 않습니다."라는 메시지와 함께 TransactionException이 표시됩니다.

at System.Transactions.TransactionState.EnlistVolatile(InternalTransaction tx, IEnlistmentNotification enlistmentNotification, EnlistmentOptions enlistmentOptions, Transaction atomicTransaction) 
    at System.Transactions.Transaction.EnlistVolatile(IEnlistmentNotification enlistmentNotification, EnlistmentOptions enlistmentOptions) 
    at System.Data.SQLite.SQLiteEnlistment..ctor(SQLiteConnection cnn, Transaction scope) 
    at System.Data.SQLite.SQLiteConnection.EnlistTransaction(Transaction transaction) 
    at System.Data.SQLite.SQLiteConnection.Open() 
    at SubSonic.SQLiteDataProvider.CreateConnection(String newConnectionString) 
    at SubSonic.SQLiteDataProvider.CreateConnection() 
    at SubSonic.SQLiteDataProvider.ExecuteScalar(QueryCommand qry) 
    at SubSonic.DataService.ExecuteScalar(QueryCommand cmd) 
    at SubSonic.ActiveRecord`1.Save(String userName) 
    at SubSonic.ActiveRecord`1.Save() 
    at (my line of code above) 

및 내부 예외는 내 생성 DAL 클래스에 사용자 지정 코드가, 또는 내가 될 것이라고 생각할 수있는 영리한 아무것도하지 않는

"트랜잭션 시간 초과"입니다 : 스택 추적입니다 이 원인.

다른 사람이 이와 같은 거래 문제가 발생했거나 누군가 내가 문제를 찾기 시작할 곳을 제안 할 수 있습니까?

감사합니다.

업데이트 : 버전 1.0.61-65 (예 : here)의 릴리스 노트에서 트랜잭션 관련 내용을 언급 했으므로 SubSonic을 최신 버전의 .Net Data Provider와 함께 사용하여 업데이트하는 것이 이러한 문제는 ...

답변

3

아음속 2.x에 대한 수정 된 sqlite 공급자를 수행하면서 기존의 아음속 sqlserver 테스트를 기반으로 한 전체 단위 테스트를 만들었습니다. (이 테스트는 수정 된 코드에서도 확인되었습니다.) 실패한 유일한 테스트는 트랜잭션과 관련된 테스트 (아마도 마이그레이션하는 테스트 일 수도 있습니다)입니다. "데이터베이스 파일이 잠겨 있습니다."라는 오류 메시지가 나타납니다. Subsonic은 주로 SQLIte처럼 파일 수준 잠금을 수행하지 않는 SQL Server 용으로 작성되었으므로 일부 기능은 작동하지 않습니다. 이것을 더 잘 처리하기 위해서는 다시 작성해야합니다.

나는 당신이 가진 것처럼 TransactionScope를 사용한 적이 없다. 나는 아음속 2.2 트랜잭션을 이렇게하며 SQLite 제공자에 대한 문제는 지금까지 없다. 여러 행을 처리하거나 정말 느린 경우 SQLite로 트랜잭션을 사용해야한다는 것을 확인할 수 있습니다.

public void DeleteStuff(List<Stuff> piaRemoves) 
{ 
    QueryCommandCollection qcc = new QueryCommandCollection(); 

    foreach(Stuff item in piaRemoves) 
    { 
     Query qry1 = new Query(Stuff.Schema); 
     qry1.QueryType = QueryType.Delete; 
     qry1.AddWhere(Stuff.Columns.ItemID, item.ItemID); 
     qry1.AddWhere(Stuff.Columns.ColumnID, item.ColumnID); 
     qry1.AddWhere(Stuff.Columns.ParentID, item.ParentID); 
     QueryCommand cmd = qry1.BuildDeleteCommand(); 
     qcc.Add(cmd); 
    } 
    DataService.ExecuteTransaction(qcc); 
} 
+0

fyi 다른 음속 버전을 보려면 http://github.com/subsonic/SubSonic-2.0/network 또는 여기에서 Paul 's 버전을 다운로드하십시오. http://github.com/PaulS /SubSonic-2.0/commit/55bcb4188c8e7b2a10ae926c8ddf1d00bf03dcf3 (새 버전이 있으면 구식이 될 것입니다). 이 새로운 버전은 동시에 여러 스레드에서 트랜잭션을 실행할 때 AccessViolationExceptions에서 가지고 있었던 다른 잠금 문제를 해결했습니다. 또한 여기에서 System.Data.SQLite 버전 1.0.65.0으로 컴파일하는 것이 좋습니다. http://sourceforge.net/projects/sqlite-dotnet2/ – Rory

0

우리는 SQLite를 사용하여 데이터베이스 작업과 관련된 코드를 테스트하고 있습니다. SQL Lite는 중첩 된 트랜잭션을 지원하지 않습니다. 우리는 NHibernate와 .Net 트랜잭션이있는 비슷한 문제를 가지고있었습니다. 궁극적으로 데이터베이스 관련 코드를 테스트하기 위해 SQL Express를 사용하여 해결해야했습니다.

2

내가 바울의 제안을 사용하여 결국이 같은 내 코드를 재 작성 :

이 실제로 데이터베이스 안타에 대한 모든 준비 트랜잭션이 열리기 전에 수행되기 때문에 훨씬 더
QueryCommandCollection qcc = new QueryCommandCollection(); 

    SomeDALObject x = new SomeDALObject() 
    x.Property1 = "blah"; 
    x.Property2 = "blah blah"; 
    qcc.Add(x.GetSaveCommand()); 

    foreach (KeyValuePair<string, string> attribute in attributes) 
    { 
     AnotherDALObject y = new AnotherDALObject() 
     y.Property1 = attribute.Key 
     y.Property2 = attribute.Value 

     qcc.Add(y.GetSaveCommand()); 
    } 

    DataService.ExecuteTransaction(qcc); 

, 그러므로 거래는 훨씬 적은 시간 동안 열릴 것입니다.

자식 레코드에 대한 INSERT를 실행하기 위해 자동 생성 된 ID를 다시 가져와야하는 경우에는 잘 작동하지 않습니다. 당신은 다른 접근법을 사용해야 할 것입니다.

그런 다음 다른 스레드/트랜잭션 문제가 발생했습니다. 동시에 DataService.ExecuteTransaction()을 실행하는 스레드가 여러 개있을 때 AccessViolationExceptions 및 NullReferenceExceptions를 얻는 것과 동시에 기본적으로 엉망입니다. 그러나 업데이트 된 SQLDataProvider를 사용하여 SubSonic의 Paul's fork을 사용하도록 변경하고 System.Data.SQLite v1.0.65.0을 사용하도록 변경하면 즉시 수정 된 것으로 보입니다. 만세!

업데이트 : 사실 저는 여전히 Subthonic과 sqlite를 사용하여 스레딩 문제가 발생합니다. 기본적으로 SubSonic의 SQLiteDataProvider는 멀티 스레딩을 처리하기 위해 작성되지 않습니다. 더 많은 것을 ...

관련 문제