记录我的程序生涯

本来是给妹妹申请的日记薄,既然妹妹不用,呵呵,我来写点程序方面的东西吧,希望每天都有新的东西可写,可能很少,不过只要每天都有新发现,也算一种成长吧。
 
Vitamin果茶 @ 2005-12-15 17:22

  上篇我们谈到了关于数据库传统的三种分页方法和他们的利弊,并且提出了一种理论上最佳的分页方法,本篇我们就来详细说说这种最佳的分页方法。

 

一:构思。
  在设计Web数据库时,如果我们要编历每一条纪录,那么只有采取分页模式才可以使Web数据库尽快,尽好的呈现给终端用户,也不会因为8秒原则而使用户失去浏览该页的兴趣。但是即使采取分页的办法,当出现多纪录的数据库时,也难免会使我们的用户感到翻页时速度太慢。就如同我的上篇文章说的那样,几乎上一片文章的三种分页方法都有一些缺陷。那么,我们如何做到能让数据库每次就取我们需要的纪录,这个很好实现,有游标返回多个纪录集就可以实现,但是如果让数据库的一端不会因为要刚好检索一页的纪录而大耗资源就很难了。最后,经过我的不断改写程序与测试,终于编写出了我认为理论上最快的Web数据库分页方法。

二:具体实现的存储过程。
  我们结合一个BBS问题来谈谈这种方法。如何让一个BBS每次每页只现实需要的一页纪录呢?而我们需要提供给数据库有那些参数呢?可能会有以下参数。
  第一:就是我们需要的当前的页数。
  第二:当前定义的每一页的纪录集数目。这样你就可以根据需要在页面程序中修改每一页的纪录数。当然,如果你不考虑程序的可扩展性,你也可以在数据库里直接规定每一页有N条纪录即可。
  第三:一个输出参数:就是从数据库里得出当前表中总纪录数目的多少。(注意,他不是一个页的纪录数目)他相当于ADO分页法中的Recordcount。如果你不需要总纪录数目可以不用返回他。
  我们来看具体存储过程的代码。。。

CREATE PROCEDURE dbo.PRO_pageview
(

@tint_tableid tinyint=1,   --这个是BBS的当前版面Id,你可以不用管他。。
@int_pagenow int=0,      
@int_pagesize int=0,
@int_recordcount int=0 output  --就是得出BBS某个版面的总贴数。。

)

AS
set nocount on

declare @int_allid int    
declare @int_beginid int,@int_endid int 
declare @int_pagebegin int, @int_pageend int
  
select @int_allid=count(*) from tab_discuss where tint_level=0 and tint_tableid=@tint_tableid
  select @int_recordcount=@int_allid     --得出该版面的总贴数
      
  declare cro_fastread cursor scroll
  for  select int_id from tab_discuss where tint_level=0 and tint_tableid=@tint_tableid order by int_id desc --这里定义游标操作,但是不用临时纪录集,而且游标也不需要全部遍历所有纪录集。
  
  open cro_fastread --打开游标
  select @int_beginid=(@int_pagenow-1)*@int_pagesize+1 得出该页的第一个纪录Id
  select @int_endid = @int_beginid+@int_pagesize-1   得出该页的最后一个纪录的Id
  
  fetch absolute @int_beginid from cro_fastread into @int_pagebegin 将他的Id传给一个变量该页开始的Id
  if @int_endid>@int_allid    --这里要注意,如果某一页不足固定页数的纪录时。如只有一页纪录,而且纪录少于我们定义的数目。或者是最后一页时。。。
    fetch last from cro_fastread into @int_pageend  --直接将游标绝对定位到最后一条纪录,得出他的id号来。。。
  else
    fetch absolute @int_endid from cro_fastread into @int_pageend
        
  select int_id,tint_level,tint_children,var_face,var_subject,datalength(txt_content) as int_len,sint_hits,var_url,var_image,var_user,dat_time,tint_tableid,bit_kernul from tab_discuss where tint_tableid=@tint_tableid and int_rootid between @int_pageend and @int_pagebegin order by int_rootid desc,num_order desc   --我们就可以利用该页的第一个id和最后一个id得出中间的id来。。。。(注意。我们这个BBS的数性结构用了一种很巧妙的算法,就是用一个orderNum浮点数即可完成排序。。。)

--开始清场。。。
  close cro_fastread     
  deallocate cro_fastread
  
  return


我们再看看Asp页面里的程序操作。。。

