큰 DB 파일 (> 600 Mb)에서 작동하는 다중 스레드 응용 프로그램이 있습니다. BLOB 데이터를 추가하면 "데이터베이스 잠김"문제가 발생하고 요청 당 30KB 이상의 BLOB 데이터로 작업이 시작됩니다. 나는 작은 HDD 속도와 관련된 문제라고 생각한다. 그것은 SQLite 삭제 - 저널 파일, 내 응용 프로그램의 한 스레드가 잠겨있어 (저널 파일을 적용하고 삭제 된 때문에), 그리고 다른 내 스레드가 DB를 사용하여 smth 싶지 않지만 SQLite 여전히 DB 파일을 업데이 트 ... 물론 , 나는 각 DB 호출 후에 잠깐 지연을 할 수 있지만, 더 많은 속도가 필요하기 때문에 이것은 해결책이 아닙니다.다중 스레드 응용 프로그램에서 SQLite "데이터베이스 잠김"오류가 발생했습니다.
이제 대화 당 (세션 당) 세션을 사용합니다. 따라서 응용 프로그램 개체 당 하나의 ISessionFactory와 많은 ISession 개체가 있습니다.
public abstract class nHibernateHelper
{
private static FluentConfiguration _configuration;
private static IPersistenceContext _persistenceContext;
static nHibernateHelper() {}
private static FluentConfiguration ConfigurePersistenceLayer()
{
return Fluently.Configure().Database(FluentNHibernate.Cfg.Db.SQLiteConfiguration.Standard.ShowSql().UsingFile(_fileName).IsolationLevel(IsolationLevel.Serializable).MaxFetchDepth(2)).
Mappings(m => m.FluentMappings.AddFromAssemblyOf<Foo>()).CurrentSessionContext(typeof(ThreadStaticSessionContext).FullName);
}
public static ISession CurrentSession
{
get { return _persistenceContext.CurrentSession; }
}
public static IDisposable OpenConnection()
{
return new DbSession(_persistenceContext);
}
}
public class PersistenceContext : IPersistenceContext, IDisposable
{
private readonly FluentConfiguration _configuration;
private readonly ISessionFactory _sessionFactory;
public PersistenceContext(FluentConfiguration configuration)
{
_configuration = configuration;
_sessionFactory = _configuration.BuildSessionFactory();
}
public FluentConfiguration Configuration { get { return _configuration; } }
public ISessionFactory SessionFactory { get { return _sessionFactory; } }
public ISession CurrentSession
{
get
{
if (!CurrentSessionContext.HasBind(SessionFactory))
{
OnContextualSessionIsNotFound();
}
var contextualSession = SessionFactory.GetCurrentSession();
if (contextualSession == null)
{
OnContextualSessionIsNotFound();
}
return contextualSession;
}
}
public void Dispose()
{
SessionFactory.Dispose();
}
private static void OnContextualSessionIsNotFound()
{
throw new InvalidOperationException("Ambient instance of contextual session is not found. Open the db session before.");
}
}
public class DbSession : IDisposable
{
private readonly ISessionFactory _sessionFactory;
public DbSession(IPersistenceContext persistentContext)
{
_sessionFactory = persistentContext.SessionFactory;
CurrentSessionContext.Bind(_sessionFactory.OpenSession());
}
public void Dispose()
{
var session = CurrentSessionContext.Unbind(_sessionFactory);
if (session != null && session.IsOpen)
{
try
{
if (session.Transaction != null && session.Transaction.IsActive)
{
session.Transaction.Rollback();
}
}
finally
{
session.Dispose();
}
}
}
}
그리고 저장소 헬퍼 클래스가있다 :
은 (당신이 볼 수 있듯이 나는 IsolationLevel.Serializable과의 CurrentSessionContext = ThreadStaticSessionContext 사용) 내 헬퍼 클래스가 있습니다. 볼 수 있듯이 모든 DB 호출마다 잠금이 있으므로 _locker 객체가 정적이므로 다른 스레드에 대해서도 동시성 DB 호출을 표시 할 수 없습니다.
public abstract class BaseEntityRepository<T, TId> : IBaseEntityRepository<T, TId> where T : BaseEntity<TId>
{
private ITransaction _transaction;
protected static readonly object _locker = new object();
public bool Save(T item)
{
bool result = false;
if ((item != null) && (item.IsTransient()))
{
lock (_locker)
{
try
{
_transaction = session.BeginTransaction();
nHibernateHelper.CurrentSession.Save(item);
nHibernateHelper.Flush();
_transaction.Commit();
result = true;
} catch
{
_transaction.Rollback();
throw;
}
//DelayAfterProcess();
}
}
return result;
}
//same for delete and update
public T Get(TId itemId)
{
T result = default(T);
lock (_locker)
{
try
{
result = nHibernateHelper.CurrentSession.Get<T>(itemId);
}
catch
{
throw;
}
}
return result;
}
public IList<T> Find(Expression<Func<T, bool>> predicate)
{
IList<T> result = new List<T>();
lock (_locker)
{
try
{
result = nHibernateHelper.CurrentSession.Query<T>().Where(predicate).ToList();
}
catch
{
throw;
}
}
return result;
}
}
나는 (내가 nHibernateHelper.OpenConnection() 스레드 당 한 번 전화) 같은 이전의 클래스를 사용합니다.
using (nHibernateHelper.OpenConnection())
{
Foo foo = new Foo();
FooRepository.Instance.Save(foo);
}
내가 ReadCommited에 IsolationLevel을 변경했지만,이 문제가되지 않습니다 변경 : 저장소는 singletone에 의해 인스턴스화됩니다. 이 빠른 HDD와 컴퓨터에 도움이
using (nHibernateHelper.OpenConnection())
{
using (IDbCommand command = nHibernateHelper.CurrentSession.Connection.CreateCommand())
{
command.CommandText = "PRAGMA journal_mode=WAL";
command.ExecuteNonQuery();
}
}
,하지만 일부에 나는 같은 오류가 발생했습니다 : 또한 나는 WAL 저널에서 변경 SQLite는 저널 모드로이 문제를 해결하기 위해 노력했다. 그럼 난 추가하려고 "DB 업데이트 파일이 존재"저장소에 확인하고, 각/삭제/업데이트를 저장 시술 후 지연 :하지 -journal 파일 근무
protected static int _delayAfterInSeconds = 1;
protected void DelayAfterProcess()
{
bool dbUpdateInProcess = false;
do
{
string fileMask = "*-wal*";
string[] files = Directory.GetFiles(Directory.GetCurrentDirectory(), fileMask);
if ((files != null) && (files.Length > 0))
{
dbUpdateInProcess = true;
Thread.Sleep(1000);
}
else
{
dbUpdateInProcess = false;
}
} while (dbUpdateInProcess);
if (_delayAfterInSeconds > 0)
{
Thread.Sleep(_delayAfterInSeconds * 1000);
}
}
같은 솔루션 (DB 업데이트 파일 확인). 그것은 저널 파일이 삭제되었다고보고했으나 여전히 오류가 있습니다. -wal 파일의 경우 작동합니다 (생각하기에 테스트 할 시간이 더 필요합니다). 그러나이 해결책은 심각하게 프로그램을 제동합니다.
나를 도와 줄 수 있습니까?
나는 SQLite가 어떤 것인지 알고 있습니다. 그래서'lock() {}'메커니즘을 사용하여 동시 연결을 피했습니다. 내가 이해할 수있는 한 ** 모든 것은 ** 다음과 같이 작동해야한다 :'my code {lock {SQLite code}}; 내 코드 {lock {SQLite code}}; ... 'SQLite 코드 작업은 잠금 블록 내에서 완료되어야합니다. 그러나 SQLite가보고 했으니, 끝났습니다 (다시 응용 프로그램으로 제어)!그래서 응용 프로그램은 잠금 블록을 남기고 다른 블록을 시작했습니다. 그러나 SQLite는 여전히 작업을 계속합니다. SQLite는 내 응용 프로그램의 상태를 속입니다. – user809808
sqlite가 준비가되었다고 생각하고 파일 시스템이 끝났다고 생각할 때 약간의 불일치가있을 수 있습니다. 파일은 결국 일정 기간 후에 잠금 해제됩니까? 또는 자물쇠에 보관 해 두었던 추가 액세스 시도가 있습니까? –
약간의 시간이 지나면 - 저널 파일이 사라지는 것을 의미하는 경우 - 아니요, 그렇지 않습니다. 어떤 기간이 지나면 여전히 저널 빈 파일 (0 바이트)이 보입니다. 그리고 예, 몇 시간이 지나면 Session.BeginTransaction 호출이 실패했지만 동일한 오류가 발생했습니다. _Begin은 SQL 예외로 인해 실패했습니다. 데이터베이스 파일이 잠겼습니다. \ r \ n 데이터베이스가 잠겼습니다. – user809808