Nhibernate和并发

时间:2013-03-21 18:02:53

标签: nhibernate concurrency transactions

使这个测试应用程序同时运行的最佳方法是什么?

当我的程序完成后,控制台应用程序将员工计数打印为4057。它应该是20000,因为我有20个线程增加员工数1000次。

Program.cs的

using System;
using System.Data;
using System.Diagnostics;
using System.Threading.Tasks;
using DataAccess;
using NHibernate;
using NHibernate.Cfg;
using NHibernate.Tool.hbm2ddl;

namespace NhibernatePlayground
{
    internal class Program
    {
        private static ISessionFactory _sessionFactory;
        private static Configuration _configuration;
        private static int TotalThreadCount = 20;
        private static int LoopCount = 1000;

        private static void Main(string[] args)
        {

            _configuration = BuildConfiguration();
            var se = new SchemaExport(_configuration);
            se.Drop(true, true);
            se.Create(false, true);


            _sessionFactory = _configuration.BuildSessionFactory();

            int companyId = Seed();

            Stopwatch sw = new Stopwatch();
            sw.Start();
            Task[] tasks = new Task[TotalThreadCount];
            for (int i = 0; i < TotalThreadCount; i ++)
            {
                tasks[i] = Task.Factory.StartNew(() => IncreaseEmployeeCount(LoopCount, companyId));
            }

            //Block until all tasks complete.
            Task.WaitAll(tasks);
            sw.Stop();

            Console.WriteLine("Employee Count: " + GetEmployeeCount(companyId));
            Console.WriteLine("Total Milliseconds: " + sw.ElapsedMilliseconds);
            Console.ReadKey();
        }

        private static Configuration BuildConfiguration()
        {
            Configuration configuration = new Configuration();
            configuration.Configure(); // A
            configuration.AddAssembly(typeof (Company).Assembly); // B            
            return configuration;
        }

        private static void IncreaseEmployeeCount(int count, int companyId)
        {
            for (int i = 0; i < count; i++)
            {
                using (ISession _session = _sessionFactory.OpenSession())
                {
                    using (ITransaction _transaction = _session.BeginTransaction())
                    {
                        var company = _session.Get<Company>(companyId);
                        company.EmployeeCount++;
                        _session.Save(company);
                        _transaction.Commit();
                    }
                }
            }
        }

        private static int Seed()
        {
            using (ISession _session = _sessionFactory.OpenSession())
            {
                using (ITransaction _transaction = _session.BeginTransaction())
                {
                    Company company = new Company
                        {
                            CompanyName = "Angus"
                        };

                    _session.Save(company);
                    _transaction.Commit();
                    return company.Id;
                }
            }
        }

        private static int GetEmployeeCount(int companyId)
        {
            using (ISession _session = _sessionFactory.OpenSession())
            {
                using (ITransaction _transaction = _session.BeginTransaction())
                {
                    Company company = _session.Get<Company>(companyId);
                    return company.EmployeeCount;
                }
            }
        }
    }
}

Company.hbm.xml

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="DataAccess" namespace="DataAccess" >

  <class name="Company">
    <id name="Id">
      <generator class="hilo" />
    </id>

    <property name="IsActive" />

    <property name="CompanyName" />

    <property name="EmployeeCount" />

    <set name="Users" table="Users_Companies" cascade="none">
      <key column="CompanyId"/>
      <many-to-many column="UserId" class="UserProfile" />
    </set>    
  </class>

</hibernate-mapping>

Company.cs

using Iesi.Collections.Generic;

namespace DataAccess
{
    public class Company : Entity<int>
    {
        public Company()
        {
            //it's not the best practice to initialize virtual properties in constructor but we're controlling 
            //the inheritance in this so doing this should be fine
            // http://stackoverflow.com/a/469577/89605
            Users = new HashedSet<UserProfile>();
        }

        public Company(string name)
            : this()
        {
            CompanyName = name;
            IsActive = true;
        }

        public virtual string CompanyName { set; get; }

        public virtual bool IsActive { set; get; }

        public virtual ISet<UserProfile> Users { set; get; }

        public virtual int EmployeeCount { set; get; }

        public virtual void CopyTo(Company target)
        {
            target.CompanyName = CompanyName;
            target.IsActive = IsActive;
        }
    }
}

1 个答案:

答案 0 :(得分:0)

在读取对象时,您需要在数据库中获取写锁定。探索Get()或ISession.Lock()方法的锁模式参数。这将是悲观锁定,这适用于这样的场景(频繁写入相同的数据)。另一种选择是乐观锁定,当不经常写入相同数据时,它最有效。为此,探索NHibernate的&lt; version&gt;映射元素。