适用于关系型数据库的抽象工厂的数据库访问类
适用于SQLite、Access、MySQL、MSSQLServer、Oracle这类关系型数据库,不适于非关系型数据库,例如MongoDB。
下面是代码:
1 using System; 2 using System.Configuration; 3 using System.Data; 4 using System.Data.Common; 5 using System.Data.SQLite; 6 7 namespace WinFormTest 8 { 9 public static class DbHelperSQL 10 { 11 private static readonly object Obj4Lock = new object(); 12 private static readonly string ConnectionString = ConfigurationManager. 13 ConnectionStrings["ConnectionString"].ConnectionString; 14 15 /// <summary> 16 /// 程序每次运行都只创建一个工厂 17 /// </summary> 18 private static DbProviderFactory DBProviderFactory 19 { 20 get 21 { 22 var providerFactoryString = ConfigurationManager.ConnectionStrings["ConnectionString"].ProviderName; 23 if (providerFactoryString == "System.Data.SQLite") 24 { 25 return SQLiteFactory.Instance; 26 } 27 28 var dbProviderFactory = DbProviderFactories.GetFactory(providerFactoryString); 29 if (dbProviderFactory == null) 30 { 31 throw new Exception("dbProviderFactory==null"); 32 } 33 34 return dbProviderFactory; 35 } 36 } 37 38 39 public static int ExecuteNonQuery(string commandText, bool isStoredProcedure) 40 { 41 if (commandText == null) 42 { 43 throw new ArgumentNullException("commandText"); 44 } 45 46 int result; 47 48 lock (Obj4Lock) 49 { 50 using (var connection = CreateConnection()) 51 { 52 using (var transaction = CreateTransaction(connection)) 53 { 54 using (var command = CreateCommand(commandText, isStoredProcedure, connection, transaction)) 55 { 56 try 57 { 58 result = command.ExecuteNonQuery(); 59 command.Parameters.Clear(); 60 transaction.Commit(); 61 } 62 catch 63 { 64 transaction.Rollback(); 65 return 0; 66 } 67 } 68 } 69 } 70 } 71 72 return result; 73 } 74 75 public static object ExecuteScalar(string commandText, bool isStoredProcedure) 76 { 77 if (commandText == null) 78 { 79 throw new ArgumentNullException("commandText"); 80 } 81 82 object result; 83 84 lock (Obj4Lock) 85 { 86 using (var connection = CreateConnection()) 87 { 88 using (var transaction = CreateTransaction(connection)) 89 { 90 using (var command = CreateCommand(commandText, isStoredProcedure, connection, transaction)) 91 { 92 try 93 { 94 result = command.ExecuteScalar(); 95 command.Parameters.Clear(); 96 transaction.Commit(); 97 } 98 catch 99 { 100 transaction.Rollback(); 101 return null; 102 } 103 } 104 } 105 } 106 } 107 108 return result; 109 } 110 111 public static IDataReader ExecuteReader(string commandText, bool isStoredProcedure) 112 { 113 if (commandText == null) 114 { 115 throw new ArgumentNullException("commandText"); 116 } 117 118 lock (Obj4Lock) 119 { 120 var connection = CreateConnection(); 121 122 var command = CreateCommand(commandText, isStoredProcedure, connection, null); 123 124 try 125 { 126 var myReader = command.ExecuteReader(CommandBehavior.CloseConnection); 127 command.Parameters.Clear(); 128 return myReader; 129 } 130 catch 131 { 132 connection.Close(); 133 throw; 134 } 135 } 136 } 137 138 public static DataSet Query(string commandText, bool isStoredProcedure) 139 { 140 if (commandText == null) 141 { 142 throw new ArgumentNullException("commandText"); 143 } 144 145 var dataSet = new DataSet(); 146 147 lock (Obj4Lock) 148 { 149 using (var connection = CreateConnection()) 150 { 151 using (var transaction = CreateTransaction(connection)) 152 { 153 using (var command = CreateCommand(commandText, isStoredProcedure, connection, transaction)) 154 { 155 using (var dataAdapter = DBProviderFactory.CreateDataAdapter()) 156 { 157 if (dataAdapter == null) 158 { 159 throw new ArgumentNullException("commandText"); 160 } 161 162 try 163 { 164 dataAdapter.Fill(dataSet, "dataSet"); 165 command.Parameters.Clear(); 166 transaction.Commit(); 167 } 168 catch 169 { 170 transaction.Rollback(); 171 return null; 172 } 173 } 174 } 175 } 176 } 177 } 178 179 return dataSet; 180 } 181 182 183 private static IDbConnection CreateConnection() 184 { 185 IDbConnection connection = DBProviderFactory.CreateConnection(); 186 if (connection == null) 187 { 188 throw new Exception("connection == null"); 189 } 190 191 connection.ConnectionString = ConnectionString; 192 193 if (connection.State != ConnectionState.Open) 194 { 195 connection.Open(); 196 } 197 198 return connection; 199 } 200 201 private static IDbTransaction CreateTransaction(IDbConnection connection) 202 { 203 var transaction = connection.BeginTransaction(); 204 if (transaction == null) 205 { 206 throw new ArgumentNullException("connection"); 207 } 208 return transaction; 209 } 210 211 private static IDbCommand CreateCommand(string commandText, bool isStoredProcedure, 212 IDbConnection connection, IDbTransaction transaction) 213 { 214 IDbCommand command = DBProviderFactory.CreateCommand(); 215 if (command == null) 216 { 217 throw new Exception("command == null"); 218 } 219 220 command.Connection = connection; 221 command.CommandType = isStoredProcedure ? CommandType.StoredProcedure : CommandType.Text; 222 command.CommandText = commandText; 223 command.Transaction = transaction; 224 225 return command; 226 } 227 } 228 }
解释:
1、Obj4Lock用于锁定代码块,保证在多线程程序中,只有一个数据库连接存在。
2、外部接口只有ExecuteNonQuery、ExecuteScalar、ExecuteReader、Query四个方法,可以使用存储过程和事务。
3、为什么不用参数化查询?一是因为面向接口编程的原因,程序中不能使用具体数据库相关的参数对象,只能使用IDbParameter和DbParameter,这两个是接口和抽象类,不能够实例化,可以写在工厂中,但是没法使用。二是我做的程序中不需要参数化查询。
4、代码可读性良好,不必注释了。
下面是配置文件:
1 <?xml version="1.0" encoding="utf-8" ?> 2 <configuration> 3 <connectionStrings> 4 <!--<add name="ConnectionString" connectionString="Data Source=Test" providerName="System.Data.SQLite"/>--> 5 <!--<add name="ConnectionString" connectionString="Provider=Microsoft.ACE.OLEDB.12.0; Data Source=TestAccess.accdb" providerName="System.Data.OleDb"/>--> 6 <add name="ConnectionString" connectionString="server=127.0.0.1;database=testDB;uid=root;pwd=123456" providerName="MySql.Data.MySqlClient"/> 7 </connectionStrings> 8 </configuration>
通过更改配置文件,就可以实现对数据库种类的屏蔽了。
下面是用了抽象工厂的数据库访问类和普通数据库访问类的效率差异:
数据库 |
类型 |
2 |
5 |
10 |
20 |
50 |
100 |
200 |
SQLite |
文件 |
0.197s |
0.285s |
0.547s |
1.099s |
2.509s |
5.632s |
11.386s |
SQLite(抽象工厂) |
文件 |
0.246s |
0.362s |
0.499s |
1.191s |
2.539s |
6.692s |
10.464s |
Access |
文件 |
0.199s |
0.280s |
0.521s |
1.071s |
2.604s |
5.320s |
10.760s |
Access(抽象工厂) |
文件 |
0.363s |
0.510s |
0.780s |
1.326s |
2.805s |
5.569s |
10.648s |
MySql |
服务器 |
0.217s |
0.106s |
0.226s |
0.331s |
0.952s |
1.545s |
2.666s |
MySql(抽象工厂) |
服务器 |
0.310s |
0.323s |
0.403s |
0.545s |
0.942s |
1.623s |
2.746s |
表中的数字是线程数,每个线程只执行一条语句。
All Comments are Welcome.