NHibernate官方文档中文版——批量插入(Batch inserts)
A naive approach t7o inserting 100 000 rows in the database using NHibernate might look like this:
一个简单的使用NHibernate来向数据库插入100000条记录的操作的方式也许是这样子的:
ISession session = sessionFactory.OpenSession();
ITransaction tx = session.BeginTransaction();
for ( int i=; i<; i++ ) {
Customer customer = new Customer(.....);
session.Save(customer);
}
tx.Commit();
session.Close();
This would fall over with an OutOfMemoryException somewhere around the 50 000th row. That's because NHibernate caches all the newly inserted Customer instances in the session-level cache.
在执行到差不多50000行数据的时候,这个方法可能会在某个地方造成OutOfMemoryException异常。这个是由于NHibernate在一级缓存中缓存了所有新插入的customer实例造成的。
在这个小节我们会想你展示如何避免这个问题。首先,如果你正在进行批量任务,如果你想要达到合理的性能的话,你肯定需要允许使用ADO的批量处理。将ADO的batch size设置成一个合理的值(例如,10-50):
In this chapter we'll show you how to avoid this problem. First, however, if you are doing batch processing, it is absolutely critical that you enable the use of ADO batching, if you intend to achieve reasonable performance. Set the ADO batch size to a reasonable number (say, 10-50):
adonet.batch_size
要注意,如果你使用一个identity的标识符生成方式的话,NHibernate会自动在ADO层级禁用批量插入功能。
你还需用禁用与二级缓存的交互。
Note that NHibernate disables insert batching at the ADO level transparently if you use an identiyidentifier generator.
You also might like to do this kind of work in a process where interaction with the second-level cache is completely disabled:
cache.use_second_level_cache false
However, this is not absolutely necessary, since we can explicitly set the CacheMode to disable interaction with the second-level cache.
然而,这并不是必要的,因为我们可以显式地设置CacheMode来禁用和二级缓存的交互。
批量插入
当持久化一个新对象的时候,你必须有计划地flush()和clear()这个session来控制第一级缓存的规模。
ISession session = sessionFactory.openSession();
ITransaction tx = session.BeginTransaction(); for ( int i=; i<; i++ ) {
Customer customer = new Customer(.....);
session.Save(customer);
if ( i % == ) { //20, same as the ADO batch size
//flush a batch of inserts and release memory:
session.Flush();
session.Clear();
}
} tx.Commit();
session.Close();
无状态的session接口
此外,NHibernate提供了一个面向指令的API来以游离态的形式来将数据从数据库取出或者存入。IStatelessSession接口不包含与之相关的持久化上下文并且也不提供更多的更高级的生命周期语法。特别的,一个无状态的session并不实现一级缓存也不和二级或者查询缓存有任何的交互。它不实现事物级别的write-behind或者自动脏数据检查。使用无状态session来实现的操作也不级联关联其他实例。集合都会被无状态session忽略。使用无状态session的操作会忽略所有的NHibernate事件模型和拦截器。无状态session很容易因为数据别名的原因产生错误,这个是由于它缺乏一级缓存。无状态session是一个低级抽象,和底层的ADO更接近。
IStatelessSession session = sessionFactory.OpenStatelessSession();
ITransaction tx = session.BeginTransaction(); var customers = session.GetNamedQuery("GetCustomers")
.Enumerable<Customer>();
while ( customers.MoveNext() ) {
Customer customer = customers.Current;
customer.updateStuff(...);
session.Update(customer);
} tx.Commit();
session.Close();
要注意这个代码段例子中,customer实例在查询之后返回,并且立即变成游离态状态。他们不会和任何持久化上下文有任何关联。
statelesssession接口定义的insert(),update()和delete()操作通常被当作直接面向数据库的行级别的操作,这个操作机会直接导致相应的insert,update和delete操作。因此,他们和Isession接口中定义的Save(), SaveOrUpdate()和Delete() 操作的语法都不相同。
Alternatively, NHibernate provides a command-oriented API that may be used for streaming data to and from the database in the form of detached objects. A IStatelessSession has no persistence context associated with it and does not provide many of the higher-level life cycle semantics. In particular, a stateless session does not implement a first-level cache nor interact with any second-level or query cache. It does not implement transactional write-behind or automatic dirty checking. Operations performed using a stateless session do not ever cascade to associated instances. Collections are ignored by a stateless session. Operations performed via a stateless session bypass NHibernate's event model and interceptors. Stateless sessions are vulnerable to data aliasing effects, due to the lack of a first-level cache. A stateless session is a lower-level abstraction, much closer to the underlying ADO.
Note that in this code example, the Customer instances returned by the query are immediately detached. They are never associated with any persistence context.
The insert(), update() and delete() operations defined by the StatelessSession interface are considered to be direct database row-level operations, which result in immediate execution of a SQLINSERT, UPDATE or DELETE respectively. Thus, they have very different semantics to the Save(), SaveOrUpdate() and Delete() operations defined by the ISession interface.
DML类型操作
就像我们已经讨论过的那样,自动并且简单的对象关系映射主要关注的是对象的状态管理。这就意味着对象状态已经加载在内存中了,因此直接在数据库中对数据进行数据操作(使用SQL数据操纵语言(DML):INSERT,UPDATE,DELETE)将不会影响到内存中的数据状态。NHibernate为bulk SQL类型的DML执行提供了一些方法,这些方法可以通过Hibernate查询语句来完成(HQL)。
这些虚拟的UPDATE和DELETE语句类似于:( UPDATE | DELETE ) FROM? EntityName (WHERE where_conditions)?。需要注意一些东西:
- 在from语句中,这个FROM关键字是可选的
- 在from语句中只能有一个实体名称,它可以是一个自定义的别名。如果这个实体名称是别名,那么所有关联到这个实体的属性都应该限定使用这个别名,如果这个实体名称不是别名,那么就不能够限定这个引用。
- 在bulk HQL 查询中,不能使用 joins(无论是显式的还是隐式的)。子查询可能可以在where语句中出现,由于这些子查询自身可能就包含join。
- where语句也是可选的、
下面例子中可以看到,可以使用IQuery.ExecuteUpdate() 方法来执行一个HQL 的UPDATE操作:
As already discussed, automatic and transparent object/relational mapping is concerned with the management of object state. This implies that the object state is available in memory, hence manipulating (using the SQL Data Manipulation Language (DML) statements: INSERT, UPDATE, DELETE) data directly in the database will not affect in-memory state. However, NHibernate provides methods for bulk SQL-style DML statement execution which are performed through the Hibernate Query Language (HQL).
The pseudo-syntax for UPDATE and DELETE statements is: ( UPDATE | DELETE ) FROM? EntityName (WHERE where_conditions)?. Some points to note:
- In the from-clause, the FROM keyword is optional
- There can only be a single entity named in the from-clause; it can optionally be aliased. If the entity name is aliased, then any property references must be qualified using that alias; if the entity name is not aliased, then it is illegal for any property references to be qualified.
- No joins (either implicit or explicit) can be specified in a bulk HQL query. Sub-queries may be used in the where-clause; the subqueries, themselves, may contain joins.
- The where-clause is also optional.
As an example, to execute an HQL UPDATE, use the IQuery.ExecuteUpdate() method:
ISession session = sessionFactory.OpenSession();
ITransaction tx = session.BeginTransaction(); string hqlUpdate = "update Customer c set c.name = :newName where c.name = :oldName";
// or string hqlUpdate = "update Customer set name = :newName where name = :oldName";
int updatedEntities = s.CreateQuery( hqlUpdate )
.SetString( "newName", newName )
.SetString( "oldName", oldName )
.ExecuteUpdate();
tx.Commit();
session.Close();HQL 的UPDATE语句,默认不会影响到实体的version或者timestamp属性值。然而你可以强制让NHibernate来适当地充值version或者timestamp属性,通过使用带版本更新的update操作。这个可以通过在update关键字后面添加一个version关键字来实现。
HQL UPDATE statements, by default do not effect the version or the timestamp property values for the affected entities. However, you can force NHibernate to properly reset the version ortimestamp property values through the use of a versioned update. This is achieved by adding the VERSIONED keyword after the UPDATE keyword.
ISession session = sessionFactory.OpenSession();
ITransaction tx = session.BeginTransaction();
string hqlVersionedUpdate = "update versioned Customer set name = :newName where name = :oldName";
int updatedEntities = s.CreateQuery( hqlUpdate )
.SetString( "newName", newName )
.SetString( "oldName", oldName )
.ExecuteUpdate();
tx.Commit();
session.Close();许要注意的是,自定义的版本类型(NHibernate.Usertype.IUserVersionType)是不能和带版本更新的update操作一起使用的。
要执行HQL的DELETE操作,同样可以使用IQuery.ExecuteUpdate() 方法:
Note that custom version types (NHibernate.Usertype.IUserVersionType) are not allowed in conjunction with a update versioned statement.
To execute an HQL DELETE, use the same IQuery.ExecuteUpdate() method:
ISession session = sessionFactory.OpenSession();
ITransaction tx = session.BeginTransaction(); String hqlDelete = "delete Customer c where c.name = :oldName";
// or String hqlDelete = "delete Customer where name = :oldName";
int deletedEntities = s.CreateQuery( hqlDelete )
.SetString( "oldName", oldName )
.ExecuteUpdate();
tx.Commit();
session.Close();IQuery.ExecuteUpdate() 方法返回的int类型的返回值意味着受到这个操作影响的实体数目。要知道这个不一定对应数据库中受到影响的行数。HQL bulk操作可能导致许多关联的子类的SQL查询语句被执行,例如,返回值说明了实际上有多少实体受到语句的影响。回到关联子类的例子中来,对其中一个子类的删除操作可能不仅仅导致子类的数据表,还可能会导致父类的数据表和整个继承结构关联中潜在的其他关联子类数据表数据的删除。
虚拟的INSERT操作语法是:INSERT INTO EntityName properties_list select_statement. 有一些点需要注意:
- 只支持INSERT INTO ... SELECT ... 格式,而不支持INSERT INTO ... VALUES ... 这样的格式。
- _list属性相当于INSERT 语句中对应的字段。对于那些继承映射的实体,只有直接在给定的类中定义的属性可以在_list属性中使用。父类属性是不允许的,且子类属性没有任何意义。话句话书哦,INSERT语句的在继承映射不支持多态。
- select语句可以是任何合理的HQL select语句,需要注意的是返回值类型必须和插入语句对应的类型相匹配。目前这种检查会在编译查询语句的时候进行,而不是把这种检查交给数据库来进行。然而需要注意的是,这可能会在两种等价的NHibernate类型造成不一致的问题。这会在NHibernate.Type.DateType和NHibernate.Type.TimestampType之间产生问题,尽管数据库不会区分这两种类型或者可能会自动对二者进行转换。
- 对于id属性,insert声明给了两个方案。你可以在_list属性中显式指定id属性(在这种情况下,它的值会从相应的select表达式中获得),或者在_list属性中缺省设置(在这种情况下,会使用自动生成的值)。后面一种方法仅仅对于使用id在数据库中自动生成的方式适用;如果尝试任何在本地id类型生成方式会在解析的时候造成异常。许要注意的是,我们讨论的目的是,数据库的id生成方式被认为是NHibernate.Id.SequenceGenerator (和它的子类)和任何NHibernate.Id.IPostInsertIdentifierGenerator的实现。最需要注意的例外是NHibernate.Id.TableHiLoGenerator,这种方式不能使用,因为它不暴露任何可以select的方式来获得它的值。
- 对于映射到version或者timestamp的属性,insert声明给你两种方案。你可以在_list属性中指定对应的属性(在这种情况下,它的值会从相应的select表达式中获得)或者在_list属性中缺省设置(在这种情况下,会使用由NHibernate.Type.IVersionType 定义的种子值)。
The int value returned by the IQuery.ExecuteUpdate() method indicate the number of entities effected by the operation. Consider this may or may not correlate to the number of rows effected in the database. An HQL bulk operation might result in multiple actual SQL statements being executed, for joined-subclass, for example. The returned number indicates the number of actual entities affected by the statement. Going back to the example of joined-subclass, a delete against one of the subclasses may actually result in deletes against not just the table to which that subclass is mapped, but also the "root" table and potentially joined-subclass tables further down the inheritence hierarchy.
The pseudo-syntax for INSERT statements is: INSERT INTO EntityName properties_list select_statement. Some points to note:
- Only the INSERT INTO ... SELECT ... form is supported; not the INSERT INTO ... VALUES ... form.
- The properties_list is analogous to the column speficiation in the SQL INSERT statement. For entities involved in mapped inheritence, only properties directly defined on that given class-level can be used in the properties_list. Superclass properties are not allowed; and subclass properties do not make sense. In other words, INSERT statements are inherently non-polymorphic.
- select_statement can be any valid HQL select query, with the caveat that the return types must match the types expected by the insert. Currently, this is checked during query compilation rather than allowing the check to relegate to the database. Note however that this might cause problems between NHibernate Types which are equivalent as opposed to equal. This might cause issues with mismatches between a property defined as a NHibernate.Type.DateType and a property defined as a NHibernate.Type.TimestampType, even though the database might not make a distinction or might be able to handle the conversion.
- For the id property, the insert statement gives you two options. You can either explicitly specify the id property in the properties_list (in which case its value is taken from the corresponding select expression) or omit it from the properties_list (in which case a generated value is used). This later option is only available when using id generators that operate in the database; attempting to use this option with any "in memory" type generators will cause an exception during parsing. Note that for the purposes of this discussion, in-database generators are considered to be NHibernate.Id.SequenceGenerator (and its subclasses) and any implementors of NHibernate.Id.IPostInsertIdentifierGenerator. The most notable exception here is NHibernate.Id.TableHiLoGenerator, which cannot be used because it does not expose a selectable way to get its values.
- For properties mapped as either version or timestamp, the insert statement gives you two options. You can either specify the property in the properties_list (in which case its value is taken from the corresponding select expressions) or omit it from the properties_list (in which case the seed value defined by the NHibernate.Type.IVersionType is used).
执行一个HQL插入操作的:
An example HQL INSERT statement execution:
ISession session = sessionFactory.OpenSession();
ITransaction tx = session.BeginTransaction(); var hqlInsert = "insert into DelinquentAccount (id, name) select c.id, c.name from Customer c where ...";
int createdEntities = s.CreateQuery( hqlInsert )
.ExecuteUpdate();
tx.Commit();
session.Close();
NHibernate官方文档中文版——批量插入(Batch inserts)的更多相关文章
- NHibernate官方文档中文版--基础ORM(Basic O/R Mapping)
映射声明 对象/关系映射在XML文件中配置.mapping文件这样设计是为了使它可读性强并且可修改.mapping语言是以对象为中心,意味着mapping是围绕着持久化类声明来建立的,而不是围绕数据表 ...
- NHibernate官方文档中文版--ISessionFactory的配置(ISessionFactory Configuration)
由于NHibernate是被设计应用在许多不同环境中的,因此它存在很多配置参数.幸运的是,这些参数大多都有合理的默认值,而且NHibernate发布的时候伴随着一个App.config 例子(可在sr ...
- NHibernate官方文档中文版——事务和并发(Transactions And Concurrency)
NHibernate本身并不是一个数据库.它是一个轻量级的对象-关系映射工具.因此,它的事务管理代理给对应的数据库连接.如果这个连接代理了一个分布式的事务,ISession管理的操作就会自动成为整个分 ...
- NHibernate官方文档中文版-框架架构(Architecture)
总体概览 一个非常高层次的NHibernate架构: 这个图展示了NHibernate使用数据库和配置信息来为应用程序提供持久化服务(和持久化对象). 我们想展示一个更加详细的运行时架构.但是NHib ...
- NHibernate官方文档中文版——持久化类(Persistent Classes)
持久化类是一个应用程序中的类,主要用来实现业务逻辑(例如,在电商应用中的客户和订单类).持久化类,就像它的名字一样,生命周期短暂并且用来持久化的据库对象实例. 如果这些类的构造能够依照一些简单的原则, ...
- NHibernate官方文档中文版--只读实体类型(Read-only entities)
重点 NHIbernate处理只读对象的方式可能和你在别处看到的不同.不正确的使用方式可能造成不可预料的结果. 当一个实体是只读的时候: NHIbernate不会对实体的简单属性和单向关联数据检查数据 ...
- NHibernate官方文档中文版--拦截器和事件(Interceptors and events)
对于应用程序来说,能够对NHibernate内部发生的事件做出响应式很有用的.这能够有助于实现一些类的功能或者扩展NHibernate的功能. 拦截器 IInterceptor接口提供了应用程序ses ...
- TestNG官方文档中文版(2)-annotation(转)
1. 介绍 TestNG是一个设计用来简化广泛的测试需求的测试框架,从单元测试(隔离测试一个类)到集成测试(测试由有多个类多个包甚至多个外部框架组成的整个系统,例如运用服务器). 编写一个测试的 ...
- 2DToolkit官方文档中文版打地鼠教程(三):Sprite Collections 精灵集合
这是2DToolkit官方文档中 Whack a Mole 打地鼠教程的译文,为了减少文中过多重复操作的翻译,以及一些无必要的句子,这里我假设你有Unity的基础知识(例如了解如何新建Sprite等) ...
随机推荐
- Linux 入门记录:十一、Linux 用户基础
一.用户.组 1. 用户 当我们使用 Linux 时,需要以一个用户的身份登录,一个进程也需要以一个用户的身份运行.用户限制使用者或进程可以使用或不可以使用哪些资源. 2. 组 组用来方便地管理用户. ...
- java===java基础学习(16)---final
final-----概念 1.当不希望父类的某个方法被子类覆盖(override)时,可以用final关键字修饰. 2.当不希望类的某个变量的值被修改时,可以用final修饰.如果要用final,则必 ...
- Perl中文件读取操作
Perl中文件读取操作 http://blog.csdn.net/yangxuan12580/article/details/51506216
- ICTPOS3.0 词性标注集
Ag 形语素 形容词性语素.形容词代码为a,语素代码g前面置以A. a 形容词 取英语形容词adjective的第1个字母. ad 副形词 直接作状语的形容词.形容词代码a和副词代码d并在一起. an ...
- MySQL的sql_mode解析与设置
https://blog.csdn.net/hhq163/article/details/54140286 https://blog.csdn.net/ccccalculator/article/de ...
- C#文件路径乱码
最近学C#,用C#写serialport遇到了一点小问题记录一下. 问题一: if (!string.IsNullOrEmpty(filePath.ToString())) { try { fs = ...
- linux和性能相关的命令及系统性能诊断
常用的和性能有关的命令 Iostat/vmstat/top/mpstat/time/strace/ipcs/ipcrm/ifconfig/tethereal/netstat/free/uptime 关 ...
- JDBC原生数据库连接
我们在开发JavaWeb项目时,常会需要连接数据库.我们以MySQL数据库为例,IDE工具为eclipse,讲述数据库连接与基本操作. 第一步,我们在Web项目的WebContent中建一个简单的前端 ...
- Leetcode 之Longest Palindromic Substring(30)
很经典的一道题,最长回文子串,有多种方法. 首先介绍的一种方法是从中间向两边展开.注意区分aba和abba型的回文串:如果当前最长的子串已经当于两边中最长的子串了,则无需再去判断. //从中间向两边展 ...
- 1:django models
重温django model 1:many-to-many 的额外属性 一般情况下,many-to-many直接就可以满足我们的要求,考虑这样一种情况: 音乐家和乐团是many-to-many的关系, ...