摘要
对于批量插入和批量修改数据,通过设置NHibernate配置文件的BatchSize属性,可以大量减少NHibernate与数据库交互的次数。
1. Batch属性介绍
设置了BatchSize属性后,NHibernate将对批量的Insert/Update操作进行自动分组,按分组提交到数据库,大量减少了与数据库交互的次数。
NHibernate目前只支持对SQL Server数据库和Oracle数据库的批量Insert/Update操作进行BatchSize优化。
对于Insert操作,NHibernate只能对主键数据类型是UNIQUEIDENTIFIER的表提供BatchSize优化。
1)IDENTITY类型主键
在上一篇文章中,Customer表主键类型是IDENTITY类型的。
程序演示
修改SessionFactory属性,添加x.BatchSize = 10的配置。
public static ISessionFactory SessionFactory
{
get
{
if (_sessionFactory == null)
{
var cfg = new Configuration();
cfg.DataBaseIntegration(x=> {
x.BatchSize = ;
});
cfg.Configure();
_sessionFactory = cfg.BuildSessionFactory();
}
return _sessionFactory;
}
}
修改Main函数
static void Main(string[] args)
{
HibernatingRhinos.Profiler.Appender.NHibernate.NHibernateProfiler.Initialize(); using (var session = SessionFactory.OpenSession())
{
for (int i = ; i < ; i++)
{
var customer = new Customer
{
FirstName = "FirstName" + i,
LastName = "LastName" + i,
MemberSince = new DateTime(, , )
};
session.Save(customer);
}
session.Flush();
Console.WriteLine("fetch the complete list");
var list = session.CreateCriteria<Customer>().List<Customer>();
foreach (Customer customer in list)
{
Console.WriteLine("{0} {1}", customer.FirstName,customer.LastName);
}
} Console.WriteLine("Completed");
Console.ReadLine();
}
打开NHibernate Profile,清空Session,执行程序,得到结果
监控到NHibernate执行了26次SQL语句,25次Insert语句和1次Select语句。
这是因为,虽然配置了BatchSize=10,但是Customer表的主键列的生成策略是Identity,每次Insert操作完成后都要计算下一条新记录的主键值,因此BatchSize没办法对其进行分组优化。
选择一条Insert监控数据,在Detail栏中看到执行了select SCOP_IDENTITY()语句。
2)UNIQUEIDENTIFIER类型主键
删除Customer表,用UNIQUEIDENTIFIER主键重建Customer表。
重建Customer表的SQL语句。
CREATE TABLE [dbo].[Customer](
--[Id] [int] IDENTITY(1,1) NOT NULL,
Id UNIQUEIDENTIFIER NOT NULL,
[FirstName] [nvarchar](100) NOT NULL,
[LastName] [nvarchar](100) NOT NULL,
[Points] [int] NULL,
[HasGoldStatus] [bit] NULL,
[MemberSince] [date] NULL,
[CreditRating] [nchar](20) NULL,
[AverageRating] [decimal](18, 4) NULL,
[Street] [nvarchar](100) NULL,
[City] [nvarchar](100) NULL,
[Province] [nvarchar](100) NULL,
[Country] [nvarchar](100) NULL,
CONSTRAINT [PK_Customer] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
修改Customer类,Id属性类型改成了Guid。
public class Customer
{
public virtual Guid Id { get; set; }
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
public virtual double AverageRating { get; set; }
public virtual int Points { get; set; }
public virtual bool HasGoldStatus { get; set; }
public virtual DateTime MemberSince { get; set; }
public virtual CustomerCreditRating CreditRating { get; set; }
public virtual string Street { get; set; }
public virtual string City { get; set; }
public virtual string Province { get; set; }
public virtual string Country { get; set; }
}
修改Customer.hbm.xml文件,将Id的generator class改成了guid.comb。
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="NHibernateDemoApp" namespace="NHibernateDemoApp">
<class name="Customer" table="Customer">
<id name="Id">
<generator class="guid.comb"/>
</id>
<property name="FirstName" not-null="true"/>
<property name="LastName" not-null ="true"/>
<property name="AverageRating"/>
<property name="Points"/>
<property name="HasGoldStatus"/>
<property name="MemberSince"/>
<property name="CreditRating" type="CustomerCreditRating"/>
<property name="Street"/>
<property name="City"/>
<property name="Province"/>
<property name="Country"/>
</class>
</hibernate-mapping>
清空NHibernate Profile的Session,执行程序,得到结果。
NHibernate只与数据库交互了四次,三次Insert,一次Select。因为表的主键类型是UNIQUEIDENTIFIER,每次Insert记录时NHibernate自动生成新记录主键值,不需要数据库计算下一条记录的主键值。
设置了BatchSize=10,NHibernate将25次Insert操作自动分成三组,第一组10条Insert语句,第二组10条Insert语句,第三组5条Insert语句,再加上最后的一次查询语句,一共是4次与数据库交互。