NHibernate - 批处理大小
在本章中,我们将介绍批处理大小更新。批处理大小允许您控制在支持的数据库中单次往返的更新次数。
从 NHibernate 3.2 开始,更新批处理大小已默认。
但是,如果您使用的是早期版本或需要调整 NHibernate 应用程序,则应查看更新批处理大小,这是一个非常有用的参数,可用于调整 NHibernate 的性能。
实际上,批处理大小控制将多少条插入推送到数据库中。
目前,只有 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(" Fetch the complete list again "); foreach (var student in students) { Console.WriteLine("{0} {1} {2} {3}", student.ID,student.FirstName, student.LastName, student.AcademicStanding); } } Console.ReadLine(); } } } }
现在让我们运行您的应用程序,您会看到所有这些更新都跳转到 NHibernate 分析器。我们有 26 次单独的数据库往返,其中 25 次用于插入,一次用于检索学生列表。
现在,为什么会这样?原因是 NHibernate 需要执行 select scope Identity,因为我们在映射文件中使用本机标识符生成策略来获取 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。这样就可以正常工作了。现在,让我们使用以下代码将本机更改为 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,如下图所示。

现在我们需要在插入数据时从 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(" Fetch the complete list again "); foreach (var student in students) { Console.WriteLine("{0} {1} {2} {3}", student.ID, student.FirstName,student.LastName, student.AcademicStanding); } } Console.ReadLine(); } } } }
现在再次运行应用程序并查看 NHibernate 分析器。现在 NHibernate 分析器将只进行 4 次往返,而不是进行 26 次往返。

它在表中插入了 10 行,然后又插入了 10 行,最后插入了剩下的 5 行。提交后,它又插入了一条记录以检索所有记录。
因此,它尽可能将其分成十个组。
因此,如果您要进行大量插入,这可以显著提高应用程序中的插入性能,因为您可以对其进行批处理。
这是因为 NHibernate 使用 guid.comb 算法自行分配这些 guid,并且它不必依赖数据库来执行此操作。
因此,使用批处理大小是一种很好的调整方法。