pagenow=cint(request("pagenow")) --当前的页面。

if pagenow<=0 then pagenow=1
pagesize=10

set cmd=server.CreateObject("adodb.command")
cmd.ActiveConnection=strconn
cmd.CommandType=4
cmd.CommandText="pro_pageview"

cmd.Parameters.Append cmd.CreateParameter("tint_tableid",adInteger,adParamInput,,tint_tableid)
cmd.Parameters.Append cmd.CreateParameter("int_pagenow",adInteger,adParamInput,,pagenow)
cmd.Parameters.Append cmd.CreateParameter("int_pagesize",adInteger,adParamInput,,pagesize)
cmd.Parameters.Append cmd.CreateParameter("int_recordcount",adInteger,adParamOutput)

set rs=cmd.Execute
if rs.eof then
  Response.Write "目前已超过了纪录个数或纪录集为空!"
  Response.End
end if

dim arrRs
arrRs=rs.getrows   '可以利用getRows将纪录集迅速保存到一个二维的数组中来提高速度。

recordcount=cmd.Parameters("int_recordcount")
'注意,当纪录不足以刚好整除单位页纪录时,我们也要将其定义为一页,如纪录数目为2页多一个纪录,此时我们的页数也要为3页纪录。
if (recordcount mod pagesize)=0 then
  pagecount=recordcount\pagesize
else
  pagecount=recordcount\pagesize+1
end if


<--分页开始 -->
固定的分页函数,其实无非是pagenow+1或pagenow-1,pagenow,pagecount











 

三:特点
  我们来看看他和传统的三种方法的区别与特点
  第一:每次只传回一页纪录,而且只形成一个纪录集,而且客户端可以采用速度最快的火线游标来完成页面输出。而不必像传统的游标法用rs.nextrecordset纪录来输出纪录。
  第二:数据库没有用到临时表,这样比转储纪录集的速度大大提高。
  第三:采用一个滚动游标,而且游标只经过二个操作就完成定位。速度也大大提高。
  
  当我采用了这种分页方法时,已经可以明显的感觉出分页速度的提高了。当然,在处理树型结构,数据库运算时,我采用了许多方法尽可能的提高速度,如:采用二分区间法来编历树型结构,全部采用存储过程来实现一切sql操作,采用触发器和数据库游标来完成数据库算法,这样就尽量避免过多的网络传输。任何操作只和数据库进行一次参数传递就可以完成。



 
Vitamin果茶 @ 2005-12-15 17:18

1,调用没有参数的存储过程 
<% 
set conn=server.CreateObject("adodb.connection") 
set cmd=server.CreateObject("adodb.command") 
strconn="dsn=pubs;uid=sa;pwd" 

conn.Open strconn 
set cmd.ActiveConnection=conn 

cmd.CommandText="{call nono}" 

‘set rs=cmc.exe 或者cmd.execute 

set rs=cmd.Execute() 

%> 
2,一个输入的参数的存储过程 
<% 
set conn=server.CreateObject("adodb.connection") 
set cmd=server.CreateObject("adodb.command") 
strconn="dsn=pubs;uid=sa;pwd" 

conn.Open strconn 
set cmd.ActiveConnection=conn 

cmd.CommandText="{call oneinput(?)}" 
cmd.Parameters.Append cmd.CreateParameter("@aaa",adInteger ,adParamInput ) 
cmd("@aaa")=100 

cmd.Execute() 

%> 
3,一个输入参数和一个输出的参数 
<% 
set conn=server.CreateObject("adodb.connection") 
set cmd=server.CreateObject("adodb.command") 
strconn="dsn=pubs;uid=sa;pwd" 

conn.Open strconn 
set cmd.ActiveConnection=conn 

cmd.CommandText = "{call oneinout(?,?)}" 
cmd.Parameters.Append cmd.CreateParameter("@aaa",adInteger,adParamInput) 
cmd("@aaa")=10 
cmd.Parameters.Append cmd.CreateParameter("@bbb",adInteger,adParamOutput) 

cmd.Execute() 

bbb=cmd("@bbb") 
%> 
4,一个输入参数,一个输出参数,和一个返回值 
<% 
set conn=server.CreateObject("adodb.connection") 
set cmd=server.CreateObject("adodb.command") 
strconn="dsn=pubs;uid=sa;pwd" 

conn.Open strconn 
set cmd.ActiveConnection=conn 

cmd.CommandText="{?=call onereturn(?,?)}" 

