﻿<?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-weidagang2046的专栏-文章分类-Java</title><link>http://www.blogjava.net/weidagang2046/category/1064.html</link><description>物格而后知致</description><language>zh-cn</language><lastBuildDate>Thu, 01 Mar 2007 18:27:06 GMT</lastBuildDate><pubDate>Thu, 01 Mar 2007 18:27:06 GMT</pubDate><ttl>60</ttl><item><title>Ajax中文乱码问题解决方案（servlet）</title><link>http://www.blogjava.net/weidagang2046/articles/86610.html</link><dc:creator>weidagang2046</dc:creator><author>weidagang2046</author><pubDate>Sat, 09 Dec 2006 15:06:00 GMT</pubDate><guid>http://www.blogjava.net/weidagang2046/articles/86610.html</guid><wfw:comment>http://www.blogjava.net/weidagang2046/comments/86610.html</wfw:comment><comments>http://www.blogjava.net/weidagang2046/articles/86610.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/weidagang2046/comments/commentRss/86610.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/weidagang2046/services/trackbacks/86610.html</trackback:ping><description><![CDATA[
		<div class="postbody">最近研究ajax，在界面上text中输入中文，发送出去后返回乱码。经过一个晚上的测试，以及得到满意答案，代码如下：<br /><br />HTML：<br />    ……<br />    //实际上这里的charset=utf-8 也是可以的，因为在中文平台下<br />    //用了GB2312<br />    &lt;meta http-equiv="Content-Type" content="text/html; charset=GB2312"&gt;<br /><br />JS：<br />    <font color="#ff0000">我用了两个方法提交：GET 和 POST。<br />    在服务器端要对应不同的提交方式转换不同的编码。</font><br />   ……<br />    //要传递的参数<br />   var queryString = "firstName=" + firstName + "&amp;lastName=" + lastName<br />                          + "&amp;birthday=" + birthday;    function  <br /> <br />    //GET方式提交<br />    doRequestUsingGET() {<br />        createXMLHttpRequest();<br />        var url = "GetAndPostExample?" + queryString + "&amp;timeStamp="<br />                          + new Date().getTime();<br />        xmlHttp.onreadystatechange = handleStateChange;<br />        xmlHttp.open("GET", url, true);<br />        xmlHttp.send(null);<br />    }<br /><br />    //POST方式提交<br />    function doRequestUsingPOST() {<br />        createXMLHttpRequest();<br />        var url = "GetAndPostExample?timeStamp=" + new Date().getTime();<br />        xmlHttp.open("POST", url, true);<br />        xmlHttp.onreadystatechange = handleStateChange;<br />        xmlHttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");<br />        xmlHttp.send(queryString);<br />    }<br /><br />servlet：<br />        response.setContentType("text/xml");<br /><br />        //<font color="#ff0000">这个一定要设置，这里的设置应该跟HTML中的一样，但是我在这里</font><br />        //用了 uft-8， 结果也是一样。<br />        response.setCharacterEncoding("GB2312");<br />      <br />        //<font color="#ff0000">当用POST方法时，一定要设置成utf-8，否则乱码</font><br />        String firstName = new String(request.getParameter("firstName").getBytes("ISO-8859-1"), "<font color="#ff0000">utf-8</font>");<br /><br />        //<font color="#ff0000">当用GET方法时，要设置成GB2312，否则乱码。</font><br />        String lastName = new String(request.getParameter("lastName").getBytes("ISO-8859-1"), "<font color="#ff0000">GB2312</font>");<br /><br />测试结果：<br />因为界面上两个控件firstName 和  lastName都输入中文。<br />接收xmlHttp.responseText后，会发现其中一个为乱码，一个可以正常显示中文。<br /><br />在网上还发现有人说用：<br />“老问题了，最简单的方法是，全部escape后发送。取回后unescape，绝对没有编码问题。”<br />我测试后发现escape后的东西全部变成null了。不知道有谁成功用过这个方法的，或者还有什么更好的解决乱码的方法，请拿出来共享一下吧 ：）<br /><br />from: <a href="http://www.themore.net/page/7/37/2006_08/detail_407_1.html">http://www.themore.net/page/7/37/2006_08/detail_407_1.html</a></div>
