[Django]翻译www.djangobook.com之第二章:Django快速上手

mikel阅读(896)

The Django Book 第2章:Django快速上手
revised by xin_wang
谢天谢地,安装Django非常容易。因为Django可以运行在任何可以运行Python的环境中,所以可以以多种方式进行配置。
在本章我们将尝试覆盖几种常见的Django安装场景。
安装Python
Django是以100%纯Python代码写就,所以你需要安装Python,Django要求安装Python2.3或更高版本。
如果你使用Linux或者MacOSX,你可能已经安装了Python
在命令行或者终端下输入“python”,如果出现类似如下提示,表示Python已经安装好了:
Python 2.4.1 (#2, Mar 31 2005, 00:05:10)
[GCC 3.3 20030304 (Apple Computer, Inc. build 1666)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>>
否则,出现错误提示“command not found”
你可以到http://www.python.org/download/下载Python安装
安装Django
安装官方发布版本的Django
http://www.djangoproject.com/download/下载tarball的Django-*.tar.gz

Java代码 复制代码
  1. tar xzvf Django-*.tar.gz  
  2. cd Django-*  
  3. sudo python setup.py install  

Windows下安装则是直接解压Django-*.tar.gz并运行python setup.py install
安装完以后,在Python交互环境下应该可以import django模块

Java代码 复制代码
  1. >>> import django  
  2. >>> django.VERSION  
  3.  (10'official')  

Python交互环境是一个命令行程序,在命令行下运行“python”即可进入交互环境
在这本书里,我们将会演示一些Python代码例子,这些例子看起来像是在交互环境里面输入的。
Python交互环境的提示符是三个大于号(>>>)
从Subversion安装Django
如果你想安装Django最新代码或者你想向Django贡献代码,你应该从Django的Subversion repository安装
Subversion是一个与CVS类似的开源版本控制系统,Django团队使用它来管理Django代码的变化。
你可以随时使用Subversion客户端获取最新的Django源代码,或者更新你本机Subversion工作拷贝"local checkout"中的
Django代码来获得Django开发人员所作的最新修改和增强。
最新的Django开发代码称为“the trunk”
得到最新的Django trunk:
1,确认你安装了Subversion客户端,下载地址为http://subversion.tigris.org
Subverion的文档http://svnbook.redbean.com
2,运行如下命令得到trunk“svn co http://code.djangoproject.com/svn/django/trunk django_src”
3,符号链接django_src/django来让django在你的Python site-packages目录下,或者更新PYTHONPATH指定它
从Subversion安装不需要运行“python setup.py install”
Django trunk经常更新bug fixs和增加feature,你可能要频繁更新它
在django_src目录下运行“svn update”即可更新代码
建立数据库
Django仅有的先决条件就是安装Python,但是本书关注Django引以为傲的众多优点之一,开发支持数据库的Web站点
所以你需要安装一个数据库服务器来存储数据
如果你只是想浅尝辄止,可以跳过这一步直接开始一个项目,可是请相信我们:你最终还是会装一个数据库,因为本书的
所有例子都假设你已经拥有一个数据库
Django1.0支持5个数据库引擎:
PostgreSQL(http://www.postgresql.org/)
SQLite 3(http://www.sqlite.org/)
MySQL(http://www.mysql.com/)
Microsoft SQL Server(http://www.microsoft.com/sql/)
Oracle(http://www.oracle.com/database/)
我们自己特别喜欢PostgreSQL,所以我们最先提到它
尽管如此,所有的这些数据库都在Django上工作得都很好
SQLite也值得特别注意,它是一个非常简单的数据库引擎,不需要任何服务器安装和配置
如果你只是想玩玩Django的话,SQLite是最容易安装的
使用PostgrSQL来和Django工作
如果你用PostgreSQL,你需要psycopg包,从http://initd.org/projects/psycopg1可以得到
确认你使用版本1而不是版本2,2还是beta版
如果你在Windows上使用PostgreSQL,可以从如下地址下载已经编译好的二进制psycopg
http://stickpeople.com/projects/python/win-psycopg/
使用SQLite 3来和Django工作
你需要SQLite 3而不是SQLite 2,从http://initd.org/tracker/pysqlite下载pysqlite
确认下载pysqlite的版本为2.0.3及以上
使用MySQL来和Django工作
Django需要MySQL版本4.0及以上,3.x版本不支持事务、嵌套存储过程以及其它标准SQL语句
你也需要MySQLdb包,下载地址http://sourceforge.net/projects/mysql-python
使用MSSQL来和Django工作
使用Oracle来和Django工作
不使用数据库来和Django工作
就像刚刚提到的,Django实际上不需要数据库
如果你仅仅希望Django来提供动态网页而不触及数据库也是可以的
和Django绑定的一些额外的工具需要数据库,如果你选择不使用数据库,你会错失那些特性
开始一个项目
如果这是你第一次使用Django,你必须注意一些初始化过程
运行“django-admin.py startproject mysite”将会在你的当前目录下创建一个mysite目录
注意,如果你使用setup.py安装Django,django-admin.py应该在你的PATH系统变量下
如果不在PATH里面,你可以从site-packages/django/bin找到它
考虑符号链接它到你的PATH里面,例如/usr/local/bin
一个项目就是一个Django实例的设置的集合,包括数据库配置、Django的专有设置以及应用程序专有设置
让我们看看startproject创建了什么:
/mysite/
__init__.py
manage.py
settings.py
urls.py
这些文件的说明如下:
manage.py
一个命令行工具,可以让你以多种方式与Django项目交互
setting.py
Django项目的配置
urls.py
Django项目的URL定义
如果你使用PHP,你可能习惯于将代码放在Web服务器的document root下,如/var/www
使用Django的话不要这样做,将Python代码放在document root下不是一个好主意
因为这样的话人们可能从Web看到你的代码,这并不安全
把你的代码放在document root以外的目录,如/home/mycode
开发用服务器
切换到mysite目录,运行“python manage.py runserver”,你将看到如下信息
Validating models…
0 errors found.
Django version 1.0, using settings 'mysite.settings'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
这样你就启动了Django开发用服务器,这是一个包含在Django中的开发阶段使用的轻量级Web服务器
我们在Django中包含了这个服务器是为了快速开发,这样在产品投入应用之前,就可以不用处理生产环境中
web server的配置工作了。
这个服务器查看你的代码,如果有改动,它自动reload,让你不需重启快速修改你的项目
虽然这个开发用服务器对于开发来说简直棒透了,还是请克制一下把它用在任何形式的生产环境中的冲动。
这个服务器一次只能可靠地处理一个请求,而且根本没有经过任何安全性的检验
如果你的站点需要上线,请参考第21章的关于部署Django程序的介绍
默认情况下runserver命令启动服务器的端口为8000,只监听本地连接
如果你希望改变端口,增加一个命令行参数即可
python manage.py runserver 8080
你也可以改变服务器监听的IP地址,当你同其它开发者分享一个开发站点时很有用
python manage.py runserver 0.0.0.0:8080
上面的命令使得Django监听任何网络接口,这样的话就允许其它计算机连接该服务器
试着访问http://127.0.0.1:8000/,你将会看到“Welcome to Django”的页面
下一步是什么?
我们已经安装好一切的东西并且让服务器运行了,让我们写一点基本代码来展示怎样使用Django提供动态页面

[Python]Python的web框架汇总

mikel阅读(891)

1.Snakelets
Snakelets 是一个 Python 编写的web server,从我了解的j几种 web framework 来讲,我认为snakelet功能似乎更强,它是一个象servlet的一个东西,许多东西已经做好了,象模板,用户认证(提供多种方式)等,看了那个Frog,我还是很喜欢他的,小研究了一下他的代码,发现实在有点复杂,不容易明白,目前没有一个合适的入门教材,而且本身有些复杂,所以处于放弃状态~
2.Django
Django是一个高级 Python web framework,它鼓励快速开发和干净的、MVC设计。它包括一个模板系统,对象相关的映射和用于动态创建管理界面的框架。
他没发布之前就已经吸引了不少人了, 比以前的,更加注重整体设计
特性介绍:
对象相关的映射
完全在Python中定义你的数据模型。你可以免费得到一个丰富的,动态访问数据库的API--但如果需要你仍然可以写SQL语句。
URL 分发
URL的设计漂亮,cruft-free,没有框架的特定限定。象你喜欢的一样灵活。
模版系统
使用DjanGo强大而可扩展的模板语言来分隔设计、内容和Python代码。
Cache系统
可以挂在内存缓冲或其它的框架实现超级缓冲 -- 实现你所需要的粒度。
自动化的管理界面
不需要你花大量的工作来创建人员管理和更新内容的接界。DjanGo可以自动完成。
支持多种数据库
已经支持PostgreSQL, MySQL, Sqlite3
我倾向使用他,但是很遗憾没调试成功~ [redface]
3.Karrigell
作 为简单web开发解决, Karrigell已经包含了web服务,Python 脚本引擎,和 100% 纯Python的数据库: KirbyBase ; 你所要关心的就是创建自个儿的动态web 应用. 这个是我目前主要研究的对象,因为DjanGo没有运行成功,而据介绍Karrigell也是一个非常优秀的 web framework 框架.现在环境设置成功了,如果可以,就可以开始入门学习了~
karrigell是利用mod_python与 apache集成,不需要再运行自已的server,Karrigell不需要挂接处理。写一个.py, .hip, .pih,.ks都是可以的。.py就是普通的python程序,print的结果会作为结果输出。.hip就是Html in Python ,与.py有些象,但在 Python 顶层可以直接以字符串形式写html的代码。.pih就是Python in Html,与其它的 Python Html 模板很象,就是在 Html 模板中嵌入 Python 程序。使用<% %>来包括。.ks就是Karrigell Service,它与 CherryPy 中的方法发布有些象,但不用设置哪个方法需要发布,也不是类的写法,只是函数的写法。
4.Quixote
快速进入 无畏的骑士! 豆瓣 的主要动力系统!正因为这个,我对他的关注也多了很多~
这个框架目前国内使用的人不多,但是豆瓣正是使用了他而成功的,目前这个框架我还没开始尝试
下面有一些资料可以帮你了解他~
http://quixote.ca/
http://www.mems-exchange.org/software/quixote/apps.html
其实Python的Web 开发框架还有很多,象TurboGears ,但我目前接触的比较多的就这几个,其他的在啄木鸟社区还有很多介绍,感兴趣的,可以自己去看看,也欢迎大家能推荐一些比较好用的Web 开发框架介绍,和使用经验,共同体验python的开发乐趣~

[DB4O]db4objects 7.4应用笔记

mikel阅读(979)

db4o是面向对象的数据库,复杂应用就不说了,说点简单的。

数据库嘛,简单的操作就是添加,删除,更新和查询。

1、添加

添加非常简单:
先建一个需要存储的对象

    public class Model
{
public int ID { get; set; }
public string Name { get; set; }
public override string ToString()
{
return string.Format("ID:{0} , Name:{1}", ID, Name);
}
}
在进行存储操作
            using (IObjectContainer db = Db4oFactory.OpenFile("d:\\d.dat"))
{
db.Store(new Model() { ID = 1, Name = "Test" });
}
或者
            IObjectContainer db = Db4oFactory.OpenFile("d:\\d.dat");
db.Store(new Model() { ID = 1, Name = "Test" });
db.Dispose();
 
2、更新
更新操作就有一个引用的概念。怎么确定是删除的对象,在db4o中是通过ObjectRefence来操作的。对象的指向一定要正确啦。所以虽然也是用Store方法进行更新操作,但是,不能直接更新。比如对于上面添加的一条记录使用
IObjectContainer db = Db4oFactory.OpenFile("d:\\d.dat");
db.Store(new Model() { ID = 1, Name = "Test" });
db.Dispose();
并不会更新,而是一个添加操作。而下面的操作也无法更新:
using (IObjectContainer db = Db4oFactory.OpenFile(Util.YapFileName))
{          
    IObjectSet list = db.QueryByExample(new Model() { ID = 1 });
    for (int i = 0; i < list.Count; i++)
    {
        db.Store(new Model() { ID = 1, Name = "Test2" });
    }
}
 
需要更新引用才可以。因此要写成:
using (IObjectContainer db = Db4oFactory.OpenFile(Util.YapFileName))
{          
    IObjectSet list = db.QueryByExample(new Model() { ID = 1 });
    for (int i = 0; i < list.Count; i++)
    {
        ((Model)list[i]).Name = "Test2";
        db.Store(list[i]);
    }
}
在循环中list[i]是无法直接赋值的。不能像下面那样用:
using (IObjectContainer db = Db4oFactory.OpenFile(Util.YapFileName))
{          
    IObjectSet list = db.QueryByExample(new Model() { ID = 1 });
    for (int i = 0; i < list.Count; i++)
    {
        list[i] = new Model() { Name = "tttttt", ID = 2 };
        db.Store(list[i]);
    }
}
可以给Model对象添加一个方法:
    public class Model
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public void SetValue(Model model)
        {
            this.ID = model.ID;
            this.Name = model.Name;
        }
        public override string ToString()
        {
            return string.Format("ID:{0} , Name:{1}", ID, Name);
        }
    }
然后使用:
using (IObjectContainer db = Db4oFactory.OpenFile(Util.YapFileName))
{
    IObjectSet list = db.QueryByExample(new Model() { ID = 1 });
    for (int i = 0; i < list.Count; i++)
    {
        ((Model)list[i]).SetValue(new Model() { Name = "tttttt", ID = 2 });
        db.Store(list[i]);
    }
}
 
当然,也可以像下面一样用:
    IObjectContainer db = Db4oFactory.OpenFile(Util.YapFileName);
    IObjectSet list = db.QueryByExample(new Model() { ID = 1 });
    for (int i = 0; i < list.Count; i++)
    {
        ((Model)list[i]).SetValue(new Model() { Name = "tttttt", ID = 2 });
        db.Store(list[i]);
    }
    db.Dispose();
 
3、删除
删除和更新差不多,也需要删除引用,可以有下面两种用法。
using (IObjectContainer db = Db4oFactory.OpenFile(Util.YapFileName))
{
IObjectSet list = db.QueryByExample(new Model() { ID = 1 });
for (int i = 0; i < list.Count; i++)
{
db.Delete(list[i]);
}
}
或者

IObjectContainer db = Db4oFactory.OpenFile(Util.YapFileName);
IObjectSet list = db.QueryByExample(new Model() { ID = 1 });
for (int i = 0; i < list.Count; i++)
{
db.Delete(list[i]);
}
db.Dispose();
4、查询
更新和删除实际上已经用了查询,查询语句可以写成:
using (IObjectContainer db = Db4oFactory.OpenFile(Util.YapFileName))
{
IObjectSet list = db.QueryByExample(new Model() { ID = 2 });
for (int i = 0; i < list.Count; i++)
{
Console.WriteLine(((Model)list[i]).ToString());
}
}
或者
 

IObjectContainer db = Db4oFactory.OpenFile(Util.YapFileName);
IObjectSet list = db.QueryByExample(new Model() { ID = 1 });
for (int i = 0; i < list.Count; i++)
{
Console.WriteLine(list[i].ToString());
}
db.Dispose();
上面是根据对象查的。下面根据是按类型,用到的方法是Query。
IObjectContainer db = Db4oFactory.OpenFile(Util.YapFileName);
IList<Model> list = db.Query<Model>(typeof(Model));
for (int i = 0; i < list.Count; i++)
{
Console.WriteLine(list[i].ToString());
}
db.Dispose();

把所有的Model类型的数据都查询出来了就。

5、简单讲解
查询的时候,比如
IObjectSet list = db.QueryByExample(new Model() { ID = 1 });
是查找所有ID为1的Model类型的数据。
如果要查找Name为“123”就写成:
IObjectSet list = db.QueryByExample(new Model() { Name = "123" });
6、封装
下面给两个操作的封装类:
对象封装
或者
静态方法封装
注意,以上两个封装并没有封装更新的方法,更新的时候需要新查询数据然后再更新。

[HTML]Pre标签自动换行

mikel阅读(844)

pre标签会原样保留HTML内容的格式,可是如果宽度过大会把页面撑坏,这时候需要自动换行来帮忙:

Wrapping the pre tag

Making preformated text wrap in CSS3, Mozilla, Opera and IEis the tip that let's you use the pre tag to keep the formatting, without cursing yourself when some of the content is too long and doesn't wrap: 

/* Browser specific (not valid) styles to make preformatted text wrap */
pre {
white-space: pre-wrap;       /* css-3 */
white-space: -moz-pre-wrap;  /* Mozilla, since 1999 */
white-space: -pre-wrap;      /* Opera 4-6 */
white-space: -o-pre-wrap;    /* Opera 7 */
word-wrap: break-word;       /* Internet Explorer 5.5+ */
} 
父标记最好加个DIV,并设置CSS属性:word-wrap: break-word;white-space : normal;

[OO]深入理解面向对象软件设计(一) —— 从具体例子谈起

mikel阅读(840)

    java和C#通常被认为是完全面向对象的语言,所有基本代码必须写在某个类中。但是,很多java和C#程序员编写的代码并不是真正面向对象的。有这种事?确实有,面向对象的编程语言只是提供了封装、继承和多态的机制,并不能保证我们用它写出的程序是面向对象的,即使我们把“人”和“狗”的代码糅合在一起,也不会导致编译和运行出错,我们来看一个c#编写的“人与狗的故事”:     

 


    class Program
{
static void Main(string[] args)
{
Story story = new Story();
Console.WriteLine(story.GetStory1());
Console.Read();
}
}
public class Story
{
private string dogName = "Aliths";//狗的名字        
        private string masterName = "Peter";//狗主人的名字        
        private string masterBabyName = "Jim";//狗主人的baby的名字        
        private string friendA = "Borbo";//A朋友的名字        
        private string babyA = "LiLy";//A朋友的baby的名字        
        public string GetStory1()
{
StringBuilder storyStr = new StringBuilder("         人与狗的故事\r\n\r\n");
storyStr.Append(string.Format("    傍晚,{0}带着儿子{1}和爱犬{2}出门散步,"
, masterName, masterBabyName, dogName));
storyStr.Append(string.Format("遇到了熟人{0},{0}带着女儿{1}在玩。\r\n"
, friendA, babyA));
storyStr.Append(string.Format("    {0}将{1}和{2}交给{3}照看,"
, masterName, masterBabyName, dogName, friendA));
storyStr.Append("自己去附近商店买烟。");
storyStr.Append(string.Format("这时{0}咬了{1}。{1}大哭,{2}气得遍地找板儿砖,"
, dogName, babyA, friendA));
storyStr.Append(string.Format("然后一板儿砖下去将{0}拍得满地找牙。\r\n"
, dogName));
//……            

storyStr.Append(string.Format("\r\n\r\n……"));
return storyStr.ToString();
}
}

 

    这段代码包含两个类Program和Story,单纯从语言层面讲,是面向对象的。但Story中把故事、狗和多个人等的代码糅合在一起(如果故事情节涉 及板砖和商店的细节,还会更乱,而且不仅用到人的名字,还有年龄穿着等,故事有时间地点等等,为例子简单,没有提及),称为面向对象的设计,完全说不过 去。

    如果需求不发生变化,这段代码不会有太大问题,没必要把类分的那么清楚。但需求还是变了,要求增加一个故事二:狗主人在另一天出门时遇到了朋友B,给B讲述了发生在前几天的故事一,并且讲述中他添油去醋,并没有按故事一的实际情节讲,我们来看代码:

 


    class Program
{
static void Main(string[] args)
{
StructStory story = new StructStory();
Console.WriteLine(story.GetStory1(1));//GetStory1增加了int参数

Console.WriteLine(story.GetStory2());//GetStory1增加了int参数

Console.Read();
}
}
public class StructStory
{
private string dogName = "Aliths";//狗的名字
        private string masterName = "Peter";//狗主人的名字
        private string masterBabyName = "Jim";//狗主人的baby的名字

private string friendA = "Borbo";//A朋友的名字
        private string babyA = "LiLy";//A朋友的baby的名字

private string friendB = "Jance";//B朋友的名字

public string GetStory1(int storyIndex)
{//为了给GetStory2调用,增加参数storyIndex,并根据不同参数进行不同的讲述

StringBuilder storyStr = new StringBuilder("         人与狗的故事\r\n\r\n");
storyStr.Append(string.Format("    傍晚,{0}带着儿子{1}和爱犬{2}出门散步,"
, masterName, masterBabyName, dogName));
storyStr.Append(string.Format("遇到了熟人{0},{0}带着女儿{1}在玩。\r\n"
, friendA, babyA));
if (storyIndex == 2)
{
//添油……
            }
if (storyIndex != 2)
{//去醋……

storyStr.Append(string.Format("    {0}将{1}和{2}交给{3}照看,"
, masterName, masterBabyName, dogName, friendA));
storyStr.Append("自己去附近商店买烟。");
}
storyStr.Append(string.Format("这时{0}咬了{1}。{1}大哭,{2}气得遍地找板儿砖,"
, dogName, babyA, friendA));
storyStr.Append(string.Format("然后一板儿砖下去将{0}拍得满地找牙。\r\n"
, dogName));
//……
            storyStr.Append(string.Format("\r\n\r\n……\r\n\r\n"));
return storyStr.ToString();
}
public string GetStory2()
{
StringBuilder storyStr = new StringBuilder("      人与狗的故事2\r\n\r\n");
storyStr.Append(string.Format("    第二天,{0}出门时遇到了熟人{1},"
, masterName, friendB));
storyStr.Append("给他讲了狗咬人的故事:\r\n");
storyStr.Append(this.GetStory1(2));
return storyStr.ToString();
}
}

 

    这时代码已经变得无法忍受了,如果需求再变,不堪设想。也许有的朋友要说,需求不至于一直变吧,我想说:需求不变才不正常,因为需求是人类思想的反映,人的想法是不断变化的,整个世界也在变化。高楼大厦之所以没有经常拆了重建,并不是人们对它满意,而是反复拆建需要大量时间和金钱。而 软件相对于建筑来说,只有设计过程(写文档和编码都是设计),没有建造过程,真正的建造过程是在代码写完后由计算机瞬间完成(编译成二进制exe、 dll),所以人们只要不满意就可能让它“重建”。可以设想一下,假如代码完成后要由人工打纸带(像最初的程序,0打孔,1不打)来编译,或许随便找一个 B/S程序够一个人打几年的,这时需求还是会变,但不会要求程序员去修改了——将就着用吧,不然就洗洗睡先。

    认同了需求是变化的,就要找办法解决问题,面向对象相对于面向过程的主要优势之一就在应对变化上,可能也是面向对象在系统软件开发方面流行的主要原因。上述代码有些过于初级,有一定经验的程序员可能会把代码写成这样: 

     Story有发生时间、地点等属性和GetStory方法,Person有被咬(被咬后的反映)和打狗等方法,如果故事情节涉及Brick(板砖)和 Shop(商店)的细节,还会有这两个类,这样基本有了貌似单一职责的几个类。其实,这仅仅是对代码的“归类”,没有做到单一职责,比如Person中的 BefallBite(被狗咬)方法会遇到这样的问题:

    如果Person实例是小孩,反映可能是坐在地上大哭

    如果是大人,可能是找板砖

    如果是狗主人家的小孩,狗可能只是轻咬他玩得,不会哭,会跟狗一起玩

    如果是大人,又是狗主人被咬,不一定舍得板砖拍……

    ……

    显然,Person还应该有一些子类:

 

    这样就基本有了职责单一的类结构。但我们还是发现了问题,Person的子类比较多,如果再加上“根据被狗咬的部位不同反映不同”(Baby被咬屁股不会 坐地上哭,可能是趴着哭;大人被咬右手可能无法拿板砖),那么子类将会更多。这时仅仅靠最基本的单一职责原则及其它几条原则已经不能做出良好的面向对象设 计,设计模式就是在面向对象的基础上进一步提高软件应对变化能力的“良药”。本例是典型的桥接模式应用场景,笔者将在后续博文中用更复杂更完整的例子和大家共同学习设计模式的综合运用。

 

PS 1:

    本文提到的三种编码方式应该可以代表三种编码阶段,在结尾提到了设计模式,其实在知道用设计模式后还有三个阶段,纯属个人看法:

    1、在单一职责等基本原则做的不太好时就接触了设计模式,根据各种模式定义的场景大量运用。这种阶段去做大项目,遇到的问题往往比最初级的混合编码阶段还多。

    2、基本功底打得扎实后,逐步学习运用设计模式,遇到问题能够根据设计模式定义进行思索,合理解决问题

    3、设计模式的定义经常不记得,设计和编码时只根据基本原则进行,遇到问题就重构代码,重构后发现好像和某种模式定义的场景类似,查书后确定是一样的……

   

    呵呵,设计模式最好不要强求,自然形成就好。

 

PS 2:

    刚开始写博客,对编辑器不熟悉,我贴的代码好好的,发布后对齐格式有点乱,反复几次搞不定;还有贴个类图要先截图存gif,再传上来,很麻烦。请高手留言指点,多谢!我用的编辑器是 TinyMCE(推荐)

[MVC]一个小Forum Web程序示例,使用ASP.NET MVC Framework,Repo

mikel阅读(787)

本文简单介绍以下内容:

1. Repository模式简介以及结合IQueryable改进的Repository模式;

2. 简单的TDD实践,使用ReSharper 4.0插件简化操作;

3. 结合使用依赖注入(Dependency Injection[中文翻译])工具StructureMap[文档下载],实现模块之间的松散耦合。

4. 提供一个很简单的论坛程序示例,Step by Step介绍以上内容。

差不多内容的blog示例在Codeplex上也早就有了,介绍MVC TDD和StructureMap的英文文章也挺多,本人才疏学浅,文采很烂,写本文是一是为了自己更深的掌握这些内容,二是为了让喜爱MVC的朋友也能 获得一些帮助,也是第一次写东西放首页上,请各位前辈多提意见和建议。

Repository简介

介绍Repository的文章比较少,其实这个模式相当简单,首先对它做一个简单的介绍:

image

这就是一个比较简单的Repository模式,首先创建一个IRepository接口,这个接口定义一系列契约,然后创建一个实现这个接口的类,负责它的具体操作。然后在Context中对它进行实例化(在本示例中,实例由依赖注入框架完成)。

当然这个模式还可以结合简单工厂模式对它进行扩充,由工厂来完成它的实例创建工作。

 

应用程序整体结构

下面介绍一下本示例的结构,也是比较简单的:

首先,我们使用ASP.NET MVC Framwork Preview 5,所有的操作(发帖、回帖、删帖等)都是由在相应的Controller中的Action来完成的。关于MVC这里就不做详细介绍了。我这里创建了一个 类库项目:TinyForum.Service,在这个项目中,创建一个IForumService定义一组契约,我们在Controller中需要一个 它的实例字段(为了好看,图中为属性,字段在Class diagram中不显示关系)来完成操作(如图)。

image

上图中的ForumService类中,需要对数据操作进行封装。为了使用不同的数据库,还得建立一个项目:TinyForum.Data,在这个项目中,我们会定义一个IForumRepository接口,又由这个接口定义一组对数据库的操作,所有操作返回类型都为IQueryable类型,这样非常的方便,在ForumService中就可以对它进行任意的转换,也不会因为返回大量的IList还可能需要做进一步的筛选影响性能。

image

这是ForumService的实现:

image

这是IForumRepository的定义(随意定义了2个方法):

image

很显然,在ForumService中,需要一个对IForumRepository的依赖,在实现的代码中,我们创建了一个构造方法来获 得这个对象,这时候出现一个麻烦问题,因为我们需要在上下文中去创建我们需要的IForumRepository的实例,这样做会造成可能需要修改 ForumService的代码,这样是违反OCP原则的;

同时ForumController也需要一个对IForumService的依赖,并且要在构造方法中获得它的示例,而MVC默认的Controller构造方法是无参的,编译可以通过,不过运行的时候会得到一个黄色的异常页面,大概是这样:

image

看来需要使用一个依赖注入工具来解救我们。我这里使用的StructureMap。

在Web项目中,添加StructureMap引用,并在Controllers目录下添加一个StructureMapControllerFactory,如图:

image 

然后我们需要为StructureMap做一点配置,让它知道该做什么,首先创建一个StructureMap的注册表:ForumRegistry

image

另外还要添加一个注册表,用于让SQLRepository获得ForumDataContext(Linq):

image 

都不是很复杂,代码已经解释得很详细了,就不做累述了。

最后需要添加一个Bootstrapper,并添加到Global.asax.cs中去,启动的时候就执行。

image

image

基本结构就介绍到这里。

目前的解决方案截图:

image

怕文章又臭又长,所以干脆分开写(至少不长,呵呵),下一个部分将介绍使用Resharper插件、和TDD步骤,并象征性实现一些基本的功能。

[C#]C# 3.0将偷懒进行到底

mikel阅读(978)

C# 3.0将偷懒进行到底

本文为博客园zpino原创

http://www.cnblogs.com/zpino/ 转载请说明出处!

 

最近在MS中了解到了一些东西。首先我要说,我绝对是一个新手。

要说核心原理,俺最多能给你搬来一点,要是刨根问底的话,去找MSDN。

 

隐藏类型局部变量

这个很多人都知道(–!我现在才知道。貌似很受打击,有点孤陋寡闻)

 


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var a = 1;  //自动判断类型。编译后成为int类型
            var b = 2;   //更加右边的值 推断左边的类型
            var c = 0;
if (b > a)
{
c = 4;
}
else
{
c = 5;
}
Console.WriteLine(c);
}
}
}

 

注意:

1 var 不是一个类型。顶多就像一个占位的东西。编译后替换成int string等等.而且只能作为局部变量!

2 var的值不能为null。不然编译器不能推断。

3 不能为对象和集合的初始化。但是可以初始化数组,包括多维数组。 var q=new{1,2,3};

初始化语句

 

 

扩展方法

这个也是一个很方便的东西

可以扩展一个类的方法。

比如

 

 


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
int g = 1;
Console.WriteLine(g.extensions()); //注意g.extensions() 。g是一个int类型
//可是却有extensions()方法。其实是我把int增强了
        }
}
}

 

extensions就是一个扩展方法。

为什么会有这个效果呢?

其实之前我建立一个静态类,和一个静态方法。而且方法接受的参数是 extensions(this int k)。

上代码^_^

 


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
public static class Class1 //必须为静态类,类名无所谓
    {
public static int extensions(this int k) //静态方法。必须是静态的。
//接受的类型之前加this。其中int可以替换为你想增强的东东。我增强int一个我自己写的新方法
        {
return k + 1;
}
}
}

