ASP.Net中的缓存方案(讨论)
作者:大石头  来源:  发布时间:2006-11-17 8:45:58  共有661位读者阅读过此文

主  题:  ASP.Net中的缓存方案(不仅仅是Cache和Session) 
作  者:  nnhy (大石头)        Blog 
等  级:   
信 誉 值:  100 
所属社区:  .NET技术 ASP.NET 
问题点数:  100 
回复次数:  83 
发表时间:  2006-11-10 10:06:55  
   
 
  

我想设计一个完善的缓冲方案,用于在程序的各个地方缓冲数据。

应用程序级的Cache和Application大家都懂,就不说了
用户会话级的Session也懂,也不说

我要说的是小一点作用范围的。

线程级:在且仅在某个线程内有效的缓存。比如,可以定义一个数据库连接对象,在线程级把它缓冲起来,那么,执行各种数据库操作的时候,就不用担心它会冲突,因为当前CPU只有一个线程在执行。我们对数据库连接的一般做法都是在每个对象内部声明一个数据库连接或者作为属性由对象外部传进去,我觉得这种做法都不方便,如果能够实现线程级,则可以在数据层各个数据对象内部直接使用这个被缓存了的数据库连接,没有冲突,也在最大限度上充分利用了数据库连接。

请求级:在且仅在某一次请求的范围内有效的缓存。有时候,对于数据库的连接,我们都希望,在程序使用时连接一次数据库,一直用到这次请求结束。这就是请求级啦。

我觉得,线程级比请求级更好,因为ASP.Net运行时是这样处理的,收到一个请求,就从线程池分派一个线程去处理这个请求,同时也是从HttpApplication实例池中拿一个HttpApplication实例去处理,所以,一个线程可以被用于多次请求,一个HttpApplication实例,也可能被用于多个请求。

经过半个月来查找资料,我已经解决了绝大部分难题,做起来也挺麻烦的。
现在想听听大家的意见,看看大家有没有更好的实现方法。

本文在我网站中的地址:http://nnhy.org/CMS/web/index.asp?Act=NewsDetail&NClassID=26&ID=63


  zorou_fatal(The world and system is even) ( ) 信誉:100    Blog  2006-11-10 10:14:00  得分: 0 
 
 
  
楼主,你的地址打不开。


 
Top 
 sp1234(终于在安全模式把Downloader病毒杀掉了) ( ) 信誉:100    Blog  2006-11-10 11:03:52  得分: 0 
 
 
  
数据库连接对象,在线程级把它缓冲起来,那么,执行各种数据库操作的时候,就不用担心它会冲突,因为当前CPU只有一个线程在执行
————————————————————————————————————————
根本不是这么理想化。你操作同一个对象才会因为这个对象而产生冲突,线程本身并没有什么冲突。你认为只要用多个线程操作被缓冲的对象就能避免多线程操作缓冲的对象冲突了,我觉得丝毫没有解决冲突问题,反而把线程弄得多余了。

拿SqlConnection类型来说,它自动维护一个缓冲池,然后asp.net页面对象本来都是异步线程方式进行处理的,所以页面中代码 new 一个SqlConnection实例Open()并且使用最后Close(),这个过程本来就天生于其它页面等在单独的线程里的,用不着你再线程。如果需要线程,应用程序会创建一个,这也并不麻烦(即使线程池也是有线程的类型)。

你要么做一个缓冲池,要么作一个线程池,不要混为一谈。


 
Top 
 nnhy(大石头) ( ) 信誉:100    Blog  2006-11-10 11:03:59  得分: 0 
 
 
  
我网站上的东西和这个一样的


 
Top 
 sp1234(终于在安全模式把Downloader病毒杀掉了) ( ) 信誉:100    Blog  2006-11-10 11:12:31  得分: 0 
 
 
  
数据库引擎有各种实现策略,对于某些引擎,当一个DBConnection被一个静态游标(例如某种DBReader)锁住的时候,此时你不关闭这个Reader,直接将DBConnection用于另外一个查询,数据库引擎就会告诉你这个DBConnection不能用于其它查询(否则现有的游标就被毁了),这跟单线程、多线程毫无关系,即使在顺序执行的程序内也照样如此冲突,你把线程全都堵塞死,目的就是为了让这种冲突少发生一点,这也太理想化了。

使用链接缓冲池,可以让线程尽量并行执行,而不是像你一样让线程尽量阻塞。

使用链接缓冲池,应用程序应该new一个链接后进行瞬间使用然后立刻关闭(放回连接池),并且应该new一个连接而不是打开别人使用了的连接。这跟你的做法是背道而驰的。


 
Top 
 yangtu86(杨土) ( ) 信誉:100    Blog  2006-11-10 11:16:10  得分: 0 
 
 
  
mark


 
Top 
 nnhy(大石头) ( ) 信誉:100    Blog  2006-11-10 12:04:33  得分: 0 
 
 
  
可能sp1234误解我的意思了,我并没有说我要多开一个线程。

