Nhibernate的Session和StatelessSession性能比较

NhibernateSessionStatelessSession性能比较

作者:邓家海

一个月入30K的大神有一天跟我说:我当年在你现在这个阶段,还在吊儿郎当呢!所以你努力吧!

有时候,一个想法就是1000秒,另一个想法只需要10秒

前言:

近段时间忙着给一个政府机关推送数据到国家数据库,数据量一共加起来有六十几万吧。这么多数据使用人工推送显然是一个不小的工作量,所以必须要使用程序来处理代码。为了方便,我们选择使用Nhibernate框架来进行CURD操作。有人大呼脑残,哈哈哈···为了方便偷懒,就是什么事情都敢做。六十几万,也算是一个大数据了吧。写程序可能才使用了三天左右的时间,然后就是跑数据。结果跑数据跑了两天多。1000条数据使用了1分钟左右。当时时间也很紧急,没有想太多。只好硬着头皮日夜加班跑数据。

这段时间回来公司有空闲,后面还要继续推送数据。于是领导就交代我一个任务,想一个跑数据更快捷的方案。

 

首先想到的是使用原生的ADO。但是,我又不甘心写太多代码,我在想为什么NHIBERNATE会这么慢?究竟是什么原因。查了一番资料。终于找到了可行的方案。自己顺便做了一个实验。证实此方案可行。原来是NHIBERNATE 的Session和StateLessSession这两个的原因。

 

测试环境:

Windows7

Access

Hibernate4

数据量:20000数据

 

首先看Session实现代码

  1 using System;
  2
  3 using System.Collections.Generic;
  4
  5 using System.Linq;
  6
  7 using System.Text;
  8
  9 using System.Threading.Tasks;
 10
 11 using NHibernate;
 12
 13 using NHibernate.Cfg;
 14
 15
 16
 17 namespace BDC.Framework
 18
 19 {
 20
 21     public class DataSourceFactoryStateless
 22
 23     {
 24
 25         private static Dictionary<string, IStatelessSession> staticSessionDictionary = new Dictionary<string, IStatelessSession>();
 26
 27         private static object lockObject = new object();
 28
 29         private const  string OracleAssembly = "BDC.ZcServer";
 30
 31         private const string AccessAssembly = "BDC.Standard";
 32
 33
 34
 35         public static IStatelessSession GetSession<T>() where T:class
 36
 37         {
 38
 39             string assembly = typeof(T).Assembly.GetName().Name;
 40
 41             IStatelessSession _session = null;
 42
 43             bool isFind = false;
 44
 45             if (staticSessionDictionary.Keys.Contains(assembly)) { _session = staticSessionDictionary[assembly]; isFind = true; }
 46
 47             try
 48
 49             {
 50
 51                 if(_session == null)
 52
 53                 {
 54
 55                     lock (lockObject)
 56
 57                     {
 58
 59                         ISessionFactory factory = null;
 60
 61                         switch (assembly) {
 62
 63                             case OracleAssembly:
 64
 65                                 factory = LoadOracleConfig();
 66
 67                                 break;
 68
 69                             case AccessAssembly:
 70
 71                                 factory = LoadAccessConfig();
 72
 73                                 break;
 74
 75                             default:
 76
 77                                 throw new Exception("没有找到对应的程序集");
 78
 79                         }
 80
 81                         // _session = factory.OpenSession();
 82
 83                         _session=factory.OpenStatelessSession();
 84
 85                         if (isFind) { staticSessionDictionary[assembly] = _session; }
 86
 87                         else { staticSessionDictionary.Add(assembly, _session); }
 88
 89                     }
 90
 91                 }
 92
 93
 94
 95                 return _session;
 96
 97             }catch(Exception ex)
 98
 99             {
100
101                 throw new Exception("数据库初始化失败");
102
103             }
104
105         }
106
107
108
109         private static ISessionFactory LoadOracleConfig()
110
111         {
112
113             Configuration config = new Configuration();
114
115             config.SetProperty("dialect", "NHibernate.Dialect.Oracle10gDialect");
116
117             config.SetProperty("hibernate.show_sql", "true");
118
119             config.SetProperty("connection.driver_class", "NHibernate.Driver.OracleManagedDataClientDriver");
120
121             config.SetProperty("connection.provider", "NHibernate.Connection.DriverConnectionProvider");
122
123             config.SetProperty("proxyfactory.factory_class", "NHibernate.Bytecode.DefaultProxyFactoryFactory, NHibernate");
124
125             config.SetProperty("connection.isolation", "ReadCommitted");
126
127              config.SetProperty("connection.release_mode", "auto");
128
129             config.SetProperty("adonet.batch_size", "500");
130
131             config.SetProperty("current_session_context_class", "call");
132
133             config.SetProperty("cache.use_query_cache", "false");
134
135             config.AddAssembly("BDC.ZcServer");
136
137             config.SetProperty("connection.connection_string", OracleConnectionString.ConnectionString);
138
139
140
141             return config.BuildSessionFactory();
142
143         }
144
145
146
147         private static ISessionFactory LoadAccessConfig()
148
149         {
150
151             Configuration config = new Configuration();
152
153             config.SetProperty("dialect", "NHibernate.JetDriver.JetDialect, NHibernate.JetDriver");
154
155             config.SetProperty("hibernate.show_sql", "true");
156
157             config.SetProperty("connection.driver_class", "NHibernate.JetDriver.JetDriver, NHibernate.JetDriver");
158
159             config.SetProperty("connection.provider","NHibernate.Connection.DriverConnectionProvider");
160
161             config.SetProperty("proxyfactory.factory_class", "NHibernate.Bytecode.DefaultProxyFactoryFactory, NHibernate");
162
163             config.SetProperty("connection.isolation", "ReadCommitted");
164
165             config.SetProperty("connection.release_mode", "auto");
166
167             config.SetProperty("adonet.batch_size", "500");
168
169             config.SetProperty("current_session_context_class", "call");
170
171             config.SetProperty("cache.use_query_cache", "false");
172
173             config.AddAssembly("BDC.Standard");
174
175             config.SetProperty("connection.connection_string", AccessConnectionString.ConnectionString);
176
177
178
179             return config.BuildSessionFactory();
180
181         }
182
183
184
185
186
187     }
188
189 }

