如何使用nHibernate添加NOLOCK?

如何在使用nhibernate时添加NOLOCK? (标准查询)


SetLockMode(LockMode.None)connection.isolation ReadUncomitted不附加NOLOCK到您的查询。

Ayende在他的博客上进入正确的答案:

如果您使用<sql-query> ,则可以执行以下操作:

<sql-query name="PeopleByName">
    <return alias="person"
                    class="Person"/>
    SELECT {person.*}
    FROM People {person} WITH(nolock)
    WHERE {person}.Name LIKE :name
</sql-query>

请注意附加到FROM子句的WTIH(nolock)


我将解释如何做到这一点,以便您可以添加NOLOCK(或任何其他查询提示),同时仍使用ICriteria或HQL,而无需将查询知识保存到映射或会话工厂配置中。

我为NHibernate 2.1写了这个。 有一些主要的注意事项,主要是由于NHibernate中的“use_sql_comments”打开时出现错误(见下文)。 我不确定这些错误是否已在NH 3中得到修复,但请尝试一下。 更新:错误没有被修复为NH 3.3。 我在这里描述的技术和解决方法仍然有效。

首先,创建一个拦截器,如下所示:

[Serializable]
public class QueryHintInterceptor : EmptyInterceptor
{
    internal const string QUERY_HINT_NOLOCK_COMMENT = "queryhint-nolock: ";

    /// <summary>
    /// Gets a comment to add to a sql query to tell this interceptor to add 'OPTION (TABLE HINT(table_alias, INDEX = index_name))' to the query.
    /// </summary>
    internal static string GetQueryHintNoLock(string tableName)
    {
        return QUERY_HINT_NOLOCK_COMMENT + tableName;
    }

    public override SqlString OnPrepareStatement(SqlString sql)
    {
        if (sql.ToString().Contains(QUERY_HINT_NOLOCK_COMMENT))
        {
            sql = ApplyQueryHintNoLock(sql, sql.ToString());
        }

        return base.OnPrepareStatement(sql);
    }

    private static SqlString ApplyQueryHintNoLock(SqlString sql, string sqlString)
    {
        var indexOfTableName = sqlString.IndexOf(QUERY_HINT_NOLOCK_COMMENT) + QUERY_HINT_NOLOCK_COMMENT.Length;

        if (indexOfTableName < 0)
            throw new InvalidOperationException(
                "Query hint comment should contain name of table, like this: '/* queryhint-nolock: tableName */'");

        var indexOfTableNameEnd = sqlString.IndexOf(" ", indexOfTableName + 1);

        if (indexOfTableNameEnd < 0)
            throw new InvalidOperationException(
                "Query hint comment should contain name of table, like this: '/* queryhint-nlock: tableName */'");

        var tableName = sqlString.Substring(indexOfTableName, indexOfTableNameEnd - indexOfTableName).Trim();

        var regex = new Regex(@"{0}s(w+)".F(tableName));

        var aliasMatches = regex.Matches(sqlString, indexOfTableNameEnd);

        if (aliasMatches.Count == 0)
            throw new InvalidOperationException("Could not find aliases for table with name: " + tableName);

        var q = 0;
        foreach (Match aliasMatch in aliasMatches)
        {
            var alias = aliasMatch.Groups[1].Value;
            var aliasIndex = aliasMatch.Groups[1].Index + q + alias.Length;

            sql = sql.Insert(aliasIndex, " WITH (NOLOCK)");
            q += " WITH (NOLOCK)".Length;
        }
        return sql;
    }

    private static SqlString InsertOption(SqlString sql, string option)
    {
        // The original code used just "sql.Length". I found that the end of the sql string actually contains new lines and a semi colon.
        // Might need to change in future versions of NHibernate.
        var regex = new Regex(@"[^;s]", RegexOptions.RightToLeft);
        var insertAt = regex.Match(sql.ToString()).Index + 1;
        return sql.Insert(insertAt, option);
    }
}

然后在某处创建一些漂亮的扩展方法:

public static class NHibernateQueryExtensions
{
    public static IQuery QueryHintNoLock(this IQuery query, string tableName)
    {
        return query.SetComment(QueryHintInterceptor.GetQueryHintNoLock(tableName));
    }

    public static ICriteria QueryHintNoLock(this ICriteria query, string tableName)
    {
        return query.SetComment(QueryHintInterceptor.GetQueryHintNoLock(tableName));
    }
}

接下来,告诉NHibernate使用你的拦截器:

config.SetInterceptor(new QueryHintInterceptor());

最后,在NHibernate配置中启用use_sql_comments属性。

你完成了! 现在你可以添加像这样的nolock提示:

var criteria = Session.CreateCriteria<Foo>()
    .QueryHintNoLock("tableFoo")
    .List<Foo>();

我将这项工作基于这里描述的技术:http://www.codewrecks.com/blog/index.php/2011/07/23/use-sql-server-query-hints-with-nhibernate-hql-and-的ICriteria /

NHibernate展示Bug:

首先,NHibernate存在这个bug,你需要修复。 (你可以通过直接修复NHibernate的源代码来修复这个bug,或者通过做我做的和创建你自己的方言来修复问题)。

其次,当您在第一页之后的任何页面上执行分页查询,并且您正在使用投影时,似乎会出现另一个错误。 由NHibernate生成的SQL在“OVER”子句周围是完全错误的。 在这个阶段,我不知道如何解决这个错误,但我正在努力。 更新:我已经详细说明了如何解决这个bug。 像其他bug一样,这个也可以通过修复NHibernate源代码或创建自己的Dialect类来修复。


如果您要在很多查询中使用它,可以通过配置属性connection.isolation将其设置为默认值。

<property name="connection.isolation">ReadUncommitted</property> 

查看该属性的文档。

链接地址: http://www.djcxy.com/p/32851.html

上一篇: How do add NOLOCK with nHibernate?

下一篇: Better concurrency in Oracle than SQL Server?