大家都知道,页面是异步线程执行的,也就是说,同一时间段,是可能多个页面实例在被处理。很多人想用静态连接对象,从而造成冲突,这个问题我也碰到过。用户完连接就close,的确,这样就永远不会冲突,但是,sqlconnection有连接池,别的不一定有,还有一个效率问题,我不用close肯定比每次close要快,就算有,链接池也解决不了跨对象数据事务问题。一个页面里面,存在多个业务处理的时候,拥有多个业务对象,每个业务对象都使用不同的连接,它们是无法共用事务的。

我说的多个线程操作同一个连接对象冲突,大概是这样的,线程A正在执行一个SQL语句,才到一半,线程被切换了,线程B也要执行一个SQL语句,这个时候,就冲突了。

都知道,用完连接就关,就不会出问题,但是,要考虑性能,考虑优化的时候,就不能这样了。

如果我要处理多个业务,使它们在同一个事务中,你觉得该怎么处理呢?给每个事务对象传同一个连接对象?我有很多业务,并且有业务的嵌套呢?也麻烦了一点了吧。我需要的只是,在这次请求中,我希望对数据库的所有操作,都处于同一个事务之中,要么全部成功,要么全部失败。

你也说了,页面实例,是异步线程处理的,所以,我就想到做一个线程级的缓存,不管哪个业务类,内部直接取这个线程级的数据库连接对象缓存来用就可以了,因为它们只有一个。在页面基类里面,一开始来个begintrans,页面unload的时候,再commitrans,这不是更好么?

呵呵,或许我真的有点理想化,我喜欢这样转牛角尖,有不对的地方,还请大家多加指点


 
Top 
 viena(维也纳nn) ( ) 信誉:100    Blog  2006-11-10 12:21:20  得分: 0 
 
 
  
Session与缓存有关系吗?


 
Top 
 viena(维也纳nn) ( ) 信誉:100    Blog  2006-11-10 12:29:19  得分: 0 
 
 
  
感觉楼主不了解Web程序运行机制,无话可说~


 
Top 
 nnhy(大石头) ( ) 信誉:100    Blog  2006-11-10 13:32:30  得分: 0 
 
 
  
我说的这个缓存,不是指那个Cache

一个用户,第一次读数据的时候,用Session缓存起来,后面访问的时候,就再也不用重新读取了。这样不算缓存?一定要所有用户共用的Cache才算缓存?

实在不明白你所说的Web程序运行机制是什么,还请指教。^_^


 
Top 
 jellon_hero(大漠孤烟) ( ) 信誉:100    Blog  2006-11-10 13:44:59  得分: 0 
 
 
  
呵呵,毕竟有自己的认识哈


 
Top 
 nnhy(大石头) ( ) 信誉:100    Blog  2006-11-10 13:47:58  得分: 0 
 
 
  
我看过一些ASP.Net运行时的资料,毕竟很少,我也知道,我要做的东西,跟这个密切相关,如果有熟悉这方面的,请多多指教。


 
Top 
 hegang888888888() ( ) 信誉:100    Blog  2006-11-10 13:52:49  得分: 0 
 
 
  
jf


 
Top 
 fcuandy(手中无剑) ( ) 信誉:100    Blog  2006-11-10 14:02:39  得分: 0 
 
 
  
理论上的东西我自己清楚,但是说不清,谁让俺书读的少,看看,就不发表批示了~~


 
Top 
 ASPNET_ASPNET() ( ) 信誉:100    Blog  2006-11-10 14:17:19  得分: 0 
 
 
  
楼主这样做的话,服务器压力会不会太大?如果总是有连接存在,对web服务器和数据库服务器好像都有很大压力,如果这两个服务器在同一台机器上,速度会不会慢呀,


 
Top 
 jaguar_yang(平凡的世界) ( ) 信誉:100    Blog  2006-11-10 14:19:07  得分: 0 
 
 
  
jf


 
 
Top 
 viena(维也纳nn) ( ) 信誉:100    Blog  2006-11-10 14:28:04  得分: 0 
 
 
  
Session是可以保存一些数据,但那与缓存的概念是两回事
目的是为了一个会话内的信息共享;Application保存全局数据同理

而缓存是为了提高性能,保存大量相对固定的数据在内存中
避免频读数据库

(另ASP里面没有缓存机制,常在Application里面保存一些数据作为缓存,.NET里没有这种)


//很多人想用静态连接对象,从而造成冲突,这个问题我也碰到过
Web程序如你所说是大量并发的,保持长连接,占用资源而不用,
是极端愚蠢的做法,连接池的连接会很快耗尽的
//我不用close肯定比每次close要快
你这个线程是快了,但你占着不让别人用,你觉得合理吗?
close方法并不是真的关闭连接,是释放到连接池
给真正需要用的线程来用或者你自己下次用
只有需要与数据库交换数据库的时候,才需要占用连接

/*
一个页面里面,存在多个业务处理的时候,拥有多个业务对象,每个业务对象都使用不同的连接,它们是无法共用事务的
*/
不知所云,一个事务当然在一个过程内,当然使用同一个连接!
如果有例外,那是极端特殊的情况,可能性极小
不在此话题讨论范围内

程序的运行是很快的
人的操作是很慢的
//在页面基类里面,一开始来个begintrans,页面unload的时候,再commitrans
长时间占用暂时用不到的宝贵资源,极端荒唐可笑!


 
Top 
 viena(维也纳nn) ( ) 信誉:100    Blog  2006-11-10 14:31:08  得分: 0 
 
 
  