Session使用时间

StatelessSession实现代码:

  1 using System;
  2
  3 using System.Collections.Generic;
  4
  5 using System.Linq;
  6
  7 using System.Text;
  8
  9 using System.Threading.Tasks;
 10
 11 using NHibernate;
 12
 13 using NHibernate.Cfg;
 14
 15
 16
 17 namespace BDC.Framework
 18
 19 {
 20
 21     public class DataSourceFactory
 22
 23     {
 24
 25         private static Dictionary<string, ISession> staticSessionDictionary = new Dictionary<string, ISession>();
 26
 27         private static object lockObject = new object();
 28
 29         private const  string OracleAssembly = "BDC.ZcServer";
 30
 31         private const string AccessAssembly = "BDC.Standard";
 32
 33
 34
 35         public static ISession GetSession<T>() where T:class
 36
 37         {
 38
 39             string assembly = typeof(T).Assembly.GetName().Name;
 40
 41             ISession _session = null;
 42
 43             bool isFind = false;
 44
 45             if (staticSessionDictionary.Keys.Contains(assembly)) { _session = staticSessionDictionary[assembly]; isFind = true; }
 46
 47             try
 48
 49             {
 50
 51                 if(_session == null)
 52
 53                 {
 54
 55                     lock (lockObject)
 56
 57                     {
 58
 59                         ISessionFactory factory = null;
 60
 61                         switch (assembly) {
 62
 63                             case OracleAssembly:
 64
 65                                 factory = LoadOracleConfig();
 66
 67                                 break;
 68
 69                             case AccessAssembly:
 70
 71                                 factory = LoadAccessConfig();
 72
 73                                 break;
 74
 75                             default:
 76
 77                                 throw new Exception("没有找到对应的程序集");
 78
 79                         }
 80
 81                         _session = factory.OpenSession();
 82
 83                         if (isFind) { staticSessionDictionary[assembly] = _session; }
 84
 85                         else { staticSessionDictionary.Add(assembly, _session); }
 86
 87                     }
 88
 89                 }
 90
 91
 92
 93                 return _session;
 94
 95             }catch(Exception ex)
 96
 97             {
 98
 99                 throw new Exception("数据库初始化失败");
100
101             }
102
103         }
104
105
106
107         private static ISessionFactory LoadOracleConfig()
108
109         {
110
111             Configuration config = new Configuration();
112
113             config.SetProperty("dialect", "NHibernate.Dialect.Oracle10gDialect");
114
115             config.SetProperty("hibernate.show_sql", "true");
116
117             config.SetProperty("connection.driver_class", "NHibernate.Driver.OracleManagedDataClientDriver");
118
119             config.SetProperty("connection.provider", "NHibernate.Connection.DriverConnectionProvider");
120
121             config.SetProperty("proxyfactory.factory_class", "NHibernate.Bytecode.DefaultProxyFactoryFactory, NHibernate");
122
123             config.SetProperty("connection.isolation", "ReadCommitted");
124
125              config.SetProperty("connection.release_mode", "auto");
126
127             config.SetProperty("adonet.batch_size", "500");
128
129             config.SetProperty("current_session_context_class", "call");
130
131             config.SetProperty("cache.use_query_cache", "false");
132
133             config.AddAssembly("BDC.ZcServer");
134
135             config.SetProperty("connection.connection_string", OracleConnectionString.ConnectionString);
136
137
138
139             return config.BuildSessionFactory();
140
141         }
142
143
144
145         private static ISessionFactory LoadAccessConfig()
146
147         {
148
149             Configuration config = new Configuration();
150
151             config.SetProperty("dialect", "NHibernate.JetDriver.JetDialect, NHibernate.JetDriver");
152
153             config.SetProperty("hibernate.show_sql", "true");
154
155             config.SetProperty("connection.driver_class", "NHibernate.JetDriver.JetDriver, NHibernate.JetDriver");
156
157             config.SetProperty("connection.provider","NHibernate.Connection.DriverConnectionProvider");
158
159             config.SetProperty("proxyfactory.factory_class", "NHibernate.Bytecode.DefaultProxyFactoryFactory, NHibernate");
160
161             config.SetProperty("connection.isolation", "ReadCommitted");
162
163             config.SetProperty("connection.release_mode", "auto");
164
165             config.SetProperty("adonet.batch_size", "500");
166
167             config.SetProperty("current_session_context_class", "call");
168
169             config.SetProperty("cache.use_query_cache", "false");
170
171             config.AddAssembly("BDC.Standard");
172
173             config.SetProperty("connection.connection_string", AccessConnectionString.ConnectionString);
174
175
176
177             return config.BuildSessionFactory();
178
179         }
180
181
182
183
184
185     }
186
187 }
188
189  

 