这样就非常简单的实现不修改代码
直接扩展方法。
其中代码:


g.extensions()

 

被编译成了


Class1。extensions(g)

 

这个指针之类的有关系,俺暂时没有深入了解,所以不乱忽悠了。

注意:

1 方法扩展有优先级。实例方法>所在的namespace>别的namespace

2 记得类、方法要用静态。 

 

匿名对象


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var qq = new {name="你好",pass=123 };  //不创建类 直接构建一个匿名类型
            var vv = new { name="hello",pass=333}; //甚至不用写属性的类型,编译的时候会自动判断
            Console.WriteLine(qq.name);
Console.WriteLine(vv.name);
Console.WriteLine(qq.pass+vv.pass);//使用起来和平时没区别。
        }
}
}

 

匿名类型。不创建类 直接构建一个匿名类型,甚至不用写属性的类型,编译的时候会自动判断,使用起来和平时没区别。

只是有点局限性,不适合跨越传递。

注意:

1 其中声明的qq和vv可以互相赋值。只要编译器判断的属性类型相同。

2 声明的匿名类型全部继承Object

 

–!写完了,有兴趣的,记得装个VS2008试试。不知道在公司用这些老板会不会发飙?:-D

[ADO]SQL Server连接池

mikel阅读(741)

SQL Server 连接池 (ADO.NET)

