我正在将 TransactionScope 与 nHibernate 一起使用。为了处理嵌套事务,我与 TransactionScope 一起创建了一个帮助器类。我的 SessionFactory :
public class SessionFactory
{
[ThreadStatic]
private static ISessionFactory iSessionFactory;
[ThreadStatic]
protected static ISession session;
private static object syncRoot = new Object();
private static void buildSessionFactory()
{
lock (syncRoot)
{
if (session == null)
{
if (iSessionFactory == null)
{
Configuration configuration = new Configuration().Configure("hibernate.cfg.xml");
Assembly assembly = Assembly.GetCallingAssembly();
iSessionFactory = configuration.BuildSessionFactory();
}
if (session != null && session.IsOpen)
session.Dispose();
CurrentSessionContext.Bind(iSessionFactory.OpenSession());
session = iSessionFactory.OpenSession();
}
}
}
public static ISession OpenSession
{
get
{
if (session == null || !session.IsOpen)
{
session = null;
buildSessionFactory();
}
return session;
}
}
}
配置文件名为 hibernate.cfg.xml ,并且为:
<configuration>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<property name="connection.driver_class">
NHibernate.Driver.MySqlDataDriver
</property>
<property name="dialect">NHibernate.Dialect.MySQL55InnoDBDialect</property>
<property name="connection.connection_string">connection string here</property>
<property name="current_session_context_class">thread_static</property>
<property name="show_sql">true</property>
<property name="generate_statistics">true</property>
<mapping assembly="assembly name here"/>
<!-- Here -->
</session-factory>
</hibernate-configuration>
<system.transactions>
<machineSettings maxTimeout="00:00:60" />
</system.transactions>
</configuration>
用于管理嵌套交易的帮助程序类:
public class TransactionScopeHelper : SessionFactory, iTransactionScopeHelper
{
public static int count = 0;
public TransactionScope getTransactionScope()
{
if (count == 0)
{
if (session != null)
session.Clear();
}
count++;
return new TransactionScope(TransactionScopeOption.Required);
}
public void complete(TransactionScope tx)
{
count--;
if (count == 0)
{
session.Flush();
session = null;
}
tx.Complete();
}
public void rollbackTransaction()
{
count = 0;
session = null;
}
}
Helper类仅在服务中使用,而在存储库中不使用 服务中使用助手的示例:
public void updateCategory(CategoryDto category_dto)
{
try
{
using (TransactionScope tx = transactionScopeHelper.getTransactionScope())
{
//works here
transactionScopeHelper.complete(tx);
}
}
catch(Exception)
{
transactionScopeHelper.rollbackTransaction();
throw;
}
}
存储库中的功能示例:
public T getById(long id)
{
ISession session = SessionFactory.OpenSession;
return session.Get<T>(id);
}
每当我更新一些实体时,在刷新几次后就会显示旧数据,而在刷新一些新数据后会再次显示。这几乎是连续的。为什么会出现这个问题?任何帮助将不胜感激。
答案 0 :(得分:2)
这里发生了很多“不寻常”的事情,我几乎不知道从哪里开始。
SessionFactory
NHibernate的会话工厂在应用程序启动时(或在第一次需要时)已进行了一次ONCE的初始化,然后该实例将在程序运行期间存活并在所有线程之间共享。通常,我们不希望每个线程都有一个单独的实例(就像ThreadStatic一样)。反复初始化会严重影响性能。
buildSessionFactory()将在存在会话的情况下处理该会话-但除非session为null,否则它将无法获取该代码,所以我不明白这里的意图是什么。
在buildSessionFactory()的结尾,iSessionFactory.OpenSession()被调用了两次!一次就足够了。
您正在配置文件中设置current_session_context_class
,然后调用CurrentSessionContext.Bind()。因此,您无需维护自己的线程静态会话变量。这就是CurrentSessionContext的作用。
最终必须处置会话。因此,调用名为OpenSession
的方法意味着我们得到一个新的会话,该会话负责关闭。但是您自己的OpenSession()可以多次返回相同的会话,因此很难理解到底是谁负责关闭该会话。最好将其命名为CurrentSession
或类似名称。
TransactionScopeHelper
这也是不可能理解的。引用了变量session
,但未显示此变量的定义和设置。代码不完整。在某些时候,会话引用被设置为null,但是没有尝试处置它,这是强制性的。
在会话上调用Clear()将删除会话中的所有状态,并使NHibernate失去对所有已加载对象的跟踪,因此将无法执行脏检查并自动持久化。其他代码需要记住要仔细地重新添加所有内容。
代码未显示会话,事务和事务范围的实际创建方式和时间。无法判断互动是否正确。会话是否知道交易范围?
最后,回答您的问题:“我为什么会遇到这个问题?”
对不起,但是整个情况看起来一团糟。凌乱的代码等于凌乱的结果。当然,除非我上面提到的问题是由于部分复制粘贴导致重要部分遗漏所致。