StatelessSession使用时间

ADO执行原生SQL

 1 using System;
 2
 3 using System.Collections.Generic;
 4
 5 using System.Data.OleDb;
 6
 7 using System.Linq;
 8
 9 using System.Text;
10
11 using System.Threading.Tasks;
12
13
14
15 namespace BDC.Standard
16
17 {
18
19     public class AccessConnectionTest
20
21     {
22
23         public bool AccessTest()
24
25         {
26
27             OleDbConnection mycon = null;
28
29             OleDbCommand mycom = null;
30
31             try {
32
33                 string strcon = @"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=E:\XXXXXXSXB.mdb;";
34
35                 mycon = new OleDbConnection(strcon);
36
37                 mycom = mycon.CreateCommand();
38
39                 mycon.Open();
40
41
42
43                 for( int j= 0; j < 20000; j++)
44
45                 {
46
47
48
49
50
51
52
53                     string sql = string.Format("insert into sqr(QLRDLJG,QLRDLRDH,QLRDLRMC,QLRFRDH,QLRFRMC,QLRMC,QLRTXDZ,QLRYB,QLRZJH,QLRZJZL,QXDM,YSDM,YWH,YWRDLJG,YWRDLRDH,YWRDLRMC,YWRFRDH,YWRFRMC,YWRMC,YWRTXDZ,YWRYB,YWRZJH,YWRZJZL) values(‘1‘,‘1‘,‘1‘,‘1‘,‘1‘,‘1‘,‘1‘,‘1‘,‘1‘,‘1‘,‘1‘,‘1‘,{0},‘1‘,‘1‘,‘1‘,‘1‘,‘1‘,‘1‘,‘1‘,‘1‘,‘1‘,‘1‘) ", j);
54
55                     mycom.CommandText = sql;
56
57                     int i = mycom.ExecuteNonQuery();
58
59                 }
60
61
62
63
64
65
66
67                 return true;
68
69             }
70
71             catch(Exception ex)
72
73             {
74
75                 return false;
76
77             }
78
79             finally
80
81             {
82
83                 mycom.Dispose();
84
85                 mycon.Close();
86
87
88
89
90
91             }
92
93         }
94
95     }
96
97 }

