NHibernate Transaction.Commit()
我有一个大问题,它涉及 NHibernate 中的事务。
首先,我可以说 SessionManager(线程安全、惰性单例)创建一个 SessionFactory 并为我提供会话对象。事务管理是内置的。
接下来,我有一个带有 hibernate 映射(xml,无流利)和 poco 的 DAL。
WCF 服务正在免费提供一些 poco,这通过以下方式发生:
public string UpdateCustomer(Customer customer, ExtraParameters extraParameters)
{
try
{
using (_daof.BeginTransaction(GetInstanceUserID(extraParameters)))
{
return _daof.GetKlantDao().UpdateCustomer(customer).SekKlant.ToString();
}
}
catch (Exception ex)
{
ServiceExceptionHandling(ex);
}
return null;
}
如您所见, using 语句处理事务和会话的处置:
public CrmDaoFactory BeginTransaction(string userID)
{
CrmSettings.Instance.UserID = userID; //Not important
SessionManager.Instance.BeginTransactionOn(configKey); //Memory leak
return this;
}
处置是通过处置模式(析构函数)完成的:
protected virtual void Dispose(bool disposing)
{
if (disposing == true)
{
if (Marshal.GetExceptionCode() == 0)
{
SessionManager.Instance.CommitTransactionOn(configKey);
}
else
{
SessionManager.Instance.RollbackTransactionOn(configKey);
}
SessionManager.Instance.CloseSessionOn(configKey);
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~CrmDaoFactory() { Dispose(false); }
在上面,您可以看到当调用 dispose 时,事务被提交(也刷新会话),当发生错误时,事务被回滚。最后,我关闭会话。
问题是当我调用服务上的方法时,我注意到内存泄漏。当我引用 BeginTransaction 行时,没有发生内存泄漏。
public CrmDaoFactory BeginTransaction(string userID)
{
CrmSettings.Instance.UserID = userID;
//SessionManager.Instance.BeginTransactionOn(configKey);
return this;
}
当我调试代码时,我非常确定所有会话在处理后都已关闭。 为了供您参考,我使用以下“SessionManager”代码:
using System;
using System.Collections;
using System.IO;
using System.Runtime.Remoting.Messaging;
using System.Web;
using System.Web.Caching;
using NHibernate;
using NHibernate.Cache;
using System.Reflection;
namespace Cevi.Hibernate
{
/// <summary>
/// Handles creation and management of sessions and transactions. It is a singleton because
/// building the initial session factory is very expensive. Inspiration for this class came
/// from Chapter 8 of Hibernate in Action by Bauer and King. Although it is a sealed singleton
/// you can use TypeMock (http://www.typemock.com) for more flexible testing.
/// </summary>
public sealed class SessionManager
{
//private static readonly DataInterceptor _dataInterceptor = new DataInterceptor();
#region Thread-safe, lazy Singleton
/// <summary>
/// This is a thread-safe, lazy singleton. See http://www.yoda.arachsys.com/csharp/singleton.html
/// for more details about its implementation.
/// </summary>
public static SessionManager Instance
{
get
{
return Nested.SessionManager;
}
}
/// <summary>
/// Private constructor to enforce singleton
/// </summary>
private SessionManager() { }
/// <summary>
/// Assists with ensuring thread-safe, lazy singleton
/// </summary>
private class Nested
{
static Nested() { }
internal static readonly SessionManager SessionManager = new SessionManager();
}
#endregion
/*
/// <summary>
/// This method attempts to find a session factory in the <see cref="HttpRuntime.Cache" />
/// via its config file path; if it can't be found it creates a new session factory and adds
/// it the cache. Note that even though this uses HttpRuntime.Cache, it should still work in
/// Windows applications; see http://www.codeproject.com/csharp/cacheinwinformapps.asp for an
/// examination of this.
/// </summary>
/// <param name="sessionFactoryConfigPath">Path location of the factory config</param>
private ISessionFactory GetSessionFactoryFor(string sessionFactoryConfigPath)
{
if (string.IsNullOrEmpty(sessionFactoryConfigPath))
throw new ArgumentNullException("sessionFactoryConfigPath may not be null nor empty");
// Attempt to retrieve a cached SessionFactory from the HttpRuntime's cache.
ISessionFactory sessionFactory = (ISessionFactory)HttpRuntime.Cache.Get(sessionFactoryConfigPath);
// Failed to find a cached SessionFactory so make a new one.
if (sessionFactory == null)
{
if (!File.Exists(sessionFactoryConfigPath))
// It would be more appropriate to throw a more specific exception than ApplicationException
throw new ApplicationException(
"The config file at '" + sessionFactoryConfigPath + "' could not be found");
NHibernate.Cfg.Configuration cfg = new NHibernate.Cfg.Configuration();
cfg.Configure(sessionFactoryConfigPath);
// Now that we have our Configuration object, create a new SessionFactory
sessionFactory = cfg.BuildSessionFactory();
if (sessionFactory == null)
{
throw new InvalidOperationException("cfg.BuildSessionFactory() returned null.");
}
HttpRuntime.Cache.Add(sessionFactoryConfigPath, sessionFactory, null, DateTime.Now.AddDays(7),
TimeSpan.Zero, CacheItemPriority.High, null);
}
return sessionFactory;
}
*/
/// <summary>
/// This method attempts to find a session factory in the <see cref="HttpRuntime.Cache" />
/// via its config file path; if it can't be found it creates a new session factory and adds
/// it the cache. Note that even though this uses HttpRuntime.Cache, it should still work in
/// Windows applications; see http://www.codeproject.com/csharp/cacheinwinformapps.asp for an
/// examination of this.
/// </summary>
/// <param name="sessionFactoryConfigPath">Path location of the factory config</param>
public ISessionFactory GetSessionFactoryFor(string sessionFactoryConfigPath)
{
if (string.IsNullOrEmpty(sessionFactoryConfigPath))
throw new ArgumentNullException("sessionFactoryConfigPath may not be null nor empty");
// Attempt to retrieve a cached SessionFactory from the HttpRuntime's cache.
ISessionFactory sessionFactory = (ISessionFactory)HttpRuntime.Cache.Get(sessionFactoryConfigPath);
// Failed to find a cached SessionFactory so make a new one.
if (sessionFactory == null)
{
string path = sessionFactoryConfigPath;
if (!Path.IsPathRooted(path))
// indien het geen absoluut pad is afhankelijk van de context waarin de hibernate laag gebruikt wordt het path anders aanvullen
{
if (HttpContext.Current != null)
path = HttpContext.Current.Server.MapPath("~/" + path);
else if (!string.IsNullOrEmpty(System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath))
path = Path.Combine(System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath, path);
else
{
string assemblyPath = (Assembly.GetEntryAssembly()!=null)?
Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) :
AppDomain.CurrentDomain.BaseDirectory;
if (!string.IsNullOrEmpty(assemblyPath))
path = Path.Combine(assemblyPath, path);
}
}
if (!File.Exists(path))
// It would be more appropriate to throw a more specific exception than ApplicationException
throw new ApplicationException(
"The config file at '" + sessionFactoryConfigPath + "' could not be found");
NHibernate.Cfg.Configuration cfg = new NHibernate.Cfg.Configuration();
cfg.Configure(path);
//cfg.SetInterceptor(new DataInterceptor());
// Now that we have our Configuration object, create a new SessionFactory
sessionFactory = cfg.BuildSessionFactory();
if (sessionFactory == null)
{
throw new InvalidOperationException("cfg.BuildSessionFactory() returned null.");
}
HttpRuntime.Cache.Add(sessionFactoryConfigPath, sessionFactory, null, DateTime.Now.AddDays(7),
TimeSpan.Zero, CacheItemPriority.High, null);
}
return sessionFactory;
}
/// <summary>
///
/// </summary>
/// <param name="sessionFactoryConfigPath"></param>
/// <param name="interceptor"></param>
public void RegisterInterceptorOn(string sessionFactoryConfigPath, IInterceptor interceptor)
{
ISession session = (ISession)ContextSessions[sessionFactoryConfigPath];
if (session != null && session.IsOpen)
{
throw new CacheException("You cannot register an interceptor once a session has already been opened");
}
GetSessionFrom(sessionFactoryConfigPath, interceptor);
}
/// <summary>
/// </summary>
/// <param name="sessionFactoryConfigPath"></param>
/// <returns></returns>
public ISession GetSessionFrom(string sessionFactoryConfigPath)
{
return GetSessionFrom(sessionFactoryConfigPath, null);
}
private ISession GetSessionFrom(string sessionFactoryConfigPath, IInterceptor interceptor)
{
ISession session = (ISession)ContextSessions[sessionFactoryConfigPath];
if (session == null)
{
session = (interceptor != null)?
GetSessionFactoryFor(sessionFactoryConfigPath).OpenSession(interceptor) :
GetSessionFactoryFor(sessionFactoryConfigPath).OpenSession();
ContextSessions[sessionFactoryConfigPath] = session;
}
if (session == null)
// It would be more appropriate to throw a more specific exception than ApplicationException
throw new ApplicationException("session was null");
return session;
}
///<summary>
///</summary>
///<param name="sessionFactoryConfigPath"></param>
public void CloseSessionOn(string sessionFactoryConfigPath)
{
ISession session = (ISession)ContextSessions[sessionFactoryConfigPath];
if (session != null && session.IsOpen)
{
session.Close();
session.Dispose();
}
ContextSessions.Remove(sessionFactoryConfigPath);
}
///<summary>
///</summary>
///<param name="sessionFactoryConfigPath"></param>
public void BeginTransactionOn(string sessionFactoryConfigPath)
{
ITransaction transaction = (ITransaction)ContextTransactions[sessionFactoryConfigPath];
if (transaction == null)
{
transaction = GetSessionFrom(sessionFactoryConfigPath).BeginTransaction();
ContextTransactions.Add(sessionFactoryConfigPath, transaction);
}
}
///<summary>
///</summary>
///<param name="sessionFactoryConfigPath"></param>
public void CommitTransactionOn(string sessionFactoryConfigPath)
{
ITransaction transaction = (ITransaction)ContextTransactions[sessionFactoryConfigPath];
try
{
if (transaction != null && !transaction.WasCommitted && !transaction.WasRolledBack)
{
transaction.Commit();
ContextTransactions.Remove(sessionFactoryConfigPath);
transaction.Dispose();
}
}
catch (HibernateException)
{
RollbackTransactionOn(sessionFactoryConfigPath);
throw;
}
}
///<summary>
///</summary>
///<param name="sessionFactoryConfigPath"></param>
public void RollbackTransactionOn(string sessionFactoryConfigPath)
{
ITransaction transaction = (ITransaction)ContextTransactions[sessionFactoryConfigPath];
try
{
ContextTransactions.Remove(sessionFactoryConfigPath);
if (transaction != null && !transaction.WasCommitted && !transaction.WasRolledBack)
{
transaction.Rollback();
}
}
finally
{
CloseSessionOn(sessionFactoryConfigPath);
}
}
/// <summary>
/// Since multiple databases may be in use, there may be one transaction per database
/// persisted at any one time. The easiest way to store them is via a hashtable
/// with the key being tied to session factory.
/// </summary>
private static Hashtable ContextTransactions
{
get
{
if (CallContext.GetData("CONTEXT_TRANSACTIONS") == null)
{
CallContext.SetData("CONTEXT_TRANSACTIONS", new Hashtable());
}
return (Hashtable)CallContext.GetData("CONTEXT_TRANSACTIONS");
}
}
/// <summary>
/// Since multiple databases may be in use, there may be one session per database
/// persisted at any one time. The easiest way to store them is via a hashtable
/// with the key being tied to session factory.
/// </summary>
private static Hashtable ContextSessions
{
get
{
if (CallContext.GetData("CONTEXT_SESSIONS") == null)
{
CallContext.SetData("CONTEXT_SESSIONS", new Hashtable());
}
return (Hashtable)CallContext.GetData("CONTEXT_SESSIONS");
}
}
/// <summary>
/// Opens a stateless session
/// </summary>
/// <param name="sessionFactoryConfigPath"></param>
/// <returns></returns>
public IStatelessSession StatelessSession(string sessionFactoryConfigPath)
{
return GetSessionFactoryFor(sessionFactoryConfigPath).OpenStatelessSession();
}
}
}
有人能给我一些线索吗?我已经没有主意了。 哦,二级缓存和查询缓存被禁用:
<property name="cache.use_second_level_cache">false</property>
<property name="cache.use_query_cache">false</property>
谢谢
I have a big problem and it concernes transactions in NHibernate.
To kick off I can say that a SessionManager (thread-safe, lazy Singleton) creates a SessionFactory and gives me session objects. Transaction Management is build in.
Next, I have a DAL with hibernate mappings (xml, no fluent) and poco's.
A WCF service is giving some poco's free and that happens via this way:
public string UpdateCustomer(Customer customer, ExtraParameters extraParameters)
{
try
{
using (_daof.BeginTransaction(GetInstanceUserID(extraParameters)))
{
return _daof.GetKlantDao().UpdateCustomer(customer).SekKlant.ToString();
}
}
catch (Exception ex)
{
ServiceExceptionHandling(ex);
}
return null;
}
As you can see, the using statement handles the transaction and the disposing of the session:
public CrmDaoFactory BeginTransaction(string userID)
{
CrmSettings.Instance.UserID = userID; //Not important
SessionManager.Instance.BeginTransactionOn(configKey); //Memory leak
return this;
}
Disposing is done via the Disposing Pattern (destructor):
protected virtual void Dispose(bool disposing)
{
if (disposing == true)
{
if (Marshal.GetExceptionCode() == 0)
{
SessionManager.Instance.CommitTransactionOn(configKey);
}
else
{
SessionManager.Instance.RollbackTransactionOn(configKey);
}
SessionManager.Instance.CloseSessionOn(configKey);
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~CrmDaoFactory() { Dispose(false); }
Above, you can see that when dispose is called, the transaction is commited (flushes also the session) and when an error occured it's rollbacked. Finally, I close the session.
The problem is when I call methods on the service, I notice a memory leak. When I quote the BeginTransaction line, no memory leak occurs.
public CrmDaoFactory BeginTransaction(string userID)
{
CrmSettings.Instance.UserID = userID;
//SessionManager.Instance.BeginTransactionOn(configKey);
return this;
}
I'm quite sure all the sessions are closed after the disposal, as I debugged the code.
For your info, I use the following 'SessionManager' code:
using System;
using System.Collections;
using System.IO;
using System.Runtime.Remoting.Messaging;
using System.Web;
using System.Web.Caching;
using NHibernate;
using NHibernate.Cache;
using System.Reflection;
namespace Cevi.Hibernate
{
/// <summary>
/// Handles creation and management of sessions and transactions. It is a singleton because
/// building the initial session factory is very expensive. Inspiration for this class came
/// from Chapter 8 of Hibernate in Action by Bauer and King. Although it is a sealed singleton
/// you can use TypeMock (http://www.typemock.com) for more flexible testing.
/// </summary>
public sealed class SessionManager
{
//private static readonly DataInterceptor _dataInterceptor = new DataInterceptor();
#region Thread-safe, lazy Singleton
/// <summary>
/// This is a thread-safe, lazy singleton. See http://www.yoda.arachsys.com/csharp/singleton.html
/// for more details about its implementation.
/// </summary>
public static SessionManager Instance
{
get
{
return Nested.SessionManager;
}
}
/// <summary>
/// Private constructor to enforce singleton
/// </summary>
private SessionManager() { }
/// <summary>
/// Assists with ensuring thread-safe, lazy singleton
/// </summary>
private class Nested
{
static Nested() { }
internal static readonly SessionManager SessionManager = new SessionManager();
}
#endregion
/*
/// <summary>
/// This method attempts to find a session factory in the <see cref="HttpRuntime.Cache" />
/// via its config file path; if it can't be found it creates a new session factory and adds
/// it the cache. Note that even though this uses HttpRuntime.Cache, it should still work in
/// Windows applications; see http://www.codeproject.com/csharp/cacheinwinformapps.asp for an
/// examination of this.
/// </summary>
/// <param name="sessionFactoryConfigPath">Path location of the factory config</param>
private ISessionFactory GetSessionFactoryFor(string sessionFactoryConfigPath)
{
if (string.IsNullOrEmpty(sessionFactoryConfigPath))
throw new ArgumentNullException("sessionFactoryConfigPath may not be null nor empty");
// Attempt to retrieve a cached SessionFactory from the HttpRuntime's cache.
ISessionFactory sessionFactory = (ISessionFactory)HttpRuntime.Cache.Get(sessionFactoryConfigPath);
// Failed to find a cached SessionFactory so make a new one.
if (sessionFactory == null)
{
if (!File.Exists(sessionFactoryConfigPath))
// It would be more appropriate to throw a more specific exception than ApplicationException
throw new ApplicationException(
"The config file at '" + sessionFactoryConfigPath + "' could not be found");
NHibernate.Cfg.Configuration cfg = new NHibernate.Cfg.Configuration();
cfg.Configure(sessionFactoryConfigPath);
// Now that we have our Configuration object, create a new SessionFactory
sessionFactory = cfg.BuildSessionFactory();
if (sessionFactory == null)
{
throw new InvalidOperationException("cfg.BuildSessionFactory() returned null.");
}
HttpRuntime.Cache.Add(sessionFactoryConfigPath, sessionFactory, null, DateTime.Now.AddDays(7),
TimeSpan.Zero, CacheItemPriority.High, null);
}
return sessionFactory;
}
*/
/// <summary>
/// This method attempts to find a session factory in the <see cref="HttpRuntime.Cache" />
/// via its config file path; if it can't be found it creates a new session factory and adds
/// it the cache. Note that even though this uses HttpRuntime.Cache, it should still work in
/// Windows applications; see http://www.codeproject.com/csharp/cacheinwinformapps.asp for an
/// examination of this.
/// </summary>
/// <param name="sessionFactoryConfigPath">Path location of the factory config</param>
public ISessionFactory GetSessionFactoryFor(string sessionFactoryConfigPath)
{
if (string.IsNullOrEmpty(sessionFactoryConfigPath))
throw new ArgumentNullException("sessionFactoryConfigPath may not be null nor empty");
// Attempt to retrieve a cached SessionFactory from the HttpRuntime's cache.
ISessionFactory sessionFactory = (ISessionFactory)HttpRuntime.Cache.Get(sessionFactoryConfigPath);
// Failed to find a cached SessionFactory so make a new one.
if (sessionFactory == null)
{
string path = sessionFactoryConfigPath;
if (!Path.IsPathRooted(path))
// indien het geen absoluut pad is afhankelijk van de context waarin de hibernate laag gebruikt wordt het path anders aanvullen
{
if (HttpContext.Current != null)
path = HttpContext.Current.Server.MapPath("~/" + path);
else if (!string.IsNullOrEmpty(System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath))
path = Path.Combine(System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath, path);
else
{
string assemblyPath = (Assembly.GetEntryAssembly()!=null)?
Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) :
AppDomain.CurrentDomain.BaseDirectory;
if (!string.IsNullOrEmpty(assemblyPath))
path = Path.Combine(assemblyPath, path);
}
}
if (!File.Exists(path))
// It would be more appropriate to throw a more specific exception than ApplicationException
throw new ApplicationException(
"The config file at '" + sessionFactoryConfigPath + "' could not be found");
NHibernate.Cfg.Configuration cfg = new NHibernate.Cfg.Configuration();
cfg.Configure(path);
//cfg.SetInterceptor(new DataInterceptor());
// Now that we have our Configuration object, create a new SessionFactory
sessionFactory = cfg.BuildSessionFactory();
if (sessionFactory == null)
{
throw new InvalidOperationException("cfg.BuildSessionFactory() returned null.");
}
HttpRuntime.Cache.Add(sessionFactoryConfigPath, sessionFactory, null, DateTime.Now.AddDays(7),
TimeSpan.Zero, CacheItemPriority.High, null);
}
return sessionFactory;
}
/// <summary>
///
/// </summary>
/// <param name="sessionFactoryConfigPath"></param>
/// <param name="interceptor"></param>
public void RegisterInterceptorOn(string sessionFactoryConfigPath, IInterceptor interceptor)
{
ISession session = (ISession)ContextSessions[sessionFactoryConfigPath];
if (session != null && session.IsOpen)
{
throw new CacheException("You cannot register an interceptor once a session has already been opened");
}
GetSessionFrom(sessionFactoryConfigPath, interceptor);
}
/// <summary>
/// </summary>
/// <param name="sessionFactoryConfigPath"></param>
/// <returns></returns>
public ISession GetSessionFrom(string sessionFactoryConfigPath)
{
return GetSessionFrom(sessionFactoryConfigPath, null);
}
private ISession GetSessionFrom(string sessionFactoryConfigPath, IInterceptor interceptor)
{
ISession session = (ISession)ContextSessions[sessionFactoryConfigPath];
if (session == null)
{
session = (interceptor != null)?
GetSessionFactoryFor(sessionFactoryConfigPath).OpenSession(interceptor) :
GetSessionFactoryFor(sessionFactoryConfigPath).OpenSession();
ContextSessions[sessionFactoryConfigPath] = session;
}
if (session == null)
// It would be more appropriate to throw a more specific exception than ApplicationException
throw new ApplicationException("session was null");
return session;
}
///<summary>
///</summary>
///<param name="sessionFactoryConfigPath"></param>
public void CloseSessionOn(string sessionFactoryConfigPath)
{
ISession session = (ISession)ContextSessions[sessionFactoryConfigPath];
if (session != null && session.IsOpen)
{
session.Close();
session.Dispose();
}
ContextSessions.Remove(sessionFactoryConfigPath);
}
///<summary>
///</summary>
///<param name="sessionFactoryConfigPath"></param>
public void BeginTransactionOn(string sessionFactoryConfigPath)
{
ITransaction transaction = (ITransaction)ContextTransactions[sessionFactoryConfigPath];
if (transaction == null)
{
transaction = GetSessionFrom(sessionFactoryConfigPath).BeginTransaction();
ContextTransactions.Add(sessionFactoryConfigPath, transaction);
}
}
///<summary>
///</summary>
///<param name="sessionFactoryConfigPath"></param>
public void CommitTransactionOn(string sessionFactoryConfigPath)
{
ITransaction transaction = (ITransaction)ContextTransactions[sessionFactoryConfigPath];
try
{
if (transaction != null && !transaction.WasCommitted && !transaction.WasRolledBack)
{
transaction.Commit();
ContextTransactions.Remove(sessionFactoryConfigPath);
transaction.Dispose();
}
}
catch (HibernateException)
{
RollbackTransactionOn(sessionFactoryConfigPath);
throw;
}
}
///<summary>
///</summary>
///<param name="sessionFactoryConfigPath"></param>
public void RollbackTransactionOn(string sessionFactoryConfigPath)
{
ITransaction transaction = (ITransaction)ContextTransactions[sessionFactoryConfigPath];
try
{
ContextTransactions.Remove(sessionFactoryConfigPath);
if (transaction != null && !transaction.WasCommitted && !transaction.WasRolledBack)
{
transaction.Rollback();
}
}
finally
{
CloseSessionOn(sessionFactoryConfigPath);
}
}
/// <summary>
/// Since multiple databases may be in use, there may be one transaction per database
/// persisted at any one time. The easiest way to store them is via a hashtable
/// with the key being tied to session factory.
/// </summary>
private static Hashtable ContextTransactions
{
get
{
if (CallContext.GetData("CONTEXT_TRANSACTIONS") == null)
{
CallContext.SetData("CONTEXT_TRANSACTIONS", new Hashtable());
}
return (Hashtable)CallContext.GetData("CONTEXT_TRANSACTIONS");
}
}
/// <summary>
/// Since multiple databases may be in use, there may be one session per database
/// persisted at any one time. The easiest way to store them is via a hashtable
/// with the key being tied to session factory.
/// </summary>
private static Hashtable ContextSessions
{
get
{
if (CallContext.GetData("CONTEXT_SESSIONS") == null)
{
CallContext.SetData("CONTEXT_SESSIONS", new Hashtable());
}
return (Hashtable)CallContext.GetData("CONTEXT_SESSIONS");
}
}
/// <summary>
/// Opens a stateless session
/// </summary>
/// <param name="sessionFactoryConfigPath"></param>
/// <returns></returns>
public IStatelessSession StatelessSession(string sessionFactoryConfigPath)
{
return GetSessionFactoryFor(sessionFactoryConfigPath).OpenStatelessSession();
}
}
}
Can someone give me some clue what's going on? I'm running out of ideas.
Oh, second level cache and query cache are disabled:
<property name="cache.use_second_level_cache">false</property>
<property name="cache.use_query_cache">false</property>
Thanks
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论