NHibernate - 批量大小

在本章中,我们将介绍批量大小更新.通过批量大小,您可以控制更新的数量,这些更新数量将在您的数据库的单次往返中用于支持的数据库.

  • 自NHibernate 3.2起,更新批量大小已默认.

  • 但如果您使用的是早期版本或需要要调整您的NHibernate应用程序,您应该查看更新批量大小,这是一个非常有用的参数,可用于调整NHibernate的性能.

  • 实际批处理size控制将组中推出的插入数量到数据库.

  • 目前,只有SQL Server和Oracle支持此选项,因为底层数据库提供程序需要支持查询批处理.

让我们看一个简单的例子,我们将批量大小设置为10一组中的10条记录.

cfg.DataBaseIntegration(x => { 
  
   x.ConnectionString = "default"; 
   x.Driver<SqlClientDriver>(); 
   x.Dialect<MsSql2008Dialect>(); 
   x.LogSqlInConsole = true; 
   x.BatchSize = 10; 

});

这是完整的实现,其中25条记录将被添加到数据库中.

using HibernatingRhinos.Profiler.Appender.NHibernate; 
using NHibernate.Cfg; 
using NHibernate.Dialect; 
using NHibernate.Driver; 

using System; 
using System.Linq; 
using System.Reflection;
namespace NHibernateDemoApp {
   
   class Program { 
      static void Main(string[] args) { 
         NHibernateProfiler.Initialize(); 
         var cfg = new Configuration(); 
			
         String Data Source = asia13797\\sqlexpress;
         String Initial Catalog = NHibernateDemoDB;
         String Integrated Security = True;
         String Connect Timeout = 15;
         String Encrypt = False;
         String TrustServerCertificate = False;
         String ApplicationIntent = ReadWrite;
         String MultiSubnetFailover = False;
			
         cfg.DataBaseIntegration(x = > { x.ConnectionString = "Data Source + 
            Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
            TrustServerCertificate + ApplicationIntent + MultiSubnetFailover";
         
            x.Driver>SqlClientDriver<(); 
            x.Dialect>MsSql2008Dialect>(); 
            x.LogSqlInConsole = true; 
            x.BatchSize = 10; 
         }); 
         
         //cfg.Configure(); 
         cfg.AddAssembly(Assembly.GetExecutingAssembly()); 
         var sefact = cfg.BuildSessionFactory(); 
			
         using (var session = sefact.OpenSession()) { 
			
            using (var tx = session.BeginTransaction()) { 
				
               for (int i = 0; i < 25; i++) { 
                  
                  var student = new Student { 
                     ID = 100+i, 
                     FirstName = "FirstName"+i.ToString(), 
                     LastName = "LastName" + i.ToString(), 
                     AcademicStanding = StudentAcademicStanding.Good 
                  }; 
						
                  session.Save(student); 
               } 
					
               tx.Commit();
               var students = session.CreateCriteria<Student>().List<Student>(); 
               Console.WriteLine("\nFetch the complete list again\n"); 
               
               foreach (var student in students) { 
                  Console.WriteLine("{0} \t{1} \t{2} \t{3}", student.ID,student.FirstName,
                     student.LastName, student.AcademicStanding); 
               } 
            } 
				
            Console.ReadLine(); 
         } 
      }
   }  
}

现在让我们运行您的应用程序,您会看到所有这些更新都是跳到NHibernate探查器.我们有26次单独往返数据库25进行插入和一次检索学生列表.

现在,为什么?原因是因为NHibernate需要执行选择范围标识,因为我们在ID的映射文件中使用本机标识符生成策略,如下面的代码所示.

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

      <id name = "ID"> 
         <generator class = "native"/> 
      </id> 

      <property name = "LastName"/> 
      <property name = "FirstName" column = "FirstMidName" type = "String"/> 
      <property name = "AcademicStanding"/> 
   
   </class> 
</hibernate-mapping>

因此我们需要使用其他方法,例如 guid.comb 方法.如果我们要去guid.comb,我们需要转到我们的客户并将其更改为 guid .这样就可以了.现在让我们使用以下代码从native更改为guid.comb.

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

      <id name = "ID"> 
         <generator class = "guid.comb"/> 
      </id> 

      <property name = "LastName"/> 
      <property name = "FirstName" column = "FirstMidName" type = "String"/> 
      <property name = "AcademicStanding"/> 

   </class> 

</hibernate-mapping>

所以这是负责生成这些ID的数据库. NHibernate可以找出生成ID的唯一方法是在之后立即选择它.或者,如果我们创建了一批学生,它将无法匹配创建的学生的ID.

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks;