其实sp1234说得很好,楼主好好看一下吧
实在看不懂也没办法了


 
Top 
 zengjd(一) ( ) 信誉:94    Blog  2006-11-10 15:18:15  得分: 0 
 
 
  
/*
一个页面里面,存在多个业务处理的时候,拥有多个业务对象,每个业务对象都使用不同的连接,它们是无法共用事务的
*/
你是说跨数据库的事务管理么?那有很多解决方案!楼主可以适当的查查资料。
如果不是,
你就是把执行事务和提交事务混为一谈了。
你不是在事务开始的时候begintrans,在事务结束的时候commitrans吧?
那如果这个事务要好长时间呢?就一直占着连接不放么?

事务执行和事务提交要分开来做。

另外,你要学会区分什么是“业务事务”什么是“数据库事务”。你就会明白你错在哪儿了。

 

 

 


 
 
Top 
 nnhy(大石头) ( ) 信誉:100    Blog  2006-11-10 15:32:17  得分: 0 
 
 
  
vierna最想表达的一个意思,是不是说:我的线程级缓存数据库连接,会占住不用。请问是这个意思么?

不要看错了,这是线程级,如果线程销毁,连接当然没有了,何来的占住不用?

我只是想,在不引起冲突的情况下,最大可能性的增加这个对象的作用范围而已。难道这不好么?一个频繁使用的对象,谁不想增加它的作用范围?令它尽可能多的被重复使用。你总不该是在每次使用数据库的时候来SqlConnection Conn=New SqlConnection吧?

我让这个对象覆盖到整个线程,不是很好么?

再说,我这个线程级缓存,是依赖于线程或者HttpApplication的,而服务器会维持着一个HttpHandler线程池,每次请求,都从池里取线程来处理HttpApplication实例池中的一个HttpApplication实例,也就是说,如果我的线程级缓存依赖于线程,那么,多次使用这个线程的请求,都可以共用这个对象;如果依赖于HttpApplication,那么,多次使用这个HttpApplication实例的请求,都可以共用这个对象。这不是很好么?

就算我只想做到请求级,每次请求结束的时候我再关闭连接,有何不妥呢?我留着这个连接,就是因为我还要用,而不是频繁的open和close。

至于多业务对象事务,可以这么理解,一个支出对象,一个收入对象,这两个业务对象自成一体,所以它们分别有自己对应的数据实体层,而每个数据实体层,都自己New一个连接,互不干涉。业务层也不干涉数据层。在最上面的一个页面过程中,调用支出对象后,再调用收入对象,此时,应该对这两个对象的调用使用事务。在这里,就行不通了,无法共用事务。有人建议在事务对象外面New连接对象,再传进业务对象,业务对象再传给自己的数据尸体对象。要是这样,这个构架,这个OOP,就没什么意义了,还不如把数据层和业务层的代码写在一起。还有,如果这里这么用,别的仅使用它们中一个对象的地方,也这么做么?

这里只是两个简单的业务而已,而实际中的业务错综复杂,多个业务,业务嵌套业务,拿可就头大了。

而使用线程级缓存,就有这么一个好处,我只要告诉程序,在这一次请求中,不管你下面包含和嵌套多少业务层,做了多少数据库操作,你们全部使用同一个连接,需要时使用同一个事务

ADO.Net的连接池可以使得各个用的都是可能都是同一个连接,但是它无法使得这么多个使用连接


 
Top 
 zengjd(一) ( ) 信誉:94    Blog  2006-11-10 15:40:18  得分: 0 
 
 
  
这样,楼主。咱们一步一步来。

你先回答,业务对象和数据库有关么?

比如: 你说的 “收入对象”、“支出对象”。他们和数据库有关系么?
(我怀疑你的“收入对象”、“支出对象”是否符合领域逻辑,或者你只是举个例子而已。)


 
 
Top 
 nnhy(大石头) ( ) 信誉:100    Blog  2006-11-10 16:08:01  得分: 0 
 
 
  
非常感谢zengjd

业务对应着一个数据实体,数据实体对应着一个数据表,或者还有几个非常简单的从表,这就是我所说的业务和数据的对应关系啦。

收入对象和支出对象只是我举的例子而已,实际上我碰到的问题,远远要比这个要复杂


 
Top 
 nnhy(大石头) ( ) 信誉:100    Blog  2006-11-10 16:09:45  得分: 0 
 
 
  
实在是太感谢zengjd了,我这个人就这样,老是表达不清楚,呵呵。

为了这个东西,我已经查了非常多资料了。

真对不起,我是刚学net才半年的新手


 
Top 
 nnhy(大石头) ( ) 信誉:100    Blog  2006-11-10 16:33:00  得分: 0 
 
 
  
不在了么?不要沉下去哦


 
Top 
 zengjd(一) ( ) 信誉:94    Blog  2006-11-10 16:41:02  得分: 0 
 
 
  
业务对应着一个数据实体,数据实体对应着一个数据表,或者还有几个非常简单的从表,这就是我所说的业务和数据的对应关系啦。
----------------------------------------------------------------
你说的数据实体是什么呢?不太懂。

