Nhibernate连接oracle数据库,主键ID用序列生成时连接数据库IO次数分析
本来打算主键ID用触发器生成,因为程序只需要一次IO就能插入一条数据。
图在下面,这里assigned不能改为native,从配置中看,是程序来生成ID,但实际oracle接受到插入消息后,触发器自动用序列替换了ID,因此遇到一个问题,就是程序不能获取到刚才插入的实体的主键ID,于是改为配置文件中指定序列创建ID,为了看它生成的sql和连接数据库的IO次数,我用NHibernateProfiler和sql server profiler进行了检测,oracle没找到好的检测连接sql的工具,因此用mssql的检测工具检测了下。用NHibernateProfiler检测生成sql时,迷惑了我,由于一系列的执行我共享了session,该工具都只显示一个session,并且列出它生成了哪些sql,让我以为它只是一个IO就把整个查询和操作弄好了,nhibernate的默认延时加载好像是如果同一个session中没有相同对象,然后从数据库获取对象,但该对象内部的其他对象会延时加载,并且他检测出的sql,并不是真正数据库获取到查询sql,比如查询都参数化了,但NHibernateProfiler没有很细的说明查询的值是什么参数,这在我查询序列的创建和传递给插入实体对象的sql时没看明白,我用sql server profiler才证实这点。
配置文件如下:
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="DomainModel" namespace="DomainModel">
<class name ="DomainModel.Entities.TestSeq,DomainModel" table="TESTSeq">
<id name="ID" column="ID" type="int">
<generator class ="assigned"></generator>
</id>
<property name="NAME" column="NAME" type="string"/>
</class>
</hibernate-mapping>
该为指定序列生成ID后的配置文件如下:
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="DomainModel" namespace="DomainModel">
<class name ="DomainModel.Entities.TestSeq,DomainModel" table="TESTSeq">
<id name="ID" column="ID" type="int">
<generator class="sequence">
<param name="sequence">TestSeq1</param>
</generator>
</id>
<property name="NAME" column="NAME" type="string"/>
</class>
</hibernate-mapping>
程序c#代码执行数据库语句如下:
var a = domainService.GetTestById("002");
var b = domainService.GetTestById("003");
用NHibernateProfiler检测如下:
看不到参数化的sql,能看到执行的sql,但看不出连接数据库的次数。于是我改为连接sql server,用sql server profiler检测了下连接的sql,由于mssql没有序列的说法,因此只能看共享同一个session生命周期时,所有操作数据库的sql,数据库这边检测到的sql查询次数,
配置文件如下:
<id name="Id" column="Id" type="Int32" unsaved-value="0">
<generator class ="native"></generator>
</id>
其他都一样,
c#代码如下:
var a2 = domainService.GetTestById3(1);
var b = domainService.GetTestById3(2);
object o2 = domainService.AddTest(new DomainModel.Entities.Test() { name = "ab" });
用NHibernateProfiler检测如下:
用sql server profiler检测如下:
能明显看到有3次数据库的打开关闭操作,因此我判断虽然nhibernate共享一个session,部分操作感觉像是一个整体的执行,而且只是查询操作时,NHibernateProfiler会把所有查询操作的sql完了或者有插入数据库操作时,才在界面上显示查询的几次sql记录,但NHibernateProfiler实际上还是对界面short sql中的每行记录都有一次连接和关闭数据库的查询操作,配置用序列创建主键ID时,从NHibernateProfiler显示也是两次数据库的查询操作。
对NHibernate还不够熟,李永京的nhibernate系列文章还不错,要多学习学习,NH3又多了些特征和功能,但我对NHibernate的二级缓存扩展还比较感兴趣,因为这个直接影响到最终用户,希望以后可以多熟悉这块。