cmd.Parameters.Append cmd.CreateParameter("@return_value",adInteger,adParamReturnValue ) 
cmd.Parameters.Append cmd.CreateParameter("@aaa",adInteger,adParamInput ) 
cmd("@aaa")=10 
cmd.Parameters.Append cmd.CreateParameter("@bbb",adInteger,adParamOutput) 

cmd.Execute() 

bbb=cmd("@bbb") 
rrr=cmd("@return_value") 
%>


 
Vitamin果茶 @ 2005-12-13 13:33

 

这几天一连三个程序由ac转sql,总结了一下这三个程序转换中遇到的问题,归纳了以下注意点

自动增加字段需要重写。在access中经常使用的自动编号字段,导入到mssql后,他并不是自增型的int,需要手工设置,把导入后的自动编号字段的标识的“否”改为“是”,“种子”和“递增量”都为“1”,才能成为自动编号

所有的默认值都丢失了。主要是数字类型和日期类型

所有now(),time(),date()要改成getdate()

所有datediff(’d’, time1, time2)要改成datediff(day, time1, time2)

所有datediff(’ww’, time1, time2)要改成datediff(week, time1, time2)

所有datediff(’d’, time1, time2)要改成datediff(day, time1, time2)

在mssql server中,有许多保留字,在access中是没有的,当你把数据导入到mssql的时候,问题就出来了。mssql在导入的时候,会自动给这些字段(包括数据库中的表名)加上“[字段名]”,因此,你必须修改你的脚本,把相应的字段名字(或者表名字)加上中括号,或改变字段名字为不是mssql的保留字

在用access关于时间的使用,大家喜欢使用“select * from aaaa while time="&now()”这样的sql语句,然而,在mssql中没有“now()”这个函数,而是使用“getdate()”,所以,所有的sql语句中的“now()”必须换成“getdate()”。

日期函数不相同,在对ACCESS数据库处理中,可用date()、time()等函数,但对
    SQL SERVER数据库处理中,只能用datediff,dateadd等函数,而不能用date()、time()等函数。

转化时,跟日期有关的字段,SQL SERVER默认为smalldatetime型,我们最好将它变为datetime型,因为datetime型的范围比smalldatetime型大。有时用smalldatetime型时,转化失败,而用datetime型时,转化成功

isnull(rowname)要改成rowname = null

CursorType要改成1,也就是打开数据库时要给出第一个数字参数为1,否则记录可能
显示不完整

备注类型要通过cast(column as varchar)来使用

true/false类型不能使用,要变为1/0

对此两种数据库进行操作的sql语句不全相同,例如:在对ACCESS数据库进行删除纪录时用:"delete * from user where id=10",而对SQL SERVER数据库进行删除是用:"delete user where id=10".

在对ACCESS数据库处理中,sql语句中直接可以用一些VB的函数,像cstr()函数,而对SQL SERVER数据库处理中,却不能用

在access的sql语句中的时间使用变量查询的时候,大家一般使用"select * from aaaa while time=#"&变量名&"#",在mssql中是不行的,他的语法是“select * from aaaa while time=’"&变量名&"’"”。(意思是让你把日期时间变量当成字符串来使用,呵呵~~~)

原来ASP里的“DELETE * FROM ……”要改为“DELETE FROM ……”

有可能rs.update失败,修改成update 表名 set 字段=‘值’ 这样通过(遇到的情况,提示为:
Microsoft OLE DB Provider for SQL Server 错误 ’80040e38’ 

乐观并发检查失败。已在此游标之外修改了该行。 

/Admin_ClassOrder.asp,行 164 )

access里面除法可以使用"\"或者"/",MSSQL里面只能使用"/"

 