理论上讲,
领域对象不跟数据库发生任何关系,也就是说,领域对象里不可能有一个Field用来存储Connection,数据库只是用来持久化领域对象。

这点你能认同么?


 
Top 
 hanchi8008(寒池) ( ) 信誉:100    Blog  2006-11-10 16:45:53  得分: 0 
 
 
  
http://www.microsoft.com/china/msdn/archives/library/dnaspnet/html/asp01242002.asp
你去看看这里,可能回对你帮助的.


 
Top 
 scow(怡红快绿) ( ) 信誉:100    Blog  2006-11-10 16:47:23  得分: 0 
 
 
  
关于缓存概念同意楼主观点, 定义个静态变量, 里面放数据也可算缓存.
取的时候不必重新查询, 可以在内存中取得之前存进来的东东就是缓存.


 
Top 
 mostice(沉默的羔羊) ( ) 信誉:97    Blog  2006-11-10 16:58:23  得分: 0 
 
 
  
好紧张的讨论。


 
Top 
 nnhy(大石头) ( ) 信誉:100    Blog  2006-11-10 17:57:59  得分: 0 
 
 
  
To zengjd

我这个数据实体,就是用来操作这个数据表的一个类。

你说的领域对象是什么?是不是就是我说的业务对象?

我的业务对象操作各种业务时,通过调用数据实体的相应方法来获取或修改数据


 
Top 
 nnhy(大石头) ( ) 信誉:100    Blog  2006-11-10 18:02:28  得分: 0 
 
 
  
非常感谢 scow(怡红快绿)


 
Top 
 nnhy(大石头) ( ) 信誉:100    Blog  2006-11-10 18:05:59  得分: 0 
 
 
  
“还可以从业务对象使用 Context 对象。”

这就是从scow提到的文章中提到的一句话,我所说的业务对象就是这个业务对象

真不好意思,跟惯微软了,术语都仿照他的


 
Top 
 shixin1198(好好学习 天天上上) ( ) 信誉:92    Blog  2006-11-10 18:21:35  得分: 0 
 
 
  
不错 讨论很精彩 大家继续
本来认为很清楚的我 现在比较晕 我去看看资料 在来说话 大家 就这个 话题继续


 
Top 
 yidc(天下) ( ) 信誉:100    Blog  2006-11-10 18:36:48  得分: 0 
 
 
  
顶一下


 
Top 
 nnhy(大石头) ( ) 信誉:100    Blog  2006-11-10 18:38:37  得分: 0 
 
 
  
Context.Items就是我前面提到的 请求级 作用范围缓存所要用到的东西


 
Top 
 a208756() ( ) 信誉:100    Blog  2006-11-10 18:43:29  得分: 0 
 
 
  
云云都顶了,我能不定吗,石头,可不能就这么沉了啊


 
Top 
 nnhy(大石头) ( ) 信誉:100    Blog  2006-11-10 19:04:43  得分: 0 
 
 
  
谢谢支持

希望得到更多的暴风雨,更多的批评,让我去改进……

两年后结帖,同时公布源码


 
Top 
 nnhy(大石头) ( ) 信誉:100    Blog  2006-11-11 0:30:17  得分: 0 
 
 
  