<img src ="http://www.blogjava.net/weidagang2046/aggbug/86610.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/weidagang2046/" target="_blank">weidagang2046</a> 2006-12-09 23:06 <a href="http://www.blogjava.net/weidagang2046/articles/86610.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>编写高性能Web应用程序的10个入门技巧</title><link>http://www.blogjava.net/weidagang2046/articles/85980.html</link><dc:creator>weidagang2046</dc:creator><author>weidagang2046</author><pubDate>Wed, 06 Dec 2006 15:57:00 GMT</pubDate><guid>http://www.blogjava.net/weidagang2046/articles/85980.html</guid><wfw:comment>http://www.blogjava.net/weidagang2046/comments/85980.html</wfw:comment><comments>http://www.blogjava.net/weidagang2046/articles/85980.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/weidagang2046/comments/commentRss/85980.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/weidagang2046/services/trackbacks/85980.html</trackback:ping><description><![CDATA[
		<p>编写高性能Web应用程序的10个入门技巧<br /><br />  数据层性能 <br />  技巧 1 — 返回多个结果集 <br />  技巧 2 — 分页的数据访问 <br />  技巧 3 — 连接池 <br />  技巧 4 — ASP.NET 缓存 API <br />  技巧 5 — 每请求缓存 <br />  技巧 6 — 后台处理 <br />  技巧 7 — 页输出缓存和代理<a href="http://www.chinahtml.com/systems/" target="_blank">服务器</a><br />  技巧 8 — 运行 IIS 6.0（只要用于内核缓存） <br />  技巧 9 — 使用 Gzip 压缩 <br />  技巧 10 — <a href="http://www.chinahtml.com/systems/" target="_blank">服务器</a>控件视图状态 <br />  <br /><br />使用 ASP.NET 编写 Web 应用程序的简单程度令人不敢相信。正因为如此简单，所以很多<br />开发人员就不会花时间来设计其应用程序的结构，以获得更好的性能了。在本文中，我将<br />讲述 10 个用于编写高性能 Web 应用程序的技巧。但是我并不会将这些建议仅局限于 <br />ASP.NET 应用程序，因为这些应用程序只是 Web 应用程序的一部分。本文不作为对 Web <br />应用程序进行性能调整的权威性指南 — 一整本书恐怕都无法轻松讲清楚这个问题。请将<br />本文视作一个很好的起点。 <br /><br />成为工作狂之前，我原来喜欢攀岩。在进行任何大型攀岩活动之前，我都会首先仔细查看<br />指南中的路线，阅读以前游客提出的建议。但是，无论指南怎么好，您都需要真正的攀岩<br />体验，然后才能尝试一个特别具有挑战性的攀登。与之相似，当您面临修复性能问题或者<br />运行一个高吞吐量站点的问题时，您只能学习如何编写高性能 Web 应用程序。<br /><br />我的个人体验来自在 Microsoft 的 ASP.NET 部门作为基础架构程序经理的经验，在此期<br />间我运行和管理 www.ASP.NET，帮助设计社区<a href="http://www.chinahtml.com/systems/" target="_blank">服务器</a>的结构，社区<a href="http://www.chinahtml.com/systems/" target="_blank">服务器</a>是几个著名 <br />ASP.NET 应用程序（组合到一个平台的 ASP.NET Forums、.Text 和 nGallery）。我确信<br />有些曾经帮助过我的技巧对您肯定也会有所帮助。<br /><br />您应该考虑将应用程序分为几个逻辑层。您可能听说过 3 层（或者 n 层）物理体系结构<br />一词。这些通常都是规定好的体系结构方式，将功能在进程和/或硬件之间进行了物理分离<br />。当系统需要扩大时，可以很轻松地添加更多的硬件。但是会出现一个与进程和机器跳跃<br />相关的性能下降，因此应该避免。所以，如果可能的话，请尽量在同一个应用程序中一起<br />运行 ASP.NET 页及其相关组件。<br /><br />因为代码分离以及层之间的边界，所以使用 Web 服务或远程处理将会使得性能下降 20% <br />甚至更多。<br /><br />数据层有点与众不同，因为通常情况下，最好具有专用于<a href="http://www.chinahtml.com/databases/" target="_blank">数据库</a>的硬件。然而进程跳跃到<br /><a href="http://www.chinahtml.com/databases/" target="_blank">数据库</a>的成本依然很高，因此数据层的性能是您在优化代码时首先要考虑的问题。<br /><br />在深入应用程序的性能修复问题之前，请首先确保对应用程序进行剖析，以便找出具体的<br />问题所在。主要性能计数器（如表示执行垃圾回收所需时间百分比的计数器）对于找出应<br />用程序在哪些位置花费了其主要时间也非常有用。然而花费时间的位置通常非常不直观。<br /><br />本文讲述了两种类型的性能改善：大型优化（如使用 ASP.NET 缓存），和进行自身重复的<br />小型优化。这些小型优化有时特别有意思。您对代码进行一点小小的更改，就会获得很多<br />很多时间。使用大型优化，您可能会看到整体性能的较大飞跃。而使用小型优化时，对于<br />某个特定请求可能只会节省几毫秒的时间，但是每天所有请求加起来，则可能会产生巨大<br />的改善。<br /><br />数据层性能<br /><br /><br />谈到应用程序的性能调整，有一个试纸性的测试可用来对工作进行优先级划分：代码是否<br />访问<a href="http://www.chinahtml.com/databases/" target="_blank">数据库</a>？如果是，频率是怎样的？请注意，这一相同测试也可应用于使用 Web 服务或<br />远程处理的代码，但是本文对这些内容未做讲述。<br /><br />如果某个特定的代码路径中必需进行<a href="http://www.chinahtml.com/databases/" target="_blank">数据库</a>请求，并且您认为要首先优化其他领域（如字<br />符串操作），则请停止，然后执行这个试纸性测试。如果您的性能问题不是非常严重的话<br />，最好花一些时间来优化一下与<a href="http://www.chinahtml.com/databases/" target="_blank">数据库</a>、返回的数据量、进出<a href="http://www.chinahtml.com/databases/" target="_blank">数据库</a>的往返频率相关的花<br />费时间。<br /><br />了解这些常规信息之后，我们来看一下可能会有助于提高应用程序性能的十个技巧。首先<br />，我要讲述可能会引起最大改观的更改。<br /><br /><br />技巧 1 — 返回多个结果集<br /><br /><br />仔细查看您的<a href="http://www.chinahtml.com/databases/" target="_blank">数据库</a>代码，看是否存在多次进入<a href="http://www.chinahtml.com/databases/" target="_blank">数据库</a>的请求路径。每个这样的往返都会<br />降低应用程序可以提供的每秒请求数量。通过在一个<a href="http://www.chinahtml.com/databases/" target="_blank">数据库</a>请求中返回多个结果集，可以<br />节省与<a href="http://www.chinahtml.com/databases/" target="_blank">数据库</a>进行通信所需的总时间长度。同时因为减少了<a href="http://www.chinahtml.com/databases/" target="_blank">数据库</a><a href="http://www.chinahtml.com/systems/" target="_blank">服务器</a>管理请求的工作<br />，还会使得系统伸缩性更强。<br /><br />虽然可以使用动态 SQL 返回多个结果集，但是我首选使用存储过程。关于业务逻辑是否应<br />该驻留于存储过程的问题还存在一些争议，但是我认为，如果存储过程中的逻辑可以约束<br />返回数据的话（缩小数据集的大小、缩短网络上所花费时间，不必筛选逻辑层的数据），<br />则应赞成这样做。<br /><br />使用 SqlCommand 实例及其 ExecuteReader 方法填充强类型的业务类时，可以通过调用 <br />NextResult 将结果集指针向前移动。图 1 显示了使用类型类填充几个 ArrayList 的示例<br />会话。只从<a href="http://www.chinahtml.com/databases/" target="_blank">数据库</a>返回您需要的数据将进一步减少<a href="http://www.chinahtml.com/systems/" target="_blank">服务器</a>上的内存分配。 <br /><br />Figure 1 Extracting Multiple Resultsets from a DataReader<br />// read the first resultset<br />reader = command.ExecuteReader();<br /><br />// read the data from that resultset<br />while (reader.Read()) {<br />    suppliers.Add(PopulateSupplierFromIDataReader( reader ));<br />}<br /><br />// read the next resultset<br />reader.NextResult();<br /><br />// read the data from that second resultset<br />while (reader.Read()) {<br />    products.Add(PopulateProductFromIDataReader( reader ));<br />}<br /><br /><br />技巧 2 — 分页的数据访问<br /><br /><br />ASP.NET DataGrid 具有一个很好的功能：数据分页支持。在 DataGrid 中启用分页时，一<br />次会显示固定数量的记录。另外，在 DataGrid 的底部还会显示分页 UI，以便在记录之间<br />进行导航。该分页 UI 使您能够在所显示的数据之间向前和向后导航，并且一次显示固定<br />数量的记录。<br /><br />还有一个小小的波折。使用 DataGrid 的分页需要所有数据均与网格进行绑定。例如，您<br />的数据层需要返回所有数据，那么 DataGrid 就会基于当前页筛选显示的所有记录。如果<br />通过 DataGrid 进行分页时返回了 100,000 个记录，那么针对每个请求会放弃 99,975 个<br />记录（假设每页大小为 25 个记录）。当记录的数量不断增加时，应用程序的性能就会受<br />到影响，因为针对每个请求必须发送越来越多的数据。<br /><br />要编写性能更好的分页代码，一个极佳的方式是使用存储过程。图 2 显示了针对 <br />Northwind <a href="http://www.chinahtml.com/databases/" target="_blank">数据库</a>中的 Orders 表进行分页的一个示例存储过程。简而言之，您此时要做<br />的只是传递页索引和页大小。然后就会计算合适的结果集，并将其返回。 <br /><br />Figure 2 Paging Through the Orders Table<br />CREATE PROCEDURE northwind_OrdersPaged<br />(<br />    @PageIndex int, <br />    @PageSize int<br />)<br />AS<br />BEGIN<br />DECLARE @PageLowerBound int<br />DECLARE @PageUpperBound int<br />DECLARE @RowsToReturn int<br /><br />-- First set the rowcount<br />SET @RowsToReturn = @PageSize * (@PageIndex + 1)<br />SET ROWCOUNT @RowsToReturn<br /><br />-- Set the page bounds<br />SET @PageLowerBound = @PageSize * @PageIndex<br />SET @PageUpperBound = @PageLowerBound + @PageSize + 1<br /><br />-- Create a temp table to store the select results<br />CREATE TABLE #PageIndex <br />(<br />    IndexId int IDENTITY (1, 1) NOT NULL,<br />    OrderID int<br />)<br /><br />-- Insert into the temp table<br />INSERT INTO #PageIndex (OrderID)<br />SELECT <br />    OrderID<br />FROM <br />    Orders<br />ORDER BY <br />    OrderID DESC<br /><br />-- Return total count<br />SELECT COUNT(OrderID) FROM Orders<br /><br />-- Return paged results<br />SELECT <br />    O.*<br />FROM <br />    Orders O,<br />    #PageIndex PageIndex<br />WHERE <br />    O.OrderID = PageIndex.OrderID AND<br />    PageIndex.IndexID &gt; @PageLowerBound AND<br />    PageIndex.IndexID &lt; @PageUpperBound<br />ORDER BY <br />    PageIndex.IndexID<br /><br />END<br /><br /><br /><br />在社区<a href="http://www.chinahtml.com/systems/" target="_blank">服务器</a>中，我们编写了一个分页<a href="http://www.chinahtml.com/systems/" target="_blank">服务器</a>控件，以完成所有的数据分页。您将会看到<br />，我使用的就是技巧 1 中讨论的理念，从一个存储过程返回两个结果集：记录的总数和请<br />求的数据。<br /><br />返回记录的总数可能会根据所执行查询的不同而有所变化。例如，WHERE 子句可用来约束<br />返回的数据。为了计算在分页 UI 中显示的总页数，必须了解要返回记录的总数。例如，<br />如果总共有 1,000,000 条记录，并且要使用一个 WHERE 子句将其筛选为 1000 条记录，<br />那么分页逻辑就需要了解记录的总数才能正确呈现分页 UI。<br /><br /><br />技巧 3 — 连接池<br /><br /><br />在 Web 应用程序和 <a href="http://www.chinahtml.com/databases/2/" target="_blank">SQL Server</a>? 之间设置 TCP 连接可能是一个非常消耗资源的操作。Mi<br />crosoft 的开发人员到目前为止能够使用连接池已经有一段时间了，这使得他们能够重用<br /><a href="http://www.chinahtml.com/databases/" target="_blank">数据库</a>连接。他们不是针对每个请求都设置一个新的 TCP 连接，而是只在连接池中没有任<br />何连接时才设置新连接。当连接关闭时，它会返回连接池，在其中它会保持与<a href="http://www.chinahtml.com/databases/" target="_blank">数据库</a>的连<br />接，而不是完全破坏该 TCP 连接。<br /><br />当然，您需要小心是否会出现泄漏连接。当您完成使用连接时，请一定要关闭这些连接。<br />再重复一遍：无论任何人对 Microsoft?.NET Framework 中的垃圾回收有什么评论，请一<br />定要在完成使用连接时针对该连接显式调用 Close 或 Dispose。不要相信公共语言运行库<br />(CLR) 会在预先确定的时间为您清除和关闭连接。尽管 CLR 最终会破坏该类，并强制连<br />接关闭，但是当针对对象的垃圾回收真正发生时，并不能保证。 <br /><br />要以最优化的方式使用连接池，需要遵守一些规则。首先打开连接，执行操作，然后关闭<br />该连接。如果您必须如此的话，可以针对每个请求多次打开和关闭连接（最好应用技巧 1<br />），但是不要一直将连接保持打开状态并使用各种不同的方法对其进行进出传递。第二，<br />使用相同的连接字符串（如果使用集成身份验证的话，还要使用相同的线程标识）。如果<br />不使用相同的连接字符串，例如根据登录的用户自定义连接字符串，那么您将无法得到连<br />接池提供的同一个优化值。如果您使用集成身份验证，同时还要模拟大量用户，连接池的<br />效率也会大大下降。尝试跟踪与连接池相关的任何性能问题时，.NET CLR 数据性能计数器<br />可能非常有用。 <br /><br />每当应用程序连接资源时，如在另一个进程中运行的<a href="http://www.chinahtml.com/databases/" target="_blank">数据库</a>，您都应该重点考虑连接该资<br />源所花时间、发送或检索数据所花时间，以及往返的数量，从而进行优化。优化应用程序<br />中任何种类的进程跳跃都是获得更佳性能的首要一点。<br /><br />应用层包含了连接数据层、将数据转换为有意义类实例和业务流程的逻辑。例如社区服务<br />器，您要在其中填充Forums 或 Threads集合，应用业务规则（如权限）；最重要的是要在<br />其中执行缓存逻辑。<br /><br /><br />技巧 4 — ASP.NET 缓存 API<br /><br /><br />编写应用程序代码行之前，一个首要完成的操作是设计应用层的结构，以便最大化利用 <br />ASP.NET 缓存功能。<br /><br />如果您的组件要在 ASP.NET 应用程序中运行，则只需在该应用程序项目中包括一个 <br />System.Web.dll 引用。当您需要访问该缓存时，请使用 HttpRuntime.Cache 属性（通过 <br />Page.Cache 和 HttpContext.Cache 也可访问这个对象）。<br /><br />对于缓存数据，有几个规则。首先，如果数据可能会多次使用时，则这是使用缓存的一个<br />很好的备选情况。第二，如果数据是通用的，而不特定于某个具体的请求或用户时，则也<br />是使用缓存的一个很好的备选情况。如果数据是特定于用户或请求的，但是寿命较长的话<br />，仍然可以对其进行缓存，但是这种情况可能并不经常使用。第三，一个经常被忽略的规<br />则是，有时可能您缓存得太多。通常在一个 x86 计算机上，为了减少内存不足错误出现的<br />机会，您会想使用不高于 800MB 的专用字节运行进程。因此缓存应该有个限度。换句话说<br />，您可能能够重用某个计算结果，但是如果该计算采用 10 个参数的话，您可能要尝试缓<br />存 10 个排列，这样有可能给您带来麻烦。一个要求 ASP.NET 的最常见支持是由于过度缓<br />存引起的内存不足错误，尤其是对于大型数据集。<br /><br /><br />缓存有几个极佳的功能，您需要对它们有所了解。首先，缓存会实现最近最少使用的算法<br />，使得 ASP.NET 能够在内存运行效率较低的情况下强制缓存清除 － 从缓存自动删除未使<br />用过的项目。第二，缓存支持可以强制失效的过期依赖项。这些依赖项包括时间、密钥和<br />文件。时间经常会用到，但是对于 ASP.NET 2.0，引入了一个功能更强的新失效类型：数<br />据库缓存失效。它指的是当<a href="http://www.chinahtml.com/databases/" target="_blank">数据库</a>中的数据发生变化时自动删除缓存中的项。有关<a href="http://www.chinahtml.com/databases/" target="_blank">数据库</a><br />缓存失效的详细信息，请参阅 MSDN?Magazine 2004 年 7 月的 Dino Esposito Cutting <br />Edge 专栏。要了解缓存的体系结构，请参阅图 3。<br /><br />技巧 5 — 每请求缓存<br /><br />在本文前面部分，我提到了经常遍历代码路径的一些小改善可能会导致较大的整体性能收<br />益。对于这些小改善，其中有一个绝对是我的最爱，我将其称之为"每请求缓存"。<br /><br />缓存 API 的设计目的是为了将数据缓存较长的一段时间，或者缓存至满足某些条件时，但<br />每请求缓存则意味着只将数据缓存为该请求的持续时间。对于每个请求，要经常访问某个<br />特定的代码路径，但是数据却只需提取、应用、修改或更新一次。这听起来有些理论化，<br />那么我们来举一个具体的示例。<br /><br />在社区<a href="http://www.chinahtml.com/systems/" target="_blank">服务器</a>的论坛应用程序中，页面上使用的每个<a href="http://www.chinahtml.com/systems/" target="_blank">服务器</a>控件都需要个性化的数据来确<br />定使用什么外观、使用什么样式表，以及其他个性化数据。这些数据中有些可以长期缓存<br />，但是有些数据却只针对每个请求提取一次，然后在执行该请求期间对其重用多次，如要<br />用于控件的外观。<br /><br />为了达到每请求缓存，请使用 ASP.NET HttpContext。对于每个请求，都会创建一个 <br />HttpContext 实例，在该请求期间从 HttpContext.Current 属性的任何位置都可访问该实<br />例。该 HttpContext 类具有一个特殊的 Items 集合属性；添加到此 Items 集合的对象和<br />数据只在该请求持续期间内进行缓存。正如您可以使用缓存来存储经常访问的数据一样，<br />您也可以使用 HttpContext.Items 来存储只基于每个请求使用的数据。它背后的逻辑非常<br />简单：数据在它不存在的时候添加到 HttpContext.Items 集合，在后来的查找中，只是返<br />回 HttpContext.Items 中的数据。<br /><br /><br />技巧 6 — 后台处理<br /><br /><br />通往代码的路径应该尽可能快速，是吗？可能有时您会觉得针对每个请求执行的或者每 <br />n 个请求执行一次的任务所需资源非常多。发送电子邮件或者分析和验证传入数据就是这<br />样的一些例子。<br /><br />剖析 ASP.NET Forums 1.0 并重新构建组成社区<a href="http://www.chinahtml.com/systems/" target="_blank">服务器</a>的内容时，我们发现添加新张贴的<br />代码路径非常慢。每次添加新张贴时，应用程序首先需要确保没有重复的张贴，然后必须<br />使用"坏词"筛选器分析该张贴，分析张贴的字符图释，对张贴添加标记并进行索引，请求<br />时将张贴添加到合适的队列，验证附件，最终张贴之后，立即向所有订阅者发出电子邮件<br />通知。很清楚，这涉及很多操作。<br /><br />经研究发现，大多数时间都花在了索引逻辑和发送电子邮件上。对张贴进行索引是一个非<br />常耗时的操作，人们发现内置的 System.Web.Mail 功能要连接 SMYP <a href="http://www.chinahtml.com/systems/" target="_blank">服务器</a>，然后连续发<br />送电子邮件。当某个特定张贴或主题领域的订阅者数量增加时，执行 AddPost 功能所需的<br />时间也越来越长。<br /><br />并不需要针对每个请求都进行电子邮件索引。理想情况下，我们想要将此操作进行批处理<br />，一次索引 25 个张贴或者每五分钟发送一次所有电子邮件。我们决定使用以前用于对数<br />据缓存失效进行原型设计的代码，这个失效是用于最终进入 Visual Studio? 2005 的内容<br />的。<br /><br />System.Threading 命名空间中的 Timer 类非常有用，但是在 .NET Framework 中不是很<br />有名，至少对于 Web 开发人员来说是这样。创建之后，这个 Timer 类将以一个可配置的<br />间隔针对 ThreadPool 中的某个线程调用指定的回调。这就表示，您可以对代码进行设置<br />，使其能够在没有对 ASP.NET 应用程序进行传入请求的情况下得以执行，这是后台处理的<br />理想情况。您还可以在此后台进程中执行如索引或发送电子邮件之类的操作。 <br /><br />但是，这一技术有几个问题。如果应用程序域卸载，该计时器实例将停止触发其事件。另<br />外，因为 CLR 对于每个进程的线程数量具有一个硬性标准，所以可能会出现这样的情形：<br /><a href="http://www.chinahtml.com/systems/" target="_blank">服务器</a>负载很重，其中计时器可能没有可在其基础上得以完成的线程，在某种程度上可能<br />会造成延迟。ASP.NET 通过在进程中保留一定数量的可用线程，并且仅使用总线程的一部<br />分用于请求处理，试图将上述情况发生的机会降到最低。但是，如果您具有很多异步操作<br />时，这可能就是一个问题了。 <br /><br />这里没有足够的空间来放置该代码，但是您可以下载一个可以看懂的示例，网址是 <br />www.rob-howard.net。请了解一下 Blackbelt TechEd 2004 演示中的幻灯片和演示。<br /><br /><br />技巧 7 — 页输出缓存和代理<a href="http://www.chinahtml.com/systems/" target="_blank">服务器</a><br /><br /><br />ASP.NET 是您的表示层（或者说应该是您的表示层）；它由页、用户控件、<a href="http://www.chinahtml.com/systems/" target="_blank">服务器</a>控件（H<br />ttpHandlers 和 HttpModules）以及它们生成的内容组成。如果您具有一个 ASP.NET 页，<br />它会生成输出（HTML、XML、图像或任何其他数据），并且您针对每个请求运行此代码时，<br />它都会生成相同的输出，那么您就拥有一个可用于页输出缓存的绝佳备选内容。 <br /><br />将此行内容添加页的最上端 <br /><br />&lt;%@ Page OutputCache VaryByParams="none" Duration="60" %&gt; <br /><br />就可以高效地为此页生成一次输出，然后对它进行多次重用，时间最长为 60 秒，此时该<br />页将重新执行，输出也将再一次添加到 ASP.NET 缓存。通过使用一些低级程序化 API 也<br />可以完成此行为。对于输出缓存有几个可配置的设置，如刚刚讲到的 VaryByParams 属性<br />。VaryByParams 刚好被请求到，但还允许您指定 HTTP GET 或 HTTP POST 参数来更改缓<br />存项。例如，只需设置 VaryByParam="Report" 即可对 default.aspx?Report=1 或 <br />default.aspx?Report=2 进行输出缓存。通过指定一个以分号分隔的列表，还可以指定其<br />他参数。 <br /><br />很多人都不知道何时使用输出缓存，ASP.NET 页还会生成一些位于缓存<a href="http://www.chinahtml.com/systems/" target="_blank">服务器</a>下游的 <br />HTTP 标头，如 Microsoft Internet Security and Acceleration Server 或 Akamai 使<br />用的标头。设置了 HTTP 缓存标头之后，可以在这些网络资源上对文档进行缓存，客户端<br />请求也可在不必返回原始<a href="http://www.chinahtml.com/systems/" target="_blank">服务器</a>的情况下得以满足。<br /><br />因此，使用页输出缓存不会使得您的应用程序效率更高，但是它可能会减少<a href="http://www.chinahtml.com/systems/" target="_blank">服务器</a>上的负<br />载，因为下游缓存技术会缓存文档。当然，这可能只是匿名内容；一旦它成为下游之后，<br />您就再也不会看到这些请求，并且再也无法执行身份验证以阻止对它的访问了。<br /><br /><br />技巧 8 — 运行 IIS 6.0（只要用于内核缓存）<br /><br /><br />如果您未运行 IIS 6.0 (<a href="http://www.chinahtml.com/systems/2/" target="_blank">Windows</a> Server? 2003)，那么您就错过了 Microsoft Web 服务<br />器中的一些很好的性能增强。在技巧 7 中，我讨论了输出缓存。在 IIS 5.0 中，请求是<br />通过 IIS 然后进入 ASP.NET 的。涉及到缓存时，ASP.NET 中的 HttpModule 会接收该请<br />求，并返回缓存中的内容。<br /><br />如果您正在使用 IIS 6.0，就会发现一个很好的小功能，称为内核缓存，它不需要对 <br />ASP.NET 进行任何代码更改。当请求由 ASP.NET 进行输出缓存时，IIS 内核缓存会接收缓<br />存数据的一个副本。当请求来自网络驱动程序时，内核级别的驱动程序（无上下文切换到<br />用户模式）就会接收该请求，如果经过了缓存，则会将缓存的数据刷新到响应，然后完成<br />执行。这就表示，当您将内核模式缓存与 IIS 和 ASP.NET 输出缓存一起使用时，就会看<br />到令人不敢相信的性能结果。在 ASP.NET 的 Visual Studio 2005 开发过程中，我一度是<br />负责 ASP.NET 性能的程序经理。开发人员完成具体工作，但是我要看到每天进行的所有报<br />告。内核模式缓存结果总是最有意思的。最常见的特征是网络充满了请求/响应，而 IIS <br />运行时的 CPU 使用率只有大约 5%。这太令人震惊了！当然使用 IIS 6.0 还有一些其他原<br />因，但是内核模式缓存是其中最明显的一个。<br /><br /><br />技巧 9 — 使用 Gzip 压缩<br /><br /><br />虽然使用 gzip 并不一定是<a href="http://www.chinahtml.com/systems/" target="_blank">服务器</a>性能技巧（因为您可能会看到 CPU 使用率的提高），但<br />是使用 gzip 压缩可以减少<a href="http://www.chinahtml.com/systems/" target="_blank">服务器</a>发送的字节数量。这就使人们觉得页速度加快了，并且<br />还减少了带宽的用量。根据所发送数据、可以压缩的程度以及客户端浏览器是否支持（IIS<br />只会向支持 gzip 压缩的客户端发送经过 gzip 压缩的内容，如 Internet Explorer <br />6.0 和 Firefox），您的<a href="http://www.chinahtml.com/systems/" target="_blank">服务器</a>每秒可以服务于更多的请求。实际上，几乎每当您减少所<br />返回数据的数量时，都会增加每秒请求数。 <br /><br />Gzip 压缩已经内置到 IIS 6.0 中，并且其性能比 IIS 5.0 中使用的 gzip 压缩要好的多<br />，这是好消息。但不幸的是，当尝试在 IIS 6.0 中打开 gzip 压缩时，您可能无法在 <br />IIS 的属性对话中找到该设置。IIS 小组在该<a href="http://www.chinahtml.com/systems/" target="_blank">服务器</a>中置入了卓越的 gzip 功能，但是忘<br />了包括一个用于启用该功能的管理 UI。要启用 gzip 压缩，您必须深入到 IIS 6.0 的 <br />XML 配置设置内部（这样不会引起心脏虚弱）。顺便提一句，这归功于 OrcsWeb 的 <br />Scott Forsyth，他帮助我提出了在 OrcsWeb 上宿主的 www.asp.net <a href="http://www.chinahtml.com/systems/" target="_blank">服务器</a>的这个问题。<br /><br /><br />本文就不讲述步骤了，请阅读 Brad Wilson 的文章，网址是 IIS6 Compression。还有一<br />篇有关为 ASPX 启用压缩的知识库文章，网址是 Enable ASPX Compression in IIS。但是<br />您应该注意，由于一些实施细节，IIS 6.0 中不能同时存在动态压缩和内核缓存。<br /><br /><br />技巧 10 — <a href="http://www.chinahtml.com/systems/" target="_blank">服务器</a>控件视图状态<br /><br /><br />视图状态是一个有趣的名称，用于表示在所生成页的隐藏输出字段中存储一些状态数据的 <br />ASP.NET。当该页张贴回<a href="http://www.chinahtml.com/systems/" target="_blank">服务器</a>时，<a href="http://www.chinahtml.com/systems/" target="_blank">服务器</a>可以分析、验证、并将此视图状态数据应用回该<br />页的控件树。视图状态是一个非常强大的功能，因为它允许状态与客户端一起保持，并且<br />它不需要 cookie 或<a href="http://www.chinahtml.com/systems/" target="_blank">服务器</a>内存即可保存此状态。很多 ASP.NET <a href="http://www.chinahtml.com/systems/" target="_blank">服务器</a>控件都使用视图状<br />态来保持在与页元素进行交互期间创建的设置，例如保存对数据进行分页时显示的当前页<br />。 <br /><br />然而使用视图状态也有一些缺点。首先，服务或请求页时，它都会增加页的总负载。对张<br />贴回<a href="http://www.chinahtml.com/systems/" target="_blank">服务器</a>的视图状态数据进行序列化或取消序列化时，也会发生额外的开销。最后，视<br />图状态会增加<a href="http://www.chinahtml.com/systems/" target="_blank">服务器</a>上的内存分配。<br /><br />几个<a href="http://www.chinahtml.com/systems/" target="_blank">服务器</a>控件有着过度使用视图状态的趋势，即使在并不需要的情况下也要使用它，其<br />中最著名的是 DataGrid。ViewState 属性的默认行为是启用，但是如果您不需要，则可以<br />在控件或页级别关闭。在控件内，只需将 EnableViewState 属性设置为 false，或者在页<br />中使用下列设置即可对其进行全局设置： <br /><br />&lt;%@ Page EnableViewState="false" %&gt;<br /><br />如果您不回发页，或者总是针对每个请求重新生成页上的控件，则应该在页级别禁用视图<br />状态。 <br /><br /><br />我为您讲述了一些我认为在编写高性能 ASP.NET 应用程序时有所帮助的技巧。正如我在本<br />文前面部分提到的那样，这是一个初步指南，并不是 ASP.NET 性能的最后结果。（有关改<br />善 ASP.NET 应用程序性能的信息，请参阅 Improving ASP.NET Performance。）只有通过<br />自己的亲身体验才能找出解决具体性能问题的最好方法。但是，在您的旅程中，这些技巧<br />应该会为您提供一些好的指南。在软件开发中，几乎没有绝对的东西；每个应用程序都是<br />唯一的。<br /><br />from: <a href="http://www.chinahtml.com/programming/8/2006/11622676777784_2.shtml">http://www.chinahtml.com/programming/8/2006/11622676777784_2.shtml</a><br /></p>
