连接数据库是程序员经常要做的事情, 通常情况下, 需要连接SQL Server中哪个数据库是已知的, 用户在输入SQL Server的服务器IP、用户名、密码和数据库名字后, 如果所有信息输入正确, 就可以建立连接了.

让用户尽量少打字

每次让用户输入这么多信息的确很糟糕, 可以改进一下设计: 服务器IP和用户名可以存放在配置文件里面, 初始化的时候默认加载到相应的文本框中; 从安全角度考虑, 密码必须经过用户手动输入; 而数据库名字则没必要让用户输入, 有了服务器IP、用户名、密码后可以尝试连接SQL Server, 连接SQL Server成功后, 把数据库中所有的数据库名加载到ComboBox让用户选择连接哪个数据库.

密码不正确

密码正确

如何实现

在后台代码中定义一个计时器, 设置它的Interval为1000毫秒, 用户输入密码时让定时器重新计时, 也就是说用户输入密码后, 如果在1秒钟内用户没有继续输入密码, 则会触发计时器的Elapsed事件, 这时程序尝试能不能连上SQL Server.

//用户停止输入密码1秒后自动尝试连接
private System.Timers.Timer m_timer=new System.Timers.Timer(1000);private void txtPassword_PasswordChanged(object sender, RoutedEventArgs e)
{m_timer.Stop();m_timer.Start();//清空数据库的选择列表cbbDatabase.Items.Clear();
}

在计时器的Elapsed事件函数中, 程序尝试连接SQL Server, 但是如下写法会出现问题.