连接到数据库服务器通常由几个需要很长时间的步骤组成。必须建立物理通道(例如套接字或命名管道),必须与服务器进行初次握手,必须分析连接字符串信息,必须由服务器对连接进行身份验证,必须运行检查以便在当前事务中登记,等等。

实际上,大多数应用程序仅使用一个或几个不同的连接配置。这意味着在执行应用程序期间,许多相同的连接将反复地打开和关闭。为了使打开连接花费的系统开销最小,ADO.NET 使用称为连接池的优化方法。

连接池使新连接必须打开的次数得以减少。池进程保持物理连接的所有权。通过为每个给定的连接配置保留一组活动连接来管理连接。每当用户在连接上调用 Open 时,池进程就会查找池中可用的连接。如果某个池连接可用,会将该连接返回给调用者,而不是打开新连接。应用程序在该连接上调用 Close 时,池进程会将连接返回到活动连接池集中,而不是关闭连接。连接返回到池中之后,即可在下一个 Open 调用中重复使用。

只有配置相同的连接可以建立池连接。ADO.NET 同时保留多个池,每种配置各一个。在使用集成的安全性时,连接按照连接字符串以及 Windows 标识分到多个池中。还根据连接是否已在事务中登记来建立池连接。

池 连接可以显著提高应用程序的性能和可缩放性。默认情况下,在 ADO.NET 中启用连接池。除非显式禁用,否则,在应用程序中打开和关闭连接时,池进程会对连接进行优化。还可以提供几个连接字符串修饰符来控制连接池的行为。有关更 多信息,请参见本主题后面的“使用连接字符串关键字控制连接池”。