上面打错了,不好意思,是两天,不是两年……


 
Top 
 cat_hsfz(我的新Blog在http://cathsfz.cnblogs.com) ( ) 信誉:92    Blog  2006-11-11 0:34:38  得分: 0 
 
 
  
我同意 viena(维也纳nn) 说的,你占着个Connection不用,就是浪费资源。我问你,以下两种数据操作方式有什么不同:
//Method1
Connection.Open();
DoDataBaseJob();
Connection.Close();
DoNonDataBaseJob();
Connection.Open();
DoDataBaseJob();
Connection.Close();

//Method2
Connection.Open();
DoDataBaseJob();
DoNonDataBaseJob();
DoDataBaseJob();
Connection.Close();

按照你的说法,方法2更好,对吧?因为省去了一个Close()和Open()。按照这种说法,我们是不是回到单线程处理时代更好呢?例如每一个HTTP请求来到就排队,每次只能有一个请求出队,然后交给唯一一个处理线程处理,那么这一个线程就能专心处理好它的工作,完全不受打扰。

我们大家都知道为什么不这样做,而宁愿选择效率更低的多线程做法,因为当HTTP请求疯狂的增多的时候,如果又不幸碰上一个超费时的处理,那么大家就在那里排队吧。所以我们都选择多线程处理HTTP请求,甚至ASP.NET 2.0还提供了Async Page的设计,允许你在执行长时间任务时将请求处理线程放回池内供其他请求使用。Connection也是一个道理,因为这是稀有资源,你占着不用别人不可能知道你想占多久,所以当你不用的时候就应该主动释放出来给别人用。


 
Top 
 jacksoncan() ( ) 信誉:100    Blog  2006-11-11 0:36:32  得分: 0 
 
 
  
无聊


 
Top 
 nnhy(大石头) ( ) 信誉:100    Blog  2006-11-11 0:44:26  得分: 0 
 
 
  
又一个误解我意思的人。

我哪里说到要回到单线程时代了?HTTP请求来了,就从线程池里面拿线程出来用呀,我哪有说只有一个线程来处理呀……

不好意思,可能我表达不好吧……


 
Top 
 viena(维也纳nn) ( ) 信誉:100    Blog  2006-11-11 9:53:31  得分: 0 
 
 
  
缓存的是数据
而数据库连接是稀缺资源
这两个怎么能扯在一起?

只要在需要读写数据库的时候,才需要占用连接!
用完就要立即释放回连接池
只要这样,在大量并发请求的情况下
才能保证都能得到可用连接

//不要看错了,这是线程级,如果线程销毁,连接当然没有了,何来的占住不用
笑话,线程运行不需要时间吗?线程运行期间连接一直存在不是占住不用吗?
要知道一切都发生在极短的时间内,此时可能有几十个线程真正地需要数据库交换数据呢
新建连接花的时间不是更多?


 
Top 
 viena(维也纳nn) ( ) 信誉:100    Blog  2006-11-11 9:58:17  得分: 0 
 
 
  
我认为
不管是线程池,还是数据库连接池,还是数据缓存
系统都已经做得很完善了,即使不完善,微软自然会做改进、升级~


 
 
Top 
 fengyecsdn(虔诚) ( ) 信誉:98    Blog  2006-11-11 10:00:16  得分: 0 
 
 
  
哈 SP1234和 VIENA 都急了啊~

哈哈哈
学习~~~
JF 嘿嘿


 
Top 
 nnhy(大石头) ( ) 信誉:100    Blog  2006-11-11 11:56:59  得分: 0 
 
 
  
viena只考虑了性能、占用等问题。

但没有从编程者角度考虑。

你所说的,一个线程内占住整个数据库连接是浪费资源,的确很有道理。我以前大多数系统,都是用了就马上close的。但是,实际开发中,这样做就不能使得多个数据库操作处于同一个事务之中,因为每一个操作都close了。此外,很少有多个操作处于同一个函数之中的,都是错综复杂,混在各个业务对象以及嵌套业务对象之中,数据库连接对象就很难控制了,这个时候,线程级或者请求级连接对象就用得上了


 
Top 
 nnhy(大石头) ( ) 信誉:100    Blog  2006-11-11 11:58:11  得分: 0 
 
 
  
我以前都是open,使用,close 这样用的

因为出现了现在的这种跨对象业务,才需要这么做的

谢谢viena


 
Top 
 viena(维也纳nn) ( ) 信誉:100    Blog  2006-11-11 12:25:35  得分: 0 
 
 
  
套用一下zengjd(一)的回复:

另外,你要学会区分什么是“业务事务”什么是“数据库事务”。你就会明白你错在哪儿了。


 
Top 
 nnhy(大石头) ( ) 信誉:100    Blog  2006-11-11 13:03:25  得分: 0 
 
 
  
我需要在业务对象之外使用数据库事务,从而构成一个大的业务事务,这个业务事务,是由很多业务子模块构成的


 
Top 
 nnhy(大石头) ( ) 信誉:100    Blog  2006-11-11 21:54:21  得分: 0 
 
 
  
zengjd怎么不在了?

不是说慢慢来么?


 
Top 
 skycountry() ( ) 信誉:100    Blog  2006-11-13 14:43:52  得分: 0 
 
 
  
viena说的对,缓存的是数据,不是连接。你把很对的业务操作凑成一个很大的数据库操作,在底层还是要分解成很小的操作,这才是web的思想,否则你干脆用批处理系统得了,那更符合你想要的东西。


 
Top 
 dyw31415926(守护) ( ) 信誉:100    Blog  2006-11-13 15:32:57  得分: 0 
 
 
  
大石头,哈哈,看我的名字知道我是谁了吧,我顶你的贴,狂顶

去指点一下我学asp.net吧,100分贴,给你冲点分分,免得你没裤衩换 ^-^
http://community.csdn.net/Expert/topic/5146/5146040.xml?temp=.8490412


 
Top 
 vivi8233(吐司) ( ) 信誉:99    Blog  2006-11-13 15:33:20  得分: 0 
 
 
  
up 学习了 业务层 与 数据库操作层是两个概念,建议多看看这方面的资料,也许会有更好的方法


 
Top 
 woaiqingqing(我爱好多人,这个月先爱晴晴) ( ) 信誉:100    Blog  2006-11-13 15:45:37  得分: 0 
 
 
  
楼主想的深了.你想的应该是cli开发者的研究问题.或者是c++编译器开发者要想的问题.

就算是你勉强实现了.你就有可能破坏了webform框架.或ado.net框架.
你这样是带来的好处大.还是坏处大那.

还有用c#不适合研究这个问题.如果你搞的是优化cpu的微指令到是很适合研究这种问题


 
Top 
 flyinging(一路走来) ( ) 信誉:99    Blog  2006-11-13 16:16:40  得分: 0 
 
 
  
新手,对底下的运行机理不太了解,不过,觉的楼主的是增加了程序的复杂度,不.net的初衷背道而驰!


 
Top 
 duduspring() ( ) 信誉:100    Blog  2006-11-13 17:05:48  得分: 0 
 
 
  
up


 
Top 
 jyk(喜欢编程。和气生财。共同提高。共同进步) ( ) 信誉:100    Blog  2006-11-13 17:25:02  得分: 0 
 
 
  
1、事务。

大家好像忽略了这个问题。

楼主主要考虑的是在事务的情况下如何使用Connection 。如果不需要事务的话,我想搂主也就不会这么麻烦了。


这里的事务指的是,在网页里作一次提交,需要操作多个表,比如转帐操作。
从A卡里面提取200元钱,转到 B 卡里面,这时就需要先 A卡 - 200 在 B 卡 + 200。

在这个操作中,有一处错了,就要整个回滚,否则就会有人找你要钱了。

显然搂主想使用ado.net里的事务(begintrans、commitrans)来实现这个功能,这里有一个要求就是不能 close ,如果 close了,事务就无法“使用”了(这里没有想好怎么描述,呵呵)。

我想问题的关键就是这里吧。


如果是我的话,我会首先考虑使用存储过程,呵呵。当然这就更不符合 OOP了。

其次呢,我会把这个操作写到一个页面里面,呵呵。这样就可以共用一个 Connection 了。

当然了并不是像您想象的,满页面里面写 Command  这些对象了,而是用我自己的“数据访问层”(类似于SQLHelp)来处理。这样代码就可以少很多。


我对OOP是很不熟悉的,也不知道按照OOP的规则要怎么处理这样的事情,只能想出一个很笨的方法了。

 


 
Top 
 jyk(喜欢编程。和气生财。共同提高。共同进步) ( ) 信誉:100    Blog  2006-11-14 9:39:25  得分: 0 
 
 
  
lz呢?


 
Top 
 myminimouse(出来发帖,迟早要结的) ( ) 信誉:92    Blog  2006-11-14 10:00:44  得分: 0 
 
 
  
初略的看了一下,没看懂大家各自表达的什么意思

继续关注


 
Top 
 xingqing83(飞天猪) ( ) 信誉:100    Blog  2006-11-14 10:09:25  得分: 0 
 
 
  
嗯,大家讨论的都很积极啊,学习了


 
Top 
 fantasylu(沉默的糕点) ( ) 信誉:100    Blog  2006-11-14 10:13:33  得分: 0 
 
 
  
有些地方不明白。
1)每次PostBack就一定会访问数据库吗?如果PostBack我是不需要访问数据库也分配连接吗?
2)如果每次PostBack都分配连接,为什么不在HttpModule进行分配,然后改写Page对象,可以直接
从继承Page对象那里获取?

