• Nhibernate的Session和StatelessSession性能比较


    NhibernateSessionStatelessSession性能比较

    作者:Jesai

    一个月入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。

     

     

  • 相关阅读:
    API网关服务
    技术攻关:从零到精通 https://mp.weixin.qq.com/s/mix-0Ft9G1F5yddNjSzkrw
    如何在团队中推广一项技术 —— 解决Odin一站式微前端的缓存问题
    设计模式的底层逻辑 找到变化,封装变化
    从Android内存到图片缓存优化
    百度C++工程师的那些极限优化(内存篇)
    享元模式
    协同编辑冲突处理算法综述
    大型前端项目内存优化总结
    雪碧图
  • 原文地址:https://www.cnblogs.com/dengjiahai/p/6953367.html
Copyright © 2020-2023  润新知