1.mdb中的ID到了Access会变成普通的int,要重新设置为“标识”。
2.SQL语句中的now()要改成getdate()。
3.SQL语句中Like后面字符串的通配符'*'要改成'%'。
4、access表内数据类型"是/否",到了sql server的表内就是 bit (not null)
5、access查询通过cdate构造日期,sql server内是convert(datetime,...)
6. 在sql server 里,就我使用的经验来看: '2004-5-29' =
convert(datetime,'2004-5-29')
7.数据库导入以后,自动增加字段需要重写,所有的数字类型需要增加长度,最好用
decimal。
8.所有的默认值都丢失了。主要是数字类型和日期类型。
9.所有now(),time(),date()要改成getdate()。
10.所有datediff('d', time1, time2)要改成datediff(day, time1, time2)
11.有可能一些true/false类型不能使用,要变为1/0。
12.备注类型要通过cast(column as varchar)来使用。
13.CursorType要改成1,也就是打开数据库时要给出第一个数字参数为1,否则记录可能
显示不完整。
14.isnull(rowname)要改成rowname = null
15.ACCESS的数据库中的自动编号类型在转化时,sql server并没有将它设为自动编号型,我们需在SQL创建语句中加上identity,表示自动编号!
16.转化时,跟日期有关的字段,SQL SERVER默认为smalldatetime型,我们最好将它变为datetime型,因为datetime型的范围比smalldatetime型大。我遇见这种情况,用smalldatetime型时,转化失败,而用datetime型时,转化成功。
17.对此两种数据库进行操作的sql语句不全相同,例如:在对ACCESS数据库进行删除纪录时用:"delete * from user where id=10",而对SQL SERVER数据库进行删除是用:"delete user where id=10".
18.日期函数不相同,在对ACCESS数据库处理中,可用date()、time()等函数,但对
SQL SERVER数据库处理中,只能用datediff,dateadd等函数,而不能用date()、time()等函数。
19.在对ACCESS数据库处理中,sql语句中直接可以用一些VB的函数,像cstr()函数,而对SQL SERVER数据库处理中,却不能用。
20:最好在有可能和系统关键字的地方使用“[”和“]”将他包围起来,以避免在移植过程中出现的运行错误问题



 
Vitamin果茶 @ 2005-12-12 15:38

43个不可不知的健康常识

1、常吃宵夜,会得胃癌,因为胃得不到休息。
  
  2、一个星期只能吃四颗蛋,吃太多对身体不好。
  
  3、鸡屁股含有致癌物,不要吃较好。
  
  4、饭后吃水果是错误的观念,应是饭前吃水果。
  
  5、女生月经来时,不要喝绿茶,反正茶类的不要喝就对了,多吃可以补血的东西。
  
  6、喝豆浆时,不要加鸡蛋及糖,也不要喝太多。
  
  7、空腹时不要吃蕃茄,最好饭后吃。
  
  8、早上醒来,先喝一杯水,预防结石。
  
  9、睡前三小时不要吃东西,会胖。
  
  10、少喝奶茶,因为高热量、高油,没有营养价值可言,长期饮用,易罹患高血压、糖尿病...等疾病。
  
  11、刚出炉的面包不宜马上食用。
  
  12、远离充电座,人体应远离30公分以上,切忌放在床边。
  
  13、天天喝水八大杯。
  
  14、每天十杯水,膀胱癌不会来。
  
  15、白天多喝水,晚上少喝水。
  
  16、一天不要喝两杯以上的咖啡,喝太多易导致失眠、胃痛。
  
  17、多油脂的食物少吃,因为得花5~7小时去消化,并使脑中血液集中到肠胃,易昏昏欲睡。
  
  18、下午五点后,大餐少少吃,因为五点后身体不需那么多能量。
  
  19、10种吃了会快乐的食物:深海鱼、香蕉、葡萄柚、全麦面包、菠菜、大蒜、番茄、低脂牛奶、鸡肉、樱桃。
  
  20、睡眠不足会变笨,一天须八小时睡眠,有午睡习惯较不会老。
  
  21、最佳睡眠时间是在晚上10点~清晨6点。
  
  22、每天喝酒不要超过一杯,因为酒精会抑制制造抗体的B细胞,增加细菌感染的机会。
  
  23、服用胶囊应以冷水吞服(可以第一个吃),睡前30分先服药,忌立即躺下