3)如果一次完整业务为什么不把事务封装入外观层,如 Facade.转账(Auser,-100,buser,+100),然后再Asp.net调用


 
Top 
 sa2q1200421(燃烧) ( ) 信誉:92    Blog  2006-11-14 10:19:25  得分: 0 
 
 
  
我想设计一个完善的缓冲方案,用于在程序的各个地方缓冲数据。

请问各个地方缓冲数据是哪些地方啊,难道你现在用的不缓存,没有所有地方用到嘛

至少我觉得我用缓存的时候,页面的每个地方都用到了~


 
Top 
 woaiqingqing(我爱好多人,这个月先爱晴晴) ( ) 信誉:100    Blog  2006-11-14 11:01:15  得分: 0 
 
 
  
在web里缓存一般是用catch.但现在也有个做法是用静态变量.比如cs里就是简单的使用静态变量.有的地方要用缓存.但是不能过多使用.
比如服务器内存是4g但是你静态变量内的数据就有3.9个g了 你说现在服务器会如何.


 
 
Top 
 woaiqingqing(我爱好多人,这个月先爱晴晴) ( ) 信誉:100    Blog  2006-11-14 11:02:13  得分: 0 
 
 
  
字打错了.


 
Top 
 nan7757(骑着蚂蚁闯红灯) ( ) 信誉:100    Blog  2006-11-15 9:07:51  得分: 0 
 
 
  
仔细看了下各位的发言

//不要看错了,这是线程级,如果线程销毁,连接当然没有了,何来的占住不用
感觉楼猪的争议就在这。一个劲的争论说是线程级的问题~
问题来了,如上众大虾所言,执行线程也是需要时间和资源的,根据楼猪的言论,感觉你是不是小网站做的太多了,从来都没有考虑多多用户同时并发请求的问题?
如果像LZ说的这样,一个线程保持一个conntion,执行一段(是一段不是一个)数据处理事物的话,LZ需要买一个什么样的服务器?你能保证你的服务器能承受到多大的压力?
LZ说的业务处理逻辑的想法很理想~想执行完某请求的所有操作才释放连接,如是想到独占线程的方法,呵呵~~其实在业务逻辑中,真正需要的同步处理数据的地方有很多种方法可以操作~数据库事务、触发器等等。。都可以去研究的。。。


 
Top 
 flashccie() ( ) 信誉:100    Blog  2006-11-15 10:10:28  得分: 0 
 
 
  
一口气看完了所有的贴
这里讨论也是我所碰到的问题。
LZ想要的是在保证良好的业务操作的前提下来优化数据库操下。
前提是业务操作是好,有良好的可操作性
sp1234想要的是良好的数据库操作前提下来执行事务。
两者的前提是不一样的。

