异步数据库查询 Z
Introduction
Microsoft .NET 4.5 introduced new "async and await" methods to provide an easy way of implementing asynchronisity using .NET "Task" objects.
This allows developers to make async calls more flexibly, as opposed to standard threading/callback methods.
In this article i've built a demo to show how this can be applied to build easy to use SQL functions which can be called async.
Getting started
For this article we shall be using the .NET SQL Client library for connecting to a Microsoft SQL Server database, however the same methodology of wrapping up code in a task can be used with any other type of connection.
In this example we will wrap our code which connects to the database to get data into a function which returns a "Task" object based on the data type we require.
Building Asynchronous Task Functions
We start by building the initial wrapper which returns a task object. We shall be returning a dataset in this example.
Side note: Any data type can be returned with task objects, as such you could return a string, integer or a custom class.
The following is the basic wrapper for our function. This bit of code will return a task object based on the datatype, with a section to add our own code to build and return the dataset.
public Task<DataSet> GetDataSetAsync(string sConnectionString, string sSQL)
{
return Task<DataSet>.Factory.StartNew(() =>
{
//MY CODE HERE
});
}
We can now insert code which connects to the server to get data based on a query into this function.
Example 1: Function to fill a dataset based on the SQL query.
In this example code has been added to the body of the function which uses a standard SQL connection string and objects from the System.Data.SQLClient .NET library to connect to the database and fill a dataset based on the query.
Once the dataset has been filled the code will then return the dataset using a standard "return" call.
public Task<DataSet> GetDataSetAsync(string sConnectionString, string sSQL, params SqlParameter[] parameters)
{
//Return task based on datatype
return Task.Run(() =>
{
using (var newConnection = new SqlConnection(sConnectionString))
using (var mySQLAdapter = new SqlDataAdapter(sSQL, newConnection))
{
mySQLAdapter.SelectCommand.CommandType = CommandType.Text;
if (parameters != null) mySQLAdapter.SelectCommand.Parameters.AddRange(parameters); DataSet myDataSet = new DataSet();
mySQLAdapter.Fill(myDataSet);
return myDataSet;
}
});
}
We can now call this function asynchronously to return a dataset of data based on our query.
Example 2: Function to execute a command, passing back the rows affected.
In this example, we have changed the data type to integer, as we simply want to pass back the rows affected for the result of this function.
public Task<int> ExecuteAsync(string sConnectionString, string sSQL, params SqlParameter[] parameters)
{
return Task.Run(() =>
{
using (var newConnection = new SqlConnection(sConnectionString))
using (var newCommand = new SqlCommand(sSQL, newConnection))
{
newCommand.CommandType = CommandType.Text;
if (parameters != null) newCommand.Parameters.AddRange(parameters); newConnection.Open();
return newCommand.ExecuteNonQuery();
}
});
}
Further to this, there are existing async task functions on the SqlCommand object which can be used to simplify the function further.
public async Task<int> ExecuteAsync(string sConnectionString,
string sSQL, params SqlParameter[] parameters)
{
using (var newConnection = new SqlConnection(sConnectionString))
using (var newCommand = new SqlCommand(sSQL, newConnection))
{
newCommand.CommandType = CommandType.Text;
if (parameters != null) newCommand.Parameters.AddRange(parameters); await newConnection.OpenAsync().ConfigureAwait(false);
return await newCommand.ExecuteNonQueryAsync().ConfigureAwait(false);
}
}
We can use this function to execute SQL and get the rows affected.
Calling Asynchronous Task Functions
Now that we have an async function to get data from SQL we can now call this asynchronously using the async\await clause from any method.
To call the function to get data we start by adding "async" into the method declaration.
private async <type> MyMethod()
Now that our method is an "async" method we can use the "await" option on the tasks returned from our SQL functions.
Execute Task Function
To execute task functions you need to add "await" before the function call.
This will execute the function, and return the "Result" to the variable should one be specified.
private async Task GetSomeData(string sSQL)
{
//Use Async method to get data
DataSet results = await GetDataSetAsync(sConnectionString, sSQL, sqlParams); //Populate once data received
grdResults.DataSource = results.Tables[0];
}
Variables do not need to be specified. You can call the function using "await" which will run the task without retrieving a result.
private async Task ExecuteSomeData(string sSQL)
{
//Use Async method to get data
await ExecuteAsync(sConnectionString, sSQL, sqlParams);
}
The "await" option can be specified multiple times if you need to make other asyncronous calls.
You can make GUI updates before and after the "await" command, as it is only the await command which is run asynchronously.
The simplest use of "async/await" is to use the "await" option, then continue with your code afterwards.
However the .NET task object provides other methods of continuation once the asynchronous task has completed.
Running Multiple Tasks/Chaining Tasks
If you need to run multiple SQL operations there are a few ways of achieving this.
Specifing Tasks As Variables Then Running Together
You can specify a number of commands as variables and run them all at once asynchronously, then get the results as necessary.
This can be achieved by setting up your tasks as variables.
Once setup you will need to add them into an array then use the "Task.WhenAll" to run all the tasks asynchronously.
You can then access the results on the task object after completion.
//Setup tasks
Task<int> ExecuteTask1 = database.ExecuteAsync(sConnectionString, sExecuteSQL1, sqlParams);
Task<int> ExecuteTask2 = database.ExecuteAsync(sConnectionString, sExecuteSQL2, sqlParams);
Task<int> ExecuteTask3 = database.ExecuteAsync(sConnectionString, sExecuteSQL3, sqlParams);
//Add to array
Task<int>[] Tasks = new Task<int>[] { ExecuteTask1, ExecuteTask2, ExecuteTask3 };
//Run all
await Task.WhenAll(Tasks);
//Get results
int iRowsAffected = Tasks[0].Result + Tasks[1].Result + Tasks[2].Result;
Calling Other Async Tasks With "ContinueWith"
Another method of chaining the tasks together is using the "ContinueWith" method on the task object returned by your SQL function.
In this example we start by running an execute task function, then once complete we run a select task function to get a dataset to a variable.
DataSet results = await database.ExecuteAsync(sConnectionString, sExecuteSQL, sqlParams).ContinueWith(t => database.GetDataSetAsync(sConnectionString, sGetSQL, sqlParams)).Result;
Calling Standard Methods With "ContinueWith"
You can call a standard method on the "ContinueWith" method.
In this example we use "ContinueWith" on the task object to pass the data through to a separate method.
private async Task RunSQLQuery(string sSQL)
{
//Use await method to get data
await GetDataSetAsync(sConnectionString, sSQL, sqlParams).ContinueWith(t => PopulateResults(t.Result));
}
private void PopulateResults(DataSet results)
{
//Do something with results
}
WARNING: When using "ContinueWith" in this way this will continue the async thread, meaning that if you intend to update GUI components such as a grid or textbox control you may encounter the error:
Cross-thread operation not valid: Control MyControl accessed from a thread other than the thread it was created on.
In cases like this you can invoke the method from within the "ContinueWith" which will allow for GUI updates.
await database.GetDataSetAsync(sConnectionString, sSQL, sqlParams).ContinueWith(t => this.Invoke((Action)(() => { PopulateResultsToScreen(t.Result); })));
异步数据库查询 Z的更多相关文章
- Python中实现异步并发查询数据库
这周又填了一个以前挖下的坑. 这个博客系统使用Psycopy库实现与PostgreSQL数据库的通信.前期,只是泛泛地了解了一下SQL语言,然后就胡乱拼凑出这么一个简易博客系统. 10月份找到工作以后 ...
- 第九十九天上课 PHP TP框架 数据库查询和增加
在Model文件夹下创建模型,文件命名规则 : 表名Model.class.php <?php namespace Home\Model; use Think\Model; class yong ...
- 转 zabbix 优化方法 以及 后台数据库查询方法 两则
############sample 1 https://blog.51cto.com/sfzhang88/1558254 如何从Zabbix数据库中获取监控数据 sfzhang关注6人评论40627 ...
- 用struts2标签如何从数据库获取数据并在查询页面显示。最近做一个小项目,需要用到struts2标签从数据库查询数据,并且用迭代器iterator标签在查询页面显示,可是一开始,怎么也获取不到数据,想了许久,最后发现,是自己少定义了一个变量,也就是var变量。
最近做一个小项目,需要用到struts2标签从数据库查询数据,并且用迭代器iterator标签在查询页面显示,可是一开始,怎么也获取不到数据,想了许久,最后发现,是自己少定义了一个变量,也就是var变 ...
- [转]C#反射,根据反射将数据库查询数据和实体类绑定,并未实体类赋值
本文来自:http://www.cnblogs.com/mrchenzh/archive/2010/05/31/1747937.html /****************************** ...
- 各数据库查询前N条记录的SQL语句
sql在不同数据库查询前几条数据 1. ORACLE SELECT * FROM TABLE_NAME WHERE ROWNUM <= N; HQL: from table_name t or ...
- Atitit DbServiceV4qb9 数据库查询类库v4 新特性
Atitit DbServiceV4qb9 数据库查询类库v4 新特性 V4新特性 安全特性,屏蔽了executeUpdate,使用v2版 Sql异常转换,特别转换了DuplicateEnt ...
- C#与mysql做ASP.NET网页数据库查询速度测试
两种方法是:1,使用mysql数据库的存储过程:2,C#编码,做网页后台与mysql数据库连接,前台测试显示测试过结果下面我将分别讲解两种方法的具体实现. 1,使用mysql数据库的存储过程插入万条大 ...
- mysql数据库查询pdo的用法
最早的php对mysql数据库查询是mysql和mysqli方法,后来php的新版本进一步封住了该方法,于是又pdo,抛开php框架,使用pdo查询数据,使用也是相当简便 <?php ini_s ...
随机推荐
- c#网络通信框架networkcomms内核解析之九 自定义处理方法的运行机制
NetworkComms网络通信框架序言 本文基于networkcomms2.3.1开源版本 gplv3协议 我们自己写的处理方法都称之为自定义处理方法 比如,我们在服务器上写的与登陆相关的处理方法 ...
- PHP EMS: 开源 在线考试系统安装
PHPEMS: 在线考试系统调测记录 下载安装软件包 PE2014.RAR 环境要求:利用了RHEL 5.X的一个环境,系统要求的运行环境是PHP 5.2以上,MYSQL 5.0以上.看了一下光盘,发 ...
- HDU 4939 Stupid Tower Defense (2014 Multi-University Training Contest 7)
思路:首先红色肯定要放在最后面.前面蓝色和绿色dp求解. dp[i][j] 表示前面(i+j) 个 有 i 个蓝色塔 j个绿色塔 能造成最大伤害. //====================== ...
- wp8.1 Study15:后台任务
一.介绍 1.多任务处理 什么是多任务处理?它意味着当App被挂起时,它仍然可以完成一些开发者设定的任务,比如更新tiles和toasts.预定toast和提醒.后台任务等. 2.后台任务 App可以 ...
- SDWebImage缓存图片的机制(转)
SDWebImage是一个很厉害的图片缓存的框架.既ASIHttp+AsyncImage之后,我一直使用AFNetworking集成的UIImageView+AFNetworking.h,但后者对于图 ...
- android切换屏幕时的生命周期
老版本总结: 1.不设置Activity的android:configChanges时 切屏会重新调用生命周期的方法,切横屏调用1次 切竖屏调用2次 2.设置Activity的android:conf ...
- Spring MVC的常用注解
一.@Controller @Controller 负责注册一个bean 到spring 上下文中,bean 的ID 默认为类名称开头字母小写,你也可以自己指定. 二.@RequestMapping ...
- 深入浅出数据分析 Head First Data Analysis Code 数据与代码
<深入浅出数据分析>英文名为Head First Data Analysis Code, 这本书中提供了学习使用的数据和程序,原书链接由于某些原因不 能打开,这里在提供一个下载的链接.去下 ...
- vim替换指令备忘
1. 替换当前行中的内容: :s/from/to/ (s即substitude) :s/from/to/ : 将当前行中的第一个from,替换成to.如果当前行含有多个 ...
- 解析HTTP协议六种请求方法,get,head,put,delete,post有什么区别
GET: 请求指定的页面信息,并返回实体主体.HEAD: 只请求页面的首部.POST: 请求服务器接受所指定的文档作为对所标识的URI的新的从属实体.PUT: 从客户端向服务器传送的数据取代指定的文档 ...