ADO执行原生SQL使用时间:

解析:综上就发现,Session效率非常低下,足足运行了1000多秒,就是23多分钟。再看后面两种方法,效率差不多。一个10秒,一个11秒。这么说,我其实还是可以偷懒的。继续使用NHIBERNATE,只需要换一个方法就可以了。那么?为什么这两个方法差别如此大呢。而且前面的方法运行一段时间会失败并抛出内存溢出异常,这是因为 Hibernate 把所有新插入的MotherCat实例在 session 级别的缓存区进行了缓存的缘故。其实不知道你们发现没有,StatelessSession 接口使用insert, update和 delete操作是操作数据库的, Session 使用save, saveOrUpdate 和delete 。区别就在Save和Insert这两个方法。

原因:使用StatelessSession(无状态 session)接口是使用流的方式来操作数据,大大提升效率。它没有持久上下文。不存在高层的生命周期。没有多级缓存,它也不管你数据的准确性,是否重复,是否存在脏数据,不级联更新数据。也不会出发Hibernate的事务和触发器等,简单的来说,就相当于一个底层的JDBC。

 

使用注意:它没有事务,没有缓存,没有脏数据检查。所以我们使用在系统的时候,千万要小心使用,不然会造成脏数据,污染数据库,或者导致数据不正确。而且如果系统抛异常,则是很危险的,数据是马上执行存取操作的。数据写到一半,抛个异常,这个数据就错了。而且还不会回滚。

 

综上,对已有数据,要求效率的时候,而且保证数据不会出现问题,异或,自己对异常,脏数据等有一套方案,可以使用NHIBERNATE的StateLessSession.不是特别追求速度的话,还是使用Session。

时间: 2024-10-26 09:12:03

Nhibernate的Session和StatelessSession性能比较的相关文章

NHibernate中Session与ASP.NET MVC中Action的综合使用

NHibernate的基本特征是完成面向对象的程序设计语言到关系数据库的映射,在NHibernate中使用持久化对象PO(Persistent Object)完成持久化操作,对PO的操作必须在Session管理下才能同步到数据库, 但是这里的Session并非指HttpSession,可以理解为基于ADO.NET的Connnection,Session是NHibernate运作的中心,对象的生命周期.事务的管理.数据库的存取都与Session息息相关,首先,我们需要知道, SessionFact

NHibernate中Session的处理 线程不安全

NHibernate中Session是线程不安全的,而且每次数据库操作 请求创建Session时对性能有些影响.在Windows应用中可以通过 [ThreadStatic]特性很简单的就可以实现线程安全,而在Web中可以通过将Session与用于请求HttpContext绑定实现线程安全,并且用户当前请求时只有一个Session.代码如下: ISessionManage.cs using System;using NHibernate; namespace Commercial.Jwsoft.F