在 初次打开连接时,将根据完全匹配算法创建连接池,该算法将池与连接中的连接字符串关联。每个连接池都与一个不同的连接字符串相关联。打开新连接时,如果连 接字符串并非与现有池完全匹配,将创建一个新池。按进程、应用程序域、连接字符串以及 Windows 标识(在使用集成的安全性时)来建立池连接。连接字符串还必须是完全匹配的;按不同顺序为同一连接提供的关键字将分到单独的池中。

在以下 C# 示例中创建了三个新的 SqlConnection 对象,但是管理时只需要两个连接池。注意,根据为 Initial Catalog 分配的值,第一个和第二个连接字符串有所不同。

using (SqlConnection connection = new SqlConnection(
"Integrated Security=SSPI;Initial Catalog=Northwind"))
{
connection.Open();
// Pool A is created.
}
using (SqlConnection connection = new SqlConnection(
"Integrated Security=SSPI;Initial Catalog=pubs"))
{
connection.Open();
// Pool B is created because the connection strings differ.
}
using (SqlConnection connection = new SqlConnection(
"Integrated Security=SSPI;Initial Catalog=Northwind"))
{
connection.Open();
// The connection string matches pool A.
}

如果 MinPoolSize 在连接字符串中未指定或指定为零,池中的连接将在一段时间不活动后关闭。但是,如果指定的 MinPoolSize 大于零,在 AppDomain 被卸载并且进程结束之前,连接池不会被破坏。非活动或空池的维护只需要最少的系统开销。