我现在天天碰到的就是多个数据库服务器之间的事务
我在A服务器做一个操作后,必须等操作完B服务器后才能知道是提交事务还是回退事务。
你说这种操作不能一开一做一关的数据库连接,有什么好的办法优化呢?

 


 
Top 
 ggggdiu(ggggdiu) ( ) 信誉:100    Blog  2006-11-15 10:33:37  得分: 0 
 
 
  
总的来说,楼主的思维还是基于线性过程上,没到基于OOP,基于事件.
一个大的程序,首先,要保证的是模块之间的正交性,(模块独立,模块之间的关联最小),楼主的框架与这个思路已经相反了.
其次,楼主对事务的思维也是线性的,其实完全可以用事件触发来很好的解决.
再次,对于分层,楼主也可能没有考虑,线程级的连接,他的地位到底是数据层,还是业务逻辑层?

菜鸟之言,看看就行了


 
 
Top 
 ggggdiu(ggggdiu) ( ) 信誉:100    Blog  2006-11-15 10:36:43  得分: 0 
 
 
  
http://blog.csdn.net/aafshzj/category/235149.aspx
这可能是楼主想要的


 
Top 
 yangye1211(杨杨) ( ) 信誉:100    Blog  2006-11-15 10:47:12  得分: 0 
 
 
  
Mircrosoft有自己的解决方案,就集成在ADO.NET中,呵呵,点到为止。


 
Top 
 job_2006(初学.net) ( ) 信誉:100    Blog  2006-11-15 11:01:21  得分: 0 
 
 
  
nnhy(大石头) ( ) 信誉:100    Blog  2006-11-10 19:04:43  得分: 0 
 
 
  
谢谢支持

希望得到更多的暴风雨,更多的批评,让我去改进……

两年后结帖,同时公布源码


 

=======
吓了我一大跳,哈哈,帮顶帮顶,学习学习!~


 
Top 
 clal(凌风) ( ) 信誉:100    Blog  2006-11-15 12:15:35  得分: 0 
 
 
  
