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,并且它不必依赖数据库来执行此操作。
因此,使用批处理大小是一种很好的调整方法。