说明:

当出现故障转移等错误时,会自动清除池。

连接池是为每个唯一的连接字符串创建的。当创建一个池后,将创建多个连接对象并将其添加到该池中,以满足最小池大小的要求。连接根据需要添加到池中,但是不能超过指定的最大池大小(默认值为 100)。连接在关闭或断开时释放回池中。

在请求 SqlConnection 对象时,如果存在可用的连接,将从池中获取该对象。连接要可用,必须未使用,具有匹配的事务上下文或未与任何事务上下文关联,并且具有与服务器的有效链接。

连接池进程通过在连接释放回池中时重新分配连接,来满足这些连接请求。如果已达到最大池大小且不存在可用的连接,则该请求将会排队。然后,池进程尝试重新建立任何连接,直到到达超时时间(默认值为 15 秒)。如果池进程在连接超时之前无法满足请求,将引发异常。

警告:

我们强烈建议您在使用完连接时一定要关闭连接,以便连接可以返回池。要关闭连接,可以使用 Connection 对象的 CloseDispose 方法,也可以通过在 C#using 语句中或 Visual Basic 的 Using 语句中打开所有连接。不是显式关闭的连接可能不会添加或返回到池中。有关更多信息,请参见using 语句(C# 参考)或 Visual Basic 的如何:释放系统资源

