static,你还敢用吗?(二)
▄︻┻┳═一「static」Agenda:
▄︻┻┳═一static,你还敢用吗?
▄︻┻┳═一static,你还敢用吗?(二)
▄︻┻┳═一【轻松一刻!】一段难倒了两名老程序猿的简单代码
为了压系统,昨天小组在测试环境模拟了一大批订单数据。今天上午查看记录的账单计息日志,发现了一大堆的MySqlException
MySql.Data.MySqlClient.MySqlException (0x80004005): There is already an open DataReader associated with this Connection which must be closed first.
诸如:
2017-01-05 00:40:49.891
账单计息异常/{"BillId":1000012082,"OrderId":"DD201701040002672"}:MySql.Data.MySqlClient.MySqlException (0x80004005): There is already an open DataReader associated with this Connection which must be closed first.
在 MySql.Data.MySqlClient.ExceptionInterceptor.Throw(Exception exception)
在 MySql.Data.MySqlClient.MySqlCommand.Throw(Exception ex)
在 MySql.Data.MySqlClient.MySqlCommand.ExecuteReader(CommandBehavior behavior)
在 MySql.Data.MySqlClient.MySqlCommand.ExecuteDbDataReader(CommandBehavior behavior)
在 System.Data.Common.DbCommand.System.Data.IDbCommand.ExecuteReader(CommandBehavior behavior)
在 CommonLibrary.CommonOrm.CommonOrm_Dapper.<QueryImpl>d__11`1.MoveNext() 位置 e:\work\yijia\trunk\CommonLibrary\CommonOrm\CommonOrm_Dapper.cs:行号 1554
在 System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
在 System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
在 CommonLibrary.CommonOrm.CommonOrm_Dapper.Query[T](IDbConnection cnn, String sql, Object param, IDbTransaction transaction, Boolean buffered, Nullable`1 commandTimeout, Nullable`1 commandType) 位置 e:\work\yijia\trunk\CommonLibrary\CommonOrm\CommonOrm_Dapper.cs:行号 1444
在 GateWay.DAL.BillsDal.BillsDal.GetOrdersBillList(String bizOrderId) 位置 e:\work\yijia\trunk\GetWay.DAL\BillsDal\BillsDal.cs:行号 123
在 GateWay.BLL.Bills.BillsBll.GetOrdersBill(String bizOrderId, BillTypeEnum billType) 位置 e:\work\yijia\trunk\GetWay.BLL\Bills\BillsBll.cs:行号 27
在 GateWay.BLL.Bills.PrincipalBillsInterest.InterestBill(t_bills principleBill) 位置 e:\work\yijia\trunk\GetWay.BLL\Bills\PrincipalBillsInterest.cs:行号 186
在 GateWay.BLL.Bills.PrincipalBillsInterest.Interest() 位置 e:\work\yijia\trunk\GetWay.BLL\Bills\PrincipalBillsInterest.cs:行号 77
通过分析程序,发现dal层的所有方法都是静态的,其中还包括一个静态的db连接对象:
public class BillsDal
{
static IDbConnection _conn = ConnUtility.GateWayConntion; /// <summary>
/// 获取指定业务订单的所有账单(by 商户code和订单号)
/// </summary>
/// <param name="bizOrderId">订单Id,唯一</param>
/// <returns></returns>
public static List<t_bills> GetOrdersBillList(string merCode, string bizOrderNo)
{
var obj = _conn.Query<t_bills>("select * from t_bills where merCode='" + merCode + "' and orderNo='" + bizOrderNo + "'");
return obj.ToList();
}
}
突然想到之前整理的blog《static,你还敢用吗?》,所以,不难分析出来原因:问题就出在这个静态的db连接对象_conn上,因为所有类的实例始终是用一个db连接,当并发出现时,又没有lock数据操作代码,那么,就很容易出现连接在未关闭时又要被建立并打开,这样就出现了db连接异常。
经模拟多线程来测试,的确如此。
问题即答案!修复这个bug的话,有如下2个方案:
- 如果仍然要保留这个static的_conn字段,就要用lock来锁住数据操作代码(GetOrdersBillList),以控制并发冲突
- 每次查询时用一个新的连接对象。
方案分析:第1种,涉及到对象只能在被释放(关闭)掉才能再次被使用(打开),性能低下,不可取。 第2种呢,其实在dal层,绝大多数的程序猿都是按照每一个数据操作只用一个db连接的方式来编码的。 由于大家一般不会把dal类的成员定义成static,所以,也就不会遇到这样的db连接异常。而我呢,倾向于用static方法,考虑到封装,就把这个db连接对象封装成静态字段了,反而忽视了静态数据成员带来的隐患——数据量小时几乎是暴露不出来问题,一旦数据量大起来,有了并发,就会出现资源被同时使用,这样的话,多个线程实例都要修改其状态时,就出现了并发异常。
由此来看,依然用static的话,就要把_conn当做只读的私有属性(不考虑代码味道):
static IDbConnection _conn
{
get { return ConnUtility.GateWayConntion; }
}
这样,当每次访问这个属性时,都会返回一个新的连接对象。
再次模拟多线程测试,ok!
static,你还敢用吗?(二)的更多相关文章
- PHP之static静态变量详解(二)
在看别人项目过程中,看到函数里面很多static修饰的变量,关于static修饰的变量,作用域,用法越看越困惑,所以查了下资料. static用法如下: 1.static 放在函数内部修饰变量 2.s ...
- 面向对象程序设计-C++ Type conversion (Static) & Inheritance & Composition【第十二次上课笔记】
这节课继续讲解了 static 作为静态数据成员 / 成员函数的用法 具体详解我都已注释出来了,大家可以慢慢看 有任何问题都可以在这篇文章下留言我会及时解答 :) //static 静态数据成员 // ...
- java static成员变量方法和非static成员变量方法的区别 ( 二 )
原创文章,未经作者允许,禁止转载!!! 静态成员变量不用new对象,在类加载的过程中就已经初始化存放在数据区域,静态成员变量是类和所有对象共有的,类和对象都可以改变它的值,每一次改变值之后,静态成员变 ...
- (转)Java中的static关键字解析
转载: http://www.cnblogs.com/dolphin0520/p/3799052.html 一.static关键字的用途 在<Java编程思想>P86页有这样一段话: &q ...
- Java中的static关键字解析
Java中的static关键字解析 static关键字是很多朋友在编写代码和阅读代码时碰到的比较难以理解的一个关键字,也是各大公司的面试官喜欢在面试时问到的知识点之一.下面就先讲述一下static关键 ...
- (转)Java中的static关键字解析
转自http://www.cnblogs.com/dolphin0520/p/3799052.html 一.static关键字的用途 在<Java编程思想>P86页有这样一段话: “sta ...
- java中的static详解
如果一个类成员被声明为static,它就能够在类的任何对象创建之前被访问,而不必引用任何对象.static 成员的最常见的例子是main( ) .因为在程序开始执行时必须调用main() ,所以它被声 ...
- Java中的static关键字解析 转载
原文链接:http://www.cnblogs.com/dolphin0520/p/3799052.html Java中的static关键字解析 static关键字是很多朋友在编写代码和阅读代码时碰到 ...
- C# 生成二维码,彩色二维码,带有Logo的二维码及普通条形码
每次写博客,第一句话都是这样的:程序员很苦逼,除了会写程序,还得会写博客!当然,希望将来的一天,某位老板看到此博客,给你的程序员职工加点薪资吧!因为程序员的世界除了苦逼就是沉默.我眼中的程序员大多都不 ...
- android 二维码扫描
了解二维码这个东西还是从微信 中,当时微信推出二维码扫描功能,自己感觉挺新颖的,从一张图片中扫一下竟然能直接加好友,不可思议啊,那时候还不了解二维码,呵呵,然后做项目的时候, 老板说要加上二维码扫描功 ...
随机推荐
- 03.SQLServer性能优化之---存储优化系列
汇总篇:http://www.cnblogs.com/dunitian/p/4822808.html#tsql 概 述:http://www.cnblogs.com/dunitian/p/60413 ...
- 从Script到Code Blocks、Code Behind到MVC、MVP、MVVM
刚过去的周五(3-14)例行地主持了技术会议,主题正好是<UI层的设计模式——从Script.Code Behind到MVC.MVP.MVVM>,是前一天晚上才定的,中午花了半小时准备了下 ...
- 04.SQLServer性能优化之---读写分离&数据同步
汇总篇:http://www.cnblogs.com/dunitian/p/4822808.html#tsql 过段时间再继续写文章吧,本来准备把SQLServer一个系列写完的,最近状态很差很不好, ...
- 学习ASP.NET Core, 怎能不了解请求处理管道[4]: 应用的入口——Startup
一个ASP.NET Core应用被启动之后就具有了针对请求的处理能力,而这个能力是由管道赋予的,所以应用的启动同时意味着管道的成功构建.由于管道是由注册的服务器和若干中间件构成的,所以应用启动过程中一 ...
- 算法与数据结构(十一) 平衡二叉树(AVL树)
今天的博客是在上一篇博客的基础上进行的延伸.上一篇博客我们主要聊了二叉排序树,详情请戳<二叉排序树的查找.插入与删除>.本篇博客我们就在二叉排序树的基础上来聊聊平衡二叉树,也叫AVL树,A ...
- 编写高质量代码:改善Java程序的151个建议(第6章:枚举和注解___建议88~92)
建议88:用枚举实现工厂方法模式更简洁 工厂方法模式(Factory Method Pattern)是" 创建对象的接口,让子类决定实例化哪一个类,并使一个类的实例化延迟到其它子类" ...
- 微软发布VSBT,无需安装Visual Studio即可实现项目编译
安装了Visual Studio的那些使用微软平台的开发者通常能够非常容易地操作自己的项目:打开解决方案,修改内容,设置好所有必须的文件以及配置后编译项目.但是在构建服务器或者持续交付系统等没有安装V ...
- Android中开发工具Android Studio修改created用户(windows环境)
最近经常有朋友反馈说我的安卓项目中,在一些类中会出现Created by panchengjia on 2016/12/30的字样,是如何自动实现的(默认一般为Administrator),如下图: ...
- [Hadoop in Action] 第6章 编程实践
Hadoop程序开发的独门绝技 在本地,伪分布和全分布模式下调试程序 程序输出的完整性检查和回归测试 日志和监控 性能调优 1.开发MapReduce程序 [本地模式] 本地模式 ...
- Linux:将rhel yum 切换到centos yum
Red Hat Enterprise Linux Server(RHEL) yum安装软件时This system is not registered with RHN. RHN support wi ...