NHibernate中session.update()及session.merge()的区别

今天的工作中遇到一个奇怪的问题,如下: "a different object with the same identifier value was already associated with the session: 19519146" 该异常的上下文如下: 1:在net.tcp绑定的wcf远程调用时产生: 2:通过UI调用方法不会产生该异常. 分析该问题: 由异常信息可以看出,该问题是由于在session.update对一组实体进行更新后,试图将新的实体associate到se

read by other session导致oracle性能低

问题背景:客户反应oracle库很慢很慢   (read by other session可以结合db file sequential read等待事件一块优化) 1检查等待事件: set linesize 200 col username for a15 col event for a35 col program for a20 col cpu_p for 99.99 select ta.*, round(ta.cpu_time / tb.total_cpu * 100, 1) cpu_usa

架构之路(九)Session Per Request

前面的两篇反应很差:没评论没赞.很伤心啊,为什么呢?搞得我好长一段时间都没更新了——呵呵,好吧,我承认,这只是我的借口.不过,还是希望大家多给反馈.没有反馈,我就只能猜了:前面两篇是不是写得太“粗”了一点?所以这一篇我们尽量详细点吧. Session Per Request是什么 这是一个使用NHibernate构建Web项目惯用的模式,相关的文章其实很多.我尽量用我的语言(意思是大白话,但可能不精确)来做一个简单的解释. 首先,你得明白什么是session.这不是ASP.NET里面的那个ses

session的工作原理和扩展

1.session工作原理: 创建Session的时候,服务器将生成一个唯一的sessionid然后用它生成一个cookie. 与其同时生成一个以sessionid相对应的文件. 当浏览器端提交到服务器时,服务器会通过sessionid去寻找与其相对应的文件,提取Session信息. 2.关闭Cookie后,session还可以使用吗? 可以回答不可以,也可以回答可以:      正常情况下,关闭Cookie后,session是不可以使用的,浏览器的请求到达服务器,服务器经过处理后返回一个coo

NHibernate系列文章二十一:延迟加载

摘要 NHibernate的延迟加载机制是很重要的内容.通过关系映射将数据库表之间的关系映射成对象之间的关系,如果没有延迟加载机制,从主表的一个对象的查询将直接查询出所有与该对象关联的其他对象,如果关联的对象上还有其他的关联对象,还要去查询其他的对象.如果这张“网”非常大,或者关联的数据库记录非常多的话,每次查询主表记录都要把整个数据库都查询一遍,这样效率会非常低下.为了解决这个问题产生了NHibernate延迟加载.对一些属性设置延迟加载,只在对象访问到这些属性的时候才去查询数据库,很大程度上

NHibernate中的API

本篇文章介绍的是NHibernate的各种API及其作用. 下图描述了NHibernate的API在分层架构中的作用,下面将进行详细说明. NHibernate的接口大致分为四类:1.  被应用程序调用进行基本数据操作(增.删.改.查)的接口.这些接口是应用程序的业务逻辑层和控制层与NHibernate的主要交互点.ISession, ITransaction, IQuery和ICriteria属于此类.2. 被应用程序用来配置NHibernate的接口.Configuration就属此类.3.

.NET进阶 — Nhibernate 持久化的三种状态

引入 在面向对象的开发中,程序的运行都是通过对象的方式对数据库进行增删改查的操作,必然在持久化过程中产生一些列的对象,比如登陆,必然会有实例化的UserEntity对象,从数据库Select出来的对象,Save到数据库的对象,如何区分这些对象以及当前会话的状态,下面看NHibernate中的对象状态的管理: Nhibernate 三态 Nhibernate在持久化对象的生命周期,将对象分为三个状态: 1.瞬时态(Transient) 也叫临时态,顾名思义,对象是临时创建的,即刚实例化的对象: U