说明:

不要在类的 Finalize 方法中对 ConnectionDataReader 或任何其他托管对象调用 CloseDispose。在终结器中,仅释放类直接拥有的非托管资源。如果类不拥有任何非托管资源,则不要在类定义中包含 Finalize 方法。有关更多信息,请参见垃圾回收

如果连接长时间空闲,或池进程检测到与服务器的连接已断开,连接池进程会将该连接从池中移除。注意,只有在尝试与服务器进行通信之后才能检测到断开的连接。如果发现某连接不再连接到服务器,则会将其标记为无效。无效连接只有在关闭或重新建立后,才会从连接池中移除。

如 果存在一个与已消失的服务器的连接,即使连接池进程尚未检测到断开的连接,也可以从池中取出此连接并将连接标记为无效。这种情况是因为检查连接是否仍有效 的系统开销将造成与服务器的另一次往返,从而抵消了池进程的优势。发生此情况时,初次尝试使用该连接将检测连接是否曾断开,并引发异常。

ADO.NET 2.0 引入了两种新的方法来清除池:ClearAllPoolsClearPoolClearAllPools 清除指定提供程序的连接池,ClearPool 清除与特定连接关联的连接池。如果在调用时连接正在使用,将对它们进行相应的标记。连接关闭时,将被丢弃,而不是返回池中。

连接是根据事务上下文来从池中取出并进行分配的。除非在连接字符串中指定了 Enlist=false,否则连接池将确保连接在 Current 上下文中登记。如果连接使用登记的 System.Transactions 事务关闭并返回到池中,连接将保留在池中,以便使用相同 System.Transactions 事务对该连接池的下一次请求将返回相同的连接(如果可用)。如果发出这样的请求,而没有可用的池连接,则会从池的非事务性部分取出一个连接并登记。如果在池的每个区域都没有可用的连接,则会创建一个新的连接并登记。

当连接关闭时,它将被释放回池中,并根据其事务上下文放入相应的子部分。因此,即使分布式事务仍然挂起,仍可以关闭该连接而不会生成错误。这样,您就可以在之后提交或中止分布式事务。

SqlConnection 对象的 ConnectionString 属性支持连接字符串键/值对,可以用于调整连接池逻辑的行为。有关更多信息,请参见 ConnectionString

池碎片是许多 Web 应用程序中的一个常见问题,应用程序可能会创建大量在进程退出后才会释放的池。这样,将打开大量的连接,占用许多内存,从而导致性能降低。

因为集成安全性产生的池碎片