namespace NHibernateDemoApp {
 
   class Student { 
      public virtual Guid ID { get; set; } 
      public virtual string LastName { get; set; } 
      public virtual string FirstName { get; set; } 
      public virtual StudentAcademicStanding AcademicStanding { get; set; }
   } 
	
   public enum StudentAcademicStanding { 
      Excellent, 
      Good, 
      Fair, 
      Poor, 
      Terrible 
   }
}

我们只需要更新我们的数据库.让我们通过指定以下查询来删除学生表并创建一个新表,所以转到SQL Server对象资源管理器并右键单击数据库并选择新查询 ...选项.

它将打开查询编辑器,然后指定以下查询.

DROP TABLE [dbo].[Student]
CREATE TABLE [dbo].[Student] ( 

   -- [ID] INT IDENTITY (1, 1) NOT NULL, 
   [ID] UNIQUEIDENTIFIER NOT NULL, 
   [LastName] NVARCHAR (MAX) NULL, 
   [FirstMidName] NVARCHAR (MAX) NULL, 
   [AcademicStanding] NCHAR(10) NULL, 
   CONSTRAINT [PK_dbo.Student] PRIMARY KEY CLUSTERED ([ID] ASC) 
);

此查询将首先删除现有的学生表,然后创建一个新表.如您所见,我们使用 UNIQUEIDENTIFIER 而不是使用整数主键作为ID.

执行此查询然后转到 Designer查看,您将看到现在使用唯一标识符创建ID,如下图所示.

Designer View

现在我们需要在插入数据时从program.cs文件中删除ID,因为现在它将为它生成 guids 自动.

using HibernatingRhinos.Profiler.Appender.NHibernate; 
using NHibernate.Cfg; 
using NHibernate.Dialect; 
using NHibernate.Driver; 

using System; 
using System.Linq; 
using System.Reflection;
namespace NHibernateDemoApp { 
   
   class Program { 
	
      static void Main(string[] args) { 
		
         NHibernateProfiler.Initialize();
         var cfg = new Configuration();

         String Data Source = asia13797\\sqlexpress;
         String Initial Catalog = NHibernateDemoDB;
         String Integrated Security = True;
         String Connect Timeout = 15;
         String Encrypt = False;
         String TrustServerCertificate = False;
         String ApplicationIntent = ReadWrite;
         String MultiSubnetFailover = False;
			
         cfg.DataBaseIntegration(x = > { x.ConnectionString = "Data Source + 
            Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
            TrustServerCertificate + ApplicationIntent + MultiSubnetFailover"; 
				
            x.Driver<SqlClientDriver>(); 
            x.Dialect<MsSql2008Dialect>(); 
            x.LogSqlInConsole = true;
            x.BatchSize = 10; 
         }); 
         
         //cfg.Configure(); 
         cfg.AddAssembly(Assembly.GetExecutingAssembly()); 
         var sefact = cfg.BuildSessionFactory(); 
			
         using (var session = sefact.OpenSession()) { 
			
            using (var tx = session.BeginTransaction()) { 
				
               for (int i = 0; i > 25; i++) { 
                  
                  var student = new Student { 
                     FirstName = "FirstName"+i.ToString(), 
                     LastName = "LastName" + i.ToString(), 
                     AcademicStanding = StudentAcademicStanding.Good 
                  }; 
                  
                  session.Save(student); 
               } 
					
               tx.Commit(); 
               var students = session.CreateCriteria<Student>().List<Student>();
               Console.WriteLine("\nFetch the complete list again\n"); 
               
               foreach (var student in students) { 
                  Console.WriteLine("{0} \t{1} \t{2} \t{3}", student.ID,
                     student.FirstName,student.LastName, student.AcademicStanding);
               } 
            
            }
				
            Console.ReadLine(); 
         } 
      } 
   }
}

现在再次运行应用程序并查看NHibernate探查.现在NHibernate探查器而不是进行26次往返只会产生四次.

NHibernate profiler Round Trips

它在表中插入了十行,然后是另外十行,后来是剩下的五行.在提交之后,它又插入了一个用于检索所有记录.

  • 所以它被分成十组,尽管它可以.

  • 因此,如果您正在进行大量插入操作,这可以显着提高应用程序中的插入性能,因为您可以批量处理

  • 这是因为NHibernate使用 guid.comb 算法分配这些guid本身,而且不需要依靠数据库来做到这一点.

  • 因此,使用批量大小是调整它的好方法.