24、酸梅具防止老化作用,青春永驻;肝火有毛病者宜多食用。
  
  25、掉发因素:熬夜、压力、烟酒、香鸡排、麻辣锅、油腻食物、调味过重的料理。
  
  26、帮助头发生长:多食用包心菜、蛋、豆类;少吃甜食(尤其是果糖)。
  
  27、每天一杯柠檬汁、柳橙汁,不但可以美白,还可以淡化黑斑。
  
  28、苹果:机车族、瘾君子、家庭主妇的常备良药;一天一颗,才能让自己有个干干净净的肺。
  
  29、抽烟又吃维他命(B胡萝卜素-A维他命的一种)会致癌,尽早戒烟,才是最健康的做法。
  
  30、女性不宜喝茶的五个时期:月经来时、孕妇、临产前、生产完后、更年期。
  
  31、抽烟:关系最大的是肺癌、唇癌、舌癌、喉癌、食道癌,也与膀胱癌有关。
  
  32、饮酒导致肝硬化,引发肝癌。
  
  33、吃槟榔会导致口腔纤维化,引发口腔癌。
  
  34、食物过于精细,缺乏纤维,含大量脂肪,尤其是胆固醇,会引发胃癌。
  
  35、食物过于粗糙,营养不足时,导致食道癌、胃癌。
  
  36、食品中的黄曲毒素、亚X类物皆具有致癌性。
  
  37、不抽烟,拒吸二手烟。
  
  38、适量饮酒,不拚酒,不醉酒。
  
  39、减少食用盐腌、烟熏、烧烤的食物。
  
  40、每天摄取新鲜的蔬菜与水果。
  
  41、每天摄取富含高纤维的五谷类及豆类。
  
  42、每天摄取均衡的饮食,不过量。
  
  43、正确饮食习惯:早上吃的像皇帝,中午吃的像平民,晚上吃的像乞丐。


 
Vitamin果茶 @ 2005-12-09 08:46

 

在浏览器的地址栏里直接输入一个doc或xls或jpg的文件的url路径,那么该文件会直接显示在浏览器里。而在很多时候我们希望能直接弹出下载提示框让用户下载,我们该怎么办呢?这里有两种方法:
1、设置你的服务器的iis,给doc等后缀名做映射
2、在向客户端发送时设置其contenttype

下面详细说明方法2

<%
Response.Buffer = true
Response.Clear

 dim url
 Dim fso,fl,flsize
 dim Dname
 Dim objStream,ContentType,flName,isre,url1
'*********************************************调用时传入的下载文件名
 Dname=trim(request("n"))
'******************************************************************
 If Dname<>"" Then
'******************************下载文件存放的服务端目录
  url=server.MapPath("/")&"\"&Dname
'***************************************************
 End If

 Set fso=Server.CreateObject("Scripting.FileSystemObject")
  Set fl=fso.getfile(url)
  flsize=fl.size
  flName=fl.name
  Set fl=Nothing
  Set fso=Nothing
 %>
 <%
  Set objStream = Server.CreateObject("ADODB.Stream")
  objStream.Open
  objStream.Type = 1
  objStream.LoadFromFile url


   Select Case lcase(Right(flName, 4))
    Case ".asf"
     ContentType = "video/x-ms-asf"
    Case ".avi"
     ContentType = "video/avi"
    Case ".doc"
     ContentType = "application/msword"
    Case ".zip"
     ContentType = "application/zip"
    Case ".xls"
     ContentType = "application/vnd.ms-excel"
    Case ".gif"
     ContentType = "image/gif"
    Case ".jpg", "jpeg"
     ContentType = "image/jpeg"
    Case ".wav"
     ContentType = "audio/wav"
    Case ".mp3"
     ContentType = "audio/mpeg3"
    Case ".mpg", "mpeg"
     ContentType = "video/mpeg"
    Case ".rtf"
     ContentType = "application/rtf"
    Case ".htm", "html"
     ContentType = "text/html"
    Case ".txt"
     ContentType = "text/plain"
    Case Else
     ContentType = "application/octet-stream"
   End Select

 

   Response.AddHeader "Content-Disposition", "attachment; filename=" & flName
   Response.AddHeader "Content-Length", flsize

   Response.Charset = "UTF-8"
   Response.ContentType = ContentType

   Response.BinaryWrite objStream.Read
   Response.Flush
   response.Clear()
  objStream.Close
  Set objStream = Nothing

%>

将下面的东西存成download.asp然后你就可以用<a herf="http://xxx.xxx.com/download.asp?n=file.doc">download!</a>来下载同一目录下的file.doc了!

但是这里有个问题就是直接将file.doc路径写在url里是不安全的,所以解决方案应该是将file.doc的路径存到数据库里,同过查找数据库后得到路径

在这个程序的最前面如果加上一个判断:

if instr(Request.ServerVariables("HTTP_REFERER"),"http://你的域名")=0 then
   Response.End
end if

就能够很好的防止别人的盗链了



 
日历
网志分类
『所有网志』 (29)
最新留言
站内搜索
友情链接
我的歪酷
妹妹的淘宝小店
CSDN
张佳佳的BLOG
思归大哥的BLOG
吕震宇的设计模式
订阅 RSS
0007250
歪酷博客