连 接根据连接字符串以及用户标识来建立池连接。因此,如果使用网站上的基本身份验证或 Windows 身份验证以及集成的安全登录,每个用户将获得一个池。尽管这样可以提高单个用户的后续数据库请求的性能,但是该用户无法利用其他用户建立的连接。这样还使 每个用户至少产生一个与数据库服务器的连接。这对特定 Web 应用程序结构会产生副作用,因为开发人员必须衡量安全性和审计要求。

因为许多数据库产生的池碎片

许 多 Internet 服务提供商在一台服务器上托管多个网站。他们可能使用单个数据库确认窗体身份验证登录,然后为该用户或用户组打开与特定数据库的连接。与身份验证数据库的 连接将建立池连接,供每个用户使用。但是,每个数据库的连接存在一个独立的池,这会增加与服务器的连接数。

这也会对应用程序设计产生副作 用。但是,可以通过一个相对简单的方式避免此副作用,而又不会影响连接 SQL Server 时的安全性。不是为每个用户或组连接独立的数据库,而是连接到服务器上的相同数据库,然后执行 Transact-SQL USE 语句来切换为所需的数据库。以下代码段演示如何创建与 master 数据库的初始连接,然后切换到 databaseName 字符串变量中指定的所需数据库。

Visual Basic
' Assumes that command is a valid SqlCommand object and that
' connectionString connects to master.
command.Text = "USE DatabaseName"
Using connection As New SqlConnection(connectionString)
connection.Open()
command.ExecuteNonQuery()
End Using
// Assumes that command is a SqlCommand object and that
// connectionString connects to master.
command.Text = "USE DatabaseName";
using (SqlConnection connection = new SqlConnection(
connectionString))
{
connection.Open();
command.ExecuteNonQuery();
}

通过调用 sp_setapprole 系统存储过程激活了 SQL Server 应用程序角色之后,该连接的安全上下文无法重置。但是,如果启用了池,连接将返回池,在重复使用池连接时会出错。有关更多信息,请参见知识库文章“SQL application role errors with OLE DB resource pooling”(OLE DB 资源池出现 SQL 应用程序角色错误)。

应用程序角色替代项

如果您使用的是 SQL Server 2005,建议您使用可以替代应用程序角色的新安全机制。有关更多信息,请参见在 SQL Server 中创建应用程序角色 (ADO.NET)

[C#]超时时间已到,但是尚未从池中获取连接

mikel阅读(999)

“/ASP.Web”应用程序中的服务器错误。
——————————————————————————–

超时时间已到。超时时间已到,但是尚未从池中获取连接。出现这种情况可能是因为所有池连接均在使用,并且达到了最大池大小。
说明: 执行当前 Web 请求期间,出现未处理的异常。请检查堆栈跟踪信息,以了解有关该错误以及代码中导致错误的出处的详细信息。

异常详细信息: System.InvalidOperationException: 超时时间已到。超时时间已到,但是尚未从池中获取连接。出现这种情况可能是因为所有池连接均在使用,并且达到了最大池大小。

这是个老问题了!你就查两点: 
  一、看所有open的连接是否都close了。 
  二、如果访问量很大,加上Max   Pool   Size=512这一句,当然这是要以损失系统性能为代价的! 
  这样以后一定可以解决你的问题!

  解决方案一

我 想原因可能是并发操作。DataReader是独占连接的,就是说你的程序可能设计上有问题。比如说最大连接设100,假设有100个人同时使用 DataReader正在读取数据库内容,那么当第101人读取的时候,连接池中的连接已经没有了,就会出现上面的错误。DataReader是独占连接 的,每个DataReader都要占用一个连接。当然这个情况是偶尔出现的,所以会很长时间出现一次,因为只有同时有超过连接池最大连接数量的并发操作才 会发生。而且你加大并发数量只能暂时缓解问题,如果你加大到200个并发连接,如果有201 人同时操作怎么办?你说了你使用Connection对象的Close()方法,这是不行的,因为Close()方法仅仅是关闭连接,但这个连接没有释 放,还是被这个对象占用,要释放必须使用Connection的Dispose()方法显式释放连接才可以,否则这个对象占用的连接只能等到垃圾收集的情 况下才能被释放。这种情况肯定会出现“超时时间已到”的错误。

解决方法:
         1 修改几个关键页面或访问比较频繁的数据库访问操作,使用DataAdapter和DataSet来获取数据库数据,不要使用DataReader。
         2 在访问数据库的页面上使用数据缓存,如果页面的数据不是经常更新(几分钟更新一次)的话,使用Cache对象可以不用访问数据库而使用缓存中的内容,那么可以大大减少连接数量。
         3 修改代码,把使用Connection对象的地方都在Close()后面加上Dispose()调用。
         4 建议对数据库操作进行大的修改,建立自己的数据库操作代理类,继承System.IDisposable接口,强迫释放资源,这样就不会出现连接数量不够的问题了。

解决方案二

解决方法(*):WEB.config 里面:在数据库连接加 Max Pool Size = 512;server=local;uid=;pwd=;database=2004;Max Pool Size = 512;">一劳永逸。

解决方案三

估计是连接(Connection)对象没有Close。倒是不必Dispose,而DataReader用完后应该关闭,但不关闭也没问题,只是不关闭的话此连接对象就一直不能用,只要你最终关闭了连接对象就不会出问题。  
   
   连接对象在Open后的操作都放在try块中,后面跟一个finally块:conn.Close();

错误:   3154一般是由于恢复数据库备份时指定的数据库名和原有数据库中数据库相同引起的 
  你指定一个不易重复的名字, 
  或者在恢复时指定选项:覆盖现存数据库 
  
   本人在将SQL2000数据库导入SQL2005出错,错误信息如下:

还原 对于 服务器“EDWARD\\TRACY”失败。 (Microsoft.SQLServer.Smo)

有关帮助信息,请单击: http://go.microsoft.com/fwlink?Prod…er&LinkId=20476

——————————
其他信息:

执行 Transact-SQL 语句或批处理时发生了异常。 (Microsoft.SQLServer.ConnectionInfo)

——————————

备份集中的数据库备份与现有的 \'foodgood\' 数据库不同。
RESTORE DATABASE 正在异常终止。 (Microsoft SQL Server,错误: 3154)

今天我准备把sql2000 的备份数据库 sp.bak 还原在sql2005 上 (因为课堂上用的是sql2000 而我自己电脑里装的是sql2005 )遇到了点麻烦。就是象sql2000 一样操作还原时出现了点问题。说不能还原,最后找到了点方法终于搞定。

1,在sql2005上新建一个数据库比如:商品

2,选择要还原的 sql2000备份文件

3,这里很重要,选中“覆…”看图

sql2000 备份的数据库还原到sql2005后,选择“数据库关系图”提示:此数据库没有有效所有者,因此无法安装数据库关系图支持对象。若要继续,请首先使用“数 据库属性”对话框的“文件”页或  Alter  AUTHORIZATION  语句将数据库所有者设置为有效登录名,然后再添加数据库关系图支持对象。 
    
解决方法如下:
1、设置兼容级别为90(2005为90)
USE  [master]
GO
EXEC  dbo.sp_dbcmptlevel  at dbname='数据库名',  @new_cmptlevel=90
GO  

或是选责你还原的数据库,点右键,选属性->选项->兼容级别,选择SQLServer2005(90) 然后确定,

      这时,你在该数据库下展开“数据库关系图”节点时会有个提示,"此数据库缺少一个或多个使用数据库关系图所需的支持对象,是否创建",选择“是”即可。

2、通过以上的方法操作,如果问题依然存在的话,按下列方法继续

选择你的数据库,然后选择"安全性"->"用户",选择dbo,打开属性页,如登录名为空的话,新建查询,然后

use [你的数据库名]
EXEC   sp_changedbowner   'sa'

执行成功后,你再选择"数据库关系图"节点,时提示 “此数据库缺少一个或多个使用数据库关系图所需的支持对象,是否创建",选择“是”即可。 就可以看到原先建的关系图了。

1、 对Table中的详细内容,以不同的颜色间隔开相邻的两行。

A:选择Table的Detail行,选择属性中的BackgroundColor,值选择表达式,输入:=iif(RowNumber(Nothing) Mod 2, "White", "Beige")。

2、设置每面显示Table表头或表尾

A:选择Table Header或Table Footer,将属性中的RepeatOnNewpage设为True dot

3、在每页都显示放入的图片或标题头等信息。

A:只须在Table Header中加行数,把你要显示的内容放到单元格中,然后再按第二条方式设置后就可以了。

 

程序功能是一次性生成要求数量的主条码,然后打印出来
我的做法是一次性把生成的代码全部放到一个arraylist里面,让后打印的时候再通过循环一个一个的从arraylist里面取出来打印,然后就导致了以下的错误.
错误如下:
有关调用实时(JIT)调试而不是此对话框的详细信息,
请参见此消息的结尾。
************** 异常文本 **************
System.InvalidOperationException: 超时时间已到。超时时间已到,但是尚未从池中获取连接。出现这种情况可能是因为所有池连接均在使用,并且达到了最大池大小。
在 System.Data.ProviderBase.DbConnectionFactory.GetConnection(DbConnection owningConnection)
在 System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory)
在 System.Data.SqlClient.SqlConnection.Open()
在 UseDB.myDB.ExecuteStoreProcedure(String ProcedureName, SqlParameter[] Parameter)
在 Barcode_Print.DataManipulate.UpdateTwoTable(String Dy_codeTail)
在 Barcode_Print.DataManipulate.MakeBarcode(String quantity)
在 Barcode_Print.FrmBarcode.button1_Click(Object sender, EventArgs e)