<img src ="http://www.blogjava.net/weidagang2046/aggbug/85980.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/weidagang2046/" target="_blank">weidagang2046</a> 2006-12-06 23:57 <a href="http://www.blogjava.net/weidagang2046/articles/85980.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于cookie的小总结</title><link>http://www.blogjava.net/weidagang2046/articles/85658.html</link><dc:creator>weidagang2046</dc:creator><author>weidagang2046</author><pubDate>Tue, 05 Dec 2006 11:38:00 GMT</pubDate><guid>http://www.blogjava.net/weidagang2046/articles/85658.html</guid><wfw:comment>http://www.blogjava.net/weidagang2046/comments/85658.html</wfw:comment><comments>http://www.blogjava.net/weidagang2046/articles/85658.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/weidagang2046/comments/commentRss/85658.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/weidagang2046/services/trackbacks/85658.html</trackback:ping><description><![CDATA[前两天看见有兄弟问cookie为什么删除不了,所以写了给小总结,希望对用cookie的各位兄弟有帮助<br />对于cookie,最主要的当然是读取和设置了,下面分两方面说明.<br />一、设置<br />Cookie是通过HttpServletResponse的addCookie方法加入到Set-Cookie应答头中的<br />例如：<br />Cookie userCookie = new Cookie("user", "admin"); <br />response.addCookie(userCookie);<br />和设置有关系的还有以下两个重要方法<br />1.setMaxAge<br />设置Cookie过期之前的时间，以秒计。如果不设置该值，则Cookie只在当前会话内有效，而且这些Cookie不会保存到磁盘上。<br />注意：删除cookie就是通过该方法实现的。将要删除的cookie的过期之前的时间指定为0就可以达到删除该cookie的目的。<br />2.setPath<br />设置Cookie适用的路径。如果不指定路径，Cookie将返回给当前页面(JSP页面或者Servlet的映射)所在目录及其子目录下的所有页面。<br />注意：<br />A：所有的cookie都是有路径的<br />B：该方法设置的路径为客户端路径，即“/”代表服务器根目录，而不是WEB应用根目录<br />C：该方法设置路径时，“/myWeb/”与“/myWeb”是不同的，要特别注意；前者可以关联到服务器的myWeb目录下，而或者则不可以。<br />D：该方法设置路径时，没有相对目录可言，即不论在哪个目录下设置setPath(“/myWeb/”)，该cookie都将关联到服务器的myWeb目录下(setPath(“/myWeb”)则不可以)，而不是当前目录的myWeb的子目录下；同样，设置setPath(“myWeb/”)和setPath(“myWeb”)也不能关联到当前目录的myWeb的子目录下<br />这里有个奇怪的例子，就是在一个web应用下设置的cookie可以在另一个web应用下获得（两个web应用在同一个服务器下）<br />目录结构：在服务器根目录上有web1和web2两个目录，在web1下有setcookie.jsp和getcookie.jsp、在web2下有getcookie.jsp<br />web1下的setcookie.jsp<br />&lt;%<br />Cookie userCookie = new Cookie("user", "admin"); <br />userCookie.setMaxAge(24*60*60);<br />userCookie.setPath("/web2/");<br />response.addCookie(userCookie);<br />%&gt;<br />web1下的getcookie.jsp<br />&lt;%<br />Cookie[] cookie = request.getCookies();<br />String user = new String();<br />if ( cookie != null ) {<br />for (int i = 0; i &lt; cookie.length; i++) {<br />Cookie myCookie = cookie[i];<br />if (myCookie.getName().equals("user")) {<br />user = myCookie.getValue();<br />}<br />}<br />}<br />out.println("user = " + user);<br />%&gt;<br />web2下的getcookie.jsp<br />&lt;%<br />Cookie[] cookie = request.getCookies();<br />String user = new String();<br />if ( cookie != null ) {<br />for (int i = 0; i &lt; cookie.length; i++) {<br />Cookie myCookie = cookie[i];<br />if (myCookie.getName().equals("user")) {<br />user = myCookie.getValue();<br />}<br />}<br />}<br />out.println("user = " + user);<br />%&gt;<br />先访问web1下的setcookie.jsp，然后分别访问web1和web2下面的getcookie.jsp文件，你会发现奇怪的现象，web1下的getcookie.jsp中user为空而web2下的getcookie.jsp中user却有值，这就实现了从一个web应用下设置的cookie在另一个web应用下获得。<br />大多数人删除cookie不成功都是因为目录原因。一个典型的原因是在某一个目录中设置了cookie（没有调用setPath方法）却在另一个目录中删除该cookie（其实是调用setMaxAge方法）<br /><br />二、读取<br />从客户端读取Cookie时调用的是HttpServletRequest的getCookies方法。该方法返回一个与HTTP请求头中的内容对应的Cookie对象数组。得到这个数组之后，一般是用循环访问其中的各个元素，调用getName检查各个Cookie的名字，直至找到目标Cookie。然后对这个目标Cookie调用getValue，根据获得的结果进行其他处理。<br />注意：若JSP和Servlet所在目录（Servlet为其映射目录）的父目录中有同名cookie，则request.getCookie()方法得到的Cookie数组中保存的是其父目录中的cookie的信息；<br /><br />from: <a href="http://www.cndiy8.com/data/web5409/20050311/20050311__3812885.html">http://www.cndiy8.com/data/web5409/20050311/20050311__3812885.html</a><img src ="http://www.blogjava.net/weidagang2046/aggbug/85658.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/weidagang2046/" target="_blank">weidagang2046</a> 2006-12-05 19:38 <a href="http://www.blogjava.net/weidagang2046/articles/85658.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一劳永逸的数据库编码解决方案</title><link>http://www.blogjava.net/weidagang2046/articles/85178.html</link><dc:creator>weidagang2046</dc:creator><author>weidagang2046</author><pubDate>Sun, 03 Dec 2006 05:22:00 GMT</pubDate><guid>http://www.blogjava.net/weidagang2046/articles/85178.html</guid><wfw:comment>http://www.blogjava.net/weidagang2046/comments/85178.html</wfw:comment><comments>http://www.blogjava.net/weidagang2046/articles/85178.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/weidagang2046/comments/commentRss/85178.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/weidagang2046/services/trackbacks/85178.html</trackback:ping><description><![CDATA[
		<p>　　<strong>问题提出</strong></p>
		<p>　　现在几乎所有的应用系统都无法避免使用数据库系统。在JAVA世界里访问数据库是一件非常轻松的事情，JDBC为JAVA应用程序访问数据库提供了一个统一的接口，通过使用JDBC接口开发者无需关心系统最终采用哪种数据库，因为JDBC仅仅是定义了访问几个JAVA的接口类，具体的实现是由数据库厂商提供的，这种做法其实与其他数据库连接方式例如ODBC是类似的。但是在实际的应用过程中，开发者发现离JDBC设计的初衷还是有一定距离，就比如说在存储字符串时的编码问题，我想很多开发者都会遇见这个问题，倒不是因为说解决它有什么技术方面的难度，而是它的的确确非常繁琐。我们必须在每次写入或者读出字符串的时候进行编码和反编码处理；或者说我们可以写一个方法可以进行编码处理的，但又必须在每次数据库操作的时候调用，虽然调用很简单，可是我非得这样吗？要是忘了编码那又要DEBUG了。当然你可能觉得这并没有什么，或者你可能很勤快，喜欢写大量重复的代码，可是你难道没有觉得这种繁琐的工作正在浪费你过于宝贵的青春吗？停止你的键盘输入，让我们来解决这个问题吧！</p>
		<p>　　<strong>解决思路</strong></p>
		<p>　　在传统的应用程序中数据库操作部分我们可以想象成两层，如图所示：一个是数据库的"连接池"，另外一个业务数据操作层。在这里数据库的连接池是广义的，你可以把JDBC中的DriverManager也当成是连接池，具体的意思就是我们可以通过这层来获取到指定数据库的连接而不去关心它是怎么获取的。如果这个时候数据库系统（有如Informix，SQL Server）要求对字符串进行转码才能存储（例如最常见的GBK-&gt;ISO8859_1转码），那我们就必须在业务数据操作层来进行，这样有多少业务数据操作我们就要做多少编码转码的工作，太麻烦了，代码中充斥中大量重复的内容。本文提出的解决方案就是利用对获取到的数据库连接实例进行二次封装，也就是在数据库连接池与业务数据操作层之间加入了连接封装层，当然了，我们也完全可以直接将连接封装集成到数据库连接池内部。关于连接池的实现请参照我的另外一篇文章《使用JAVA动态代理实现数据库连接池》</p>
		<p align="center">
				<img height="173" src="http://www.javafan.net/uploadfiles/20041212111952100.gif" width="247" border="0" />
				<br />图一</p>
		<p>　　我们知道进行编码和转码工作都是集中在JDBC的两个接口PreparedStatement和ResultSet上进行的，主要涉及PreparedStatement的setString方法以及ResultSet的getString方法。前面我们讲过需要加入一个连接封装层来对数据库连接实例进行二次封装，但是怎么通过这个封装来改变PreparedStatement和ResultSet这两个接口的行为呢？这个问题其实也很简单，因为PreparedStatement接口必须通过Connection接口来获取实例，而ResultSet接口又必须从Statement或者PreparedStatement接口来获取实例，有了这样的级联关系，问题也就迎刃而解了。还是利用我在文章《使用JAVA动态代理实现数据库连接池》中使用的动态接口代理技术。首先我们设计Connection接口的代理类_Connection，这个代理类接管了Connection接口中所有可能获取到Statement或者PreparedStatement接口实例的方法，例如：prepareStatement和createStatement。改变这两个方法使之返回的是经过接管后的Statement或者PreparedStatement实例。通过对于Statement接口也有相应的代理类_Statement，这个代理类接管用于获取ResultSet接口实例的所有方法，包括对setString方法的接管以决定是否对字符串进行编码处理。对于接口ResultSet的接管类_ResultSet就相应的比较简单，它只需要处理getString方法即可。</p>
		<p>　　<strong>关键代码</strong></p>
		<p>　　前面我们大概介绍了这个解决方案的思路，下面我们给出关键的实现代码包括Connection的代理类，Statement的代理类，ResultSet的代理类。这些代码是在原来关于数据库连接池实现的基础上进行扩充使之增加对自动编码处理的功能。有需要源码打包的可以通过电子邮件跟我联系。</p>
		<p>_Connection.java</p>
		<p style="BACKGROUND: #eeeeee">/* <br /> * Created on 2003-10-23 by Liudong <br /> */<br />package lius.pool;<br />import java.sql.*;<br />import java.lang.reflect.*;<br /><br />/*<br /> * <br /> * 数据库连接的代理类 <br /> * @author Liudong <br /> */<br /> class _Connection implements InvocationHandler{<br /> private Connection conn = null;<br /> private boolean coding = false;<br /> //指定是否进行字符串转码操作<br /> _Connection(Connection conn, boolean coding){<br />  this.conn = conn;<br />  this.coding = coding;<br />  initConnectionParam(this.conn);<br /> <br /> }<br /> <br /> /**  <br />  * Returns the conn.  <br />  * @return Connection  <br />  */<br />  <br /> public Connection getConnection() {<br />  Class[] interfaces = conn.getClass().getInterfaces();<br />  if(interfaces==null||interfaces.length==0){<br />   interfaces = new Class[1];<br />   interfaces[0] = Connection.class;<br />  <br />  }<br /> <br />  Connection conn2 = (Connection)Proxy.newProxyInstance( conn.getClass().getClassLoader(), interfaces,this);<br />  return conn2;<br /> <br /> }<br /> <br /> /**  <br />  * @see java.lang.reflect.InvocationHandler#invoke  <br />  */<br /> public Object invoke(Object proxy, Method m, Object[] args) throws Throwable { <br />  String method = m.getName();<br />  //调用相应的操作<br />  Object obj = null;<br />  try{<br />   obj = m.invoke(conn, args);<br />   //接管用于获取语句句柄实例的方法<br />   if((CS.equals(method)||PS.equals(method))&amp;&amp;coding) <br />    return new _Statement((Statement)obj,true).getStatement();<br />  <br />  } catch(InvocationTargetException e) {<br />   throw e.getTargetException();<br />  }<br />  return obj;<br /> }<br /> <br /> private final static String PS = "prepareStatement";<br /> private final static String CS = "createStatement";<br />}</p>
		<p>
				<br />_Statement.java</p>
		<p style="BACKGROUND: #eeeeee">/* <br /> * Created on 2003-10-23 by Liudong <br /> */<br /> <br />package lius.pool;<br />import java.sql.*;<br />import java.lang.reflect.*;<br /><br />/** <br /> * 数据库语句对象实例的代理类 <br /> * @author Liudong <br /> */<br />class _Statement implements InvocationHandler{ <br /> private Statement statement ; //保存所接管对象的实例 <br /> private boolean decode = false; //指定是否进行字符串转码 <br /><br /> public _Statement(Statement stmt,boolean decode) { <br />  this.statement = stmt;<br />  this.decode = decode;<br /> }<br /> <br /> /**  <br />  * 获取一个接管后的对象实例  <br />  * @return  <br />  */<br /> public Statement getStatement() {<br />  Class[] interfaces = statement.getClass().getInterfaces();<br />  if(interfaces==null||interfaces.length==0){ <br />   interfaces = new Class[1];<br />   interfaces[0] = Statement.class;<br />  } <br />  Statement stmt = (Statement)Proxy.newProxyInstance(   <br />   statement.getClass().getClassLoader(), <br />   interfaces,this);<br />  return stmt;<br /> <br /> }<br /> <br /> /**  <br />  * 方法接管  <br />  */<br /> public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {<br />  String method = m.getName(); //接管setString方法 <br />  if(decode &amp;&amp; SETSTRING.equals(method)) {<br />   try{<br />    String param = (String)args[1];<br />    if(param!=null)<br />     param = new String(param.getBytes(),"8859_1");<br />    return m.invoke(statement,new Object[]{args[0],param});<br />   } catch(InvocationTargetException e){<br />    throw e.getTargetException();<br />        <br />   }  <br />  }<br />  <br />  //接管executeQuery方法<br />  <br />  if(decode &amp;&amp; EXECUTEQUERY.equals(method)){<br />   try{<br />    ResultSet rs = (ResultSet)m.invoke(statement,args);<br />    return new _ResultSet(rs,decode).getResultSet();<br />   <br />   }catch(InvocationTargetException e){<br />    throw e.getTargetException();<br />    }  <br />  }<br />  <br />  try{<br />   return m.invoke(statement, args);<br />  } catch(InvocationTargetException e) {<br />   throw e.getTargetException();<br />   } <br /> }<br /> //两个要接管的方法名<br /> <br /> private final static String SETSTRING = "setString";<br /> private final static String EXECUTEQUERY = "executeQuery";<br />}</p>
		<p>
				<br />_ResultSet.java</p>
		<p style="BACKGROUND: #eeeeee">/* <br /> * Created on 2003-10-23 by Liudong <br /> */<br /> <br />package lius.pool;<br />import java.sql.ResultSet;<br />import java.lang.reflect.InvocationHandler;<br />import java.lang.reflect.InvocationTargetException;<br />import java.lang.reflect.Method;<br />import java.lang.reflect.Proxy;<br /><br />/** <br /> * 数据库结果集的代理类 <br /> * @author Liudong <br /> */<br /> class _ResultSet implements InvocationHandler{ <br /> private ResultSet rs = null;<br /> private boolean decode = false;<br /> <br /> public _ResultSet(ResultSet rs,boolean decode) {<br />  this.rs = rs;<br />  this.decode = decode;<br /> }<br /> <br /> public ResultSet getResultSet(){ <br />  Class[] interfaces = rs.getClass().getInterfaces();<br />  if(interfaces==null||interfaces.length==0){<br />   interfaces = new Class[1];<br />   interfaces[0] = ResultSet.class;  <br />  }<br /> <br />  ResultSet rs2 = (ResultSet)Proxy.newProxyInstance(rs.getClass().getClassLoader(),interfaces,this);<br />  return rs2;<br /> <br /> }<br /><br /> /**  <br />  * 结果getString方法  <br />  */<br /> public Object invoke(Object proxy, Method m, Object[] args) throws Throwable { <br />  String method = m.getName();<br />  if(decode &amp;&amp; GETSTRING.equals(method)){<br />   try{<br />    String result = (String)m.invoke(rs,args);<br />    if(result!=null)     <br />     return new String(result.getBytes("8859_1"));<br />    return null;<br />   <br />   }catch(InvocationTargetException e){<br />    throw e.getTargetException();<br />    }<br />   <br />  } <br />  <br />  try{<br />   return m.invoke(rs, args);<br />  }catch(InvocationTargetException e){<br />   throw e.getTargetException();<br />  }<br /> }<br /> <br /> private final static String GETSTRING = "getString";<br /><br />}</p>
		<p>　　现在我们已经把三个接口的代理类做好了，下一步就是怎么来使用这三个类。其实对于使用者来讲并不需要关心三个类，只需要了解_Connection就可以了，因为另外两个是_Connection直接调用的。为了使用_Connection我们必须传入两个参数，第一个是数据库实际的数据库连接实例，另外一个是布尔值代表是否进行转码处理。我们必须先通过实际的情况获取到数据库连接后再传入_Connection的构造函数作为参数，下面例子告诉你如何来使用_Connection这个类：</p>
		<p style="BACKGROUND: #eeeeee">　　Connection conn = getConnection(); //获取数据库连接<br />　　boolean coding = false; //从配置或者其他地方读取是否进行转码的配置 <br />　　//接管数据库连接实例 <br />　　_Connection _conn = new _Connection(conn,coding);<br />　　//获得接管后的数据库连接实例，以后直接使用conn2而不是conn <br />　　Connection conn2 = _conn.getConnection();</p>
		<p>　　因为对一个应用系统来讲，数据库连接的获取必然有统一的方法，在这个方法中加入对连接的接管就可以一劳永逸的解决数据库的编码问题。</p>
		<p>　　<strong>性能比较</strong></p>
		<p>　　功能没有问题了，开发者接下来就会关心性能的问题，因为在进行一些对响应速度要求很高或者大数据量的处理情况下性能就成为一个非常突出的问题。由于JAVA中的动态接口代理采用的是反射（Reflection）机制，同时又加入我们自己的一些代码例如方法名判断，字符串转码等操作因此在性能上肯定比不上直接使用没有经过接管的数据库连接。但是这点性能上的差别是不是我们可以忍受的呢，为此我做了一个试验对二者进行了比较：</p>
		<p>　　测试环境简单描述：</p>
		<p>　　使用ACCESS数据库，建两张结构一样的表，计算从获取连接后到插入数据完毕后的时间差，两个程序（直连数据库和使用连接接管）都进行的字符串的转码操作。</p>
		<p>　　测试结果：</p>
		<table cellspacing="1" cellpadding="1" width="500" align="center" bgcolor="#999999" border="0">
				<tbody>
						<tr bgcolor="#ffffff">
								<td align="middle" height="25">插入记录数</td>
								<td align="middle">直连数据库程序耗时 单位：ms</td>
								<td align="middle">使用连接接管程序耗时</td>
								<td align="middle">性能比较</td>
						</tr>
						<tr bgcolor="#ffffff">
								<td height="25">1000</td>
								<td>2063</td>
								<td>2250</td>
								<td>9.0%</td>
						</tr>
						<tr bgcolor="#ffffff">
								<td height="25">5000</td>
								<td>8594</td>
								<td>8359</td>
								<td>-2.7%</td>
						</tr>
						<tr bgcolor="#ffffff">
								<td height="25">10000</td>
								<td>16750</td>
								<td>17219</td>
								<td>2.8%</td>
						</tr>
						<tr bgcolor="#ffffff">
								<td height="25">15000</td>
								<td>22187</td>
								<td>23000</td>
								<td>3.6%</td>
						</tr>
						<tr bgcolor="#ffffff">
								<td height="25">20000</td>
								<td>27031</td>
								<td>27813</td>
								<td>2.9%</td>
						</tr>
				</tbody>
		</table>
		<p>　　从上面这张测试结果表中来看，二者的性能的差别非常小，尽管在两万条数据的批量插入的时候时间差别也不会多于一秒钟，这样的结果应该说还是令人满意的，毕竟为了程序良好的结构有时候牺牲一点点性能还是值得的。</p>
		<p>　　本文算是我之前文章《使用JAVA动态代理实现数据库连接池》中提出的数据库连接池实现的进一步完善，同样使用动态接口代理的技术来解决数据库编码的问题。JAVA的这个高级技术可以用来解决许多实际中非常棘手的问题，就像本文提到的编码问题的处理以及数据库连接池的实现，同时在WEB开发框架的实现上也有非常大的作为。欢迎对这方面感兴趣的朋友来信共同来研究。<br /><br />from: <a href="http://www.javafan.net/article/20041212111952983.html">http://www.javafan.net/article/20041212111952983.html</a></p>
<img src ="http://www.blogjava.net/weidagang2046/aggbug/85178.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/weidagang2046/" target="_blank">weidagang2046</a> 2006-12-03 13:22 <a href="http://www.blogjava.net/weidagang2046/articles/85178.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java中关于汉字问题原理深入谈 </title><link>http://www.blogjava.net/weidagang2046/articles/85023.html</link><dc:creator>weidagang2046</dc:creator><author>weidagang2046</author><pubDate>Sat, 02 Dec 2006 07:29:00 GMT</pubDate><guid>http://www.blogjava.net/weidagang2046/articles/85023.html</guid><wfw:comment>http://www.blogjava.net/weidagang2046/comments/85023.html</wfw:comment><comments>http://www.blogjava.net/weidagang2046/articles/85023.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/weidagang2046/comments/commentRss/85023.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/weidagang2046/services/trackbacks/85023.html</trackback:ping><description><![CDATA[
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">一、主题：关于JAVA的中文问题 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">JAVA的中文问题比较突出，主要表现在控制面板输出，JSP页面输出和数据库访问上。本文尽量避开字体问题，而只谈编码。通过本文，你可以了解JAVA中文问题的由来，问题的解决方法，其中提了一下用JDBC访问数据库的方法。 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">
				</font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">二、问题描述： </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">1）在中文W2000中文窗口编译和运行，用的是国际版的JDK，连接的是中文W2000下的Cp936编码的SQL SERVER数据库： </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">
				</font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">J:\exercise\demo\encode\HelloWorld&gt;make </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">Created by XCompiler. PhiloSoft All Rights Reserved. </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">Wed May 30 02:54:45 CST 2001 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">
				</font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">J:\exercise\demo\encode\HelloWorld&gt;run </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">Created by XRunner. PhiloSoft All Rights Reserved. </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">Wed May 30 02:51:33 CST 2001 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">中文 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">[B@7bc8b569 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">[B@7b08b569 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">[B@7860b569 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">中文 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">中文 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">???? </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">中文 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">中文 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">???? </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">?? </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">?? </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">?? </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">
				</font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">2）如果在中文W2000的西文窗口（编码为437）下编译，用JAVA运行则由于无字体而无法正常显示，如果象上面一样在中文W2000的中文窗口运行，输出为： </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">
				</font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">J:\exercise\demo\encode\HelloWorld&gt;run </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">Created by XRunner. PhiloSoft All Rights Reserved. </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">Wed May 30 02:51:33 CST 2001 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">???? </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">[B@7bc0b66a </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">[B@7b04b66a </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">[B@7818b66a </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">???? </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">???? </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">???? </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">???? </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">???? </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">???? </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">中文 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">中文 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">???? </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">
				</font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">三）分析 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">
				</font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">1）出现有乱码（也就是？）。由于只出现？而没出现小方框，说明只是编码有问题，而不是字体问题。 在编码中，如果从一种字符集转换到别一种字符集，比较典型的是从GB2312转换到ISO8859_1（即ASCII），那么很多汉字（半个汉字）是无法映射到西文字符中去的，在这种情形下，系统就把这些字符用？代替。同样，也存在小字符集无法到大字符集的情况，具体原因这里就不详谈了。 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">
				</font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">2）出现了中文环境编译，中文环境运行时汉字显示有正确也有不正确的地方，同样，在西文环境下编译，在中文环境下运行时也出现类似情况。这是由于自动（默认）或手工（也就new String(bytes[,encode])和bytes getBytes([encode])）转码的结果。 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">
				</font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">2.1）在JAVA源文件--&gt;JAVAC--&gt;Class--&gt;Java--&gt;getBytes()--&gt;new String()--&gt;显示的过程中，每一步都有编码的转换过程，这个过程总是存在的，只是有的时候用默认的参数进行。下面我们一步一步分析为什么出现上面的情形。 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">
				</font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">2.2）这里是源代码： </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">
				</font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">HelloWorld.java: </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">------------------------ </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">public class HelloWorld </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">{ </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">public static void main(String[] argv){ </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">try{ </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">System.out.println("中文");//1 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">System.out.println("中文".getBytes());//2 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">System.out.println("中文".getBytes("GB2312"));//3 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">System.out.println("中文".getBytes("ISO8859_1"));//4 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">
				</font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">System.out.println(new String("中文".getBytes()));//5 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">System.out.println(new String("中文".getBytes(),"GB2312"));//6 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">System.out.println(new String("中文".getBytes(),"ISO8859_1"));//7 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">
				</font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">System.out.println(new String("中文".getBytes("GB2312")));//8 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">System.out.println(new String("中文".getBytes("GB2312"),"GB2312"));//9 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">System.out.println(new </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">
				</font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">String("中文".getBytes("GB2312"),"ISO8859_1"));//10 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">
				</font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">System.out.println(new String("中文".getBytes("ISO8859_1")));//11 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">System.out.println(new </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">
				</font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">String("中文".getBytes("ISO8859_1"),"GB2312"));//12 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">System.out.println(new </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">
				</font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">String("中文".getBytes("ISO8859_1"),"ISO8859_1"));//13 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">} </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">catch(Exception e){ </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">e.printStackTrace(); </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">} </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">} </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">} </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">
				</font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">为了方便起见，在每个转换的后面加了操作序号，分别为1,2,...,13。 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">
				</font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">2.3）需要说明的是，JAVAC是以系统默认编码读入源文件，然后按UNICODE进行编码的。在JAVA运行的时候，JAVA也是采用UNICODE编码的，并且默认输入和输出的都是操作系统的默认编码，也就是说在new String(bytes[,encode])中，系统认为输入的是编码为encode的字节流，换句话说，如果按encode来翻译bytes才能得到正确的结果，这个结果最后要在JAVA中保存，它还是要从这个encode转换成Unicode，也就是说有bytes--&gt;encode字符--&gt;Unicode字符的转换；而在String.getBytes([encode])中，系统要做一个Unicode字符--&gt;encode字符--&gt;bytes的转换。 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">
				</font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">在这个例子中，除那个英文窗口编码的时候除外，其实情形下默认编码都是GBK（在本例中，我们暂且把GBK和GB2312等同看待）。 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">
				</font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">2.4）由于在未指明在上面的两个用代码实现的转换中，如果未指定encode，系统将采用默认的编码（这里为GBK），我们认为上面的5,6,7和8,9,10是一样的，8和9、11和12也是一样的，所以我们在讨论中将只讨论1,9,10,12,13。其中的2,3,4只是用于测试，不在我们的讨论范围之内。 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">
				</font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">2.5）下面我们来跟踪程序中的“中”字的转换历程，我们先说在中文窗口下作的编译和运行过程，注意在下面的字母下标中，我有意识地使用了一些数字，以表示相同，相异还是相关2.5.1)我们先以上面的13个代码段中的的代码9为例： </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">
				</font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">步骤 内容 地点 说明 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">01： C1 HelloWorld.java C1泛指一个GBK字符 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">02： U1 JAVAC读取 U1泛指一个Unicode字符 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">03： C1 getBytes()第一步 JAVA先和操作系统交流 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">04： B1,B2 getBytes()第二步 然后返回字节数组 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">05： C1 new String()第一步 JAVA先和操作系统交流 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">06： U1 new String()第二步 然后返回字符 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">07： C1 println(String) 能显示“中”字，内容和原来的相同 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">
				</font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">2.5.2）然后再以代码段10为例，我们注意到只是： </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">
				</font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">步骤 内容 地点 说明 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">01： C1 HelloWorld.java C1泛指一个GBK字符 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">02： U1 JAVAC读取 U1泛指一个Unicode字符 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">03： C1 getBytes()第一步 JAVA先和操作系统交流 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">04： B1,B2 getBytes()第二步 然后返回字节数组 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">05： C3,C4 new String()第一步 JAVA先和操作系统交流，这时解析错误 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">06： U5,U6 new String()第二步 然后返回字符 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">07： C3,C4 println(String) 由于中字给分成了两半，在ISO8859_1中刚好也没有字符 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">
				</font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">能映射上，所以显示为“??”。在上面的示例中， </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">“中文”两个字就显示为“？？？？” </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">2.5.3）在完全中文模式下的其它情形类似，我就不多说了 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">
				</font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">2.6）我们接着看为什么在西文DOS窗口下编译出来的类在中文窗口下也出现类似情形，特别是为什么居然有的情形下还能正确显示汉字。 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">
				</font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">2.6.1）我们还是先以代码段9为例： </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">
				</font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">步骤 内容 地点 说明 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">01： C1C2 HelloWorld.java C1C2分别泛指一个ISO8859_1字符，“中”字被拆开 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">02： U3U4 JAVAC读取 U1U2泛指一个Unicode字符 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">03： C5C6 getBytes()第一步 JAVA先和操作系统交流，这时解析错误 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">04： B5B6B7B8 getBytes()第二步 然后返回字节数组 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">05： C5C6 new String()第一步 JAVA先和操作系统交流 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">06： U3U4 new String()第二步 然后返回字符 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">07： C5C6 println(String) 虽然同是两个字符，但已不是最初的“两个ISO8859_1字 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">
				</font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">符”，而是“两个BGK字符”，“中”显示成了“？？” </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">而“中文”就显示成了“？？？？” </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">
				</font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">2.6.2）下面我们以代码段12为例，因为它能正确显示汉字 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">
				</font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">步骤 内容 地点 说明 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">
				</font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">01： C1C2 HelloWorld.java C1C2分别泛指一个ISO8859_1字符，“中”字被拆开 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">02： U3U4 JAVAC读取 U1U2泛指一个Unicode字符 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">03： C1C2 getBytes()第一步 JAVA先和操作系统交流（注意还是正确的哦！） </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">04： B5B6 getBytes()第二步 然后返回字节数组（这是很关键的一步！） </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">05： C12 new String()第一步 JAVA先和操作系统交流（这是更关键的一步，JAVA已经知道B5B6要解析成一个汉字！） </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">06： U7 new String()第二步 然后返回字符（真是一个项两！U7包含了U3U4的信息） </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">07： C12 println(String) 这就原来的“中”字，很委屈被JAVAC冤枉了一回，不过被程序员拨乱反正了一下！当然，“中文”两个字都能正确显示了！ </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">
				</font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">3）那为什么有的时候用JDBC的 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">new String(Recordset.getBytes(int)[,encode]) </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">Recordset.getSting(int) </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">Recordset.setBytes(String.getBytes([encode])) </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">和 </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">Recordset.setString(String) </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">的时候会出现乱码了呢？ </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">
				</font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font face="Courier New" size="2">其实问题就出现在编写JDBC的的也考虑了编码问题，它从数据库读取数据后，可能自作主张做了一个从GB2312（默认编码）到Unicode的转换，我的这个WebLogic For SQL Server的JDBC Driver就是这样的，当我读字串的时候，发出读到的不是正确的汉字，可恨的是我却可以直接写汉字字串，这让人多少有点难以接受！ </font>
		</p>
		<p style="TEXT-INDENT: 2em">
				<font size="2">
						<font face="Courier New">也就是说，我们不得不在读或写的时候进行转码，尽管这个转码有的时候不是那么明显，这是因为我们使用了默认的编码进行转码。JDBC Driver所做的操作，我们只有进入到源代码内部才能清楚，不是吗？<br /><br />from: </font>
						<a href="http://java.ccidnet.com/art/3737/20060605/571079_1.html">
								<font face="Courier New">http://java.ccidnet.com/art/3737/20060605/571079_1.html</font>
						</a>
				</font>
		</p>
<img src ="http://www.blogjava.net/weidagang2046/aggbug/85023.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/weidagang2046/" target="_blank">weidagang2046</a> 2006-12-02 15:29 <a href="http://www.blogjava.net/weidagang2046/articles/85023.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>URL中文参数传递问题</title><link>http://www.blogjava.net/weidagang2046/articles/84943.html</link><dc:creator>weidagang2046</dc:creator><author>weidagang2046</author><pubDate>Fri, 01 Dec 2006 12:43:00 GMT</pubDate><guid>http://www.blogjava.net/weidagang2046/articles/84943.html</guid><wfw:comment>http://www.blogjava.net/weidagang2046/comments/84943.html</wfw:comment><comments>http://www.blogjava.net/weidagang2046/articles/84943.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/weidagang2046/comments/commentRss/84943.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/weidagang2046/services/trackbacks/84943.html</trackback:ping><description><![CDATA[
		<p>(1)确定JSP页面头部是否有:&lt;%@ page contentType="text/html; charset=GBK" %&gt;<br />(2)用这个转码:<br />     String param= new String(request.getParameter("param").getBytes("ISO-8859-1"), "GBK");<br />(3)添加filter字符过滤器</p>
		<p>(4)如果是通过"a.jsp?param=中文"传递参数,则需要:<br />     a.在传参数之前先把参数进行转码:java.net.URLEncoder.encode(param);<br />       取值用java.net.URLDncoder.decode(param);再转回中文<br />     b.在你的Tomcat目录--&gt;conf目录--&gt;server.xml里找出这段:<br />       &lt;Connector <br />         port="8080"               maxThreads="150" minSpareThreads="25" maxSpareThreads="75"<br />               enableLookups="false" redirectPort="8443" acceptCount="100"<br />               debug="0" connectionTimeout="20000" <br />               disableUploadTimeout="true" &lt;!--在里边加上这个参数--&gt;URIEncoding="gb2312"/&gt; <br /><br />from: <a href="http://www.yuanma.org/data/2006/0911/article_1503.htm">http://www.yuanma.org/data/2006/0911/article_1503.htm</a></p>
<img src ="http://www.blogjava.net/weidagang2046/aggbug/84943.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/weidagang2046/" target="_blank">weidagang2046</a> 2006-12-01 20:43 <a href="http://www.blogjava.net/weidagang2046/articles/84943.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>url传递中文的解决方案总结 </title><link>http://www.blogjava.net/weidagang2046/articles/84941.html</link><dc:creator>weidagang2046</dc:creator><author>weidagang2046</author><pubDate>Fri, 01 Dec 2006 12:40:00 GMT</pubDate><guid>http://www.blogjava.net/weidagang2046/articles/84941.html</guid><wfw:comment>http://www.blogjava.net/weidagang2046/comments/84941.html</wfw:comment><comments>http://www.blogjava.net/weidagang2046/articles/84941.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/weidagang2046/comments/commentRss/84941.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/weidagang2046/services/trackbacks/84941.html</trackback:ping><description><![CDATA[1.设置web.config文件。<br />&lt;system.web&gt; <br />...... <br />&lt;globalization requestEncoding="gb2312" responseEncoding="gb2312" culture="zh-CN" fileEncoding="gb2312" /&gt; <br />...... <br />&lt;/system.web&gt; <br /><br />或者：<br />aspx文件中:<br />&lt;meta http-equiv="Content-Type" content="text/html; charset=gb2312"&gt;<br /><br />2.传递中文之前，将要传递的中文参数进行编码，在接收时再进行解码。 <br />&gt;&gt; 进行传递 <br />string Name = "中文参数"; <br />Response.Redirect("B.aspx?Name="+Server.UrlEncode(Name)); <br /><br />&gt;&gt; 进行接收 <br />string Name = Request.QueryString["Name"]; <br />Response.Write(Server.UrlDecode(Name)); <br />或者：<br /><br />NavigateURL='&lt;%# "WebForm2.aspx?Singer=" + HttpUtility.UrlEncode("中国人", System.Text.Encoding.GetEncoding("GB2312")) %&gt;'<br /><br /><br />3.如果是从 .HTML 文件向 .Aspx 文件进行传递中文参数的话（即不从后台用 Redirect()方法进行 Url 转换）。一样要将传递的中文参数进行编码，在接收时再进行解码。 <br />&gt;&gt; 进行传递 <br />&lt;script language="JavaScript"&gt; <br />function GoUrl() <br />{ <br />var Name = "中文参数"; <br />location.href = "B.aspx?Name="+escape(Name); <br />} <br />&lt;/script&gt; <br />&lt;body onclick="GoUrl()"&gt; <br />&gt;&gt; 进行接收 <br />string Name = Request.QueryString["Name"]; <br />Response.Write(Server.UrlDecode(Name)); <br /><br />一般来说。设置web.config文件就可以了。但是如果你用 JavaScript 调用 webservice 方法的话（往webservice里面传递中文参数）。设置 web.config 文件好象无效。 <br /><br />————————————————————<br />在html中实现编解码：<br /><br />&lt;script language="javascript"&gt;<br />function openUrl(src)<br />{<br />var strUrl=escape(src);<br />window.open(strUrl);<br />}<br /><br /><br />function change_url(src)<br />{<br />document.location.href=escape(src);<br />}<br /><br />&lt;/script&gt; <br /><br />在新窗口保存<br />&lt;a href='javascript:openUrl("css/20040603123628交易中心烟叶网上集中交易系统合同.doc");' &gt;20040603123628交易中心网上集中交易系统合同&lt;/a&gt;<br /><br /><br />当前位置保存，无闪烁。<br />&lt;a href="#" onclick=javascript:change_url("css/20040603123628交易中心烟叶网上集中交易系统合同.doc")&gt;20040603123628交易中心网上集中交易系统合同&lt;/a&gt;<br /><br />注意：路径中的斜线是：“/”，而不是“\”，否则也不行啊。<br /><br /><br /><br /><br />－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－<br />前一阵遇到在做.net Web开发时，碰到一个很奇怪的问题，就是Url中，如果将中文字符作为参数值传递时，QueryString得到的值可能会出错。简单的说，比如下面这个Url：<br />UrlParmTest.aspx?parm1=中国&amp;parm2=中国人<br />在Request.QueryString时，parm1和parm2得到都是"中国"，显然出现了问题，可是在某些情况下却是正常的。<br /><br />如果请求不是直接通过URL，而使用Response.Redirect在服务器端操作，没有遇到过类似的问题。<br /><br />当时我想中文是双字节编码，可能传递的时候就是有不确定性，还是用英文好。<br /><br />可是为什么在Server端Redirect就是正常的，问题在哪里呢？<br /><br />：<br />如果在.cs文件中设置中文参数，请在中文参数外使用Server.UrlEncode("中文")对中文进行Encode<br />如果在.aspx文件中设置，请使用&lt;%=Server.UrlEncode("中文")%&gt;进行Encode<br />在QueryString时，不用再进行Decode，可以获得正常的中文字符串<br /><br />下面是给出的一些解释：<br />UrlEncode把一些多字节字符转换成url里允许的单字节字符，本来浏览器就会自动做的，但是目前确实存在一些问题，所以自己再Encode一下，在接受端会自动对Url进行Decode。<br /><br />我想Response.Redirect可能可以确保作Encode的工作，所以没有问题。<br /><br />from: <a href="http://blog.iecn.net/article/html/tid-870.html">http://blog.iecn.net/article/html/tid-870.html</a><img src ="http://www.blogjava.net/weidagang2046/aggbug/84941.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/weidagang2046/" target="_blank">weidagang2046</a> 2006-12-01 20:40 <a href="http://www.blogjava.net/weidagang2046/articles/84941.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>解决Tomcat 5.0.19中文参数传递问题</title><link>http://www.blogjava.net/weidagang2046/articles/84939.html</link><dc:creator>weidagang2046</dc:creator><author>weidagang2046</author><pubDate>Fri, 01 Dec 2006 12:38:00 GMT</pubDate><guid>http://www.blogjava.net/weidagang2046/articles/84939.html</guid><wfw:comment>http://www.blogjava.net/weidagang2046/comments/84939.html</wfw:comment><comments>http://www.blogjava.net/weidagang2046/articles/84939.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/weidagang2046/comments/commentRss/84939.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/weidagang2046/services/trackbacks/84939.html</trackback:ping><description><![CDATA[
		<span class="javascript" id="text44042">實際運用 Tomcat 5.0.19，我們了解在不修改 Tomcat 原始碼的狀況下，使用者透過 Form submit 的資料將一律以 ISO8859-1 處理，程式設計師必須自行將字串將轉換為 Big5(繁體中文) or GB2312/GBK(簡體中文)，我們在應用程式中，對所有的 request.getParameter("xx"); 作了 toBig5String() 的處理，理論上，所有的中文問題應該不會出現才對，結果，還是發現某些狀況下，中文還是變成亂碼！ <br /><br />經過分析整理，我們發現問題出在 QueryString 的解析，以前在 Tomcat 4.x 時代，無論 SUBMIT 時採用 GET or POST，Tomcat server 對 parameters 的處理都採用相同的編碼，但在 Tomcat 5.x 版，不知何故，卻將 QueryString 的解析獨立出來，目前確認，Form 的 Method 採用 GET 及直接將參數寫在 URL 上的中文，上傳到 Tomcat 時，無論如何轉碼，都會變成亂碼，那怕你事先作過 URLEncode 也一樣。 <br /><br />網站上，有人針對這個問題，建議將所有中文改採用 base64 編碼，到了 server 上，程式將自行土 base64 decode 回來，確保中文不會發生問題。這樣作法當然可以解決這個問題，但是所有網頁變成限定要採用 POST，且程式設計師要隨時分清楚，那個參數是採用 GET 上傳，那個參數是採用 POST 上傳，然後再針對不同的方式採用不同的解析，這樣的程式一點兒移植性都沒有，更別提跨平台、跨國際語言了。 <br /><br />研究 Tomcat 的文件及原始碼，我們找到了問題所在及解決的方法，只有按著以下的作法，才能使 Form submit 的資料完全按著 ISO8859-1 的編碼，當然，若是全照著 Tomcat 的文件說明去作，肯定還是不行，你還是得加上這個參數到 server.xml 中才行。 <br /><br />解決方案 <br /><br />請先研究 $TOMCAT_HOME/webapps/tomcat-docs/config/http.html 這個說明檔，擷錄重點如下： <br /><b>URIEncoding</b>：This specifies the character encoding used to decode the URI bytes, after %xx decoding the URL. If not specified, ISO-8859-1 will be used. <br /><br /><b>useBodyEncodingForURI</b>：This specifies if the encoding specified in contentType should be used for URI query parameters, instead of using the URIEncoding. This setting is present for compatibility with Tomcat 4.1.x, where the encoding specified in the contentType, or explicitely set using Request.setCharacterEncoding method was also used for the parameters from the URL. The default value is false. <br /><br />上述二個 Tomcat 參數，是設定在 server.xml 中的 http &lt;Connector /&gt; 區塊，要解決 QueryString 中文變成亂碼的問題，你必須至少設定這二個參數其中之一。 <br />URIEncoding 請設定為 URIEncoding="ISO-8859-1" 指定為 "ISO-8859-1" 編碼，讓 QueryString 的字元編碼與 post body 相同。 <br />useBodyEncodingForURI 這是用來相容 Tomcat 4.x 版的，設定的值是 "true" or "false"，意思是指 "要不要讓 QueryString 與 POST BODY 採用相同的字元編碼 ?"，若是設成 true，那也可達到 "ISO-8859-1" 編碼的需求。 <br />建議，採用 URIEncoding 的設定，畢竟 useBodyEncodingForURI 的作法是為了相容 Tomcat 4.X。不過若照原文的說明，理論上這二個參數都不設，Tomcat 也該採用 "ISO-8859-1" 的編碼，那為什麼還是會有問題呢 ? 我們由 Tomcat Source Code 來看就清楚了。 <br /><table class="java" cellspacing="1" cellpadding="3" bgcolor="#999999" border="0"><tbody><tr><td valign="top" align="left" width="1" bgcolor="#dddddd"><pre><font color="#555555">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br /></font></pre></td><td valign="top" align="left" bgcolor="#ffffff"><pre><font class="java-comment">// 這一段碼是 Tomcat 用來解 QueryString 的程式，</font><font class="java-comment">// 在 org.apache.tomcat.util.http.Parameters 這個 class 裡。</font><font class="java-reserved_word"><b>private</b></font> String urlDecode(ByteChunk bc, String enc)
  <font class="java-reserved_word"><b>throws</b></font> IOException <font class="java-bracket">{</font><font class="java-reserved_word"><b>if</b></font>( urlDec==<font class="java-reserved_word"><b>null</b></font> ) <font class="java-bracket">{</font>
     urlDec=<font class="java-reserved_word"><b>new</b></font> UDecoder(); 
  <font class="java-bracket">}</font>
  urlDec.convert(bc);
  String result = <font class="java-reserved_word"><b>null</b></font>;
  <font class="java-reserved_word"><b>if</b></font> (enc != <font class="java-reserved_word"><b>null</b></font>) <font class="java-bracket">{</font>
    bc.setEncoding(enc);
    result = bc.toString();
  <font class="java-bracket">}</font><font class="java-reserved_word"><b>else</b></font><font class="java-bracket">{</font>
    CharChunk cc = tmpNameC;
    cc.allocate(bc.getLength(), -1);
    <font class="java-comment">// Default encoding: fast conversion</font><font class="java-reserved_word"><b>byte</b></font>[] bbuf = bc.getBuffer();
    <font class="java-reserved_word"><b>char</b></font>[] cbuf = cc.getBuffer();
    <font class="java-reserved_word"><b>int</b></font> start = bc.getStart();
    <font class="java-reserved_word"><b>for</b></font> (<font class="java-reserved_word"><b>int</b></font> i = 0; i &lt; bc.getLength(); i++) <font class="java-bracket">{</font>
      cbuf[i] = (<font class="java-reserved_word"><b>char</b></font>) (bbuf[i + start] &amp; 0xff);
    <font class="java-bracket">}</font>
    cc.setChars(cbuf, 0, bc.getLength());
    result = cc.toString();
    cc.recycle();
  <font class="java-bracket">}</font><font class="java-reserved_word"><b>return</b></font> result;
<font class="java-bracket">}</font></pre></td></tr></tbody></table><br />請特別注意紅色區塊，當 Tomcat 發現 QueryString 並沒有設定 encode 時，並非像文件中所說預設採用 ISO-8859-1 的編碼，而是用一段 fast conversion 來處理，才會造成中文問題，所以，還是必須在 Server.xml 中，加上 URLEncoding 的參數設定才行哦。 <br /><br />Connector 的設定範例： <br /><table class="java" cellspacing="1" cellpadding="3" bgcolor="#999999" border="0"><tbody><tr><td valign="top" align="left" width="1" bgcolor="#dddddd"><pre><font color="#555555">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br /></font></pre></td><td valign="top" align="left" bgcolor="#ffffff"><pre>&lt;Connector
debug=<font class="java-string">"0"</font>
acceptCount=<font class="java-string">"100"</font>
connectionTimeout=<font class="java-string">"20000"</font>
disableUploadTimeout=<font class="java-string">"true"</font>
port=<font class="java-string">"80"</font>
redirectPort=<font class="java-string">"8443"</font>
enableLookups=<font class="java-string">"false"</font>
minSpareThreads=<font class="java-string">"25"</font>
maxSpareThreads=<font class="java-string">"75"</font>
maxThreads=<font class="java-string">"150"</font>
maxPostSize=<font class="java-string">"0"</font>
URIEncoding=<font class="java-string">"ISO-8859-1"</font>
&gt;
&lt;/Connector&gt;
</pre></td></tr></tbody></table></span>
		<br />from: <a href="http://www.javaworld.com.tw/jute/post/view?bid=9&amp;id=44042&amp;sty=1&amp;tpg=1&amp;age=0">http://www.javaworld.com.tw/jute/post/view?bid=9&amp;id=44042&amp;sty=1&amp;tpg=1&amp;age=0</a><img src ="http://www.blogjava.net/weidagang2046/aggbug/84939.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/weidagang2046/" target="_blank">weidagang2046</a> 2006-12-01 20:38 <a href="http://www.blogjava.net/weidagang2046/articles/84939.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JDBC性能优化技巧</title><link>http://www.blogjava.net/weidagang2046/articles/84051.html</link><dc:creator>weidagang2046</dc:creator><author>weidagang2046</author><pubDate>Tue, 28 Nov 2006 06:59:00 GMT</pubDate><guid>http://www.blogjava.net/weidagang2046/articles/84051.html</guid><wfw:comment>http://www.blogjava.net/weidagang2046/comments/84051.html</wfw:comment><comments>http://www.blogjava.net/weidagang2046/articles/84051.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/weidagang2046/comments/commentRss/84051.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/weidagang2046/services/trackbacks/84051.html</trackback:ping><description><![CDATA[ 
<p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'">         </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">如果可能，避免访问数据库</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l159 level1 lfo12; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings; mso-bidi-font-weight: bold">l<span style="FONT: 7pt 'Times New Roman'">         </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">为应用选择最好最快的 JDBC </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">驱动 ,参考<a href="http://www.flyjava.com/performance/index.htm"><font color="#0000ff">本站文章</font></a> 。 JDBC3.0</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">提供了新的特性来提高性能，诸如连接池， statemente池的改进</span><b><span lang="EN-US"><o:p>   </o:p></span></b></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l159 level1 lfo12; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings; mso-bidi-font-weight: bold">l<span style="FONT: 7pt 'Times New Roman'">        </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">对数据库使用连接池并且重用连接，而不要重复打开和关闭连接。最佳的连接池大小是当连接池大到足够使服务请求不等待</span><b><span lang="EN-US"><o:p></o:p></span></b></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l159 level1 lfo12; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'">         </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">尽量使用支持 JDBC3.0 的驱动，因为 JDBC3.0 支持包括 DataSource 对象，连接池，分布式事务支持， RowSets 和 prepared statement 池等性能增强特性</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l159 level1 lfo12; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'">         </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">Prepared statement 池（自从 JDBC3.0 开始有）高速缓存已经预先优化并运行了的 SQL 查询，这样，他们被再次请求的时候，不必经历再次的优化预处理（避免最优化步骤，诸如检查语法，验证地址，优化访问路径和执行计划）。 Statement 池是一个很好的，重要的性能优化方法</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-list: l172 level1 lfo14; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'">         </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">JDBC3.0 中的 Statement 池和连接池能合作共享 statement 池，这样，能使用一个已高速缓存的 statement （该 statement 来自另外一个连接）的连接，在由任一连接执行的 一些SQL 首次被执行时，产生的 statement 准备开销仅一次</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l159 level1 lfo12; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'">         </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">RowSet对象与 ResultSet 对象相似，但是能提供当断开连接的时候对数据库数据的访问。这允许数据以它最简单的形式被高效的高速缓存</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-list: l172 level1 lfo14; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'">         </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">用同一个连接执行多个 statements</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l159 level1 lfo12; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'">         </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">关闭 autocommit ，但不要让事务打开太久</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l159 level1 lfo12; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'">         </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">避免将事务分布开（事务跨越多个连接）</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l159 level1 lfo12; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'">         </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">最小化数据库的行和列数据获取。使用 setMaxRows, setMaxFieldSize,</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">和 SetFetchSize</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l159 level1 lfo12; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings; mso-bidi-font-weight: bold">l<span style="FONT: 7pt 'Times New Roman'">         </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">使用最高效的数据类型：字符串比整数型快，整数型比浮点类型和时间戳类型都要高效（是否不太理解^&amp;^，这是针对DB2数据库处理来说的，处理character类型最快，而处理integer类型通常需要一些转换或者字节排序）</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l159 level1 lfo12; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'">         </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">使用 updateXXX()</span>方法<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">更新： updateXXX() 在可更新的结果集上调用。结果集已经定位到了一行 , 因此当使用一个 UPDATE statement 时，可以消除通常的查找要更新的数据行的开销</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l159 level1 lfo12; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'">         </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">Cache任何请求的元数据（ metadata ）并尽可能少的使用元数据 方法，其慢的程度一用便知</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l159 level1 lfo12; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'">         </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">避免在元数据 查询中使用 null 参数</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l159 level1 lfo12; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'">         </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">使用虚拟查询获得一行的元数据，不要使用getcolumns()（假如应用允许用户使用列数据，应用是使用getColumns来返回列的信息给用户还是准备一个虚拟查询而后调用getMetadata呢？</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l159 level1 lfo12; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'">         </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">使用存储过程，避免多余的网络传输</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l159 level1 lfo12; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'">         </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">在存储过程中使用参量，不要将数据挨个地放在statement中，最小化解析开销。此条针对DB2来说，其它数据库未必适用。SQL总是以字符串形式发送给DB2数据库，例如：</span><br /><font color="#ff0000">CallableStatement cstmt = conn.prepareCall ("call getCustName (12345)");<br />ResultSet rs = cstmt.executeQuery ();</font><br />DB2服务器必须解析该SQL，验证参量类型，并将参量转化为正确的数据类型。</p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l159 level1 lfo12; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'">         </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">对需要重复执行的statement使用预处理statement（PreparedStatement）</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l159 level1 lfo12; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'">         </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">选择使用最佳游标：对连续读取使用游标；对双向滚动使用游标。对仅返回一行的查询避免使用游标。</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'">         </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">在JVM中Cache频繁请求的数据，避免不必要的数据库请求</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'">         </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">采用预读取机制， 批量取行，而不要一次一行 。调整批大小和预取行的数量。避免使用预取 BLOB 数据。</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'">         </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">除非绝对需要，否则避免移动数据</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'">         </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">在数据穿过网络之前要使流化数据（ Streamline data ）</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'">         </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">避免每次处理一行，尽可能一起处理多行。</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'">         </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">在表中统计个数（例如：使用 select count(*) from myTable,yourTable where …</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">）属于资源密集型的。试试首先选入临时表，仅返回该计数（count），然后发送精确的二次查询获得临时表中的行的子集。</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'">         </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Times New Roman; mso-hansi-font-family: Times New Roman">恰</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">当的使用 SQL 能减少资源请求。使用返回所需数据的最小值的查询：避免 select * 查询。一个返回小的数据子集的复杂查询，比一个简单的，返回超过所需的大量数据的简单查询更高效。</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'">         </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">使你的查询尽可能精巧，例如：尽可能精确地最小化要传输的数据，使其是所需的子集</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'">         </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">努力批量更新：将 statement 收集到一起，然后在一个事务里面一起执行。如果可能，使用有条件的逻辑和临时变量来达到 statement 批处理</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'">         </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">永远不要让 DBMS 事务跨越用户输入</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'">         </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">考虑使用乐观锁。乐观锁使用时间戳验证数据是否还没有被其他用户改变，否则事务失败</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'">         </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Times New Roman; mso-hansi-font-family: Times New Roman"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">使用 恰当的更新，例如：更新行</span>/<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">表中已经存在的数据，而不要添加或者删除行</span>/<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">表。在适当的位置更新数据要比移动数据快得多，如果更新需要的空间比表设计能提供的更多，这可能是需要的。如果你设计的行需要空间初始化，更新将会更快。交易是你的表可能需要更多的磁盘空间，但可能速度更快。由于磁盘空间是便宜的，使用一点点能提高性能</span>，这应该说是非常有价值的投资</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'">         </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">分开存储正在操作的数据和历史数据（更一般的情况是将频繁使用的数据和不常使用的数据分开存储）</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'">         </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">尽可能小的保留你的操作数据集，避免必须读那些不相关的数据</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'">         </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">DBMS可以很好的并行运转，尽量将应用设计成当和 DBMS交互时应用能做其他事情。</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'">         </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">使用流水线操作和并行操作。 将应用设计成支持大量并行进程， 使应用运行更快。如果要处理多步，努力设计好应用，以使后来的步骤能够在任何优先的进程已经完成的数据部分上开始工作，而不是必须等到优先进程完成</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'">      </span></span> <span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Times New Roman; mso-hansi-font-family: Times New Roman">事物的保护级别越高，性能损失就越大。事物级别按增长的顺序为： TRANSACTION_NONE, TRANSACTION_READ_UNCOMMITTED, TRANSACTION_READ_COMMITTED, TRANSACTION_REPEATABLE_READ, TRANSACTION_SERIALIZABLE。使用Connection.setTransactionIsolation() 设置你想要的事物级别</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'">      </span></span><span lang="EN-US" style="FONT-WEIGHT: normal; FONT-SIZE: 7pt; FONT-STYLE: normal; FONT-FAMILY: Wingdings; FONT-VARIANT: normal"></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Times New Roman; mso-hansi-font-family: Times New Roman">默认的自动提交模式由于使每一个数据库命令都成为一个单独的事务，这会严重影响性能，关闭自动提交（Connection.setAutoCommit(false) ），明确声明事务</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'">         </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Times New Roman; mso-hansi-font-family: Times New Roman">通过整合多个事务为一个的批量操作，并在一个statement中使用Statement.addBatch() 和Statement.executeBatch()</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'">     </span></span><span style="FONT: 7pt 'Times New Roman'"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Times New Roman; mso-hansi-font-family: Times New Roman"> Savepoints (from JDBC3.0)需要昂贵的资源。一旦不再需要，就立刻使用Connection.releaseSavepoint()释放掉Savepoints</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'">         </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Times New Roman; mso-hansi-font-family: Times New Roman">ConnectionPoolDataSource (from JDBC3.0)和PooledConnection接口为连接池提供了built-in支持</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'">         </span></span><span style="FONT: 7pt 'Times New Roman'">  </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Times New Roman; mso-hansi-font-family: Times New Roman">使用setLogWriter() (from Driver, DataSource, or ConnectionPooledDataSource; from JDBC3.0) 帮助跟踪JDBC流</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'">         </span></span><span style="FONT: 7pt 'Times New Roman'">  </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Times New Roman; mso-hansi-font-family: Times New Roman">使用Connection.setReadOnly(true)优化只读数据库（操作）交互</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'">         </span></span><span lang="EN-US"></span><span style="FONT: 7pt 'Times New Roman'">  <span style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA"></span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Times New Roman; mso-hansi-font-family: Times New Roman">使用Connection.nativeSQL()察看SQL查询如何在数据库种执行，帮助确保SQL已被优化</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'">         </span></span><span style="FONT: 7pt 'Times New Roman'"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Times New Roman; mso-hansi-font-family: Times New Roman">切记：一旦可能，立刻关闭Statement和ResultSet</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'">         </span></span><span style="FONT: 7pt 'Times New Roman'"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Times New Roman; mso-hansi-font-family: Times New Roman">使用DatabaseMetaData获得数据库功能性信息</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'">         </span></span><span style="FONT: 7pt 'Times New Roman'"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Times New Roman; mso-hansi-font-family: Times New Roman">一直捕捉和处理数据库警告和异常</span></p><p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-list: l77 level1 lfo11; tab-stops: list 21.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'">         </span></span><span style="FONT: 7pt 'Times New Roman'"> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Times New Roman; mso-hansi-font-family: Times New Roman">使用最恰当的数据类型明确数据的类型，例如：以date类型存储日期，儿不要用varchar</span><