mark


 
Top 
 cat_hsfz(我的新Blog在http://cathsfz.cnblogs.com) ( ) 信誉:92    Blog  2006-11-15 12:41:22  得分: 0 
 
 
  
我打的比喻,是把Connection比作Thread,而你的做法就像回到单线程时代。

至于事务,这是一个和表现层无关的东西,本来就没“缓存”这个概念。你缓存的意思仅仅是为了跨越页面生命周期而读取。事务可以脱离表现层运行,你需要的只是确保每次表现层都能取回这个事务的指针/句柄一类的东西,然后在表现层更新你所要显示的信息。


 
Top 
 yonps() ( ) 信誉:100    Blog  2006-11-15 13:37:40  得分: 0 
 
 
  
1:每次New要比占住一个链接不放要快
2:你完全可以把事务放到数据库里实现
3:事物是原子性的,你提倡什么事物共享,不如做到一个事物里去
4:觉得楼主有点注重名词,而不注重理解


 
Top 
 nnhy(大石头) ( ) 信誉:100    Blog  2006-11-15 14:54:14  得分: 0 
 
 
  
想不到这么多人关注:

首先,我大概看了一遍回复,jyk(喜欢编程。和气生财。共同提高。共同进步) 最理解我了,他所说的,正是我所想要的,如果有人没有碰到过这个问题,那可能是他没做过又大又复杂的系统,同时又要求是OO编程的。

非常非常感谢 jyk(喜欢编程。和气生财。共同提高。共同进步)  帮我把我的意思表达清楚

另外,关于我给的分数问题,我在CSDN注册几年,向来都是喜欢查资料,而不是问问题,所以我自己的分不多,还有,我一次能给的最多也就100,再说,这文章也不是问问题,而是看看大家对缓存的想法


 
Top 
 cnlamar(无中生有) ( ) 信誉:93    Blog  2006-11-15 14:56:07  得分: 0 
 
 
  
不理解楼主为什么要这样去理解这个问题。


 
Top 
 nnhy(大石头) ( ) 信誉:100    Blog  2006-11-15 15:05:21  得分: 0 
 
 
   To  ggggdiu(ggggdiu)

正是为了保证模块独立,不需要数据库连接这个东东把它们串起来,我才想到用缓存。

考虑线程,对于线程这个执行环境来说,线程级缓存是全局的,在这个环境内的所有对象,都可以直接使用,而不需要为每个对象设置数据库连接属性。

大家要明白:我这么做,都是为了事务,普通的操作,我才不会那么麻烦

还有,改HttpModule也太麻烦了,我有一个很好的想法,迟点把代码发上来,这两天很忙,有一个即将要部署给客户的系统需要我做性能优化
 
 
Top 
 nnhy(大石头) ( ) 信誉:100    Blog  2006-11-15 15:26:19  得分: 0 
 
 
   To  cat_hsfz(我的新Blog在http://cathsfz.cnblogs.com)

我说的缓存的意思,就是为了跨越页面生命周期或者跨越业务对象(就是我说的“跨对象事务”)而读取。所有数据库操作,都得先经过复杂的业务处理,所以,我在表现层,调用业务对象的地方,使用事务。

To yonps()
1,我不赞成你这个观点,我不是反对,而是说不一定。前面也有人提到,说我只是做小网站的,没有考虑到大量用户并发的情况,那么,我想请问,你可知道,用于处理HttpModule的线程,都是来自于一个线程池的?呵呵^_^
2,要是一个存储过程就能搞定的简单业务,的确用不着这么麻烦
3,正是因为事务是原子性的,所以,我把它控制在线程级,而不是直接使用Cache或者静态变量
4,不好意思,可能我表达不清楚,但是我想,等我写一个简单的代码,大家就什么都明白了


我说说普通的缓存吧。
在用户量非常少的时候,大家都应该知道,把数据库连接设置为静态变量,或者使用Cache缓存,性能上,明显比每次Open和Close要快许多,不信自己试试看,这点我想应该大家没什么异议吧。而用户多的时候,就很容易出现冲突了,一个人在执行一个数据库查询,还没完成,线程就被切换了,然后另一个人也要查询,还是用这个连接,这时候就!◎#¥%……我想这点我没说错吧。然后,有人就想出这样的办法来,用锁,是的,用锁不会冲突,但是,或者这个锁,就是你整个系统的关口,你这个锁,掐死系统的脖子了,大量用户的时候,一个连接哪里够用呀。所以,我们的想法就是,在保证连接数够用的情况下,尽可能重用连接,尽可能少New连接,这也是连接池所要实现的。如果我说错了,还请大家指正^_^

ADO.Net是有连接池,但是,我做这个缓存,主要就是为了处理好数据库事务,要是ADO.Net能支持,那该多好……

数据库连接写成静态变量,是个好东西,又是坏东西,不知道大家有没有这种感觉。我想做的,就是找到一个用最简单的办法就可以实现的平衡点解决方案。^_^

我不怕挨批,继续^_^
 
 
Top 
 a208756() ( ) 信誉:100    Blog  2006-11-15 15:55:42  得分: 0 
 
 
   为大石头顶一下,希望大家广发自己的意见与建议
我也在期待中...
 
 
Top 
 ljf840303(校园X怪怪) ( ) 信誉:100    Blog  2006-11-15 16:04:27  得分: 0 
 
 
   线程级别?连我不做多线程的都知道有临界资源的.
如果线程1正在修改.而线程2正在读同一资源.这时是什么效果?
线程,线程池不是说做就做的.而且做了效率不一定高.

没有临界资源.又何来缓存?


 
Top 
 jyk(喜欢编程。和气生财。共同提高。共同进步) ( ) 信誉:100    Blog  2006-11-15 16:12:51  得分: 0 
 
 
   1、我对搂主的理解完全是感觉上的理解,而不是字面意思上的理解。
也就是说如果我没有和楼主类似的经历(包括表述能力),我是不会有这样的理解的。

2、缓存 —— 我觉得在这里“缓存”是一个误导。我觉得搂主要说的和缓存根本没有什么关系,呵呵。

3、楼主可以看看我的几篇文章,也许会有所帮助。

http://www.cnblogs.com/jyk/category/67121.html

里面有我的数据访问层的说明,和一个我的“三层结构”的说明。


ps:
我的表述能力是很差的,最近一直在努力提高中。


 
Top 
 nnhy(大石头) ( ) 信誉:100    Blog  2006-11-15 16:36:51  得分: 0 
 
 
   To ljf840303(校园X怪怪)

为什么要做线程级?就是为了防止和别的线程读同一资源嘛。不好意思,我解释起来吃力……
线程池是ASP.Net本身就使用的,不用我管

To jyk
从上面的回复看来,很多人都没有过我和你一样的经历哦。
嗯,可能我的“缓存”的确误导了。
但是,不要仅仅把这个东西用于数据库连接呀,我还用在别的方面了^_^
 
 
Top 
 qiusp001() ( ) 信誉:100    Blog  2006-11-15 17:32:43  得分: 0 
 
 
   mark
 
 
Top 
 myminimouse(出来发帖,迟早要结的) ( ) 信誉:92    Blog  2006-11-16 10:39:43  得分: 0 
 
 
   等代码中。。。

代码+注释不就很明白么?整这么多名词


 
 
Top 
 nnhy(大石头) ( ) 信誉:100    Blog  2006-11-16 14:45:13  得分: 0 
 
 
   请求级:

public class DbConn
{
static public SqlConnection GetConn()
{
SqlConnection Conn=(HttpContext.Current.Items["Conn"] as SqlConnection);
if(Conn==null)
{
Conn=new SqlConnection();
HttpContext.Current.Items.Add("Conn", Conn);
}
return Conn;
}

使用:
DbConn.GetConn
 
 
Top 
 jyk(喜欢编程。和气生财。共同提高。共同进步) ( ) 信誉:100    Blog  2006-11-16 17:39:39  得分: 0 
 
 
   没看懂。

请问怎么清除这个连接对象呢?


 
 
Top 
 nnhy(大石头) ( ) 信誉:100    Blog  2006-11-16 17:54:21  得分: 0 
 
 
   忘了加了,呵呵

在Application_EndRequest中关闭

DbConn类中,还应该加一个开关来设置是否使用请求级缓存,如果不使用,则直接New一个返回

别的用途,原理一致
 

新生命 XCMS1.0 Build0206 版权所有 All Copyrights @2009 桂ICP备06011573号
站长:大石头 信箱:gxuhy@21cn.com QQ:99363590
本站带宽由酷睿数据提供