字串9

在 System.Windows.Forms.Control.OnClick(EventArgs e)
在 System.Windows.Forms.Button.OnClick(EventArgs e)
在 System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
在 System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
在 System.Windows.Forms.Control.WndProc(Message& m)
在 System.Windows.Forms.ButtonBase.WndProc(Message& m)
在 System.Windows.Forms.Button.WndProc(Message& m)
在 System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
在 System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
在 System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
连接对象没有及时关闭
我都检查过了,好像没有这样的错误阿
注意每次与数据库交换数据前再定义并打开连接,完后立即关闭.Close()(不要调用Dispose),把连接释放到连接池
不要定义全局型(比如类成员)连接变量
注意用try catch块而且连接关闭一定要放在finally块里面

字串1

和你的条码打印队列没什么关系,和其间或其外使用的数据库连接获取与释放有关系,因为很显然,连接耗尽了。连接应该准备工作完成马上就要提交数据或请求了再申请,用完了立即释放,越早越好。
为什么不能调用dispose?我都是close和dispose一起用的,like this:
conn.close();
conn.dispose();
这个是国外的一个re,但是好像持的是相反的观点
This can lead to heated debate, hopefully I'll answer first and then you can
ignore everyone else
Seriously though, this is what Dispose does (actual code):
switch (this._objectState)
{
case ConnectionState.Open:
{
this.Close();
break;
}
}
this._constr = null;
as you can see, all it does it call Close(). So you might be tempted to say
"i should just call close and save some stack". However, there is a dipose
pattern which you should follow. while you can call one, or the other or
both to achieve the same result, this behaviour could change with future
release. One day (for example 2.0) Dispose might do more…and then you'd

字串8

have to go through all your code and make sure you had called Dispose.
Additionally, languages like C# are dispose-aware thanks to the using
keyword.
As far as i'm concerned, those two points are enough to make sure I always
call Dipose on classes which inherit IDisposable.
As for close, my personal feeling is that it doesn't need to be called if
you are calling Dispose. And, since it's better to be consistent, I'd say
never call it. Why? well, none of the .net language are close-aware, and by
definition of what Dispose does, it would be a mistake from the class
designer (ie, microsoft) to implement cleanup functionality in close which
Dispose also woudlnt' do (possibly simply by running close, as it currently
does).
Karl
另外这一句怎么解释呢?
"注意用try catch块而且连接关闭一定要放在finally块里面"
正如viena(维也纳nn)所说的每次完成都要调用Close(), SqlConnection连接对象会回到连接池中,SqlClient使用的是内部连接机制,类似COM 对象池.这里需要注意的是连接池的参数配置,涉及到连接池的设计. 字串2
Connection Lifetime 设置连接的销毁时间
Max Pool Size 最大连接数
Min Pool Size 最小连接数
如果涉及到事务性处理,连接池的设计也不同.
我刚才查了一下关于connection pool的资料(虽然大部分都是java的)
知道为什么上面有朋友说不要用dispose了
因为close()只是释放连接让这个sqlconnection回到pool中,但是如果是dispose()的话可能pool都被释放掉了么??
Dispose不是释放pool,是释放连接
/*
另外这一句怎么解释呢?
"注意用try catch块而且连接关闭一定要放在finally块里面
*/
考虑数据库操作发生异常的情况:
1 没有异常处理,直接弹出错误对话框,程序终止,连接没有关闭
2 有异常处理,必须在程序运行的每个可能分支最后加连接关闭,否则连接可能没有关闭
如果放在finally块里面,不论是否发生异常,都会执行~