private void timer_Elapsed(object sender, ElapsedEventArgs e)
{Dispatcher.BeginInvoke((Action)delegate(){var conStr = String.Format("Data Source={0};Integrated Security=False;User ID={1};Password={2};", txtServer.Text, txtUser.Text, txtPassword.Password);using (var con = new SqlConnection(conStr)){try{con.Open();}catch{//TODO: 提示连接数据库失败return;}//TODO:提示连接数据库成功var sql = "select name from sys.databases";var cmd = new SqlCommand(sql, con);IAsyncResult asyncResult = cmd.BeginExecuteReader();SqlDataReader reader = cmd.EndExecuteReader(asyncResult);if (!reader.HasRows){//TODO: 提示SQL Server中不存在数据库return;}//TODO: 在这里释放Timerwhile (reader.Read()){cbbDatabase.Items.Add(reader[0].ToString());}}});
}

如果数据库的IP是错误的, con.Open()则要花费约30秒左右才会抛出异常, 这段时间UI线程会一直卡死, 经过测试, 30秒后才抛异常与数据库连接字符串的Connect Timeout属性没有关系.

可以写一个SqlConnection的扩展方法, 在这个方法里面用一个码表对执行con.Open()的时间计时, 用一个bool型变量标识有没有成功的con.Open(), 如果在规定的时间内没有成功连上SQL Server则抛出一个异常.

扩展SqlConnection

public static class SqlExtension
{public static void TryOpen(this SqlConnection connection, int millisecondTimeout){Stopwatch sw = new Stopwatch();bool succeed = false;Thread t = new Thread(() =>{try{sw.Start();connection.Open();//打开连接后设置succeed为truesucceed = true;}catch{}});t.IsBackground = true;t.Start();t.Join(millisecondTimeout);t.Abort();//如果没有成功, 则抛出一个异常if (!succeed)throw new Exception();}
}

这样在原来的代码中调用con.TryOpen()就可以解决问题.

扩展delegate

其实扩展方法的第一个参数并不是一定要是一个class类, 其实delegate也是可以的, delegate其实在编译之后就是一个类, 如下改写刚刚的SqlConnection扩展方法, 就可以写一个通用的尝试操作的扩展方法.

public static class ActionExtension
{public static void Invoke(this Action action, int millisecondTimeout){Stopwatch sw = new Stopwatch();bool succeed = false;Thread t = new Thread(() =>{try{sw.Start();action();succeed = true;}catch{}});t.IsBackground = true;t.Start();t.Join(millisecondTimeout);if (!succeed)throw new Exception();}
}

这样写, 代码则更为通用一些, 以后一些耗时的操作(当然要满足Action的签名)都可以调用这个方法, 在本例中, 可以如下调用:

((Action)con.Open).Invoke(2000);

对delegate进行扩展 打造通用的计时完成方法相关推荐

  1. 如何一个模型走天下?集成训练多数据集,打造通用目标检测模型方法详解

    在目标检测的实际应用中,常常会出现需要泛化的目标检测系统的情况.如城市安防中,需要目标检测系统能够检测足够多类别的目标,才能达到更好的安防效果. 但目前常用的目标检测数据集中包含的类别数量有限,使用单 ...

  2. springboot+aop+自定义注解,打造通用的全局异常处理和参数校验切面(通用版)

    springboot+aop+自定义注解,打造通用的全局异常处理和参数校验切面(通用版) 参考文章: (1)springboot+aop+自定义注解,打造通用的全局异常处理和参数校验切面(通用版) ( ...

  3. jdbc增删改查有哪些步骤_JDBC打造通用增删改方法

    [JDBC]打造通用增删改方法原创 简介:在我们学习JDBC的时候或者编写简单的Servlet程序的时候,经常需要增删改查等操作,很多小伙伴的做法是:增删改查各写一个方法,这样写虽然可以实现我们想要的 ...

  4. 08_android_打造通用svg地图自定义组件

    android_打造通用svg地图自定义组件 一.地图svg数据准备 这里笔者已经整理了云南省16个地州.129个县的svg path数据,如果你要绘制的是其他省份,甚至是中国地图,那么可以从下面这个 ...

  5. 最新web/springboot打造通用的短信验证码微服务(详细)

    前言 很久之前的一篇文章, 最新web/java/jsp实现发送手机短信验证码和邮箱验证码的注册登录功能(详细),截止到目前,依然有很多小伙伴,私信需要帮助,于是我再加一篇,让大家能更好的使用.(当然 ...

  6. 这样设计一个可扩展、通用的、健壮性组件

    点击上方关注 小生方勤,一起学习,天天进步 前言 组件是页面不可或缺的部分,而设计组件就成为了前端同学每日工作. 所以 一位程序员的职业生涯大约十年,只有人寿命的十分之一.前端项目只是你生活工作的一部 ...

  7. 旷视科技为何战略投资Video++?版图扩展打造AI+IoT 闭环 | 专访唐文斌

    "AI+文娱",是一个千亿级的新兴市场,承载着新的广告.电商.互动娱乐等业务. 新智元获悉,极链科技Video++于近日完成由阿里巴巴.云锋基金.Face++旷视科技领投,国投.头 ...

  8. 通用的产品功能设计方法

    通用的产品功能设计方法 1.如何设计注册/登录功能 1.1 注册功能设计 1.2 登录功能的设计 2.如何设计APP启动页功能和引导页功能 2.1 启动页功能设计 2.2 引导页功能设计 3.如何设计 ...

  9. 解决删除U盘时提示无法停止‘通用卷’设备的方法

    解决删除U盘时提示无法停止'通用卷'设备的方法 文章分类:JavaEye 关键字: u盘停止'通用卷' 删除U盘时提示无法停止'通用卷'设备的解决方法 安全删除U盘时,大家常常会遇到提示"无 ...

最新文章

  1. 深度学习中的优化算法之BGD
  2. 《FPGA全程进阶---实战演练》第一章之如何学习FPGA
  3. C六:指针可以比较大小
  4. 文件内容、关键字匹配,split 和 indexOf 均可实现
  5. c++ 原子操作 赋值_原子操作原理
  6. C++多线程强制终止
  7. 清华,北大坐实亚洲大学Top2,泰晤士2020亚洲大学榜
  8. Git Stash的使用方法与注意事项
  9. MyBatis使用动态SQL语句
  10. php---兄弟连的php培训视频的总结(1)
  11. (一)密码学之数论基础
  12. 怎样设计访谈提纲_如何设计调查问卷与访谈提纲要点分析.ppt
  13. 征途服务器维护时间,征途私服服务器维护是什么问题
  14. Ubuntu系统Vscode安装以及配置C++环境(一条龙服务)
  15. springboott整合mybatis-plus和sharding-jdbc实现分库分表和读写分离(含完整项目代码)
  16. 酷派大观4 8970 刷android 4.4,极速达百兆! 移动4G版酷派大观4网络体验
  17. android模拟器访问本地网站
  18. idea :不支持发行版本11问题
  19. 读 Flink 源码,肝进阿里云 Flink 组了。。
  20. djangoday02

热门文章

  1. 13种编程语言名称的来历
  2. [译] 数据可视化教程:基于Google Sheets 和 RStudio Shiny 建立实时仪表盘
  3. SQL Server实用操作小技巧集合
  4. 将sqlite查询结果导入到文本文件
  5. IT资产管理的演变原文-Generations of IT Asset Management
  6. ASP.NET 初级开发成员面试题部分面试题
  7. 为什么电脑不能打字_为什么新电脑不能安装win7系统?
  8. retract手机版怎么登录服务器未响应,retract和retreat各自的用法以及它们的区别
  9. indesign如何画弧线_硬币画警车简笔画【图文+视频教程】
  10. mysql 5.7 收费_MySQL5.7 常用用户操作