简体   繁体   English

休眠和并发

[英]Nhibernate and Concurrency

What's the best way to make this test application to run concurrently? 使该测试应用程序同时运行的最佳方法是什么?

When my program has finished, the console application prints the employee count as 4057 . 我的程序完成后,控制台应用程序将雇员计数打印为4057 It should be 20000 because I have 20 threads incrementing the employee count 1000 times. 应该是20000因为我有20线程将雇员计数增加1000次。

Program.cs 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 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 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;
        }
    }
}

You need to grab a write-lock in the database while reading the object. 在读取对象时,您需要在数据库中获取写锁。 Explore the lock mode parameter to Get(), or the ISession.Lock() method. 探索Get()或ISession.Lock()方法的锁定模式参数。 This would be pessimistic locking, which would be appropriate for a scenario like this (frequent writes to the same data). 这将是悲观锁定,适用于这种情况(频繁写入同一数据)。 The alternative is optimistic locking, which works best when there are infrequent writes to the same data. 另一种选择是乐观锁定,当很少写入相同数据时,这种方法最有效。 For that, explore NHibernate's <version> mapping element. 为此,请探索NHibernate的<version>映射元素。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM