<?xml version="1.0" encoding="gb2312"?>

<!-- RSS generated by oioj.net on 4/16/2004 ; 感谢LeXRus提供 RSS 2.0 文档; 此文件可自由使用，但请保留此行信息 --> 
<!-- Source download URL: http://blogger.org.cn/blog/rss2.asp       -->
<rss version="2.0">

<channel>
<title>lhwork的博客</title>
<link>http://blogger.org.cn/blog/blog.asp?name=lhwork</link>
<description>lhwork的博客</description>
<copyright>blogger.org.cn</copyright>
<generator>W3CHINA Blog</generator>
<webMaster>webmaster@blogger.org.cn</webMaster>
<item>
<title><![CDATA[Java中压缩与解压--中文文件名乱码解决办法]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=lhwork&amp;id=33407</link>
<author>lhwork</author>
<pubDate>2008/4/2 21:30:15</pubDate>
<description><![CDATA[java对於文字的编码是以 unicode为基础，因此，若是以ZipInputStream及ZipOutputStream来处理压缩及解压缩的工作，碰到中文档名或路径，那当然是以unicode来处理罗！但是，现在市面上的压缩及解压缩软体，例如winzip，却是不支援unicode的，一碰到档名以unicode编码的档案，它就不处理。 那要如何才能做出让WinRar能够处理的压缩档呢？那就得从修改ZipInputStream及ZipOutputStream对於档名的编码方式来着手了。我们可以从jdk的src.zip取得ZipInputStream及ZipOutputStream的原始码来加以修改<BR><BR>一、ZipOutputStream.java<BR>1.从jdk的src.zip取得ZipOutputStream.java原始码，另存到一个新文件中，档名改为CnZipOutputStream.java。<BR>2.开始修改原始码，将class名称改为CnZipOutputStream<BR>3.建构式也必须更改为CnZipOutputStream<BR>4.新增member，这个member记录编码方式<BR>&nbsp; private String encoding="UTF-8";<BR>5.再新增一个建构式(这个建构式可以让这个class在new的时候，设定档名的编码)<BR>&nbsp; public CZipOutputStream(OutputStream out,String encoding) {<BR>&nbsp;&nbsp;&nbsp;&nbsp; this(out);<BR>&nbsp;&nbsp;&nbsp;&nbsp; this.encoding=encoding;<BR>&nbsp; }<BR>6.找到byte[] nameBytes = getUTF8Bytes(e.name);(有二个地方)，将它修改如下：<BR>
<DIV class=hl-surround>
<OL class="hl-main ln-show" ondblclick=linenumber(this) title="Double click to hide line number.">
<LI class=hl-firstline><SPAN class=hl-types>byte</SPAN><SPAN style="COLOR: olive">[]</SPAN><SPAN style="COLOR: gray"> </SPAN><SPAN style="COLOR: blue">nameBytes</SPAN><SPAN style="COLOR: gray"> = </SPAN><SPAN style="COLOR: green">null</SPAN><SPAN style="COLOR: gray">;</SPAN> 
<LI><SPAN style="COLOR: gray">&nbsp;</SPAN><SPAN style="COLOR: green">try</SPAN> 
<LI><SPAN style="COLOR: gray">&nbsp;</SPAN><SPAN style="COLOR: olive">{</SPAN> 
<LI><SPAN style="COLOR: gray">&nbsp;</SPAN><SPAN style="COLOR: green">if</SPAN><SPAN style="COLOR: gray"> </SPAN><SPAN style="COLOR: olive">(</SPAN><SPAN style="COLOR: green">this</SPAN><SPAN style="COLOR: gray">.</SPAN><SPAN style="COLOR: blue">encoding</SPAN><SPAN style="COLOR: gray">.</SPAN><SPAN style="COLOR: blue">toUpperCase</SPAN><SPAN style="COLOR: olive">()</SPAN><SPAN style="COLOR: gray">.</SPAN><SPAN style="COLOR: blue">equals</SPAN><SPAN style="COLOR: olive">(</SPAN><SPAN style="COLOR: #8b0000">"</SPAN><SPAN style="COLOR: red">UTF-8</SPAN><SPAN style="COLOR: #8b0000">"</SPAN><SPAN style="COLOR: olive">))</SPAN> 
<LI><SPAN style="COLOR: gray">&nbsp;</SPAN><SPAN style="COLOR: blue">nameBytes</SPAN><SPAN style="COLOR: gray"> =</SPAN><SPAN style="COLOR: blue">getUTF8Bytes</SPAN><SPAN style="COLOR: olive">(</SPAN><SPAN style="COLOR: blue">e</SPAN><SPAN style="COLOR: gray">.</SPAN><SPAN style="COLOR: blue">name</SPAN><SPAN style="COLOR: olive">)</SPAN><SPAN style="COLOR: gray">;</SPAN> 
<LI><SPAN style="COLOR: gray">&nbsp;</SPAN><SPAN style="COLOR: green">else</SPAN> 
<LI><SPAN style="COLOR: gray">&nbsp;</SPAN><SPAN style="COLOR: blue">nameBytes</SPAN><SPAN style="COLOR: gray">= </SPAN><SPAN style="COLOR: blue">e</SPAN><SPAN style="COLOR: gray">.</SPAN><SPAN style="COLOR: blue">name</SPAN><SPAN style="COLOR: gray">.</SPAN><SPAN style="COLOR: blue">getBytes</SPAN><SPAN style="COLOR: olive">(</SPAN><SPAN style="COLOR: green">this</SPAN><SPAN style="COLOR: gray">.</SPAN><SPAN style="COLOR: blue">encoding</SPAN><SPAN style="COLOR: olive">)</SPAN><SPAN style="COLOR: gray">;</SPAN> 
<LI><SPAN style="COLOR: gray">&nbsp;</SPAN><SPAN style="COLOR: olive">}</SPAN> 
<LI><SPAN style="COLOR: gray">&nbsp;</SPAN><SPAN style="COLOR: green">catch</SPAN><SPAN style="COLOR: olive">(</SPAN><SPAN style="COLOR: blue">Exception</SPAN><SPAN style="COLOR: gray"> </SPAN><SPAN style="COLOR: blue">byteE</SPAN><SPAN style="COLOR: olive">)</SPAN> 
<LI><SPAN style="COLOR: gray">&nbsp;</SPAN><SPAN style="COLOR: olive">{</SPAN> 
<LI><SPAN style="COLOR: gray">&nbsp;</SPAN><SPAN style="COLOR: blue">nameBytes</SPAN><SPAN style="COLOR: gray">=</SPAN><SPAN style="COLOR: blue">getUTF8Bytes</SPAN><SPAN style="COLOR: olive">(</SPAN><SPAN style="COLOR: blue">e</SPAN><SPAN style="COLOR: gray">.</SPAN><SPAN style="COLOR: blue">name</SPAN><SPAN style="COLOR: olive">)</SPAN><SPAN style="COLOR: gray">;</SPAN> 
<LI><SPAN style="COLOR: gray">&nbsp;</SPAN><SPAN style="COLOR: olive">}</SPAN></LI></OL></DIV><BR><BR>二、ZipInputStream.java<BR>1.从jdk的src.zip取得ZipInputStream.java原始码，另存到一个新文件中，档名改为CnZipInputStream.java。<BR>2.开始修改原始码，将class名称改为CnZipInputStream<BR>3.建构式也必须更改为CnZipInputStream<BR>4.新增member，这个member记录编码方式<BR>&nbsp; private String encoding="UTF-8";<BR>5.再新增一个建构式如下(这个建构式可以让这个class在new的时候，设定档名的编码)<BR>public CZipInputStream(InputStream in,String encoding) {<BR>&nbsp; this(in);<BR>&nbsp; this.encoding=encoding;<BR>}<BR><BR>6.找到ZipEntry e = createZipEntry(getUTF8String(b, 0, len));这一行，将它改成如下：<BR>
<DIV class=hl-surround>
<OL class="hl-main ln-show" ondblclick=linenumber(this) title="Double click to hide line number.">
<LI class=hl-firstline><SPAN style="COLOR: blue">ZipEntry</SPAN><SPAN style="COLOR: gray"> </SPAN><SPAN style="COLOR: blue">e</SPAN><SPAN style="COLOR: gray">=</SPAN><SPAN style="COLOR: green">null</SPAN><SPAN style="COLOR: gray">;</SPAN> 
<LI><SPAN style="COLOR: gray">&nbsp;</SPAN><SPAN style="COLOR: green">try</SPAN> 
<LI><SPAN style="COLOR: gray">&nbsp;</SPAN><SPAN style="COLOR: olive">{</SPAN> 
<LI><SPAN style="COLOR: gray">&nbsp;</SPAN><SPAN style="COLOR: green">if</SPAN><SPAN style="COLOR: gray"> </SPAN><SPAN style="COLOR: olive">(</SPAN><SPAN style="COLOR: green">this</SPAN><SPAN style="COLOR: gray">.</SPAN><SPAN style="COLOR: blue">encoding</SPAN><SPAN style="COLOR: gray">.</SPAN><SPAN style="COLOR: blue">toUpperCase</SPAN><SPAN style="COLOR: olive">()</SPAN><SPAN style="COLOR: gray">.</SPAN><SPAN style="COLOR: blue">equals</SPAN><SPAN style="COLOR: olive">(</SPAN><SPAN style="COLOR: #8b0000">"</SPAN><SPAN style="COLOR: red">UTF-8</SPAN><SPAN style="COLOR: #8b0000">"</SPAN><SPAN style="COLOR: olive">))</SPAN> 
<LI><SPAN style="COLOR: gray">&nbsp;</SPAN><SPAN style="COLOR: blue">e</SPAN><SPAN style="COLOR: gray">=</SPAN><SPAN style="COLOR: blue">createZipEntry</SPAN><SPAN style="COLOR: olive">(</SPAN><SPAN style="COLOR: blue">getUTF8String</SPAN><SPAN style="COLOR: olive">(</SPAN><SPAN style="COLOR: blue">b</SPAN><SPAN style="COLOR: gray">, </SPAN><SPAN style="COLOR: maroon">0</SPAN><SPAN style="COLOR: gray">, </SPAN><SPAN style="COLOR: blue">len</SPAN><SPAN style="COLOR: olive">))</SPAN><SPAN style="COLOR: gray">;</SPAN> 
<LI><SPAN style="COLOR: gray">&nbsp;</SPAN><SPAN style="COLOR: green">else</SPAN> 
<LI><SPAN style="COLOR: gray">&nbsp;</SPAN><SPAN style="COLOR: blue">e</SPAN><SPAN style="COLOR: gray">=</SPAN><SPAN style="COLOR: blue">createZipEntry</SPAN><SPAN style="COLOR: olive">(</SPAN><SPAN style="COLOR: green">new</SPAN><SPAN style="COLOR: gray"> </SPAN><SPAN style="COLOR: blue">String</SPAN><SPAN style="COLOR: olive">(</SPAN><SPAN style="COLOR: blue">b</SPAN><SPAN style="COLOR: gray">,</SPAN><SPAN style="COLOR: maroon">0</SPAN><SPAN style="COLOR: gray">,</SPAN><SPAN style="COLOR: blue">len</SPAN><SPAN style="COLOR: gray">,</SPAN><SPAN style="COLOR: green">this</SPAN><SPAN style="COLOR: gray">.</SPAN><SPAN style="COLOR: blue">encoding</SPAN><SPAN style="COLOR: olive">))</SPAN><SPAN style="COLOR: gray">;</SPAN> 
<LI><SPAN style="COLOR: gray">&nbsp;</SPAN><SPAN style="COLOR: olive">}</SPAN> 
<LI><SPAN style="COLOR: gray">&nbsp;</SPAN><SPAN style="COLOR: green">catch</SPAN><SPAN style="COLOR: olive">(</SPAN><SPAN style="COLOR: blue">Exception</SPAN><SPAN style="COLOR: gray"> </SPAN><SPAN style="COLOR: blue">byteE</SPAN><SPAN style="COLOR: olive">)</SPAN> 
<LI><SPAN style="COLOR: gray">&nbsp;</SPAN><SPAN style="COLOR: olive">{</SPAN> 
<LI><SPAN style="COLOR: gray">&nbsp;</SPAN><SPAN style="COLOR: blue">e</SPAN><SPAN style="COLOR: gray">=</SPAN><SPAN style="COLOR: blue">createZipEntry</SPAN><SPAN style="COLOR: olive">(</SPAN><SPAN style="COLOR: blue">getUTF8String</SPAN><SPAN style="COLOR: olive">(</SPAN><SPAN style="COLOR: blue">b</SPAN><SPAN style="COLOR: gray">, </SPAN><SPAN style="COLOR: maroon">0</SPAN><SPAN style="COLOR: gray">, </SPAN><SPAN style="COLOR: blue">len</SPAN><SPAN style="COLOR: olive">))</SPAN><SPAN style="COLOR: gray">;</SPAN> 
<LI><SPAN style="COLOR: gray">&nbsp;</SPAN><SPAN style="COLOR: olive">}</SPAN></LI></OL></DIV><BR><BR><BR>以上两个档案储存後compile产生CZipOutputStream.class及CZipInputStream.class，使用winzip开启 [java_home]\jre\lib\rt.jar这个档案，将CnZipOutputStream.class及 CnZipInputStream.class加进去,以後当压缩及解压缩时有中文档名及路径的问题时，就可以指定编码方式来处理了。<BR><BR>使用方法:<BR>CnZipOutputStream zos=new CnZipOutputStream(OutputStream os,String encoding);<BR>CnZipInputStream zins=new CnZipInputStream(InputStream ins,String encoding);<BR><BR>对于前面文章中文件打包下载中遇到的中文文件问题,解决手法是:<BR>OutputStream os = response.getOutputStream();<BR>CnZipOutputStream zos = new CnZipOutputStream(os,"gbk"); //加上中文编码类型<BR>]]></description>
</item><item>
<title><![CDATA[对当前目录下所有文件进行压缩代码]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=lhwork&amp;id=33406</link>
<author>lhwork</author>
<pubDate>2008/4/2 20:48:48</pubDate>
<description><![CDATA[<P>import java.io.*;<BR>import java.util.zip.*;</P>
<P>public class Test<BR>{<BR>&nbsp;&nbsp; static final int BUFFER = 2048;<BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp; public static String ChangeName(String s)<BR>&nbsp;&nbsp; {&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int j = 0;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String newstring = "";<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int i=0; i&lt;s.length(); i++)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;if (s.charAt(i)== '.')<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;j = i;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; newstring = s.substring(0,j);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return&nbsp; newstring;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp; } </P>
<P>&nbsp;&nbsp; public static void main (String argv[]) <BR>&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BufferedInputStream origin = null;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String filename = "";<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; byte data[] = new byte[BUFFER];<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; File f = new File("."); <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String files[] = f.list();</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int i=0; i &lt; files.length; i++) <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; filename = files[i];<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FileOutputStream dest = new FileOutputStream(ChangeName(filename) +".zip");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(dest));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("Adding: "+files[i]);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FileInputStream fi = new FileInputStream(files[i]);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; origin = new BufferedInputStream(fi, BUFFER);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ZipEntry entry = new ZipEntry(files[i]);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; out.putNextEntry(entry);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int count;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while((count = origin.read(data, 0,BUFFER)) != -1) <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; out.write(data, 0, count);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; origin.close();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; out.close();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch(Exception e)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; e.printStackTrace();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp; }<BR>} <BR></P>]]></description>
</item><item>
<title><![CDATA[java zip 中文问题]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=lhwork&amp;id=33405</link>
<author>lhwork</author>
<pubDate>2008/4/2 20:47:36</pubDate>
<description><![CDATA[用ant解压包含中文文件名的压缩文件 <BR>中文问题是java中的普遍性问题.今天下午遇到一个包含中文文件名的压缩文件解压问题.找了不少资料.现贴出解集.<BR>在java.util.zip包也可以用来处理解压问题,不过对含有中文文件名的压缩包无能为力,这是因为ZipOutputStream压缩和解压ZIP文件对文件名都是以UTF-8编码方式来处理的,而我们用winzip压缩文件对文件名只会以ASCII编码方式来处理.所以会出现编码不一致的问题.<BR>有两种解决方案:<BR>第一种就是修改ZipOutputStream,参考修改如下:(这个我没有测试过)<BR>// ZipEntry e = createZipEntry(getUTF8String(b, 0, len));<BR>ZipEntry e=null;<BR>try <BR>{<BR>&nbsp;&nbsp;&nbsp; if (this.encoding.toUpperCase().equals("UTF-8"))<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; e=createZipEntry(getUTF8String(b, 0, len));<BR>&nbsp;&nbsp;&nbsp; else<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; e=createZipEntry(new String(b,0,len,this.encoding));<BR>}catch(Exception byteE) {<BR>&nbsp;&nbsp;&nbsp; e=createZipEntry(getUTF8String(b, 0, len));<BR>}<BR>再加一个<BR>public ZipInputStream(InputStream in,String encoding) {<BR>&nbsp;&nbsp;&nbsp; super(new PushbackInputStream(in,512),new Inflater(true),512);<BR>&nbsp;&nbsp;&nbsp; usesDefaultInflater = true;<BR>&nbsp;&nbsp;&nbsp; if(in == null) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw new NullPointerException("in is null");<BR>&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; this.encoding=encoding;<BR>} <BR>第二种方法就是用ant包,可以在官方网站<A href="http://ant.apache.org/bindownload.cgi">http://ant.apache.org/bindownload.cgi</A>下载,把ant.jar导入到类中.<BR>参考用例如下:<BR>public void unzip(String zipFileName,String outputDirectory) throws Exception{<BR>try {<BR>&nbsp;&nbsp;&nbsp; org.apache.tools.zip.ZipFile zipFile = new org.apache.tools.zip.ZipFile(zipFileName);<BR>&nbsp;&nbsp;&nbsp; java.util.Enumeration e = zipFile.getEntries();<BR>&nbsp;&nbsp;&nbsp; org.apache.tools.zip.ZipEntry zipEntry = null;<BR>&nbsp;&nbsp;&nbsp; while (e.hasMoreElements()){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; zipEntry = (org.apache.tools.zip.ZipEntry)e.nextElement();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("unziping "+zipEntry.getName());<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (zipEntry.isDirectory()){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String name=zipEntry.getName();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; name=name.substring(0,name.length()-1);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("输出路径："+outputDirectory+File.separator+name);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; File f1=new File(outputDirectory+File.separator);<BR>f1.mkdir();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; File f=new File(outputDirectory+File.separator+name);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f.mkdir();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("创建目录："+outputDirectory+File.separator+name);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }else{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; File f=new File(outputDirectory+File.separator+zipEntry.getName());<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f.createNewFile();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; InputStream in = zipFile.getInputStream(zipEntry);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FileOutputStream out=new FileOutputStream(f);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //--------解决了图片失真的情况<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int c;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; byte[] by=new byte[1024];<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while((c=in.read(by)) != -1){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; out.write(by,0,c);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; out.close();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; in.close();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; }<BR>}<BR>catch (Exception ex){<BR>}<BR>}&nbsp;<BR>]]></description>
</item><item>
<title><![CDATA[iBatis for Paging]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=lhwork&amp;id=33384</link>
<author>lhwork</author>
<pubDate>2008/4/2 9:38:54</pubDate>
<description><![CDATA[<P>I'm trying to move from pure jdbc to iBatis DAO and SQLMaps. Why iBatis? I have the experience and it is comfortable to be used in an environment where are lots of pre written database procedures and complex queries.</P>
<P>One of the reason why the move to iBatis was due to paging, the requirement is to show data from more than 4 million records, querying data for paging was taking a lot of time using result set. Next step was moving to scrollable result set, however managing the connection and the open result set, i'm afraid will be daunting to the developers, some of them new. We can surely destroy the connection once the session expires but how about the result sets we may need to open when users access other pages for which data is to be queried in millions of row table?</P>
<P>Ibatis to the rescue, with the PaginatedList interface and PaginatedDataList as the implementation. Using iBatis is very simple. Below is a sample to do dynamic queries with poperty name and value substitution.</P><PRE>&lt;?xml version="1.0" encoding="UTF-8" ?&gt;
&lt;!DOCTYPE sqlMap PUBLIC "-//iBATIS.com//DTD SQL Map 2.0//EN" 
  "http://www.ibatis.com/dtd/sql-map-2.dtd"&gt;
&lt;sqlMap&gt;
	&lt;!-- Data is cached at server depending on the size --&gt;
	&lt;cacheModel id="domain1Cache" type="LRU"&gt;
		&lt;flushInterval hours="1"/&gt;
		&lt;property name="size" value="100" /&gt;
	&lt;/cacheModel&gt;

	&lt;!-- aliasing, --&gt;
	&lt;typeAlias alias="domain1VO" type="com.company.domain1.domain1VO" /&gt;
	
	&lt;!-- 
		Result mapping from sql to java object of domain1VO which is com.company.domain1.domain1VO.
		If there is more that one column with the same name, use sql aliasing.
	--&gt;
	&lt;resultMap id="domain1Result" class="domain1VO"&gt;
		&lt;result property="domain1No" column="FIELD1"/&gt;
		&lt;result property="referenceNo" column="FIELD2"/&gt;
		&lt;result property="status" column="FIELD3"/&gt;
		...
	&lt;/resultMap&gt;
	
	&lt;!--
		Each select has a unique id, the data to be used for criteria, empty if there isn't any. If 
		multiple string criteria, put them in a map use the parameterMap keyword instead of parameterClass
	--&gt;
	&lt;select id="finddomain1" parameterClass="com.company.domain1.domain1SearchVO"
		resultMap="domain1Result" cacheModel="domain1Cache"&gt;
		&lt;!-- We are using CDATA for the following sql fragment because of the 'STATUS &lt;&gt; 'N'' notice
			 the less than, greater than symbols which are xml markers.
	    --&gt;
		&lt;![CDATA[
			SELECT FIELD1, FIELD2, FIELD3 
			FROM TABLE WHERE ( FIELD4 &lt;&gt; 'N' ) AND #code# IN (CODE) AND ID = #companyId#
		]]&gt;
		&lt;!--
			#Code# &lt;- substitues domain1SearchVO.Code value
		--&gt;

		&lt;!--
			Below does dynamic query, depending if the property has data, create query reflecting the data.
			isNotEmpty is used to substitute 
			&lt;code&gt;
		        if ((search.getValue() != null) &amp;&amp; (search.getValue().length() &gt; 0)) {
		            getdomain1s.append(" AND " + search.getCriteria());
		            getdomain1s.append(" = '");
		            getdomain1s.append(search.getValue());
		            getdomain1s.append("'");
		        }
			&lt;/code&gt;
			
			$criteria$ &lt;- this is for substituting property name. Note $ instead of # which is for property value
		--&gt;		
			&lt;isNotEmpty prepend="AND" property="value" &gt;
				$criteria$ = #value#
			&lt;/isNotEmpty&gt;
			
			&lt;isNotEmpty prepend="AND" property="status" &gt;
				STATUS = #status#
			&lt;/isNotEmpty&gt;
			 ORDER BY ID
	&lt;/select&gt;
&lt;/sqlMap&gt;
</PRE>]]></description>
</item><item>
<title><![CDATA[再析在spring框架中解决多数据源的问题]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=lhwork&amp;id=32877</link>
<author>lhwork</author>
<pubDate>2008/3/25 17:53:37</pubDate>
<description><![CDATA[<DIV class="postbody clearfix">
<DIV id=related_topics style="POSITION: relative" _eventID="2" _madePositioned="true">相关文章: <SPAN class=close><A title=关闭 onclick="$('related_topics').hide();return false;" href="http://www.javaeye.com/topic/91667#">&nbsp;</A></SPAN> 
<UL>
<LI><A href="http://www.javaeye.com/topic/72486" target=_blank>如何在spring框架中解决多数据源的问题</A> 
<LI><A href="http://www.javaeye.com/topic/119767" target=_blank>DWR帮助文档－dwr.xml文件的配置</A> </LI></UL><BR><SPAN>推荐圈子: <A href="http://jbpm.group.javaeye.com/" target=_blank>JBPM @net</A></SPAN> <BR><A href="http://www.javaeye.com/wiki/topic/91667" target=_blank>更多相关推荐</A> </DIV>
<SCRIPT type=text/javascript>
            new Draggable("related_topics");
          </SCRIPT>
<SPAN style="FONT-FAMILY: 宋体">在前面我写了《<A href="http://www.javaeye.com/blog/72486">如何在</A></SPAN><SPAN><A href="javascript:void(0);/*1182164310671*/">spring</A></SPAN><SPAN style="FONT-FAMILY: 宋体"><A href="javascript:void(0);/*1182164310671*/">框架中解决多数据源的问题</A>》，通过设计模式中的</SPAN><SPAN>Decorator</SPAN><SPAN style="FONT-FAMILY: 宋体">模式在</SPAN><SPAN>spring</SPAN><SPAN style="FONT-FAMILY: 宋体">框架中解决多数据源的问题，得到了许多网友的关注。在与网友探讨该问题的过程中，我发现我的方案并不完善，它只解决了一部分问题。</SPAN> 
<P class=MsoNormal style="TEXT-INDENT: 26.25pt"><SPAN style="FONT-FAMILY: 宋体">总结多数据源的问题，其实它需要分为以下三种情况：各个数据源的数据结构不同、各个数据源的数据结构相同、各个数据源的数据结构部分相同又有部分不同。对于第二种情况，各个数据源的数据结构相同，我们使用一个</SPAN><SPAN>sessionFactory</SPAN><SPAN style="FONT-FAMILY: 宋体">，而在</SPAN><SPAN>sessionFactory</SPAN><SPAN style="FONT-FAMILY: 宋体">中通过</SPAN><SPAN>MultiDataSource</SPAN><SPAN style="FONT-FAMILY: 宋体">来动态切换数据源，应当是一个不错的方案，既解决了多个</SPAN><SPAN>sessionFactory</SPAN><SPAN style="FONT-FAMILY: 宋体">对相同的值对象重复装载对内存的浪费，又使数据源的切换对客户程序透明，简化了代码的实现和对客户程序的影响。但是，对于第一种情况，各个数据源的数据结构不同，运用这样的方案存在潜在风险。</SPAN></P>
<P class=MsoNormal style="TEXT-INDENT: 26.25pt"><SPAN style="FONT-FAMILY: 宋体">对于各个数据源的数据结构不同的情况，使用一个</SPAN><SPAN>sessionFactory</SPAN><SPAN style="FONT-FAMILY: 宋体">而在这个</SPAN><SPAN>sessionFactory</SPAN><SPAN style="FONT-FAMILY: 宋体">中动态切换数据源，可能造成数据访问的张冠李戴。譬如，数据源</SPAN><SPAN>A</SPAN><SPAN style="FONT-FAMILY: 宋体">有表</SPAN><SPAN>T</SPAN><SPAN style="FONT-FAMILY: 宋体">而数据源</SPAN><SPAN>B</SPAN><SPAN style="FONT-FAMILY: 宋体">没有，可能造成客户程序在访问表</SPAN><SPAN>T</SPAN><SPAN style="FONT-FAMILY: 宋体">的时候却尝试去连接数据源</SPAN><SPAN>B</SPAN><SPAN style="FONT-FAMILY: 宋体">，因为客户程序访问哪个数据源是在程序运行期间由客户程序决定的，因此这样的错误是很难发现的。也许客户程序的一个不经意的错误就可能造成错误。解决这个问题的方法有两个：一是严格要求客户程序不要写错，这当然是可以做到的，但作为框架设计者，另一个解决方法是在框架中就避免出现这样的情况。因此我祭出了</SPAN><SPAN>MultiSessionFactory</SPAN><SPAN style="FONT-FAMILY: 宋体">的方案来解决各个数据源的数据结构不同的多数据源问题。</SPAN></P>
<H2><SPAN style="FONT-FAMILY: 黑体">问题的分析</SPAN></H2>
<P class=MsoNormal style="TEXT-INDENT: 26.25pt"><SPAN style="FONT-FAMILY: 宋体">与</SPAN><SPAN>MultiDataSource</SPAN><SPAN style="FONT-FAMILY: 宋体">的方案一样，</SPAN><SPAN>MultiSessionFactory</SPAN><SPAN style="FONT-FAMILY: 宋体">同样是在</SPAN><SPAN>spring</SPAN><SPAN style="FONT-FAMILY: 宋体">框架下调用</SPAN><SPAN>ApplicationContext</SPAN><SPAN style="FONT-FAMILY: 宋体">的</SPAN><SPAN>getBean()</SPAN><SPAN style="FONT-FAMILY: 宋体">方法而不会另外创建</SPAN><SPAN>beanFacoty</SPAN><SPAN style="FONT-FAMILY: 宋体">，也同样使用</SPAN><SPAN>Decorator</SPAN><SPAN style="FONT-FAMILY: 宋体">模式来处理切换的问题。</SPAN><SPAN>MultiSessionFactory</SPAN><SPAN style="FONT-FAMILY: 宋体">的对象关系如图：</SPAN></P>
<P class=MsoNormal style="TEXT-INDENT: 26.25pt"><SPAN></SPAN></P>
<P class=MsoNormal style="TEXT-INDENT: 26.25pt"><SPAN style="FONT-FAMILY: 宋体"><IMG height=387 alt="" src="http://www.javaeye.com/upload/picture/pic/3974/10f6052e-a238-46fd-b6d3-b62321b2c51d.jpg" width=563 _counted="undefined"></SPAN></P><SPAN style="FONT-FAMILY: 宋体">在该方案中，</SPAN><SPAN>SessionFactory</SPAN><SPAN style="FONT-FAMILY: 宋体">就是</SPAN><SPAN>Hibernate</SPAN><SPAN style="FONT-FAMILY: 宋体">的</SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 'Courier New'">org.hibernate.SessionFactory</SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 宋体">接口，</SPAN><SPAN>Decorator</SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 宋体">就是</SPAN><SPAN>MultiSessionFactory</SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 宋体">，</SPAN><SPAN>SessionFactory1</SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 宋体">和</SPAN><SPAN>SessionFactory2</SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 宋体">往往是</SPAN><SPAN>spring</SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 宋体">的</SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'">org.springframework.orm.hibernate3.LocalSessionFactoryBean</SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">。细心的朋友可能会注意，实际上</SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'">LocalSessionFactoryBean</SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">并不是</SPAN><SPAN>SessionFactory</SPAN><SPAN style="FONT-FAMILY: 宋体">的实现，这个方案是否有问题呢？这个问题其实也一直困扰了我好久，最后我发现，我们通过</SPAN><SPAN>ApplicationContext</SPAN><SPAN style="FONT-FAMILY: 宋体">的</SPAN><SPAN>getBean()</SPAN><SPAN style="FONT-FAMILY: 宋体">得到一个</SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'">LocalSessionFactoryBean</SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">的时候其实并不是真正地得到了它，而是得到了一个</SPAN><SPAN>SessionFactory</SPAN><SPAN style="FONT-FAMILY: 宋体">，因为</SPAN><SPAN>spring</SPAN><SPAN style="FONT-FAMILY: 宋体">为</SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'">LocalSessionFactoryBean</SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">重写了</SPAN><SPAN>getObject()</SPAN><SPAN style="FONT-FAMILY: 宋体">，使其返回的是</SPAN><SPAN>SessionFactory</SPAN><SPAN style="FONT-FAMILY: 宋体">。一个简单的明证就是，</SPAN><SPAN>HibernateDaoSupport</SPAN><SPAN style="FONT-FAMILY: 宋体">的</SPAN><SPAN>sessionFactory</SPAN><SPAN style="FONT-FAMILY: 宋体">属性的类型是</SPAN><SPAN>SessionFactory</SPAN><SPAN style="FONT-FAMILY: 宋体">，而我们在</SPAN><SPAN>spring</SPAN><SPAN style="FONT-FAMILY: 宋体">配置的时候注入的却是</SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'">LocalSessionFactoryBean</SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">。</SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'"></SPAN> 
<H2><SPAN style="FONT-FAMILY: 黑体">方案的实现</SPAN><SPAN></SPAN></H2>
<P class=MsoNormal style="TEXT-INDENT: 26.25pt"><SPAN style="FONT-FAMILY: 宋体">在整个这个方案中，我们需要实现的只有</SPAN><SPAN>MultiSessionFactory</SPAN><SPAN style="FONT-FAMILY: 宋体">类和我们可爱的</SPAN><SPAN>Spserver</SPAN><SPAN style="FONT-FAMILY: 宋体">，总共就两个类，然后呢就是一些</SPAN><SPAN>spring</SPAN><SPAN style="FONT-FAMILY: 宋体">的配置，就完成了。</SPAN></P>
<P class=MsoNormal style="TEXT-INDENT: 26.25pt"><SPAN>MultiSessionFactory</SPAN><SPAN style="FONT-FAMILY: 宋体">实现了</SPAN><SPAN>SessionFactory</SPAN><SPAN style="FONT-FAMILY: 宋体">，同时为了得到</SPAN><SPAN>AplicationContext</SPAN><SPAN style="FONT-FAMILY: 宋体">而实现了</SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 'Courier New'">ApplicationContextAware</SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 宋体">。</SPAN><SPAN>MultiSessionFactory</SPAN><SPAN style="FONT-FAMILY: 宋体">的代码如下：</SPAN></P>
<DIV class=code_title>java 代码</DIV><SPAN>
<DIV class=dp-highlighter>
<OL class=dp-j>
<LI class=alt><SPAN><SPAN class=keyword>public</SPAN><SPAN>&nbsp;</SPAN><SPAN class=keyword>class</SPAN><SPAN>&nbsp;MultiSessionFactory&nbsp;</SPAN><SPAN class=keyword>implements</SPAN><SPAN>&nbsp;SessionFactory,&nbsp;ApplicationContextAware&nbsp;{ &nbsp;&nbsp;</SPAN></SPAN> 
<LI><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=keyword>private</SPAN><SPAN>&nbsp;</SPAN><SPAN class=keyword>static</SPAN><SPAN>&nbsp;</SPAN><SPAN class=keyword>final</SPAN><SPAN>&nbsp;</SPAN><SPAN class=keyword>long</SPAN><SPAN>&nbsp;serialVersionUID&nbsp;=&nbsp;2064557324203496378L; &nbsp;&nbsp;</SPAN> 
<LI class=alt><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=keyword>private</SPAN><SPAN>&nbsp;</SPAN><SPAN class=keyword>static</SPAN><SPAN>&nbsp;</SPAN><SPAN class=keyword>final</SPAN><SPAN>&nbsp;Log&nbsp;log&nbsp;=&nbsp;LogFactory.getLog(MultiSessionFactory.</SPAN><SPAN class=keyword>class</SPAN><SPAN>); &nbsp;&nbsp;</SPAN> 
<LI><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=keyword>private</SPAN><SPAN>&nbsp;ApplicationContext&nbsp;applicationContext&nbsp;=&nbsp;</SPAN><SPAN class=keyword>null</SPAN><SPAN>; &nbsp;&nbsp;</SPAN> 
<LI class=alt><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=keyword>private</SPAN><SPAN>&nbsp;SessionFactory&nbsp;sessionFactory&nbsp;=&nbsp;</SPAN><SPAN class=keyword>null</SPAN><SPAN>; &nbsp;&nbsp;</SPAN> 
<LI><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=keyword>public</SPAN><SPAN>&nbsp;ApplicationContext&nbsp;getApplicationContext()&nbsp;{ &nbsp;&nbsp;</SPAN> 
<LI class=alt><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=keyword>return</SPAN><SPAN>&nbsp;applicationContext; &nbsp;&nbsp;</SPAN> 
<LI><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</SPAN> 
<LI class=alt><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=keyword>public</SPAN><SPAN>&nbsp;</SPAN><SPAN class=keyword>void</SPAN><SPAN>&nbsp;setApplicationContext(ApplicationContext&nbsp;applicationContext)&nbsp;{ &nbsp;&nbsp;</SPAN> 
<LI><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=keyword>this</SPAN><SPAN>.applicationContext&nbsp;=&nbsp;applicationContext; &nbsp;&nbsp;</SPAN> 
<LI class=alt><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</SPAN> 
<LI><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=keyword>public</SPAN><SPAN>&nbsp;SessionFactory&nbsp;getSessionFactory(String&nbsp;sessionFactoryName)&nbsp;{ &nbsp;&nbsp;</SPAN> 
<LI class=alt><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log.debug(</SPAN><SPAN class=string>"sessionFactoryName:"</SPAN><SPAN>+sessionFactoryName); &nbsp;&nbsp;</SPAN> 
<LI><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=keyword>try</SPAN><SPAN>{ &nbsp;&nbsp;</SPAN> 
<LI class=alt><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=keyword>if</SPAN><SPAN>(sessionFactoryName==</SPAN><SPAN class=keyword>null</SPAN><SPAN>||sessionFactoryName.equals(</SPAN><SPAN class=string>""</SPAN><SPAN>)){ &nbsp;&nbsp;</SPAN> 
<LI><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=keyword>return</SPAN><SPAN>&nbsp;sessionFactory; &nbsp;&nbsp;</SPAN> 
<LI class=alt><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</SPAN> 
<LI><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=keyword>return</SPAN><SPAN>&nbsp;(SessionFactory)</SPAN><SPAN class=keyword>this</SPAN><SPAN>.getApplicationContext().getBean(sessionFactoryName); &nbsp;&nbsp;</SPAN> 
<LI class=alt><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</SPAN><SPAN class=keyword>catch</SPAN><SPAN>(NoSuchBeanDefinitionException&nbsp;ex){ &nbsp;&nbsp;</SPAN> 
<LI><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=keyword>throw</SPAN><SPAN>&nbsp;</SPAN><SPAN class=keyword>new</SPAN><SPAN>&nbsp;DaoException(</SPAN><SPAN class=string>"There&nbsp;is&nbsp;not&nbsp;the&nbsp;sessionFactory&nbsp;</SPAN> 
<LI class=alt><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</SPAN> 
<LI><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</SPAN> 
<LI class=alt><SPAN>&nbsp;&nbsp;</SPAN> 
<LI><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=keyword>public</SPAN><SPAN>&nbsp;SessionFactory&nbsp;getSessionFactory()&nbsp;{ &nbsp;&nbsp;</SPAN> 
<LI class=alt><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;sessionFactoryName&nbsp;=&nbsp;SpObserver.getSp(); &nbsp;&nbsp;</SPAN> 
<LI><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=keyword>return</SPAN><SPAN>&nbsp;getSessionFactory(sessionFactoryName); &nbsp;&nbsp;</SPAN> 
<LI class=alt><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</SPAN> 
<LI><SPAN>&nbsp;&nbsp;</SPAN> 
<LI class=alt><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=keyword>public</SPAN><SPAN>&nbsp;</SPAN><SPAN class=keyword>void</SPAN><SPAN>&nbsp;setSessionFactory(SessionFactory&nbsp;sessionFactory)&nbsp;{ &nbsp;&nbsp;</SPAN> 
<LI><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=keyword>this</SPAN><SPAN>.sessionFactory&nbsp;=&nbsp;sessionFactory; &nbsp;&nbsp;</SPAN> 
<LI class=alt><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</SPAN> 
<LI><SPAN>&nbsp;&nbsp;</SPAN> 
<LI class=alt><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=comment>//&nbsp;SessionFactory接口需要实现的方法 </SPAN><SPAN>&nbsp;&nbsp;</SPAN> 
<LI><SPAN>&nbsp;&nbsp;</SPAN> 
<LI class=alt><SPAN>...... &nbsp;&nbsp;</SPAN> 
<LI><SPAN>&nbsp;&nbsp;</SPAN> 
<LI class=alt><SPAN>}&nbsp;&nbsp;</SPAN> </LI></OL></DIV>
<P class=MsoNormal style="TEXT-INDENT: 26.25pt">MultiSessionFactory<SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体">的完整代码见我提供的附件。</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'">setSessionFactory()</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体">实际上是设定的默认</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'">sessionFactory</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体">，它在</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'">spring</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体">装载的时候调用，其对应的数据源应当是主数据源，即项目初始化中需要读取初始化数据的数据源。在任何多数据源项目中，都应当有一个存放初始化数据、系统维护数据、用户权限数据的数据源，这就是主数据源。因此</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'">MultiSessionFactory</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体">的配置应当这样写：</SPAN></P><SPAN>
<DIV class=code_title>xml 代码</DIV></SPAN><SPAN>
<DIV class=dp-highlighter>
<OL class=dp-xml>
<LI class=alt><SPAN><SPAN class=tag>&lt;</SPAN><SPAN class=tag-name>bean</SPAN><SPAN>&nbsp;</SPAN><SPAN class=attribute>id</SPAN><SPAN>=</SPAN><SPAN class=attribute-value>"sessionFactory"</SPAN><SPAN>&nbsp;</SPAN><SPAN class=attribute>class</SPAN><SPAN>=</SPAN><SPAN class=attribute-value>"com.htxx.service.dao.MultiSessionFactory"</SPAN><SPAN class=tag>&gt;</SPAN><SPAN>&nbsp;&nbsp;</SPAN></SPAN> 
<LI><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=tag>&lt;</SPAN><SPAN class=tag-name>property</SPAN><SPAN>&nbsp;</SPAN><SPAN class=attribute>name</SPAN><SPAN>=</SPAN><SPAN class=attribute-value>"sessionFactory"</SPAN><SPAN class=tag>&gt;</SPAN><SPAN class=tag>&lt;</SPAN><SPAN class=tag-name>ref</SPAN><SPAN>&nbsp;</SPAN><SPAN class=attribute>bean</SPAN><SPAN>=</SPAN><SPAN class=attribute-value>"hostSessionFactory"</SPAN><SPAN class=tag>/&gt;<SPAN class=tag><SPAN class=tag-name>property</SPAN><SPAN class=tag>&gt;</SPAN><SPAN>&nbsp;</SPAN></SPAN> </SPAN>
<LI class=alt><SPAN class=tag><SPAN class=tag-name><SPAN class=tag>&gt;</SPAN><SPAN>&nbsp;&nbsp;</SPAN></SPAN> </SPAN></LI></OL></DIV>
<P class=MsoNormal style="TEXT-INDENT: 26.25pt">SpServer<SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体">的写法与<A href="http://www.javaeye.com/blog/72486">《如何在</A></SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'"><A href="javascript:void(0);/*1182164875171*/">spring</A></SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体"><A href="javascript:void(0);/*1182164875171*/">框架中解决多数据源的问题》</A>中的一样，我就不再累赘了。</SPAN></P>
<P class=MsoNormal style="TEXT-INDENT: 26.25pt"><SPAN style="FONT-FAMILY: 宋体">另外，在</SPAN><SPAN>spring</SPAN><SPAN style="FONT-FAMILY: 宋体">配置中配置多个数据源，每个数据源对应一个</SPAN><SPAN>sessionFactory</SPAN><SPAN style="FONT-FAMILY: 宋体">，这个对应的</SPAN><SPAN>sessionFactory</SPAN><SPAN style="FONT-FAMILY: 宋体">中的值对象应当是该数据源的值对象。客户程序在执行数据访问前，通过调用</SPAN><SPAN>SpServer</SPAN><SPAN style="FONT-FAMILY: 宋体">的</SPAN><SPAN>putSp()</SPAN><SPAN style="FONT-FAMILY: 宋体">方法，告诉</SPAN><SPAN>MultiSessionFactory</SPAN><SPAN style="FONT-FAMILY: 宋体">需要切换到哪个</SPAN><SPAN>sessionFactory</SPAN><SPAN style="FONT-FAMILY: 宋体">，然后执行数据访问。这样，不同数据源的值对象通过放在不同的</SPAN><SPAN>sessionFactory</SPAN><SPAN style="FONT-FAMILY: 宋体">中，避免了张冠李戴的情况。具体的示例见附件的</SPAN><SPAN>MultiSessionFactoryTest</SPAN><SPAN style="FONT-FAMILY: 宋体">。</SPAN></P>
<H2><SPAN style="FONT-FAMILY: 黑体">另外的方案</SPAN><SPAN></SPAN></H2>
<P class=MsoNormal style="TEXT-INDENT: 26.25pt"><SPAN style="FONT-FAMILY: 宋体">也许有些朋友对以上方案还不满意，因为在执行数据访问前毕竟还要多做一步指定</SPAN><SPAN>sessionFactory</SPAN><SPAN style="FONT-FAMILY: 宋体">的工作。实际上，对于各个数据源的数据结构不同的项目，一个值对象应当使用哪个数据源有一个非常确定的对应关系。如果通过配置文件将值对象与它的</SPAN><SPAN>sessionFactory</SPAN><SPAN style="FONT-FAMILY: 宋体">对应起来，那么我们在执行数据访问的时候传递的是哪个值对象，</SPAN><SPAN>MultiSessionFactory</SPAN><SPAN style="FONT-FAMILY: 宋体">马上就可以去找到对应的</SPAN><SPAN>sessionFactory</SPAN><SPAN style="FONT-FAMILY: 宋体">。这个方案你可以通过</SPAN><SPAN>AOP</SPAN><SPAN style="FONT-FAMILY: 宋体">来制作一个拦截器拦截所有诸如</SPAN><SPAN>save()</SPAN><SPAN style="FONT-FAMILY: 宋体">、</SPAN><SPAN>delete()</SPAN><SPAN style="FONT-FAMILY: 宋体">、</SPAN><SPAN>get()</SPAN><SPAN style="FONT-FAMILY: 宋体">、</SPAN><SPAN>load()</SPAN><SPAN style="FONT-FAMILY: 宋体">等方法来实现，也可以扩展</SPAN><SPAN>HibernateDaoSupport</SPAN><SPAN style="FONT-FAMILY: 宋体">来实现。这样的方案使客户程序甚至都不用知道他是在操作的一个多数据源系统。当然，这个方案感兴趣的朋友可以自己去实现。</SPAN></P>
<P class=MsoNormal style="TEXT-INDENT: 26.25pt"><SPAN style="FONT-FAMILY: 宋体">另外，在这个方案中的核心是运用</SPAN><SPAN>Decorator</SPAN><SPAN style="FONT-FAMILY: 宋体">设计模式来解决切换</SPAN><SPAN>sessionFactory</SPAN><SPAN style="FONT-FAMILY: 宋体">的目的，即</SPAN><SPAN>MultiSessionFactory</SPAN><SPAN style="FONT-FAMILY: 宋体">的实现。至于通过什么方式来通知</SPAN><SPAN>MultiSessionFactory</SPAN><SPAN style="FONT-FAMILY: 宋体">应当切换到哪个</SPAN><SPAN>SessionFactory</SPAN><SPAN style="FONT-FAMILY: 宋体">，可以根据不同项目的情况自由选择。我在这里给大家提供了通过</SPAN><SPAN>SpOberver</SPAN><SPAN style="FONT-FAMILY: 宋体">和建立值对象与</SPAN><SPAN>sessionFactory</SPAN><SPAN style="FONT-FAMILY: 宋体">关系的配置文件这两个方案，你也可以有自己的方案解决。</SPAN></P>
<H2><SPAN style="FONT-FAMILY: 黑体">第三种情况的解决方案</SPAN><SPAN></SPAN></H2>
<P class=MsoNormal style="TEXT-INDENT: 26.25pt"><SPAN style="FONT-FAMILY: 宋体">前面我已经给出了第一种和第二种情况的解决方案：各个数据源的数据结构不同的情况用</SPAN><SPAN>MultiSessionFactory</SPAN><SPAN style="FONT-FAMILY: 宋体">解决；各个数据源的数据结构相同的情况用</SPAN><SPAN>MultiDataSource</SPAN><SPAN style="FONT-FAMILY: 宋体">解决。那么第三种情况，各个数据源的数据结构部分相同又有部分不同，又应当如何解决呢？当然是将</SPAN><SPAN>MultiSessionFactory</SPAN><SPAN style="FONT-FAMILY: 宋体">和</SPAN><SPAN>MultiDataSource</SPAN><SPAN style="FONT-FAMILY: 宋体">结合起来解决。对于数据结构不同的部分，其分别创建各自的</SPAN><SPAN>sessionFactory</SPAN><SPAN style="FONT-FAMILY: 宋体">然后通过</SPAN><SPAN>MultiSessionFactory</SPAN><SPAN style="FONT-FAMILY: 宋体">来切换，而对于数据结构相同的部分，建立共同的</SPAN><SPAN>sessionFactory</SPAN><SPAN style="FONT-FAMILY: 宋体">和多个不同的</SPAN><SPAN>dataSource</SPAN><SPAN style="FONT-FAMILY: 宋体">然后通过</SPAN><SPAN>MultiDataSource</SPAN><SPAN style="FONT-FAMILY: 宋体">来切换就可以了。</SPAN></P><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体">还有的朋友问到这样的方案其事务处理和二级缓存的情况。这个方案是在</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'">spring</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体">框架下的解决方案，其事务处理的能力也是由</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'">spring</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体">的能力来决定的。目前</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'">spring</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体">要处理跨数据库的事务处理是通过</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'">JTA</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体">来实现的，这种方式在该方案中同样可以实现，朋友们可以试一试。另外，本方案能使用二级缓存吗？当然可以。对于</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'">MultiSessionFactory</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体">当然没有任何问题，它通过不同的</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'">sessionFactory</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体">分离开了不同的数据源和值对象，我们可以毫无顾忌地使用。对于</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'">MultiDataSource</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体">来说，就有点问题了。</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'">MultiDataSource</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体">使多个数据源使用共同的</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'">sessionFactory</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体">，因此它仿佛就是将多个数据源在逻辑上合并为一个数据源。正因为如此，我们需要保证对于同一个表在所有数据源中都要主键唯一。什么意思呢？数据源</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'">A</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体">和数据源</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'">B</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体">都有表</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'">T</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体">，如果数据源</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'">A</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体">中的表</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'">T</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体">拥有</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'">ID</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体">为</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'">001</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体">的一条数据，那么在数据源</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'">B</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体">的表</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'">T</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体">中就不能有</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'">ID</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体">为</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'">001</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体">的记录。如果你总是通过</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'">MultiDataSource</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体">来执行表的插入操作，并且使用uuid.hex生成主键，这当然不会有问题。但如果你有通过其它方式插入表的操作，你应当保证这样的唯一性。另外，对于查询的操作，缓存中存放的既可能是数据源</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'">A</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体">的数据，也可能是数据源</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'">B</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体">的数据，因此你应当对数据有一个规划。对于表</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'">T</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体">的数据，哪些应当插入到数据源</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'">A</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体">中，哪些应当插入到</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'">B</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体">中，应当有一个定义。假如是通过不同单位来决定插入哪个数据源，那么在查询数据源</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'">A</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体">的表</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'">T</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体">是，应当增加条件只查询数据源</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'">A</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体">应当有的单位而排除调其它单位。如此这样，你只要注意到这两个问题，你就可以放心大胆地使用二级缓存。</SPAN></SPAN></SPAN> </DIV>
<DIV class=attachments>
<UL>
<LI><A href="http://www.javaeye.com/topics/download/ff2cdd35-efb4-4a79-96d2-3136b40533aa">example.rar</A> (16.4 KB) 
<LI>描述: 示例文件 
<LI>下载次数: 365 </LI></UL></DIV>]]></description>
</item><item>
<title><![CDATA[如何在spring框架中解决多数据源的问题]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=lhwork&amp;id=32876</link>
<author>lhwork</author>
<pubDate>2008/3/25 17:50:53</pubDate>
<description><![CDATA[<H3><A href="http://fangang.javaeye.com/blog/72486">如何在spring框架中解决多数据源的问题</A></H3><STRONG>关键字</STRONG>: 设计模式 
<DIV class=blog_content>
<P class=MsoNormal style="TEXT-INDENT: 17.95pt"><SPAN style="FONT-FAMILY: 宋体"><SPAN style="FONT-FAMILY: 宋体">在我们的项目中遇到这样一个问题：我们的项目需要连接多个数据库，而且不同的客户在每次访问中根据需要会去访问不同的数据库。我们以往在</SPAN><SPAN>spring</SPAN><SPAN style="FONT-FAMILY: 宋体">和</SPAN><SPAN>hibernate</SPAN><SPAN style="FONT-FAMILY: 宋体">框架中总是配置一个数据源，因而</SPAN><SPAN>sessionFactory</SPAN><SPAN style="FONT-FAMILY: 宋体">的</SPAN><SPAN>dataSource</SPAN><SPAN style="FONT-FAMILY: 宋体">属性总是指向这个数据源并且恒定不变，所有</SPAN><SPAN>DAO</SPAN><SPAN style="FONT-FAMILY: 宋体">在使用</SPAN><SPAN>sessionFactory</SPAN><SPAN style="FONT-FAMILY: 宋体">的时候都是通过这个数据源访问数据库。但是现在，由于项目的需要，我们的</SPAN><SPAN>DAO</SPAN><SPAN style="FONT-FAMILY: 宋体">在访问</SPAN><SPAN>sessionFactory</SPAN><SPAN style="FONT-FAMILY: 宋体">的时候都不得不在多个数据源中不断切换，问题就出现了：如何让</SPAN><SPAN>sessionFactory</SPAN><SPAN style="FONT-FAMILY: 宋体">在执行数据持久化的时候，根据客户的需求能够动态切换不同的数据源？我们能不能在</SPAN><SPAN>spring</SPAN><SPAN style="FONT-FAMILY: 宋体">的框架下通过少量修改得到解决？是否有什么设计模式可以利用呢？</SPAN></SPAN>&nbsp;&nbsp; </P>
<H2><SPAN style="FONT-FAMILY: 黑体">问题的分析</SPAN></H2>
<P class=MsoNormal style="TEXT-INDENT: 17.95pt"><SPAN style="FONT-FAMILY: 宋体">我首先想到在</SPAN><SPAN>spring</SPAN><SPAN style="FONT-FAMILY: 宋体">的</SPAN><SPAN>applicationContext</SPAN><SPAN style="FONT-FAMILY: 宋体">中配置所有的</SPAN><SPAN>dataSource</SPAN><SPAN style="FONT-FAMILY: 宋体">。这些</SPAN><SPAN>dataSource</SPAN><SPAN style="FONT-FAMILY: 宋体">可能是各种不同类型的，比如不同的数据库：</SPAN><SPAN>Oracle</SPAN><SPAN style="FONT-FAMILY: 宋体">、</SPAN><SPAN>SQL Server</SPAN><SPAN style="FONT-FAMILY: 宋体">、</SPAN><SPAN>MySQL</SPAN><SPAN style="FONT-FAMILY: 宋体">等，也可能是不同的数据源：比如</SPAN><SPAN>apache </SPAN><SPAN style="FONT-FAMILY: 宋体">提供的</SPAN><SPAN>org.apache.commons.dbcp.BasicDataSource</SPAN><SPAN style="FONT-FAMILY: 宋体">、</SPAN><SPAN>spring</SPAN><SPAN style="FONT-FAMILY: 宋体">提供的</SPAN><SPAN>org.springframework.jndi.JndiObjectFactoryBean</SPAN><SPAN style="FONT-FAMILY: 宋体">等。然后</SPAN><SPAN>sessionFactory</SPAN><SPAN style="FONT-FAMILY: 宋体">根据客户的每次请求，将</SPAN><SPAN>dataSource</SPAN><SPAN style="FONT-FAMILY: 宋体">属性设置成不同的数据源，以到达切换数据源的目的。</SPAN></P>
<P class=MsoNormal style="TEXT-INDENT: 17.95pt"><SPAN style="FONT-FAMILY: 宋体">但是，我很快发现一个问题：当多用户同时并发访问数据库的时候会出现资源争用的问题。这都是“单例模式”惹的祸。众所周知，我们在使用</SPAN><SPAN>spring</SPAN><SPAN style="FONT-FAMILY: 宋体">框架的时候，在</SPAN><SPAN>beanFactory</SPAN><SPAN style="FONT-FAMILY: 宋体">中注册的</SPAN><SPAN>bean</SPAN><SPAN style="FONT-FAMILY: 宋体">基本上都是采用单例模式，即</SPAN><SPAN>spring</SPAN><SPAN style="FONT-FAMILY: 宋体">在启动的时候，这些</SPAN><SPAN>bean</SPAN><SPAN style="FONT-FAMILY: 宋体">就装载到内存中，并且每个</SPAN><SPAN>bean</SPAN><SPAN style="FONT-FAMILY: 宋体">在整个项目中只存在一个对象。正因为只存在一个对象，对象的所有属性，更准确说是实例变量，表现得就如同是个静态变量（实际上“静态”与“单例”往往是非常相似的两个东西，我们常常用“静态”来实现“单例”）。拿我们的问题来说，</SPAN><SPAN>sessionFactory</SPAN><SPAN style="FONT-FAMILY: 宋体">在整个项目中只有一个对象，它的实例变量</SPAN><SPAN>dataSource</SPAN><SPAN style="FONT-FAMILY: 宋体">也就只有一个，就如同一个静态变量一般。如果不同的用户都不断地去修改</SPAN><SPAN>dataSource</SPAN><SPAN style="FONT-FAMILY: 宋体">的值，必然会出现多用户争用一个变量的问题，对系统产生隐患。</SPAN></P>
<P class=MsoNormal style="TEXT-INDENT: 17.95pt"><SPAN style="FONT-FAMILY: 宋体">通过以上的分析，解决多数据源访问问题的关键，就集中在</SPAN><SPAN>sessionFactory</SPAN><SPAN style="FONT-FAMILY: 宋体">在执行数据持久化的时候，能够通过某段代码去根据客户的需要动态切换数据源，并解决资源争用的问题。</SPAN></P>
<H2><SPAN style="FONT-FAMILY: 黑体">问题的解决</SPAN></H2>
<H4 style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; tab-stops: list 21.0pt"><SPAN><SPAN>(一)<SPAN style="FONT-FAMILY: 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN></SPAN><SPAN style="FONT-FAMILY: 黑体">采用</SPAN><SPAN>Decorator</SPAN><SPAN style="FONT-FAMILY: 黑体">设计模式</SPAN></H4>
<P class=MsoNormal style="TEXT-INDENT: 17.95pt"><SPAN style="FONT-FAMILY: 宋体">要解决这个问题，我的思路锁定在了这个</SPAN><SPAN>dataSource</SPAN><SPAN style="FONT-FAMILY: 宋体">上了。如果</SPAN><SPAN>sessionFactory</SPAN><SPAN style="FONT-FAMILY: 宋体">指向的</SPAN><SPAN>dataSource</SPAN><SPAN style="FONT-FAMILY: 宋体">可以根据客户的需求去连接客户所需要的真正的数据源，即提供动态切换数据源的功能，那么问题就解决了。那么我们怎么做呢？去修改那些我们要使用的</SPAN><SPAN>dataSource</SPAN><SPAN style="FONT-FAMILY: 宋体">源码吗？这显然不是一个好的方案，我们希望我们的修改与原</SPAN><SPAN>dataSource</SPAN><SPAN style="FONT-FAMILY: 宋体">代码是分离的。根据以上的分析，使用</SPAN><SPAN>GoF</SPAN><SPAN style="FONT-FAMILY: 宋体">设计模式中的</SPAN><SPAN>Decorator</SPAN><SPAN style="FONT-FAMILY: 宋体">模式（装饰者模式）应当是我们可以选择的最佳方案。</SPAN></P>
<P class=MsoNormal style="TEXT-INDENT: 17.95pt"><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体">什么是“</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'">Decorator</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体">模式”？简单点儿说就是当我们需要修改原有的功能，但我们又不愿直接去修改原有的代码时，设计一个</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'">Decorator</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体">套在原有代码外面。当我们使用</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'">Decorator</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体">的时候与原类完全一样，当</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'">Decorator</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体">的某些功能却已经修改为了我们需要修改的功能。</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'">Decorator</SPAN><SPAN style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体">模式的结构如图。</SPAN></P>
<P class=MsoNormal align=center><SPAN style="FONT-FAMILY: 宋体"><IMG height=183 alt="" src="http://fangang.javaeye.com/upload/picture/pic/3753/0a7ad179-b609-4fb5-ae49-d266f0fb9ee5.jpg" width=480 _counted="undefined"></SPAN></P>
<P class=MsoNormal><SPAN style="FONT-FAMILY: 宋体"><SPAN style="FONT-FAMILY: 宋体"><SPAN style="FONT-FAMILY: 宋体">我们本来需要修改图中所有具体的</SPAN><SPAN>Component</SPAN><SPAN style="FONT-FAMILY: 宋体">类的一些功能，但却并不是去直接修改它们的代码，而是在它们的外面增加一个</SPAN><SPAN>Decorator</SPAN><SPAN style="FONT-FAMILY: 宋体">。</SPAN><SPAN>Decorator</SPAN><SPAN style="FONT-FAMILY: 宋体">与具体的</SPAN><SPAN>Component</SPAN><SPAN style="FONT-FAMILY: 宋体">类都是继承的</SPAN><SPAN>AbstractComponent</SPAN><SPAN style="FONT-FAMILY: 宋体">，因此它长得和具体的</SPAN><SPAN>Component</SPAN><SPAN style="FONT-FAMILY: 宋体">类一样，也就是说我们在使用</SPAN><SPAN>Decorator</SPAN><SPAN style="FONT-FAMILY: 宋体">的时候就如同在使用</SPAN><SPAN>ConcreteComponentA</SPAN><SPAN style="FONT-FAMILY: 宋体">或者</SPAN><SPAN>ConcreteComponentB</SPAN><SPAN style="FONT-FAMILY: 宋体">一样，甚至那些使用</SPAN><SPAN>ConcreteComponentA</SPAN><SPAN style="FONT-FAMILY: 宋体">或者</SPAN><SPAN>ConcreteComponentB</SPAN><SPAN style="FONT-FAMILY: 宋体">的客户程序都不知道它们用的类已经改为了</SPAN><SPAN>Decorator</SPAN><SPAN style="FONT-FAMILY: 宋体">，但是</SPAN><SPAN>Decorator</SPAN><SPAN style="FONT-FAMILY: 宋体">已经对具体的</SPAN><SPAN>Component</SPAN><SPAN style="FONT-FAMILY: 宋体">类的部分方法进行了修改，执行这些方法的结果已经不同了。</SPAN></SPAN></SPAN></P>
<H4 style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; tab-stops: list 21.0pt"><SPAN><SPAN>(二)<SPAN style="FONT-FAMILY: 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN></SPAN><SPAN style="FONT-FAMILY: 黑体">设计</SPAN><SPAN>MultiDataSource</SPAN><SPAN style="FONT-FAMILY: 黑体">类</SPAN></H4>
<P class=MsoNormal style="TEXT-INDENT: 17.95pt"><SPAN style="FONT-FAMILY: 宋体">现在回到我们的问题，我们需要对</SPAN><SPAN>dataSource</SPAN><SPAN style="FONT-FAMILY: 宋体">的功能进行变更，但又不希望修改</SPAN><SPAN>dataSource</SPAN><SPAN style="FONT-FAMILY: 宋体">中的任何代码。我这里指的</SPAN><SPAN>dataSource</SPAN><SPAN style="FONT-FAMILY: 宋体">是所有实现</SPAN><SPAN>javax.sql.DataSource</SPAN><SPAN style="FONT-FAMILY: 宋体">接口的类，我们常用的包括</SPAN><SPAN>apache </SPAN><SPAN style="FONT-FAMILY: 宋体">提供的</SPAN><SPAN>org.apache.commons.dbcp.BasicDataSource</SPAN><SPAN style="FONT-FAMILY: 宋体">、</SPAN><SPAN>spring</SPAN><SPAN style="FONT-FAMILY: 宋体">提供的</SPAN><SPAN>org.springframework.jndi.JndiObjectFactoryBean</SPAN><SPAN style="FONT-FAMILY: 宋体">等，这些类我们不可能修改它们本身，更不可能对它们一个个地修改以实现动态分配数据源的功能，同时，我们又希望使用</SPAN><SPAN>dataSource</SPAN><SPAN style="FONT-FAMILY: 宋体">的</SPAN><SPAN>sessionFactory</SPAN><SPAN style="FONT-FAMILY: 宋体">根本就感觉不到这样的变化。</SPAN><SPAN>Decorator</SPAN><SPAN style="FONT-FAMILY: 宋体">模式就正是解决这个问题的设计模式。</SPAN></P>
<P class=MsoNormal><SPAN style="FONT-FAMILY: 宋体">首先写一个</SPAN><SPAN>Decorator</SPAN><SPAN style="FONT-FAMILY: 宋体">类，我取名叫</SPAN><SPAN>MultiDataSource，通过它来动态切换数据源</SPAN><SPAN style="FONT-FAMILY: 宋体">。同时在配置文件中将sessionFactory的dataSource属性由原来的某个具体的dataSource改为MultiDataSource。如图：</SPAN></P>
<P class=MsoNormal align=center><SPAN style="FONT-FAMILY: 宋体"><IMG height=283 alt="" src="http://fangang.javaeye.com/upload/picture/pic/3751/e853e195-11a9-4836-9e3c-83db72d6ed39.jpg" width=480 _counted="undefined"></SPAN></P>
<P class=MsoNormal><SPAN>对比原<SPAN>Decorator</SPAN><SPAN style="FONT-FAMILY: 宋体">模式，</SPAN><SPAN>AbstractComponent</SPAN><SPAN style="FONT-FAMILY: 宋体">是一个抽象类，但在这里我们可以将这个抽象类用接口来代替，即</SPAN><SPAN>DataSource</SPAN><SPAN style="FONT-FAMILY: 宋体">接口，而</SPAN><SPAN>ConcreteComponent</SPAN><SPAN style="FONT-FAMILY: 宋体">就是那些</SPAN><SPAN>DataSource</SPAN><SPAN style="FONT-FAMILY: 宋体">的实现类，如</SPAN><SPAN>BasicDataSource</SPAN><SPAN style="FONT-FAMILY: 宋体">、</SPAN><SPAN>JndiObjectFactoryBean</SPAN><SPAN style="FONT-FAMILY: 宋体">等。</SPAN>MultiDataSource</SPAN><SPAN style="FONT-FAMILY: 宋体">封装了具体的dataSource，并实现了数据源动态切换：</SPAN></P><SPAN style="FONT-FAMILY: 宋体">
<DIV class=code_title>java 代码</DIV></SPAN><SPAN style="FONT-FAMILY: 宋体">
<DIV class=dp-highlighter>
<OL class=dp-j>
<LI class=alt><SPAN><SPAN class=keyword>public</SPAN><SPAN>&nbsp;</SPAN><SPAN class=keyword>class</SPAN><SPAN>&nbsp;MultiDataSource&nbsp;</SPAN><SPAN class=keyword>implements</SPAN><SPAN>&nbsp;DataSource&nbsp;{ &nbsp;&nbsp;</SPAN></SPAN> 
<LI><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=keyword>private</SPAN><SPAN>&nbsp;DataSource&nbsp;dataSource&nbsp;=&nbsp;</SPAN><SPAN class=keyword>null</SPAN><SPAN>; &nbsp;&nbsp;</SPAN> 
<LI class=alt><SPAN class=keyword>public</SPAN><SPAN>&nbsp;MultiDataSource(DataSource&nbsp;dataSource){ &nbsp;&nbsp;</SPAN> 
<LI><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=keyword>this</SPAN><SPAN>.dataSource&nbsp;=&nbsp;dataSource; &nbsp;&nbsp;</SPAN> 
<LI class=alt><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</SPAN> 
<LI><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=comment>/*&nbsp;(non-Javadoc) </SPAN>&nbsp; 
<LI class=alt><SPAN><SPAN class=comment>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@see&nbsp;javax.sql.DataSource#getConnection() </SPAN>&nbsp;</SPAN> 
<LI><SPAN><SPAN class=comment>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</SPAN><SPAN>&nbsp;&nbsp;</SPAN></SPAN> 
<LI class=alt><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=keyword>public</SPAN><SPAN>&nbsp;Connection&nbsp;getConnection()&nbsp;</SPAN><SPAN class=keyword>throws</SPAN><SPAN>&nbsp;SQLException&nbsp;{ &nbsp;&nbsp;</SPAN> 
<LI><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=keyword>return</SPAN><SPAN>&nbsp;getDataSource().getConnection(); &nbsp;&nbsp;</SPAN> 
<LI class=alt><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</SPAN> 
<LI><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=comment>//其它DataSource接口应当实现的方法 </SPAN><SPAN>&nbsp;&nbsp;</SPAN> 
<LI class=alt><SPAN>&nbsp;&nbsp;</SPAN> 
<LI><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=keyword>public</SPAN><SPAN>&nbsp;DataSource&nbsp;getDataSource(){ &nbsp;&nbsp;</SPAN> 
<LI class=alt><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=keyword>return</SPAN><SPAN>&nbsp;</SPAN><SPAN class=keyword>this</SPAN><SPAN>.dataSource; &nbsp;&nbsp;</SPAN> 
<LI><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</SPAN> 
<LI class=alt><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</SPAN> 
<LI><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=keyword>public</SPAN><SPAN>&nbsp;</SPAN><SPAN class=keyword>void</SPAN><SPAN>&nbsp;setDataSource(DataSource&nbsp;dataSource)&nbsp;{ &nbsp;&nbsp;</SPAN> 
<LI class=alt><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=keyword>this</SPAN><SPAN>.dataSource&nbsp;=&nbsp;dataSource; &nbsp;&nbsp;</SPAN> 
<LI><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</SPAN> 
<LI class=alt><SPAN>} &nbsp;&nbsp;</SPAN> </LI></OL></DIV>
<P class=MsoNormal style="TEXT-INDENT: 17.95pt">客户在发出请求的时候，将dataSourceName放到request中，然后把request中的数据源名通过调用new <SPAN style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 'Courier New'">MultiDataSource(dataSource)</SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 宋体">时可以告诉</SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 'Courier New'">MultiDataSource</SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 宋体">客户需要的数据源，就可以实现动态切换数据源了。但细心的朋友会发现这在单例的情况下就是问题的，因为</SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 'Courier New'">MultiDataSource</SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 宋体">在系统中只有一个对象，它的实例变量</SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 'Courier New'">dataSource</SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 宋体">也只有一个，就如同一个静态变量一般。正因为如此，</SPAN><SPAN style="FONT-FAMILY: 宋体">单例模式让许多设计模式都不得不需要更改，这将在我的《“单例”更改了我们的设计模式》中详细讨论。那么，我们在单例模式下如何设计呢？</SPAN></P>
<H4 style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; tab-stops: list 21.0pt"><SPAN><SPAN>(三)<SPAN style="FONT-FAMILY: 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN></SPAN><SPAN style="FONT-FAMILY: 黑体">单例模式下的</SPAN><SPAN>MultiDataSource</SPAN></H4>
<P class=MsoNormal style="TEXT-INDENT: 17.95pt"><SPAN style="FONT-FAMILY: 宋体">在单例模式下，由于我们在每次调用</SPAN><SPAN>MultiDataSource</SPAN><SPAN style="FONT-FAMILY: 宋体">的方法的时候，</SPAN><SPAN>dataSource</SPAN><SPAN style="FONT-FAMILY: 宋体">都可能是不同的，所以我们不能将</SPAN><SPAN>dataSource</SPAN><SPAN style="FONT-FAMILY: 宋体">放在实例变量</SPAN><SPAN>dataSource</SPAN><SPAN style="FONT-FAMILY: 宋体">中，最简单的方式就是在方法</SPAN><SPAN>getDataSource()</SPAN><SPAN style="FONT-FAMILY: 宋体">中增加参数，告诉</SPAN><SPAN>MultiDataSource</SPAN><SPAN style="FONT-FAMILY: 宋体">我到底调用的是哪个</SPAN><SPAN>dataSource</SPAN><SPAN style="FONT-FAMILY: 宋体">：</SPAN></P><SPAN style="FONT-FAMILY: 宋体">
<DIV class=code_title>java 代码</DIV>
<DIV class=dp-highlighter>
<OL class=dp-j>
<LI class=alt><SPAN><SPAN class=keyword>public</SPAN><SPAN>&nbsp;DataSource&nbsp;getDataSource(String&nbsp;dataSourceName){ &nbsp;&nbsp;</SPAN></SPAN> 
<LI><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log.debug(</SPAN><SPAN class=string>"dataSourceName:"</SPAN><SPAN>+dataSourceName); &nbsp;&nbsp;</SPAN> 
<LI class=alt><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=keyword>try</SPAN><SPAN>{ &nbsp;&nbsp;</SPAN> 
<LI><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=keyword>if</SPAN><SPAN>(dataSourceName==</SPAN><SPAN class=keyword>null</SPAN><SPAN>||dataSourceName.equals(</SPAN><SPAN class=string>""</SPAN><SPAN>)){ &nbsp;&nbsp;</SPAN> 
<LI class=alt><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=keyword>return</SPAN><SPAN>&nbsp;</SPAN><SPAN class=keyword>this</SPAN><SPAN>.dataSource; &nbsp;&nbsp;</SPAN> 
<LI><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</SPAN> 
<LI class=alt><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=keyword>return</SPAN><SPAN>&nbsp;(DataSource)</SPAN><SPAN class=keyword>this</SPAN><SPAN>.applicationContext.getBean(dataSourceName); &nbsp;&nbsp;</SPAN> 
<LI><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</SPAN><SPAN class=keyword>catch</SPAN><SPAN>(NoSuchBeanDefinitionException&nbsp;ex){ &nbsp;&nbsp;</SPAN> 
<LI class=alt><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=keyword>throw</SPAN><SPAN>&nbsp;</SPAN><SPAN class=keyword>new</SPAN><SPAN>&nbsp;DaoException(</SPAN><SPAN class=string>"There&nbsp;is&nbsp;not&nbsp;the&nbsp;dataSource&nbsp;</SPAN> 
<LI><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</SPAN> 
<LI class=alt><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</SPAN> </LI></OL></DIV>
<P class=MsoNormal style="TEXT-INDENT: 17.95pt">值得一提的是，我需要的数据源已经都在<SPAN>spring</SPAN><SPAN style="FONT-FAMILY: 宋体">的配置文件中注册，</SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 'Courier New'">dataSourceName</SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 宋体">就是其对应的</SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 'Courier New'">id</SPAN><SPAN style="FONT-FAMILY: 宋体">。</SPAN></P><SPAN style="FONT-FAMILY: 宋体">
<DIV class=code_title>xml 代码</DIV>
<DIV class=dp-highlighter>
<OL class=dp-xml>
<LI class=alt><SPAN><SPAN class=tag>&lt;</SPAN><SPAN class=tag-name>bean</SPAN><SPAN>&nbsp;</SPAN><SPAN class=attribute>id</SPAN><SPAN>=</SPAN><SPAN class=attribute-value>"dataSource1"</SPAN><SPAN>&nbsp;&nbsp;</SPAN></SPAN> 
<LI><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=attribute>class</SPAN><SPAN>=</SPAN><SPAN class=attribute-value>"org.apache.commons.dbcp.BasicDataSource"</SPAN><SPAN class=tag>&gt;</SPAN><SPAN>&nbsp;&nbsp;</SPAN> 
<LI class=alt><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=tag>&lt;</SPAN><SPAN class=tag-name>property</SPAN><SPAN>&nbsp;</SPAN><SPAN class=attribute>name</SPAN><SPAN>=</SPAN><SPAN class=attribute-value>"driverClassName"</SPAN><SPAN class=tag>&gt;</SPAN><SPAN>&nbsp;&nbsp;</SPAN> 
<LI><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=tag>&lt;</SPAN><SPAN class=tag-name>value</SPAN><SPAN class=tag>&gt;</SPAN><SPAN>oracle.jdbc.driver.OracleDriver</SPAN><SPAN class=tag><SPAN class=tag-name>value</SPAN><SPAN class=tag>&gt;</SPAN><SPAN>&nbsp;&nbsp;</SPAN> </SPAN>
<LI class=alt><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=tag><SPAN class=tag-name>property</SPAN><SPAN class=tag>&gt;</SPAN><SPAN>&nbsp;</SPAN></SPAN> 
<LI class=alt><SPAN class=tag></SPAN><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;...... &nbsp;&nbsp;</SPAN> 
<LI class=alt><SPAN class=tag><SPAN class=tag-name>bean</SPAN><SPAN class=tag>&gt;</SPAN><SPAN>&nbsp;&nbsp;</SPAN> </SPAN>
<LI><SPAN class=tag>&lt;</SPAN><SPAN class=tag-name>bean</SPAN><SPAN>&nbsp;</SPAN><SPAN class=attribute>id</SPAN><SPAN>=</SPAN><SPAN class=attribute-value>"dataSource2"</SPAN><SPAN>&nbsp;&nbsp;</SPAN> 
<LI class=alt><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=attribute>class</SPAN><SPAN>=</SPAN><SPAN class=attribute-value>"org.apache.commons.dbcp.BasicDataSource"</SPAN><SPAN class=tag>&gt;</SPAN><SPAN>&nbsp;&nbsp;</SPAN> 
<LI><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=tag>&lt;</SPAN><SPAN class=tag-name>property</SPAN><SPAN>&nbsp;</SPAN><SPAN class=attribute>name</SPAN><SPAN>=</SPAN><SPAN class=attribute-value>"driverClassName"</SPAN><SPAN class=tag>&gt;</SPAN><SPAN>&nbsp;&nbsp;</SPAN> 
<LI class=alt><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=tag>&lt;</SPAN><SPAN class=tag-name>value</SPAN><SPAN class=tag>&gt;</SPAN><SPAN>oracle.jdbc.driver.OracleDriver</SPAN><SPAN class=tag><SPAN class=tag-name>value</SPAN><SPAN class=tag>&gt;</SPAN><SPAN>&nbsp;</SPAN></SPAN> 
<LI><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=tag><SPAN class=tag-name>property</SPAN><SPAN class=tag>&gt;</SPAN><SPAN>&nbsp;&nbsp;</SPAN>&nbsp;</SPAN> 
<LI class=alt><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;...... &nbsp;&nbsp;</SPAN> 
<LI><SPAN class=tag><SPAN class=tag-name>bean</SPAN><SPAN class=tag>&gt;</SPAN><SPAN>&nbsp;&nbsp;</SPAN>&nbsp;</SPAN> </LI></OL></DIV>
<P class=MsoNormal style="TEXT-INDENT: 17.95pt">为了得到<SPAN>spring</SPAN><SPAN style="FONT-FAMILY: 宋体">的</SPAN><SPAN>ApplicationContext</SPAN><SPAN style="FONT-FAMILY: 宋体">，</SPAN><SPAN>MultiDataSource</SPAN><SPAN style="FONT-FAMILY: 宋体">类必须实现接口</SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 'Courier New'">org.springframework.context.ApplicationContextAware</SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 宋体">，并且实现方法：</SPAN></P>
<DIV class=code_title>java 代码</DIV>
<DIV class=dp-highlighter>
<OL class=dp-j>
<LI class=alt><SPAN><SPAN class=keyword>private</SPAN><SPAN>&nbsp;ApplicationContext&nbsp;applicationContext&nbsp;=&nbsp;</SPAN><SPAN class=keyword>null</SPAN><SPAN>; &nbsp;&nbsp;</SPAN></SPAN> 
<LI><SPAN class=keyword>public</SPAN><SPAN>&nbsp;</SPAN><SPAN class=keyword>void</SPAN><SPAN>&nbsp;setApplicationContext(ApplicationContext&nbsp;applicationContext)&nbsp;</SPAN><SPAN class=keyword>throws</SPAN><SPAN>&nbsp;BeansException&nbsp;{ &nbsp;&nbsp;</SPAN> 
<LI class=alt><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=keyword>this</SPAN><SPAN>.applicationContext&nbsp;=&nbsp;applicationContext; &nbsp;&nbsp;</SPAN> 
<LI><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</SPAN> </LI></OL></DIV>
<P class=MsoNormal style="TEXT-INDENT: 17.95pt">如此这样，我就可以通过<STRONG><SPAN style="FONT-SIZE: 10pt; COLOR: #7f0055; FONT-FAMILY: 'Courier New'">this</SPAN></STRONG><SPAN style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 'Courier New'">.</SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: #0000c0; FONT-FAMILY: 'Courier New'">applicationContext</SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 'Courier New'">.getBean(dataSourceName)</SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 宋体">得到</SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 'Courier New'">dataSource</SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 宋体">了。</SPAN></P>
<H4 style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; tab-stops: list 21.0pt"><SPAN><SPAN>(四)<SPAN style="FONT-FAMILY: 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN></SPAN><SPAN style="FONT-FAMILY: 黑体">通过线程传递</SPAN><SPAN>dataSourceName</SPAN></H4>
<P class=MsoNormal style="TEXT-INDENT: 17.95pt"><SPAN style="FONT-FAMILY: 宋体">查看以上设计，</SPAN><SPAN>MultiDataSource</SPAN><SPAN style="FONT-FAMILY: 宋体">依然无法运行，因为用户在发出请求时，他需要连接什么数据库，其数据源名是放在</SPAN><SPAN>request</SPAN><SPAN style="FONT-FAMILY: 宋体">中的，要将</SPAN><SPAN>request</SPAN><SPAN style="FONT-FAMILY: 宋体">中的数据源名传给</SPAN><SPAN>MultiDataSource</SPAN><SPAN style="FONT-FAMILY: 宋体">，需要经过</SPAN><SPAN>BUS</SPAN><SPAN style="FONT-FAMILY: 宋体">和</SPAN><SPAN>DAO</SPAN><SPAN style="FONT-FAMILY: 宋体">，也就是说为了把数据源名传给</SPAN><SPAN>MultiDataSource</SPAN><SPAN style="FONT-FAMILY: 宋体">，</SPAN><SPAN>BUS</SPAN><SPAN style="FONT-FAMILY: 宋体">和</SPAN><SPAN>DAO</SPAN><SPAN style="FONT-FAMILY: 宋体">的所有方法都要增加</SPAN><SPAN>dataSourceName</SPAN><SPAN style="FONT-FAMILY: 宋体">的参数，这是我们不愿看到的。写一个类，通过线程的方式跳过</SPAN><SPAN>BUS</SPAN><SPAN style="FONT-FAMILY: 宋体">和</SPAN><SPAN>DAO</SPAN><SPAN style="FONT-FAMILY: 宋体">直接传递给</SPAN><SPAN>MultiDataSource</SPAN><SPAN style="FONT-FAMILY: 宋体">是一个不错的设计：</SPAN></P>
<P class=MsoNormal style="TEXT-INDENT: 17.95pt" align=center><SPAN style="FONT-FAMILY: 宋体"><IMG height=146 alt="" src="http://fangang.javaeye.com/upload/picture/pic/3752/58696c8a-fd62-4a7f-b6f1-1973c1ef7954.jpg" width=480 _counted="undefined"></SPAN></P><SPAN style="FONT-FAMILY: 宋体">
<DIV class=code_title>java 代码</DIV>
<DIV class=dp-highlighter>
<OL class=dp-j>
<LI class=alt><SPAN><SPAN class=keyword>public</SPAN><SPAN>&nbsp;</SPAN><SPAN class=keyword>class</SPAN><SPAN>&nbsp;SpObserver&nbsp;{ &nbsp;&nbsp;</SPAN></SPAN> 
<LI><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=keyword>private</SPAN><SPAN>&nbsp;</SPAN><SPAN class=keyword>static</SPAN><SPAN>&nbsp;ThreadLocal&nbsp;local&nbsp;=&nbsp;</SPAN><SPAN class=keyword>new</SPAN><SPAN>&nbsp;ThreadLocal(); &nbsp;&nbsp;</SPAN> 
<LI class=alt><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=keyword>public</SPAN><SPAN>&nbsp;</SPAN><SPAN class=keyword>static</SPAN><SPAN>&nbsp;</SPAN><SPAN class=keyword>void</SPAN><SPAN>&nbsp;putSp(String&nbsp;sp)&nbsp;{ &nbsp;&nbsp;</SPAN> 
<LI><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local.set(sp); &nbsp;&nbsp;</SPAN> 
<LI class=alt><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</SPAN> 
<LI><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=keyword>public</SPAN><SPAN>&nbsp;</SPAN><SPAN class=keyword>static</SPAN><SPAN>&nbsp;String&nbsp;getSp()&nbsp;{ &nbsp;&nbsp;</SPAN> 
<LI class=alt><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=keyword>return</SPAN><SPAN>&nbsp;(String)local.get(); &nbsp;&nbsp;</SPAN> 
<LI><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</SPAN> 
<LI class=alt><SPAN>} &nbsp;&nbsp;</SPAN> </LI></OL></DIV>
<P class=MsoNormal style="TEXT-INDENT: 17.95pt">做一个<SPAN>filter</SPAN><SPAN style="FONT-FAMILY: 宋体">，每次客户发出请求的时候就调用</SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 'Courier New'">SpObserver.<EM>petSp</EM>(</SPAN><SPAN>dataSourceName</SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 'Courier New'">)</SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 宋体">，将</SPAN><SPAN>request</SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 宋体">中的</SPAN><SPAN>dataSourceName</SPAN><SPAN style="FONT-FAMILY: 宋体">传递给</SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 'Courier New'">SpObserver</SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 宋体">对象。</SPAN><SPAN style="FONT-FAMILY: 宋体">最后修改</SPAN><SPAN>MultiDataSource</SPAN><SPAN style="FONT-FAMILY: 宋体">的方法</SPAN><SPAN>getDataSource()</SPAN><SPAN style="FONT-FAMILY: 宋体">：</SPAN></P>
<DIV class=code_title>java 代码</DIV>
<DIV class=dp-highlighter>
<OL class=dp-j>
<LI class=alt><SPAN><SPAN class=keyword>public</SPAN><SPAN>&nbsp;DataSource&nbsp;getDataSource(){ &nbsp;&nbsp;</SPAN></SPAN> 
<LI><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;sp&nbsp;=&nbsp;SpObserver.getSp(); &nbsp;&nbsp;</SPAN> 
<LI class=alt><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=keyword>return</SPAN><SPAN>&nbsp;getDataSource(sp); &nbsp;&nbsp;</SPAN> 
<LI><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</SPAN> </LI></OL></DIV>
<P class=MsoNormal style="TEXT-INDENT: 17.95pt">完整的<SPAN>MultiDataSource</SPAN><SPAN style="FONT-FAMILY: 宋体">代码在附件中。</SPAN></P>
<H4 style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; tab-stops: list 21.0pt"><SPAN><SPAN>(五)<SPAN style="FONT-FAMILY: 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN></SPAN><SPAN style="FONT-FAMILY: 黑体">动态添加数据源</SPAN></H4>
<P class=MsoNormal style="TEXT-INDENT: 17.95pt"><SPAN style="FONT-FAMILY: 宋体">通过以上方案，我们解决了动态分配数据源的问题，但你可能提出疑问：方案中的数据源都是配置在</SPAN><SPAN>spring</SPAN><SPAN style="FONT-FAMILY: 宋体">的</SPAN><SPAN>ApplicationContext</SPAN><SPAN style="FONT-FAMILY: 宋体">中，如果我在程序运行过程中动态添加数据源怎么办？这确实是一个问题，而且在我们的项目中也确实遇到。</SPAN><SPAN>spring</SPAN><SPAN style="FONT-FAMILY: 宋体">的</SPAN><SPAN>ApplicationContext</SPAN><SPAN style="FONT-FAMILY: 宋体">是在项目启动的时候加载的。加载以后，我们如何动态地加载新的</SPAN><SPAN>bean</SPAN><SPAN style="FONT-FAMILY: 宋体">到</SPAN><SPAN>ApplicationContext</SPAN><SPAN style="FONT-FAMILY: 宋体">中呢？我想到如果用</SPAN><SPAN>spring</SPAN><SPAN style="FONT-FAMILY: 宋体">自己的方法解决这个问题就好了。所幸的是，在查看</SPAN><SPAN>spring</SPAN><SPAN style="FONT-FAMILY: 宋体">的源代码后，我找到了这样的代码，编写了</SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 'Courier New'">DynamicLoadBean</SPAN><SPAN style="FONT-FAMILY: 宋体">类，只要</SPAN><SPAN style="FONT-FAMILY: 宋体">调用<SPAN>loadBean()</SPAN><SPAN style="FONT-FAMILY: 宋体">方法，就可以将某个或某几个配置文件中的</SPAN><SPAN>bean</SPAN><SPAN style="FONT-FAMILY: 宋体">加载到</SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 'Courier New'">ApplicationContext</SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 宋体">中（见附件）。不通过配置文件直接加载对象，在</SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 'Courier New'">spring</SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 宋体">的源码中也有，感兴趣的朋友可以自己研究。</SPAN></SPAN></P>
<H4 style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; tab-stops: list 21.0pt"><SPAN><SPAN>(六)<SPAN style="FONT-FAMILY: 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN></SPAN><SPAN style="FONT-FAMILY: 黑体">在</SPAN><SPAN>spring</SPAN><SPAN style="FONT-FAMILY: 黑体">中配置</SPAN></H4>
<P class=MsoNormal style="TEXT-INDENT: 17.95pt"><SPAN style="FONT-FAMILY: 宋体">在完成了所有这些设计以后，我最后再唠叨一句。我们应当在</SPAN><SPAN>spring</SPAN><SPAN style="FONT-FAMILY: 宋体">中做如下配置：</SPAN></P><SPAN style="FONT-FAMILY: 宋体">
<DIV class=code_title>xml 代码</DIV>
<DIV class=dp-highlighter>
<OL class=dp-xml>
<LI class=alt><SPAN><SPAN class=tag>&lt;</SPAN><SPAN class=tag-name>bean</SPAN><SPAN>&nbsp;</SPAN><SPAN class=attribute>id</SPAN><SPAN>=</SPAN><SPAN class=attribute-value>"dynamicLoadBean"</SPAN><SPAN>&nbsp;</SPAN><SPAN class=attribute>class</SPAN><SPAN>=</SPAN><SPAN class=attribute-value>"com.htxx.service.dao.DynamicLoadBean"</SPAN><SPAN class=tag>&gt;</SPAN><SPAN class=tag><SPAN class=tag-name>bean</SPAN><SPAN class=tag>&gt;</SPAN><SPAN>&nbsp;&nbsp;</SPAN></SPAN> </SPAN>
<LI><SPAN class=tag>&lt;</SPAN><SPAN class=tag-name>bean</SPAN><SPAN>&nbsp;</SPAN><SPAN class=attribute>id</SPAN><SPAN>=</SPAN><SPAN class=attribute-value>"dataSource"</SPAN><SPAN>&nbsp;</SPAN><SPAN class=attribute>class</SPAN><SPAN>=</SPAN><SPAN class=attribute-value>"com.htxx.service.dao.MultiDataSource"</SPAN><SPAN class=tag>&gt;</SPAN><SPAN>&nbsp;&nbsp;</SPAN> 
<LI class=alt><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=tag>&lt;</SPAN><SPAN class=tag-name>property</SPAN><SPAN>&nbsp;</SPAN><SPAN class=attribute>name</SPAN><SPAN>=</SPAN><SPAN class=attribute-value>"dataSource"</SPAN><SPAN class=tag>&gt;</SPAN><SPAN>&nbsp;&nbsp;</SPAN> 
<LI><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=tag>&lt;</SPAN><SPAN class=tag-name>ref</SPAN><SPAN>&nbsp;</SPAN><SPAN class=attribute>bean</SPAN><SPAN>=</SPAN><SPAN class=attribute-value>"dataSource1"</SPAN><SPAN>&nbsp;</SPAN><SPAN class=tag>/&gt;</SPAN><SPAN>&nbsp;&nbsp;</SPAN> 
<LI class=alt><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=tag><SPAN class=tag-name>property</SPAN><SPAN class=tag>&gt;</SPAN><SPAN>&nbsp;&nbsp;</SPAN> </SPAN>
<LI><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=tag><SPAN class=tag-name>bean</SPAN><SPAN class=tag>&gt;</SPAN><SPAN>&nbsp;&nbsp;</SPAN> </SPAN>
<LI class=alt><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=tag>&lt;</SPAN><SPAN class=tag-name>bean</SPAN><SPAN>&nbsp;</SPAN><SPAN class=attribute>id</SPAN><SPAN>=</SPAN><SPAN class=attribute-value>"sessionFactory"</SPAN><SPAN>&nbsp;</SPAN><SPAN class=attribute>class</SPAN><SPAN>=</SPAN><SPAN class=attribute-value>"org.springframework.orm.hibernate3.LocalSessionFactoryBean"</SPAN><SPAN class=tag>&gt;</SPAN><SPAN>&nbsp;&nbsp;</SPAN> 
<LI><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=tag>&lt;</SPAN><SPAN class=tag-name>property</SPAN><SPAN>&nbsp;</SPAN><SPAN class=attribute>name</SPAN><SPAN>=</SPAN><SPAN class=attribute-value>"dataSource"</SPAN><SPAN class=tag>&gt;</SPAN><SPAN>&nbsp;&nbsp;</SPAN> 
<LI class=alt><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=tag>&lt;</SPAN><SPAN class=tag-name>ref</SPAN><SPAN>&nbsp;</SPAN><SPAN class=attribute>bean</SPAN><SPAN>=</SPAN><SPAN class=attribute-value>"dataSource"</SPAN><SPAN>&nbsp;</SPAN><SPAN class=tag>/&gt;</SPAN><SPAN>&nbsp;&nbsp;</SPAN> 
<LI><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=tag><SPAN class=tag-name>property</SPAN><SPAN class=tag>&gt;</SPAN><SPAN>&nbsp;&nbsp;</SPAN> </SPAN>
<LI class=alt><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;...... &nbsp;&nbsp;</SPAN> 
<LI><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN class=tag><SPAN class=tag-name>bean</SPAN><SPAN class=tag>&gt;</SPAN><SPAN>&nbsp;&nbsp;</SPAN> </SPAN></LI></OL></DIV>
<P class=MsoNormal style="TEXT-INDENT: 17.95pt">其中<SPAN>dataSource</SPAN><SPAN style="FONT-FAMILY: 宋体">属性实际上更准确地说应当是</SPAN><SPAN>defaultDataSource</SPAN><SPAN style="FONT-FAMILY: 宋体">，即</SPAN><SPAN>spring</SPAN><SPAN style="FONT-FAMILY: 宋体">启动时以及在客户没有指定数据源时应当指定的默认数据源。</SPAN> </P>
<H2><SPAN style="FONT-FAMILY: 黑体">该方案的优势</SPAN></H2>
<P>&nbsp;</P><SPAN style="FONT-FAMILY: 宋体">
<P class=MsoNormal style="TEXT-INDENT: 17.95pt"><SPAN style="FONT-FAMILY: 宋体">以上方案与其它方案相比，它有哪些优势呢？</SPAN></P>
<P class=MsoNormal style="TEXT-INDENT: 17.95pt"><SPAN style="FONT-FAMILY: 宋体">首先，这个方案完全是在</SPAN><SPAN>spring</SPAN><SPAN style="FONT-FAMILY: 宋体">的框架下解决的，数据源依然配置在</SPAN><SPAN>spring</SPAN><SPAN style="FONT-FAMILY: 宋体">的配置文件中，</SPAN><SPAN>sessionFactory</SPAN><SPAN style="FONT-FAMILY: 宋体">依然去配置它的</SPAN><SPAN>dataSource</SPAN><SPAN style="FONT-FAMILY: 宋体">属性，它甚至都不知道</SPAN><SPAN>dataSource</SPAN><SPAN style="FONT-FAMILY: 宋体">的改变。唯一不同的是在真正的</SPAN><SPAN>dataSource</SPAN><SPAN style="FONT-FAMILY: 宋体">与</SPAN><SPAN>sessionFactory</SPAN><SPAN style="FONT-FAMILY: 宋体">之间增加了一个</SPAN><SPAN>MultiDataSource</SPAN><SPAN style="FONT-FAMILY: 宋体">。</SPAN></P>
<P class=MsoNormal style="TEXT-INDENT: 17.95pt"><SPAN style="FONT-FAMILY: 宋体">其次，实现简单，易于维护。这个方案虽然我说了这么多东西，其实都是分析，真正需要我们写的代码就只有</SPAN><SPAN>MultiDataSource</SPAN><SPAN style="FONT-FAMILY: 宋体">、</SPAN><SPAN>SpObserver</SPAN><SPAN style="FONT-FAMILY: 宋体">两个类。</SPAN><SPAN>MultiDataSource</SPAN><SPAN style="FONT-FAMILY: 宋体">类真正要写的只有</SPAN><SPAN>getDataSource()</SPAN><SPAN style="FONT-FAMILY: 宋体">和</SPAN><SPAN>getDataSource(sp)</SPAN><SPAN style="FONT-FAMILY: 宋体">两个方法，而</SPAN><SPAN>SpObserver</SPAN><SPAN style="FONT-FAMILY: 宋体">类更简单了。实现越简单，出错的可能就越小，维护性就越高。</SPAN></P>
<P class=MsoNormal style="TEXT-INDENT: 17.95pt"><SPAN style="FONT-FAMILY: 宋体">最后，这个方案可以使单数据源与多数据源兼容。这个方案完全不影响</SPAN><SPAN>BUS</SPAN><SPAN style="FONT-FAMILY: 宋体">和</SPAN><SPAN>DAO</SPAN><SPAN style="FONT-FAMILY: 宋体">的编写。如果我们的项目在开始之初是单数据源的情况下开发，随着项目的进行，需要变更为多数据源，则只需要修改</SPAN><SPAN>spring</SPAN><SPAN style="FONT-FAMILY: 宋体">配置，并少量修改</SPAN><SPAN>MVC</SPAN><SPAN style="FONT-FAMILY: 宋体">层以便在请求中写入需要的数据源名，变更就完成了。如果我们的项目希望改回单数据源，则只需要简单修改配置文件。这样，为我们的项目将增加更多的弹性。</SPAN></P>
<P class=MsoNormal style="TEXT-INDENT: 17.95pt"><SPAN style="FONT-FAMILY: 宋体">相关博客：<A href="http://www.javaeye.com/topic/91667">再析在spring框架中解决多数据源的问题</A> </SPAN></P></SPAN></SPAN></SPAN></SPAN></SPAN></SPAN></DIV>
<DIV class=attachments>
<UL>
<LI><A href="http://fangang.javaeye.com/topics/download/11b45eb4-9732-4fcb-85de-dd88238958b2">example.rar</A> (32.1 KB) 
<LI>描述: 源码及示例 
<LI>下载次数: 712 </LI></UL></DIV>]]></description>
</item><item>
<title><![CDATA[SELinux 的配置小解]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=lhwork&amp;id=32533</link>
<author>lhwork</author>
<pubDate>2008/3/18 9:14:57</pubDate>
<description><![CDATA[【转载】<BR>SELinux 是从FC3和AS4起，所提供的一个高级安全特性。<BR>它可以对系统上运行的任何一个应用程序做权限上的控制。<BR>版本低于FC3/AS4的Linux，没有提供SELinux特性，或者默认就是禁用这个特性的。<BR><BR>为了运行Plesk，需要对SELinux做一些修改，否则可能会造成某些服务运行不正常或者启动失败。<BR><BR>SElinux把所有的拒绝信息输出到：/var/log/messages 位置。<BR>如果某个服务比如bind不能正常启动，请查询messages文件来确认是否是SELinux造成服务不能运行。<BR>这些信息可以很简单的使用/usr/bin/audit2allow来更改规则。<BR><BR>运行如下命令，查看哪些程序的访问被SELinux拦截掉了：<BR>cat /var/log/messages | /usr/bin/audit2allow<BR><BR>然后，把列出的被拒绝的访问加入到SELinux的配置文件中。<BR><BR>通常，建议加入如下内容：<BR><BR>/etc/selinux/targeted/src/policy/domains/program/apache.te<BR>----------------------------------------------------------------<BR>allow httpd_sys_script_t var_t:file { execute getattr };<BR>allow httpd_t self:tcp_socket connect;<BR>allow httpd_t usr_t:dir write;<BR>allow httpd_t var_log_t:file { append getattr setattr };<BR>allow httpd_sys_script_t devlog_t:sock_file write;<BR>allow httpd_sys_script_t self:unix_dgram_socket { connect create write };<BR>allow httpd_sys_script_t ld_so_cache_t:file execute;<BR>allow httpd_sys_script_t syslogd_t:unix_dgram_socket sendto;<BR>allow httpd_sys_script_t var_t:dir { add_name remove_name write };<BR>allow httpd_sys_script_t var_t:fifo_file write;<BR>allow httpd_sys_script_t var_t:file { create execute_no_trans link read unlink write };<BR>----------------------------------------------------------------<BR><BR>/etc/selinux/targeted/src/policy/domains/program/named.te<BR>----------------------------------------------------------------<BR>allow named_t named_zone_t:chr_file read;<BR>allow ndc_t named_zone_t:file { getattr read write };<BR>allow named_t named_zone_t:dir { add_name write read remove_name };<BR>allow named_t named_zone_t:file { create unlink write };<BR>----------------------------------------------------------------<BR><BR>/etc/selinux/targeted/src/policy/domains/program/syslogd.te<BR>----------------------------------------------------------------<BR>allow syslogd_t usr_t:file append;<BR>allow syslogd_t usr_t:file ioctl;<BR>-------------------------------------------------------------------------<BR><BR>最后使用如下命令重新加载SELinux：<BR>make -C /etc/selinux/targeted/src/policy reload<BR><BR><BR><BR>重灌 server 並啟用 SELinux 以後,發現 asp.net 應用程式無法啟動.<BR><BR>經過研讀文件之後,大致上對 SELinux 有一定的瞭解.<BR>SELinux 本身純粹是作安全性的加強,所以不管是 user, file, directory, socket, process...等等的,都另外有了 security context,作為安全性的第二道防線.<BR>當系統要存取這些資源的時候,首先會使用原有的 unix permission 去作檢查,接著 SELinux 會再依照 security context 作第二道檢查,當檢查沒問題之後,才會允許存取.<BR><BR>SELinux 裡面有所謂的 identity, domain, type, security context, target context 等等物件...<BR>大致上來說, identity 決定身份, domain 決定 process 能幹麼, type 決定 process 以外的物件可以幹麼, security context, target context 則是 identity + domain + type 的組合. policy 則用來定義 security context, target context 可以存取哪些物件. (這些組合,真的很讓人頭暈.)<BR><BR>存取的指令也蠻多的:<BR>要看檔案目錄的 security context, 可以加上 -Z (ls -Z)<BR>要看process的 security context, 也可以用 -Z (ps axZ)<BR>要看自己的security context,可以用 id<BR>要改security context, 可以用 chcon<BR>要 reset security context, 可以用 restorecon<BR>...<BR><BR><BR>整個研讀完之後,發現應該是 policy 問題.<BR>今天下午用Google去找到這篇文章,發現有這麼個工具 - audit2allow,他是在 policycoreutils 套件裡面的指令,可以根據 warning message 產生 policy,省掉不少編寫的麻煩.<BR><BR>為了要能重新編譯 policy, 你需要安裝 selinux-policy-targeted-sources 這個套件<BR><BR>yum install selinux-policy-targeted-sources<BR><BR><BR>再使用 audit2allow 這個指令,從 dmesg 裡面分析 warning, 並將產生以後的 policy 寫入到 mono.policy 檔案中.<BR><BR>audit2allow -d -o mono.policy<BR><BR>接著把 mono.policy 更名為 local.te, 放到 /etc/selinux/targeted/src/policy/domains/misc/ .<BR>放完之後,切換到 /etc/selinux/targeted/src/policy<BR>強制 selinux 重新編譯 policy<BR><BR>make load<BR><BR>最後重新啟動我的 Apache server,就大功告成了.]]></description>
</item><item>
<title><![CDATA[apache+mod_ssl中证书生成方法]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=lhwork&amp;id=32480</link>
<author>lhwork</author>
<pubDate>2008/3/14 16:13:37</pubDate>
<description><![CDATA[<P>为配置一个安全连接，必须要给mod_ssl设置一个安全证书，CentOS默认提供一套证书，但是使用的时候每次都会提示证书签名的域名不正确，于是想弄一套自己的证书，google了很久，很多方法都有问题，最终从<A href="http://www.apache-ssl.org/" target=_blank><FONT color=#ff6600>这里</FONT></A>找到了合适的方法。</P>
<P>首先生成证书请求：</P>
<P>#openssl req -new &gt; server.csr</P>
<P>按照提示输入相关信息后，会在当前目录自动生成server.csr和privkey.pem两个文件，privkey.pem是私钥文件，默认会有passphrase，如果不移除的话，每次运行apache的时候都会提示输入passphrase，所以如果服务器重启后如果你不在服务器前面，则apache无法正常运行。</P>
<P>所以，第二步需要移除passphrase：</P>
<P>#openssl rsa -in privkey.pem -out server.key</P>
<P>这一步会让你输入前面设定的passphrase，所以在前面的时候不要胡乱设定一个passphrase哈。</P>
<P>第三步，生成服务器证书：</P>
<P>#openssl req -x509 -days 3650 -key server.key -in server.csr &gt; server.crt</P>
<P>days参数是指定证书有效期的，3650是10 年，够长的了吧？<BR>最后，在httpd.conf里的相应域名配置里加上：</P>
<P>SSLCertificateFile /etc/httpd/conf/key/server.crt<BR>SSLCertificateKeyFile /etc/httpd/conf/key/server.key</P>
<P>然后重启apache即可。</P>
<P>====</P>
<P>UPDATE：</P>
<P>还有一种方法，先按照指定算法生成密钥：</P>
<P>#openssl genrsa -des3 1024 -new &gt; server.old.key</P>
<P>然后移除passphrase：</P>
<P>#openssl rsa -in server.old.key -out server.key</P>
<P>然后生成证书请求：</P>
<P>#openssl req -new -key server.key &gt; server.csr</P>
<P>最后生成证书：</P>
<P>#openssl req -x509 -days 3650 -key server.key -in server.csr &gt; server.crt </P><SPAN style="DISPLAY: none">Technorati Tags: <A href="http://www.technorati.com/tag/apache" rel=tag><FONT color=#ff6600>apache</FONT></A>, <A href="http://www.technorati.com/tag/Certificate" rel=tag><FONT color=#ff6600>Certificate</FONT></A>, <A href="http://www.technorati.com/tag/mod+ssl" rel=tag><FONT color=#ff6600>mod ssl</FONT></A>, <A href="http://www.technorati.com/tag/openssl" rel=tag><FONT color=#ff6600>openssl</FONT></A>, <A href="http://www.technorati.com/tag/ssl" rel=tag><FONT color=#ff6600>ssl</FONT></A><BR></SPAN>]]></description>
</item><item>
<title><![CDATA[StatSVN的使用（续）]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=lhwork&amp;id=32478</link>
<author>lhwork</author>
<pubDate>2008/3/14 15:43:29</pubDate>
<description><![CDATA[<P><FONT size=2>前面一篇我们讲到了StatSVN的简单使用，但是如果每次都要手工去做那些工作，实在麻烦得很。所以这里我们需要写一个脚本，让它定时执行那些操作，这样可以保持报表信息最新的。关于脚本的语言，我选择用了python，哦，又是python，请原谅我，因为最近在学习python，所以什么都想通过python来做。</FONT></P>
<P><FONT size=2>讲一下主要思路：读取配置文件，取得所需的信息；查看版本库是否存在，不存在则checkout，存在则update；执行svn log生成日期文件；调用java -jar statsvn.jar生成版本库的报表。</FONT></P>
<P><FONT size=2>开始实现：</FONT></P>
<P><FONT size=2>1.配置文件两个respository.cfg.xml，statsvn.cfg.xml：</FONT></P>
<P><FONT size=2>respository.cfg.xml样式</FONT></P>
<P><FONT size=2>&lt;?xml version="1.0"?&gt;<BR>&lt;respositoryconfig&gt;<BR>&lt;respository httpurl = "</FONT><A href="http://localhost:8080/svn/test"><FONT size=2>http://localhost:8080/svn/test</FONT></A><FONT size=2>" fileurl = "</FONT><A href="file:///F:/AMP/SVNRespository/test"><FONT size=2>file:///F:/AMP/SVNRespository/test</FONT></A><FONT size=2>" &gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp; &lt;checkoutdir dir = "F:/Test" /&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp; &lt;outputdir dir = "F:/TestReport" /&gt;<BR>&lt;/respository&gt;<BR>&lt;/respositoryconfig&gt;</FONT></P>
<P><FONT size=2>statsvn.cfg.xml样式</FONT></P>
<P><FONT size=2>&lt;?xml version="1.0"?&gt;<BR>&lt;statsvnconfig&gt;<BR>&lt;svnhome dir = "F:/AMP/Subversion/bin" /&gt;<BR>&lt;statsvnjar dir = "F:/statsvn.jar" /&gt;<BR>&lt;/statsvnconfig&gt;</FONT></P>
<P><FONT size=2>2.pytho脚本：</FONT></P>
<P><FONT size=2>from xml.dom.minidom import parse, parseString<BR>import os, sys</FONT></P>
<P><FONT size=2>class respconfig:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; def __setattr__(self, attr, value):<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if attr == 'reposhttpurl':<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.__dict__[attr] = value<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; elif attr == 'reposfileurl':<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.__dict__[attr] = value<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; elif attr == 'checkoutdir':<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.__dict__[attr] = value<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; elif attr == 'outputdir':<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.__dict__[attr] = value<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; raise AttributeError, attr + ' not allowed'<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; def __getattr__(self, attr):<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if attr == "reposhttpurl":<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return self.__dict__[attr]<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; elif attr == "reposfileurl":<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return self.__dict__[attr]<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; elif attr == 'checkoutdir':<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return self.__dict__[attr]<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; elif attr == 'outputdir':<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return self.__dict__[attr]<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; raise AttributeError, attr</FONT></P>
<P><FONT size=2>class statsvnconfig:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; def __setattr__(self, attr, value):<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if attr == 'svnhome':<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.__dict__[attr] = value<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; elif attr == 'statsvnjar':<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.__dict__[attr] = value<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; raise AttributeError, attr + ' not allowed'<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; def __getattr__(self, attr):<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if attr == "svnhome":<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return self.__dict__[attr]<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; elif attr == 'statsvnjar':<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return self.__dict__[attr]<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; raise AttributeError, attr<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<BR>def loadRespConfig(xmlfile):<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dom1 = parse(xmlfile)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; config_element = dom1.getElementsByTagName("respositoryconfig")[0]<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; resps = config_element.getElementsByTagName("respository")<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; respconfigs = []<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for resp in resps:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; respcfg = respconfig()<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; respcfg.reposhttpurl = resp.attributes["httpurl"].value<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; respcfg.reposfileurl = resp.attributes["fileurl"].value<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; respcfg.checkoutdir = resp.getElementsByTagName("checkoutdir")[0].attributes["dir"].value<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; respcfg.outputdir = resp.getElementsByTagName("outputdir")[0].attributes["dir"].value<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; respconfigs.append(respcfg)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return respconfigs</FONT></P>
<P><FONT size=2>def loadStatSvnConfig(xmlfile):<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dom1 = parse(xmlfile)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; config_element = dom1.getElementsByTagName("statsvnconfig")[0]<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; statsvncfg = statsvnconfig()<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; statsvncfg.svnhome = config_element.getElementsByTagName("svnhome")[0].attributes["dir"].value<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; statsvncfg.statsvnjar = config_element.getElementsByTagName("statsvnjar")[0].attributes["dir"].value<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return statsvncfg</FONT></P>
<P><FONT size=2>def createSvnLog(svnhome, reposhttpurl, checkouturl):<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cmd = '%s/svn log %s -v --xml &gt; %s/logfile.log'% (svnhome, reposhttpurl, checkouturl)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; os.popen(cmd, 'r')</FONT></P>
<P><FONT size=2>def updateRepos(svnhome, checkouturl):<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cmd = '%s/svn update %s'% (svnhome, checkouturl)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; os.popen(cmd, 'r')</FONT></P>
<P><FONT size=2>def checkoutRepos(svnhome, reposfileurl, checkouturl):<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cmd = '%s/svn checkout %s %s'% (svnhome, reposfileurl, checkouturl)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; os.popen(cmd, 'r')</FONT></P>
<P><FONT size=2>def createStatSvnReport(statsvnjar, outputdir, checkoutdir):<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cmd = 'java -jar %s -output-dir %s -threads 10 %s/logfile.log %s'% (statsvnjar, outputdir, checkoutdir, checkoutdir)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; os.popen(cmd, 'r')</FONT></P>
<P><FONT size=2>def checkoutRequired(checkoutdir):<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if os.path.exists(checkoutdir):<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return False<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return True<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<BR>if __name__ == '__main__':<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; respconfigs = loadRespConfig(os.getcwd() + "respository.cfg.xml")<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; statsvncfg = loadStatSvnConfig(os.getcwd() + "statsvn.cfg.xml")<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; i = 0<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; length = len(respconfigs)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while 1:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if i &gt;= length:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if checkoutRequired(respconfigs[i].checkoutdir):<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; checkoutRepos(statsvncfg.svnhome, respconfigs[i].reposfileurl, respconfigs[i].checkoutdir)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; updateRepos(statsvncfg.svnhome, respconfigs[i].checkoutdir)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; createSvnLog(statsvncfg.svnhome, respconfigs[i].reposhttpurl, respconfigs[i].checkoutdir)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; createStatSvnReport(statsvncfg.statsvnjar, respconfigs[i].outputdir, respconfigs[i].checkoutdir)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; i = i + 1<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sys.exit()</FONT></P>
<P><FONT size=2>剩下的就是通过py2exe把py脚本生成exe或者写个bat文件调用改py脚本，把exe或者bat文件放到windows计划任务中去就可以了。</FONT></P>]]></description>
</item><item>
<title><![CDATA[[原创]MySQL的LIST分区体验与总结]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=lhwork&amp;id=32444</link>
<author>lhwork</author>
<pubDate>2008/3/13 22:06:47</pubDate>
<description><![CDATA[<DIV id=art style="MARGIN: 15px" width="100%">终于有点空闲时间了，测试一下LIST分区，因为LIST在我们的开发中用到。他分区以后再补上。<BR>版本：<BR>Server version:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5.1.23a-maria-alpha-log MySQL Community Server [Maria] (GPL)<BR><SPAN style="COLOR: rgb(0,128,255)">一、讲在前面</SPAN><BR><SPAN style="COLOR: rgb(255,1,2)">注意：</SPAN><BR style="COLOR: rgb(255,1,2)"><SPAN style="COLOR: rgb(255,1,2)">1、ALTER TABLE也可以用于对带分区的表进行重新分区，所以不能在建表之后再用ALTER TABLE语法。<BR>2、如果你表中有KEY。用来分区的字段必须是KEY的一部份。<BR>3、现在的分区属于水平分区。（垂直分区我们可以自己模拟，这个以后再写）<BR><BR></SPAN><BR><CODE><SPAN style="COLOR: rgb(0,0,0)"><SPAN style="COLOR: rgb(0,1,2)">mysql&gt; use t_girl</SPAN><BR style="COLOR: rgb(0,1,2)"><SPAN style="COLOR: rgb(0,1,2)">Database changed</SPAN><BR style="COLOR: rgb(0,153,2)"><SPAN style="COLOR: rgb(0,153,2)">先建立一个普通表</SPAN><BR>mysql<SPAN style="COLOR: rgb(0,0,204)">&gt;</SPAN> <SPAN style="COLOR: rgb(0,0,255)">create</SPAN> <SPAN style="COLOR: rgb(0,0,255)">table</SPAN> category<SPAN style="COLOR: rgb(0,0,204)">(</SPAN> cid int unsigned <SPAN style="COLOR: rgb(0,0,255)">not</SPAN> <SPAN style="COLOR: rgb(0,0,255)">null</SPAN> auto_increment <SPAN style="COLOR: rgb(0,0,255)">primary</SPAN> <SPAN style="COLOR: rgb(0,0,255)">key</SPAN><SPAN style="COLOR: rgb(0,0,204)">,</SPAN> cname <SPAN style="COLOR: rgb(0,0,255)">varchar</SPAN><SPAN style="COLOR: rgb(0,0,204)">(</SPAN>64<SPAN style="COLOR: rgb(0,0,204)">)</SPAN> <SPAN style="COLOR: rgb(0,0,255)">not</SPAN> <SPAN style="COLOR: rgb(0,0,255)">null</SPAN><SPAN style="COLOR: rgb(0,0,204)">,</SPAN> parent_id int <SPAN style="COLOR: rgb(0,0,255)">not</SPAN> <SPAN style="COLOR: rgb(0,0,255)">null</SPAN><SPAN style="COLOR: rgb(0,0,204)">)</SPAN><SPAN style="COLOR: rgb(0,0,204)">;</SPAN><BR>Query OK<SPAN style="COLOR: rgb(0,0,204)">,</SPAN> 0 <SPAN style="COLOR: rgb(0,0,255)">rows</SPAN> affected <SPAN style="COLOR: rgb(0,0,204)">(</SPAN>0<SPAN style="COLOR: rgb(0,0,204)">.</SPAN>00 sec<SPAN style="COLOR: rgb(0,0,204)">)</SPAN><BR>mysql<SPAN style="COLOR: rgb(0,0,204)">&gt;</SPAN> <SPAN style="COLOR: rgb(0,0,255)">create</SPAN> <SPAN style="COLOR: rgb(0,0,255)">table</SPAN> parent<SPAN style="COLOR: rgb(0,0,204)">(</SPAN>parent_id int <SPAN style="COLOR: rgb(0,0,255)">not</SPAN> <SPAN style="COLOR: rgb(0,0,255)">null</SPAN> auto_increment <SPAN style="COLOR: rgb(0,0,255)">primary</SPAN> <SPAN style="COLOR: rgb(0,0,255)">key</SPAN><SPAN style="COLOR: rgb(0,0,204)">,</SPAN>pname <SPAN style="COLOR: rgb(0,0,255)">varchar</SPAN><SPAN style="COLOR: rgb(0,0,204)">(</SPAN>64<SPAN style="COLOR: rgb(0,0,204)">)</SPAN> <SPAN style="COLOR: rgb(0,0,255)">not</SPAN> <SPAN style="COLOR: rgb(0,0,255)">null</SPAN><SPAN style="COLOR: rgb(0,0,204)">)</SPAN><SPAN style="COLOR: rgb(0,0,204)">;</SPAN><BR>Query OK<SPAN style="COLOR: rgb(0,0,204)">,</SPAN> 0 <SPAN style="COLOR: rgb(0,0,255)">rows</SPAN> affected <SPAN style="COLOR: rgb(0,0,204)">(</SPAN>0<SPAN style="COLOR: rgb(0,0,204)">.</SPAN>00 sec<SPAN style="COLOR: rgb(0,0,204)">)</SPAN><BR><BR style="COLOR: rgb(0,153,2)"><SPAN style="COLOR: rgb(0,153,2)">分区表</SPAN><BR>mysql<SPAN style="COLOR: rgb(0,0,204)">&gt;</SPAN> <SPAN style="COLOR: rgb(0,0,255)">create</SPAN> <SPAN style="COLOR: rgb(0,0,255)">table</SPAN> category_part<SPAN style="COLOR: rgb(0,0,204)">(</SPAN> cid int unsigned <SPAN style="COLOR: rgb(0,0,255)">not</SPAN> <SPAN style="COLOR: rgb(0,0,255)">null</SPAN> auto_increment<SPAN style="COLOR: rgb(0,0,204)">,</SPAN>cname <SPAN style="COLOR: rgb(0,0,255)">varchar</SPAN><SPAN style="COLOR: rgb(0,0,204)">(</SPAN>64<SPAN style="COLOR: rgb(0,0,204)">)</SPAN> <SPAN style="COLOR: rgb(0,0,255)">not</SPAN> <SPAN style="COLOR: rgb(0,0,255)">null</SPAN><SPAN style="COLOR: rgb(0,0,204)">,</SPAN>parent_id int <SPAN style="COLOR: rgb(0,0,255)">not</SPAN> <SPAN style="COLOR: rgb(0,0,255)">null</SPAN><SPAN style="COLOR: rgb(0,0,204)">,</SPAN><SPAN style="COLOR: rgb(0,0,255)">primary</SPAN> <SPAN style="COLOR: rgb(0,0,255)">key</SPAN> <SPAN style="COLOR: rgb(0,0,204)">(</SPAN>cid<SPAN style="COLOR: rgb(0,0,204)">,</SPAN>parent_id<SPAN style="COLOR: rgb(0,0,204)">)</SPAN><SPAN style="COLOR: rgb(0,0,204)">)</SPAN><BR>partition <SPAN style="COLOR: rgb(0,0,255)">by</SPAN> <SPAN style="COLOR: rgb(255,0,0)">list</SPAN><SPAN style="COLOR: rgb(0,0,204)">(</SPAN>parent_id<SPAN style="COLOR: rgb(0,0,204)">)</SPAN><SPAN style="COLOR: rgb(0,0,204)">(</SPAN><BR>partition p1 <SPAN style="COLOR: rgb(0,0,255)">values</SPAN> <SPAN style="COLOR: rgb(0,0,255)">in</SPAN> <SPAN style="COLOR: rgb(0,0,204)">(</SPAN>1<SPAN style="COLOR: rgb(0,0,204)">,</SPAN>2<SPAN style="COLOR: rgb(0,0,204)">,</SPAN>3<SPAN style="COLOR: rgb(0,0,204)">,</SPAN>6<SPAN style="COLOR: rgb(0,0,204)">,</SPAN>9<SPAN style="COLOR: rgb(0,0,204)">)</SPAN><SPAN style="COLOR: rgb(0,0,204)">,</SPAN><BR>partition p2 <SPAN style="COLOR: rgb(0,0,255)">values</SPAN> <SPAN style="COLOR: rgb(0,0,255)">in</SPAN> <SPAN style="COLOR: rgb(0,0,204)">(</SPAN>4<SPAN style="COLOR: rgb(0,0,204)">,</SPAN>5<SPAN style="COLOR: rgb(0,0,204)">,</SPAN>10<SPAN style="COLOR: rgb(0,0,204)">,</SPAN>22<SPAN style="COLOR: rgb(0,0,204)">,</SPAN>23<SPAN style="COLOR: rgb(0,0,204)">)</SPAN><SPAN style="COLOR: rgb(0,0,204)">,</SPAN><BR>partition p3 <SPAN style="COLOR: rgb(0,0,255)">values</SPAN> <SPAN style="COLOR: rgb(0,0,255)">in</SPAN> <SPAN style="COLOR: rgb(0,0,204)">(</SPAN>7<SPAN style="COLOR: rgb(0,0,204)">,</SPAN>8<SPAN style="COLOR: rgb(0,0,204)">,</SPAN>11<SPAN style="COLOR: rgb(0,0,204)">,</SPAN>12<SPAN style="COLOR: rgb(0,0,204)">,</SPAN>13<SPAN style="COLOR: rgb(0,0,204)">)</SPAN><SPAN style="COLOR: rgb(0,0,204)">,</SPAN><BR>partition p4 <SPAN style="COLOR: rgb(0,0,255)">values</SPAN> <SPAN style="COLOR: rgb(0,0,255)">in</SPAN> <SPAN style="COLOR: rgb(0,0,204)">(</SPAN>14<SPAN style="COLOR: rgb(0,0,204)">,</SPAN>15<SPAN style="COLOR: rgb(0,0,204)">,</SPAN>16<SPAN style="COLOR: rgb(0,0,204)">,</SPAN>17<SPAN style="COLOR: rgb(0,0,204)">,</SPAN>20<SPAN style="COLOR: rgb(0,0,204)">)</SPAN><SPAN style="COLOR: rgb(0,0,204)">,</SPAN><BR>partition p5 <SPAN style="COLOR: rgb(0,0,255)">values</SPAN> <SPAN style="COLOR: rgb(0,0,255)">in</SPAN> <SPAN style="COLOR: rgb(0,0,204)">(</SPAN>18<SPAN style="COLOR: rgb(0,0,204)">,</SPAN>19<SPAN style="COLOR: rgb(0,0,204)">,</SPAN>21<SPAN style="COLOR: rgb(0,0,204)">,</SPAN>24<SPAN style="COLOR: rgb(0,0,204)">,</SPAN>25<SPAN style="COLOR: rgb(0,0,204)">)</SPAN><BR><SPAN style="COLOR: rgb(0,0,204)">)</SPAN><SPAN style="COLOR: rgb(0,0,204)">;</SPAN><BR>Query OK<SPAN style="COLOR: rgb(0,0,204)">,</SPAN> 0 <SPAN style="COLOR: rgb(0,0,255)">rows</SPAN> affected <SPAN style="COLOR: rgb(0,0,204)">(</SPAN>0<SPAN style="COLOR: rgb(0,0,204)">.</SPAN>01 sec<SPAN style="COLOR: rgb(0,0,204)">)</SPAN><BR><BR style="COLOR: rgb(0,153,2)"><SPAN style="COLOR: rgb(0,153,2)">插入数据部分省略。。。</SPAN><BR style="COLOR: rgb(0,153,2)"><SPAN style="COLOR: rgb(0,153,2)">建立索引。</SPAN><BR>mysql<SPAN style="COLOR: rgb(0,0,204)">&gt;</SPAN> <SPAN style="COLOR: rgb(0,0,255)">create</SPAN> <SPAN style="COLOR: rgb(0,0,255)">index</SPAN> f_parent_id <SPAN style="COLOR: rgb(0,0,255)">on</SPAN> category<SPAN style="COLOR: rgb(0,0,204)">(</SPAN>parent_id<SPAN style="COLOR: rgb(0,0,204)">)</SPAN><SPAN style="COLOR: rgb(0,0,204)">;</SPAN><BR>Query OK<SPAN style="COLOR: rgb(0,0,204)">,</SPAN> 2048000 <SPAN style="COLOR: rgb(0,0,255)">rows</SPAN> affected <SPAN style="COLOR: rgb(0,0,204)">(</SPAN>17<SPAN style="COLOR: rgb(0,0,204)">.</SPAN>61 sec<SPAN style="COLOR: rgb(0,0,204)">)</SPAN><BR>Records<SPAN style="COLOR: rgb(0,0,204)">:</SPAN> 2048000 Duplicates<SPAN style="COLOR: rgb(0,0,204)">:</SPAN> 0 Warnings<SPAN style="COLOR: rgb(0,0,204)">:</SPAN> 0<BR>mysql&gt; show index from category;<BR>+----------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+<BR>| Table&nbsp;&nbsp;&nbsp; | Non_unique | Key_name&nbsp;&nbsp;&nbsp; | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |<BR>+----------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+<BR>| category |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0 | PRIMARY&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1 | cid&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | A&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp; 2048000 |&nbsp;&nbsp;&nbsp;&nbsp; NULL | NULL&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | BTREE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | <BR>| category |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1 | f_parent_id |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1 | parent_id&nbsp;&nbsp; | A&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 25 |&nbsp;&nbsp;&nbsp;&nbsp; NULL | NULL&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | BTREE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | <BR>+----------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+<BR>2 rows in set (0.00 sec)<SPAN style="COLOR: rgb(0,0,204)"></SPAN><BR><BR><BR>mysql<SPAN style="COLOR: rgb(0,0,204)">&gt;</SPAN> <SPAN style="COLOR: rgb(0,0,255)">create</SPAN> <SPAN style="COLOR: rgb(0,0,255)">index</SPAN> f_parent_id <SPAN style="COLOR: rgb(0,0,255)">on</SPAN> category_part<SPAN style="COLOR: rgb(0,0,204)">(</SPAN>parent_id<SPAN style="COLOR: rgb(0,0,204)">)</SPAN><SPAN style="COLOR: rgb(0,0,204)">;</SPAN><BR>Query OK<SPAN style="COLOR: rgb(0,0,204)">,</SPAN> 2048000 <SPAN style="COLOR: rgb(0,0,255)">rows</SPAN> affected <SPAN style="COLOR: rgb(0,0,204)">(</SPAN>18<SPAN style="COLOR: rgb(0,0,204)">.</SPAN>57 sec<SPAN style="COLOR: rgb(0,0,204)">)</SPAN><BR>Records<SPAN style="COLOR: rgb(0,0,204)">:</SPAN> 2048000 Duplicates<SPAN style="COLOR: rgb(0,0,204)">:</SPAN> 0 Warnings<SPAN style="COLOR: rgb(0,0,204)">:</SPAN> 0<BR><BR>mysql&gt; show index from category_part;<BR>+---------------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+<BR>| Table&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | Non_unique | Key_name&nbsp;&nbsp;&nbsp; | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |<BR>+---------------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+<BR>| category_part |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0 | PRIMARY&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1 | cid&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | A&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp; 2048000 |&nbsp;&nbsp;&nbsp;&nbsp; NULL | NULL&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | BTREE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | <BR>| category_part |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0 | PRIMARY&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2 | parent_id&nbsp;&nbsp; | A&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp; 2048000 |&nbsp;&nbsp;&nbsp;&nbsp; NULL | NULL&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | BTREE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | <BR>| category_part |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1 | f_parent_id |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1 | parent_id&nbsp;&nbsp; | A&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 318 |&nbsp;&nbsp;&nbsp;&nbsp; NULL | NULL&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | BTREE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | <BR>+---------------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+<BR>3 rows in set (0.01 sec)<SPAN style="COLOR: rgb(0,0,204)"></SPAN><BR><BR>mysql<SPAN style="COLOR: rgb(0,0,204)">&gt;</SPAN> <SPAN style="COLOR: rgb(0,0,255)">select</SPAN> <SPAN style="COLOR: rgb(255,0,0)">count</SPAN><SPAN style="COLOR: rgb(0,0,204)">(</SPAN><SPAN style="COLOR: rgb(0,0,204)">*</SPAN><SPAN style="COLOR: rgb(0,0,204)">)</SPAN> <SPAN style="COLOR: rgb(0,0,255)">from</SPAN> category<SPAN style="COLOR: rgb(0,0,204)">;</SPAN><BR><SPAN style="COLOR: rgb(0,0,204)">+</SPAN><SPAN style="COLOR: rgb(255,153,0)">----------+<BR></SPAN><BR><SPAN style="COLOR: rgb(0,0,204)">|</SPAN> <SPAN style="COLOR: rgb(255,0,0)">count</SPAN><SPAN style="COLOR: rgb(0,0,204)">(</SPAN><SPAN style="COLOR: rgb(0,0,204)">*</SPAN><SPAN style="COLOR: rgb(0,0,204)">)</SPAN> <SPAN style="COLOR: rgb(0,0,204)">|</SPAN><BR><SPAN style="COLOR: rgb(0,0,204)">+</SPAN><SPAN style="COLOR: rgb(255,153,0)">----------+<BR></SPAN><BR><SPAN style="COLOR: rgb(0,0,204)">|</SPAN> 2048000 <SPAN style="COLOR: rgb(0,0,204)">|</SPAN><BR><SPAN style="COLOR: rgb(0,0,204)">+</SPAN><SPAN style="COLOR: rgb(255,153,0)">----------+<BR></SPAN><BR>1 <SPAN style="COLOR: rgb(0,0,255)">row</SPAN> <SPAN style="COLOR: rgb(0,0,255)">in</SPAN> <SPAN style="COLOR: rgb(0,0,255)">set</SPAN> <SPAN style="COLOR: rgb(0,0,204)">(</SPAN>0<SPAN style="COLOR: rgb(0,0,204)">.</SPAN>00 sec<SPAN style="COLOR: rgb(0,0,204)">)</SPAN><BR><BR>mysql<SPAN style="COLOR: rgb(0,0,204)">&gt;</SPAN> <SPAN style="COLOR: rgb(0,0,255)">select</SPAN> <SPAN style="COLOR: rgb(255,0,0)">count</SPAN><SPAN style="COLOR: rgb(0,0,204)">(</SPAN><SPAN style="COLOR: rgb(0,0,204)">*</SPAN><SPAN style="COLOR: rgb(0,0,204)">)</SPAN> <SPAN style="COLOR: rgb(0,0,255)">from</SPAN> category_part<SPAN style="COLOR: rgb(0,0,204)">;</SPAN><BR><SPAN style="COLOR: rgb(0,0,204)">+</SPAN><SPAN style="COLOR: rgb(255,153,0)">----------+<BR></SPAN><BR><SPAN style="COLOR: rgb(0,0,204)">|</SPAN> <SPAN style="COLOR: rgb(255,0,0)">count</SPAN><SPAN style="COLOR: rgb(0,0,204)">(</SPAN><SPAN style="COLOR: rgb(0,0,204)">*</SPAN><SPAN style="COLOR: rgb(0,0,204)">)</SPAN> <SPAN style="COLOR: rgb(0,0,204)">|</SPAN><BR><SPAN style="COLOR: rgb(0,0,204)">+</SPAN><SPAN style="COLOR: rgb(255,153,0)">----------+<BR></SPAN><BR><SPAN style="COLOR: rgb(0,0,204)">|</SPAN> 2048000 <SPAN style="COLOR: rgb(0,0,204)">|</SPAN><BR><SPAN style="COLOR: rgb(0,0,204)">+</SPAN><SPAN style="COLOR: rgb(255,153,0)">----------+<BR></SPAN><BR>1 <SPAN style="COLOR: rgb(0,0,255)">row</SPAN> <SPAN style="COLOR: rgb(0,0,255)">in</SPAN> <SPAN style="COLOR: rgb(0,0,255)">set</SPAN> <SPAN style="COLOR: rgb(0,0,204)">(</SPAN>0<SPAN style="COLOR: rgb(0,0,204)">.</SPAN>00 sec<SPAN style="COLOR: rgb(0,0,204)">)</SPAN><BR><BR>mysql<SPAN style="COLOR: rgb(0,0,204)">&gt;</SPAN> <SPAN style="COLOR: rgb(0,0,255)">select</SPAN> <SPAN style="COLOR: rgb(255,0,0)">count</SPAN><SPAN style="COLOR: rgb(0,0,204)">(</SPAN><SPAN style="COLOR: rgb(0,0,204)">*</SPAN><SPAN style="COLOR: rgb(0,0,204)">)</SPAN> <SPAN style="COLOR: rgb(0,0,255)">from</SPAN> parent<SPAN style="COLOR: rgb(0,0,204)">;</SPAN><BR><SPAN style="COLOR: rgb(0,0,204)">+</SPAN><SPAN style="COLOR: rgb(255,153,0)">----------+<BR></SPAN><BR><SPAN style="COLOR: rgb(0,0,204)">|</SPAN> <SPAN style="COLOR: rgb(255,0,0)">count</SPAN><SPAN style="COLOR: rgb(0,0,204)">(</SPAN><SPAN style="COLOR: rgb(0,0,204)">*</SPAN><SPAN style="COLOR: rgb(0,0,204)">)</SPAN> <SPAN style="COLOR: rgb(0,0,204)">|</SPAN><BR><SPAN style="COLOR: rgb(0,0,204)">+</SPAN><SPAN style="COLOR: rgb(255,153,0)">----------+<BR></SPAN><BR><SPAN style="COLOR: rgb(0,0,204)">|</SPAN> 25 <SPAN style="COLOR: rgb(0,0,204)">|</SPAN><BR><SPAN style="COLOR: rgb(0,0,204)">+</SPAN><SPAN style="COLOR: rgb(255,153,0)">----------+<BR></SPAN><BR>1 <SPAN style="COLOR: rgb(0,0,255)">row</SPAN> <SPAN style="COLOR: rgb(0,0,255)">in</SPAN> <SPAN style="COLOR: rgb(0,0,255)">set</SPAN> <SPAN style="COLOR: rgb(0,0,204)">(</SPAN>0<SPAN style="COLOR: rgb(0,0,204)">.</SPAN>00 sec<SPAN style="COLOR: rgb(0,0,204)">)</SPAN><BR><SPAN style="COLOR: rgb(0,0,204)"></SPAN><BR><SPAN style="COLOR: rgb(0,128,255)">二、具体测试</SPAN><BR><SPAN style="COLOR: rgb(0,153,2)">1、我们来看一下查询性能比较：</SPAN><BR style="COLOR: rgb(0,153,2)"><SPAN style="COLOR: rgb(102,1,153)">1)、单表查询</SPAN><BR>mysql<SPAN style="COLOR: rgb(0,0,204)">&gt;</SPAN> <SPAN style="COLOR: rgb(0,0,255)">select</SPAN> <SPAN style="COLOR: rgb(255,0,0)">count</SPAN><SPAN style="COLOR: rgb(0,0,204)">(</SPAN><SPAN style="COLOR: rgb(0,0,204)">*</SPAN><SPAN style="COLOR: rgb(0,0,204)">)</SPAN> <SPAN style="COLOR: rgb(0,0,255)">from</SPAN> category <SPAN style="COLOR: rgb(0,0,255)">where</SPAN> parent_id <SPAN style="COLOR: rgb(0,0,255)">in</SPAN> <SPAN style="COLOR: rgb(0,0,204)">(</SPAN>22<SPAN style="COLOR: rgb(0,0,204)">,</SPAN>20<SPAN style="COLOR: rgb(0,0,204)">)</SPAN><SPAN style="COLOR: rgb(0,0,204)">;</SPAN><BR><SPAN style="COLOR: rgb(0,0,204)">+</SPAN><SPAN style="COLOR: rgb(255,153,0)">----------+<BR></SPAN><BR><SPAN style="COLOR: rgb(0,0,204)">|</SPAN> <SPAN style="COLOR: rgb(255,0,0)">count</SPAN><SPAN style="COLOR: rgb(0,0,204)">(</SPAN><SPAN style="COLOR: rgb(0,0,204)">*</SPAN><SPAN style="COLOR: rgb(0,0,204)">)</SPAN> <SPAN style="COLOR: rgb(0,0,204)">|</SPAN><BR><SPAN style="COLOR: rgb(0,0,204)">+</SPAN><SPAN style="COLOR: rgb(255,153,0)">----------+<BR></SPAN><BR><SPAN style="COLOR: rgb(0,0,204)">|</SPAN> 17002 <SPAN style="COLOR: rgb(0,0,204)">|</SPAN><BR><SPAN style="COLOR: rgb(0,0,204)">+</SPAN><SPAN style="COLOR: rgb(255,153,0)">----------+<BR></SPAN><BR>1 <SPAN style="COLOR: rgb(0,0,255)">row</SPAN> <SPAN style="COLOR: rgb(0,0,255)">in</SPAN> <SPAN style="COLOR: rgb(0,0,255)">set</SPAN> <SPAN style="COLOR: rgb(0,0,204)">(</SPAN>0<SPAN style="COLOR: rgb(0,0,204)">.</SPAN>03 sec<SPAN style="COLOR: rgb(0,0,204)">)</SPAN><BR><BR>mysql<SPAN style="COLOR: rgb(0,0,204)">&gt;</SPAN> <SPAN style="COLOR: rgb(0,0,255)">select</SPAN> <SPAN style="COLOR: rgb(255,0,0)">count</SPAN><SPAN style="COLOR: rgb(0,0,204)">(</SPAN><SPAN style="COLOR: rgb(0,0,204)">*</SPAN><SPAN style="COLOR: rgb(0,0,204)">)</SPAN> <SPAN style="COLOR: rgb(0,0,255)">from</SPAN> category_part <SPAN style="COLOR: rgb(0,0,255)">where</SPAN> parent_id <SPAN style="COLOR: rgb(0,0,255)">in</SPAN> <SPAN style="COLOR: rgb(0,0,204)">(</SPAN>22<SPAN style="COLOR: rgb(0,0,204)">,</SPAN>20<SPAN style="COLOR: rgb(0,0,204)">)</SPAN><SPAN style="COLOR: rgb(0,0,204)">;</SPAN><BR><SPAN style="COLOR: rgb(0,0,204)">+</SPAN><SPAN style="COLOR: rgb(255,153,0)">----------+<BR></SPAN><BR><SPAN style="COLOR: rgb(0,0,204)">|</SPAN> <SPAN style="COLOR: rgb(255,0,0)">count</SPAN><SPAN style="COLOR: rgb(0,0,204)">(</SPAN><SPAN style="COLOR: rgb(0,0,204)">*</SPAN><SPAN style="COLOR: rgb(0,0,204)">)</SPAN> <SPAN style="COLOR: rgb(0,0,204)">|</SPAN><BR><SPAN style="COLOR: rgb(0,0,204)">+</SPAN><SPAN style="COLOR: rgb(255,153,0)">----------+<BR></SPAN><BR><SPAN style="COLOR: rgb(0,0,204)">|</SPAN> 17002 <SPAN style="COLOR: rgb(0,0,204)">|</SPAN><BR><SPAN style="COLOR: rgb(0,0,204)">+</SPAN><SPAN style="COLOR: rgb(255,153,0)">----------+<BR></SPAN><BR>1 <SPAN style="COLOR: rgb(0,0,255)">row</SPAN> <SPAN style="COLOR: rgb(0,0,255)">in</SPAN> <SPAN style="COLOR: rgb(0,0,255)">set</SPAN> <SPAN style="COLOR: rgb(0,0,204)">(</SPAN>0<SPAN style="COLOR: rgb(0,0,204)">.</SPAN>02 sec<SPAN style="COLOR: rgb(0,0,204)">)</SPAN><BR><SPAN style="COLOR: rgb(0,153,2)">分区表普通的做了索引的速度上快了一点，不过差别不是很大。</SPAN><BR><BR>mysql&gt; explain select count(*) from category where parent_id in (22,20);<BR>+----+-------------+----------+-------+---------------+-------------+---------+------+-------+--------------------------+<BR>| id | select_type | table&nbsp;&nbsp;&nbsp; | type&nbsp; | possible_keys | key&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | key_len | ref&nbsp; | rows&nbsp; | Extra&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |<BR>+----+-------------+----------+-------+---------------+-------------+---------+------+-------+--------------------------+<BR>|&nbsp; 1 | SIMPLE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | category | range | f_parent_id&nbsp;&nbsp; | f_parent_id | 4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | NULL | 14335 | Using where; Using index | <BR>+----+-------------+----------+-------+---------------+-------------+---------+------+-------+--------------------------+<BR>1 row in set (0.00 sec)<BR><BR>mysql&gt; explain partitions select count(*) from category_part where parent_id in (22,20);<BR>+----+-------------+---------------+------------+-------+---------------+-------------+---------+------+-------+--------------------------+<BR>| id | select_type | table&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | partitions | type&nbsp; | possible_keys | key&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | key_len | ref&nbsp; | rows&nbsp; | Extra&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |<BR>+----+-------------+---------------+------------+-------+---------------+-------------+---------+------+-------+--------------------------+<BR>|&nbsp; 1 | SIMPLE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | category_part | p2,p4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | range | f_parent_id&nbsp;&nbsp; | f_parent_id | 4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | NULL | 16893 | Using where; Using index | <BR>+----+-------------+---------------+------------+-------+---------------+-------------+---------+------+-------+--------------------------+<BR>1 row in set (0.00 sec)<SPAN style="COLOR: rgb(0,0,204)"></SPAN><BR><BR>mysql<SPAN style="COLOR: rgb(0,0,204)">&gt;</SPAN> <SPAN style="COLOR: rgb(0,0,255)">select</SPAN> <SPAN style="COLOR: rgb(255,0,0)">count</SPAN><SPAN style="COLOR: rgb(0,0,204)">(</SPAN><SPAN style="COLOR: rgb(0,0,204)">*</SPAN><SPAN style="COLOR: rgb(0,0,204)">)</SPAN> <SPAN style="COLOR: rgb(0,0,255)">from</SPAN> category <SPAN style="COLOR: rgb(0,0,255)">where</SPAN> parent_id <SPAN style="COLOR: rgb(0,0,204)">=</SPAN> 25<SPAN style="COLOR: rgb(0,0,204)">;</SPAN> <BR><SPAN style="COLOR: rgb(0,0,204)">+</SPAN><SPAN style="COLOR: rgb(255,153,0)">----------+<BR></SPAN><BR><SPAN style="COLOR: rgb(0,0,204)">|</SPAN> <SPAN style="COLOR: rgb(255,0,0)">count</SPAN><SPAN style="COLOR: rgb(0,0,204)">(</SPAN><SPAN style="COLOR: rgb(0,0,204)">*</SPAN><SPAN style="COLOR: rgb(0,0,204)">)</SPAN> <SPAN style="COLOR: rgb(0,0,204)">|</SPAN><BR><SPAN style="COLOR: rgb(0,0,204)">+</SPAN><SPAN style="COLOR: rgb(255,153,0)">----------+<BR></SPAN><BR><SPAN style="COLOR: rgb(0,0,204)">|</SPAN> 2001 <SPAN style="COLOR: rgb(0,0,204)">|</SPAN><BR><SPAN style="COLOR: rgb(0,0,204)">+</SPAN><SPAN style="COLOR: rgb(255,153,0)">----------+<BR></SPAN><BR>1 <SPAN style="COLOR: rgb(0,0,255)">row</SPAN> <SPAN style="COLOR: rgb(0,0,255)">in</SPAN> <SPAN style="COLOR: rgb(0,0,255)">set</SPAN> <SPAN style="COLOR: rgb(0,0,204)">(</SPAN>0<SPAN style="COLOR: rgb(0,0,204)">.</SPAN>01 sec<SPAN style="COLOR: rgb(0,0,204)">)</SPAN><BR><BR>mysql<SPAN style="COLOR: rgb(0,0,204)">&gt;</SPAN> <SPAN style="COLOR: rgb(0,0,255)">select</SPAN> <SPAN style="COLOR: rgb(255,0,0)">count</SPAN><SPAN style="COLOR: rgb(0,0,204)">(</SPAN><SPAN style="COLOR: rgb(0,0,204)">*</SPAN><SPAN style="COLOR: rgb(0,0,204)">)</SPAN> <SPAN style="COLOR: rgb(0,0,255)">from</SPAN> category_part <SPAN style="COLOR: rgb(0,0,255)">where</SPAN> parent_id <SPAN style="COLOR: rgb(0,0,204)">=</SPAN> 25<SPAN style="COLOR: rgb(0,0,204)">;</SPAN><BR><SPAN style="COLOR: rgb(0,0,204)">+</SPAN><SPAN style="COLOR: rgb(255,153,0)">----------+<BR></SPAN><BR><SPAN style="COLOR: rgb(0,0,204)">|</SPAN> <SPAN style="COLOR: rgb(255,0,0)">count</SPAN><SPAN style="COLOR: rgb(0,0,204)">(</SPAN><SPAN style="COLOR: rgb(0,0,204)">*</SPAN><SPAN style="COLOR: rgb(0,0,204)">)</SPAN> <SPAN style="COLOR: rgb(0,0,204)">|</SPAN><BR><SPAN style="COLOR: rgb(0,0,204)">+</SPAN><SPAN style="COLOR: rgb(255,153,0)">----------+<BR></SPAN><BR><SPAN style="COLOR: rgb(0,0,204)">|</SPAN> 2001 <SPAN style="COLOR: rgb(0,0,204)">|</SPAN><BR><SPAN style="COLOR: rgb(0,0,204)">+</SPAN><SPAN style="COLOR: rgb(255,153,0)">----------+<BR></SPAN><BR>1 <SPAN style="COLOR: rgb(0,0,255)">row</SPAN> <SPAN style="COLOR: rgb(0,0,255)">in</SPAN> <SPAN style="COLOR: rgb(0,0,255)">set</SPAN> <SPAN style="COLOR: rgb(0,0,204)">(</SPAN>0<SPAN style="COLOR: rgb(0,0,204)">.</SPAN>00 sec<SPAN style="COLOR: rgb(0,0,204)">)</SPAN><BR><BR>mysql<SPAN style="COLOR: rgb(0,0,204)">&gt;</SPAN> explain <SPAN style="COLOR: rgb(0,0,255)">select</SPAN> <SPAN style="COLOR: rgb(255,0,0)">count</SPAN><SPAN style="COLOR: rgb(0,0,204)">(</SPAN><SPAN style="COLOR: rgb(0,0,204)">*</SPAN><SPAN style="COLOR: rgb(0,0,204)">)</SPAN> <SPAN style="COLOR: rgb(0,0,255)">from</SPAN> category <SPAN style="COLOR: rgb(0,0,255)">where</SPAN> parent_id <SPAN style="COLOR: rgb(0,0,204)">=</SPAN> 25<SPAN style="COLOR: rgb(0,0,204)">;</SPAN><BR><SPAN style="COLOR: rgb(0,0,204)">+----+-------------+----------+------+---------------+-------------+---------+-------+-------+-------------+<BR>| id | select_type | table&nbsp;&nbsp;&nbsp; | type | possible_keys | key&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | key_len | ref&nbsp;&nbsp; | rows&nbsp; | Extra&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |<BR>+----+-------------+----------+------+---------------+-------------+---------+-------+-------+-------------+<BR>|&nbsp; 1 | SIMPLE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | category | ref&nbsp; | f_parent_id&nbsp;&nbsp; | f_parent_id | 4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | const | 38240 | Using index | <BR>+----+-------------+----------+------+---------------+-------------+---------+-------+-------+-------------+</SPAN><BR>1 <SPAN style="COLOR: rgb(0,0,255)">row</SPAN> <SPAN style="COLOR: rgb(0,0,255)">in</SPAN> <SPAN style="COLOR: rgb(0,0,255)">set</SPAN> <SPAN style="COLOR: rgb(0,0,204)">(</SPAN>0<SPAN style="COLOR: rgb(0,0,204)">.</SPAN>00 sec<SPAN style="COLOR: rgb(0,0,204)">)</SPAN><BR><BR>mysql<SPAN style="COLOR: rgb(0,0,204)">&gt;</SPAN> explain partitions <SPAN style="COLOR: rgb(0,0,255)">select</SPAN> <SPAN style="COLOR: rgb(255,0,0)">count</SPAN><SPAN style="COLOR: rgb(0,0,204)">(</SPAN><SPAN style="COLOR: rgb(0,0,204)">*</SPAN><SPAN style="COLOR: rgb(0,0,204)">)</SPAN> <SPAN style="COLOR: rgb(0,0,255)">from</SPAN> category_part <SPAN style="COLOR: rgb(0,0,255)">where</SPAN> parent_id <SPAN style="COLOR: rgb(0,0,204)">=</SPAN> 25<SPAN style="COLOR: rgb(0,0,204)">;</SPAN><BR><SPAN style="COLOR: rgb(0,0,204)">+----+-------------+---------------+------------+------+---------------+-------------+---------+-------+------+-------------+<BR>| id | select_type | table&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | partitions | type | possible_keys | key&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | key_len | ref&nbsp;&nbsp; | rows | Extra&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |<BR>+----+-------------+---------------+------------+------+---------------+-------------+---------+-------+------+-------------+<BR>|&nbsp; 1 | SIMPLE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | category_part | p5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | ref&nbsp; | f_parent_id&nbsp;&nbsp; | f_parent_id | 4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | const | 4647 | Using index | <BR>+----+-------------+---------------+------------+------+---------------+-------------+---------+-------+------+-------------+</SPAN><BR>1 <SPAN style="COLOR: rgb(0,0,255)">row</SPAN> <SPAN style="COLOR: rgb(0,0,255)">in</SPAN> <SPAN style="COLOR: rgb(0,0,255)">set</SPAN> <SPAN style="COLOR: rgb(0,0,204)">(</SPAN>0<SPAN style="COLOR: rgb(0,0,204)">.</SPAN>00 sec<SPAN style="COLOR: rgb(0,0,204)">)</SPAN><BR><SPAN style="COLOR: rgb(0,153,2)">可以看出，扫描的行数大幅度减少</SPAN><BR><SPAN style="COLOR: rgb(102,1,153)">2)、多表内联性能</SPAN><BR><BR>mysql<SPAN style="COLOR: rgb(0,0,204)">&gt;</SPAN> <SPAN style="COLOR: rgb(0,0,255)">select</SPAN> <SPAN style="COLOR: rgb(255,0,0)">count</SPAN><SPAN style="COLOR: rgb(0,0,204)">(</SPAN><SPAN style="COLOR: rgb(0,0,204)">*</SPAN><SPAN style="COLOR: rgb(0,0,204)">)</SPAN> <SPAN style="COLOR: rgb(0,0,255)">from</SPAN> category <SPAN style="COLOR: rgb(0,0,255)">as</SPAN> a inner join parent <SPAN style="COLOR: rgb(0,0,255)">as</SPAN> b <SPAN style="COLOR: rgb(0,0,255)">using</SPAN><SPAN style="COLOR: rgb(0,0,204)">(</SPAN>parent_id<SPAN style="COLOR: rgb(0,0,204)">)</SPAN><SPAN style="COLOR: rgb(0,0,204)">;</SPAN> <BR><SPAN style="COLOR: rgb(0,0,204)">+</SPAN><SPAN style="COLOR: rgb(255,153,0)">----------+<BR></SPAN><BR><SPAN style="COLOR: rgb(0,0,204)">|</SPAN> <SPAN style="COLOR: rgb(255,0,0)">count</SPAN><SPAN style="COLOR: rgb(0,0,204)">(</SPAN><SPAN style="COLOR: rgb(0,0,204)">*</SPAN><SPAN style="COLOR: rgb(0,0,204)">)</SPAN> <SPAN style="COLOR: rgb(0,0,204)">|</SPAN><BR><SPAN style="COLOR: rgb(0,0,204)">+</SPAN><SPAN style="COLOR: rgb(255,153,0)">----------+<BR></SPAN><BR><SPAN style="COLOR: rgb(0,0,204)">|</SPAN> 2048000 <SPAN style="COLOR: rgb(0,0,204)">|</SPAN><BR><SPAN style="COLOR: rgb(0,0,204)">+</SPAN><SPAN style="COLOR: rgb(255,153,0)">----------+<BR></SPAN><BR>1 <SPAN style="COLOR: rgb(0,0,255)">row</SPAN> <SPAN style="COLOR: rgb(0,0,255)">in</SPAN> <SPAN style="COLOR: rgb(0,0,255)">set</SPAN> <SPAN style="COLOR: rgb(0,0,204)">(</SPAN>0<SPAN style="COLOR: rgb(0,0,204)">.</SPAN>84 sec<SPAN style="COLOR: rgb(0,0,204)">)</SPAN><BR><BR>mysql<SPAN style="COLOR: rgb(0,0,204)">&gt;</SPAN> <SPAN style="COLOR: rgb(0,0,255)">select</SPAN> <SPAN style="COLOR: rgb(255,0,0)">count</SPAN><SPAN style="COLOR: rgb(0,0,204)">(</SPAN><SPAN style="COLOR: rgb(0,0,204)">*</SPAN><SPAN style="COLOR: rgb(0,0,204)">)</SPAN> <SPAN style="COLOR: rgb(0,0,255)">from</SPAN> category_part <SPAN style="COLOR: rgb(0,0,255)">as</SPAN> a inner join parent <SPAN style="COLOR: rgb(0,0,255)">as</SPAN> b <SPAN style="COLOR: rgb(0,0,255)">using</SPAN><SPAN style="COLOR: rgb(0,0,204)">(</SPAN>parent_id<SPAN style="COLOR: rgb(0,0,204)">)</SPAN><SPAN style="COLOR: rgb(0,0,204)">;</SPAN><BR><SPAN style="COLOR: rgb(0,0,204)">+</SPAN><SPAN style="COLOR: rgb(255,153,0)">----------+<BR></SPAN><BR><SPAN style="COLOR: rgb(0,0,204)">|</SPAN> <SPAN style="COLOR: rgb(255,0,0)">count</SPAN><SPAN style="COLOR: rgb(0,0,204)">(</SPAN><SPAN style="COLOR: rgb(0,0,204)">*</SPAN><SPAN style="COLOR: rgb(0,0,204)">)</SPAN> <SPAN style="COLOR: rgb(0,0,204)">|</SPAN><BR><SPAN style="COLOR: rgb(0,0,204)">+</SPAN><SPAN style="COLOR: rgb(255,153,0)">----------+<BR></SPAN><BR><SPAN style="COLOR: rgb(0,0,204)">|</SPAN> 2048000 <SPAN style="COLOR: rgb(0,0,204)">|</SPAN><BR><SPAN style="COLOR: rgb(0,0,204)">+</SPAN><SPAN style="COLOR: rgb(255,153,0)">----------+<BR></SPAN><BR>1 <SPAN style="COLOR: rgb(0,0,255)">row</SPAN> <SPAN style="COLOR: rgb(0,0,255)">in</SPAN> <SPAN style="COLOR: rgb(0,0,255)">set</SPAN> <SPAN style="COLOR: rgb(0,0,204)">(</SPAN>0<SPAN style="COLOR: rgb(0,0,204)">.</SPAN>88 sec<SPAN style="COLOR: rgb(0,0,204)">)</SPAN><BR>mysql<SPAN style="COLOR: rgb(0,0,204)">&gt;</SPAN> explain <SPAN style="COLOR: rgb(0,0,255)">select</SPAN> <SPAN style="COLOR: rgb(255,0,0)">count</SPAN><SPAN style="COLOR: rgb(0,0,204)">(</SPAN><SPAN style="COLOR: rgb(0,0,204)">*</SPAN><SPAN style="COLOR: rgb(0,0,204)">)</SPAN> <SPAN style="COLOR: rgb(0,0,255)">from</SPAN> category <SPAN style="COLOR: rgb(0,0,255)">as</SPAN> a inner join parent <SPAN style="COLOR: rgb(0,0,255)">as</SPAN> b <SPAN style="COLOR: rgb(0,0,255)">using</SPAN><SPAN style="COLOR: rgb(0,0,204)">(</SPAN>parent_id<SPAN style="COLOR: rgb(0,0,204)">)</SPAN><SPAN style="COLOR: rgb(0,0,204)">;</SPAN><BR><SPAN style="COLOR: rgb(0,0,204)">+----+-------------+-------+-------+---------------+-------------+---------+--------------------+-------+-------------+<BR>| id | select_type | table | type&nbsp; | possible_keys | key&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | key_len | ref&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | rows&nbsp; | Extra&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |<BR>+----+-------------+-------+-------+---------------+-------------+---------+--------------------+-------+-------------+<BR>|&nbsp; 1 | SIMPLE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | b&nbsp;&nbsp;&nbsp;&nbsp; | index | PRIMARY&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | PRIMARY&nbsp;&nbsp;&nbsp;&nbsp; | 4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | NULL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp; 25 | Using index | <BR>|&nbsp; 1 | SIMPLE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | a&nbsp;&nbsp;&nbsp;&nbsp; | ref&nbsp;&nbsp; | f_parent_id&nbsp;&nbsp; | f_parent_id | 4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | t_girl.b.parent_id | 81920 | Using index | <BR>+----+-------------+-------+-------+---------------+-------------+---------+--------------------+-------+-------------+</SPAN><BR>2 <SPAN style="COLOR: rgb(0,0,255)">rows</SPAN> <SPAN style="COLOR: rgb(0,0,255)">in</SPAN> <SPAN style="COLOR: rgb(0,0,255)">set</SPAN> <SPAN style="COLOR: rgb(0,0,204)">(</SPAN>0<SPAN style="COLOR: rgb(0,0,204)">.</SPAN>00 sec<SPAN style="COLOR: rgb(0,0,204)">)</SPAN><BR><BR>mysql<SPAN style="COLOR: rgb(0,0,204)">&gt;</SPAN> explain partitions <SPAN style="COLOR: rgb(0,0,255)">select</SPAN> <SPAN style="COLOR: rgb(255,0,0)">count</SPAN><SPAN style="COLOR: rgb(0,0,204)">(</SPAN><SPAN style="COLOR: rgb(0,0,204)">*</SPAN><SPAN style="COLOR: rgb(0,0,204)">)</SPAN> <SPAN style="COLOR: rgb(0,0,255)">from</SPAN> category_part <SPAN style="COLOR: rgb(0,0,255)">as</SPAN> a inner join parent <SPAN style="COLOR: rgb(0,0,255)">as</SPAN> b <SPAN style="COLOR: rgb(0,0,255)">using</SPAN><SPAN style="COLOR: rgb(0,0,204)">(</SPAN>parent_id<SPAN style="COLOR: rgb(0,0,204)">)</SPAN><SPAN style="COLOR: rgb(0,0,204)">;</SPAN><BR><SPAN style="COLOR: rgb(0,0,204)">+----+-------------+-------+----------------+-------+---------------+-------------+---------+--------------------+------+-------------+<BR>| id | select_type | table | partitions&nbsp;&nbsp;&nbsp;&nbsp; | type&nbsp; | possible_keys | key&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | key_len | ref&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | rows | Extra&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |<BR>+----+-------------+-------+----------------+-------+---------------+-------------+---------+--------------------+------+-------------+<BR>|&nbsp; 1 | SIMPLE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | b&nbsp;&nbsp;&nbsp;&nbsp; | NULL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | index | PRIMARY&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | PRIMARY&nbsp;&nbsp;&nbsp;&nbsp; | 4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | NULL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp; 25 | Using index | <BR>|&nbsp; 1 | SIMPLE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | a&nbsp;&nbsp;&nbsp;&nbsp; | p1,p2,p3,p4,p5 | ref&nbsp;&nbsp; | f_parent_id&nbsp;&nbsp; | f_parent_id | 4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | t_girl.b.parent_id | 6421 | Using index | <BR>+----+-------------+-------+----------------+-------+---------------+-------------+---------+--------------------+------+-------------+</SPAN><BR>2 <SPAN style="COLOR: rgb(0,0,255)">rows</SPAN> <SPAN style="COLOR: rgb(0,0,255)">in</SPAN> <SPAN style="COLOR: rgb(0,0,255)">set</SPAN> <SPAN style="COLOR: rgb(0,0,204)">(</SPAN>0<SPAN style="COLOR: rgb(0,0,204)">.</SPAN>00 sec<SPAN style="COLOR: rgb(0,0,204)">)</SPAN><BR style="COLOR: rgb(0,153,2)"><SPAN style="COLOR: rgb(0,153,2)">可以看出，扫描的行数大幅度减少</SPAN><BR><BR>mysql<SPAN style="COLOR: rgb(0,0,204)">&gt;</SPAN> explain <SPAN style="COLOR: rgb(0,0,255)">select</SPAN> <SPAN style="COLOR: rgb(255,0,0)">count</SPAN><SPAN style="COLOR: rgb(0,0,204)">(</SPAN><SPAN style="COLOR: rgb(0,0,204)">*</SPAN><SPAN style="COLOR: rgb(0,0,204)">)</SPAN> <SPAN style="COLOR: rgb(0,0,255)">from</SPAN> category <SPAN style="COLOR: rgb(0,0,255)">as</SPAN> a inner join parent <SPAN style="COLOR: rgb(0,0,255)">as</SPAN> b <SPAN style="COLOR: rgb(0,0,255)">using</SPAN><SPAN style="COLOR: rgb(0,0,204)">(</SPAN>parent_id<SPAN style="COLOR: rgb(0,0,204)">)</SPAN> <SPAN style="COLOR: rgb(0,0,255)">where</SPAN> a<SPAN style="COLOR: rgb(0,0,204)">.</SPAN>parent_id <SPAN style="COLOR: rgb(0,0,204)">=</SPAN>19<SPAN style="COLOR: rgb(0,0,204)">;</SPAN><BR><SPAN style="COLOR: rgb(0,0,204)">+----+-------------+-------+-------+---------------+-------------+---------+-------+------+-------------+<BR>| id | select_type | table | type&nbsp; | possible_keys | key&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | key_len | ref&nbsp;&nbsp; | rows | Extra&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |<BR>+----+-------------+-------+-------+---------------+-------------+---------+-------+------+-------------+<BR>|&nbsp; 1 | SIMPLE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | b&nbsp;&nbsp;&nbsp;&nbsp; | const | PRIMARY&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | PRIMARY&nbsp;&nbsp;&nbsp;&nbsp; | 4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | const |&nbsp;&nbsp;&nbsp; 1 | Using index | <BR>|&nbsp; 1 | SIMPLE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | a&nbsp;&nbsp;&nbsp;&nbsp; | ref&nbsp;&nbsp; | f_parent_id&nbsp;&nbsp; | f_parent_id | 4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | const | 6746 | Using index | <BR>+----+-------------+-------+-------+---------------+-------------+---------+-------+------+-------------+</SPAN><SPAN style="COLOR: rgb(255,153,0)"><BR></SPAN><BR>2 <SPAN style="COLOR: rgb(0,0,255)">rows</SPAN> <SPAN style="COLOR: rgb(0,0,255)">in</SPAN> <SPAN style="COLOR: rgb(0,0,255)">set</SPAN> <SPAN style="COLOR: rgb(0,0,204)">(</SPAN>0<SPAN style="COLOR: rgb(0,0,204)">.</SPAN>00 sec<SPAN style="COLOR: rgb(0,0,204)">)</SPAN><BR><BR>mysql<SPAN style="COLOR: rgb(0,0,204)">&gt;</SPAN> explain partitions <SPAN style="COLOR: rgb(0,0,255)">select</SPAN> <SPAN style="COLOR: rgb(255,0,0)">count</SPAN><SPAN style="COLOR: rgb(0,0,204)">(</SPAN><SPAN style="COLOR: rgb(0,0,204)">*</SPAN><SPAN style="COLOR: rgb(0,0,204)">)</SPAN> <SPAN style="COLOR: rgb(0,0,255)">from</SPAN> category_part <SPAN style="COLOR: rgb(0,0,255)">as</SPAN> a inner join parent <SPAN style="COLOR: rgb(0,0,255)">as</SPAN> b <SPAN style="COLOR: rgb(0,0,255)">using</SPAN><SPAN style="COLOR: rgb(0,0,204)">(</SPAN>parent_id<SPAN style="COLOR: rgb(0,0,204)">)</SPAN> <SPAN style="COLOR: rgb(0,0,255)">where</SPAN> a<SPAN style="COLOR: rgb(0,0,204)">.</SPAN>parent_id <SPAN style="COLOR: rgb(0,0,204)">=</SPAN>19<SPAN style="COLOR: rgb(0,0,204)">;</SPAN><BR><SPAN style="COLOR: rgb(0,0,204)">+----+-------------+-------+------------+-------+---------------+-------------+---------+-------+------+-------------+<BR>| id | select_type | table | partitions | type&nbsp; | possible_keys | key&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | key_len | ref&nbsp;&nbsp; | rows | Extra&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |<BR>+----+-------------+-------+------------+-------+---------------+-------------+---------+-------+------+-------------+<BR>|&nbsp; 1 | SIMPLE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | b&nbsp;&nbsp;&nbsp;&nbsp; | NULL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | const | PRIMARY&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | PRIMARY&nbsp;&nbsp;&nbsp;&nbsp; | 4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | const |&nbsp;&nbsp;&nbsp; 1 | Using index | <BR>|&nbsp; 1 | SIMPLE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | a&nbsp;&nbsp;&nbsp;&nbsp; | p5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | ref&nbsp;&nbsp; | f_parent_id&nbsp;&nbsp; | f_parent_id | 4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | const | 5203 | Using index | <BR>+----+-------------+-------+------------+-------+---------------+-------------+---------+-------+------+-------------+</SPAN><BR>2 <SPAN style="COLOR: rgb(0,0,255)">rows</SPAN> <SPAN style="COLOR: rgb(0,0,255)">in</SPAN> <SPAN style="COLOR: rgb(0,0,255)">set</SPAN> <SPAN style="COLOR: rgb(0,0,204)">(</SPAN>0<SPAN style="COLOR: rgb(0,0,204)">.</SPAN>00 sec<SPAN style="COLOR: rgb(0,0,204)">)</SPAN><BR><BR style="COLOR: rgb(0,153,2)"><SPAN style="COLOR: rgb(0,153,2)">由以上数据可以看出，数据越大，查询性能提升的越明显！</SPAN><BR><BR><SPAN style="COLOR: rgb(0,153,2)">2、下来看看写性能</SPAN><BR>mysql<SPAN style="COLOR: rgb(0,0,204)">&gt;</SPAN> <SPAN style="COLOR: rgb(0,0,255)">insert</SPAN> <SPAN style="COLOR: rgb(0,0,255)">into</SPAN> category<SPAN style="COLOR: rgb(0,0,204)">(</SPAN>cname<SPAN style="COLOR: rgb(0,0,204)">,</SPAN>parent_id<SPAN style="COLOR: rgb(0,0,204)">)</SPAN> <SPAN style="COLOR: rgb(0,0,255)">values</SPAN> <SPAN style="COLOR: rgb(0,0,204)">(</SPAN><SPAN style="COLOR: rgb(255,0,255)">'Test'</SPAN><SPAN style="COLOR: rgb(0,0,204)">,</SPAN>1<SPAN style="COLOR: rgb(0,0,204)">)</SPAN><SPAN style="COLOR: rgb(0,0,204)">;</SPAN><BR>Query OK<SPAN style="COLOR: rgb(0,0,204)">,</SPAN> 1 <SPAN style="COLOR: rgb(0,0,255)">row</SPAN> affected <SPAN style="COLOR: rgb(0,0,204)">(</SPAN>0<SPAN style="COLOR: rgb(0,0,204)">.</SPAN>01 sec<SPAN style="COLOR: rgb(0,0,204)">)</SPAN><BR><BR>mysql<SPAN style="COLOR: rgb(0,0,204)">&gt;</SPAN> <SPAN style="COLOR: rgb(0,0,255)">insert</SPAN> <SPAN style="COLOR: rgb(0,0,255)">into</SPAN> category_part<SPAN style="COLOR: rgb(0,0,204)">(</SPAN>cname<SPAN style="COLOR: rgb(0,0,204)">,</SPAN>parent_id<SPAN style="COLOR: rgb(0,0,204)">)</SPAN> <SPAN style="COLOR: rgb(0,0,255)">values</SPAN> <SPAN style="COLOR: rgb(0,0,204)">(</SPAN><SPAN style="COLOR: rgb(255,0,255)">'Test'</SPAN><SPAN style="COLOR: rgb(0,0,204)">,</SPAN>1<SPAN style="COLOR: rgb(0,0,204)">)</SPAN><SPAN style="COLOR: rgb(0,0,204)">;</SPAN><BR>Query OK<SPAN style="COLOR: rgb(0,0,204)">,</SPAN> 1 <SPAN style="COLOR: rgb(0,0,255)">row</SPAN> affected <SPAN style="COLOR: rgb(0,0,204)">(</SPAN>0<SPAN style="COLOR: rgb(0,0,204)">.</SPAN>00 sec<SPAN style="COLOR: rgb(0,0,204)">)</SPAN><BR><BR><BR>mysql<SPAN style="COLOR: rgb(0,0,204)">&gt;</SPAN> <SPAN style="COLOR: rgb(0,0,255)">select</SPAN> <SPAN style="COLOR: rgb(0,0,204)">*</SPAN> <SPAN style="COLOR: rgb(0,0,255)">from</SPAN> category <SPAN style="COLOR: rgb(0,0,255)">into</SPAN> outfile <SPAN style="COLOR: rgb(255,0,255)">'/tmp/a.txt'</SPAN><SPAN style="COLOR: rgb(0,0,204)">;</SPAN><BR>ERROR 1086 <SPAN style="COLOR: rgb(0,0,204)">(</SPAN>HY000<SPAN style="COLOR: rgb(0,0,204)">)</SPAN><SPAN style="COLOR: rgb(0,0,204)">:</SPAN> <SPAN style="COLOR: rgb(0,0,255)">File</SPAN> <SPAN style="COLOR: rgb(255,0,255)">'/tmp/a.txt'</SPAN> already <SPAN style="COLOR: rgb(0,0,255)">exists</SPAN><BR>mysql<SPAN style="COLOR: rgb(0,0,204)">&gt;</SPAN> <SPAN style="COLOR: rgb(0,0,255)">select</SPAN> <SPAN style="COLOR: rgb(0,0,204)">*</SPAN> <SPAN style="COLOR: rgb(0,0,255)">from</SPAN> category <SPAN style="COLOR: rgb(0,0,255)">into</SPAN> outfile <SPAN style="COLOR: rgb(255,0,255)">'/tmp/test.dat'</SPAN><SPAN style="COLOR: rgb(0,0,204)">;</SPAN><BR>Query OK<SPAN style="COLOR: rgb(0,0,204)">,</SPAN> 2048005 <SPAN style="COLOR: rgb(0,0,255)">rows</SPAN> affected <SPAN style="COLOR: rgb(0,0,204)">(</SPAN>2<SPAN style="COLOR: rgb(0,0,204)">.</SPAN>82 sec<SPAN style="COLOR: rgb(0,0,204)">)</SPAN><BR><BR>mysql<SPAN style="COLOR: rgb(0,0,204)">&gt;</SPAN> <SPAN style="COLOR: rgb(0,0,255)">truncate</SPAN> <SPAN style="COLOR: rgb(0,0,255)">table</SPAN> category<SPAN style="COLOR: rgb(0,0,204)">;</SPAN><BR>Query OK<SPAN style="COLOR: rgb(0,0,204)">,</SPAN> 0 <SPAN style="COLOR: rgb(0,0,255)">rows</SPAN> affected <SPAN style="COLOR: rgb(0,0,204)">(</SPAN>0<SPAN style="COLOR: rgb(0,0,204)">.</SPAN>06 sec<SPAN style="COLOR: rgb(0,0,204)">)</SPAN><BR><BR>mysql<SPAN style="COLOR: rgb(0,0,204)">&gt;</SPAN> <SPAN style="COLOR: rgb(0,0,255)">truncate</SPAN> <SPAN style="COLOR: rgb(0,0,255)">table</SPAN> category_part<SPAN style="COLOR: rgb(0,0,204)">;</SPAN><BR>Query OK<SPAN style="COLOR: rgb(0,0,204)">,</SPAN> 2048005 <SPAN style="COLOR: rgb(0,0,255)">rows</SPAN> affected <SPAN style="COLOR: rgb(0,0,204)">(</SPAN>0<SPAN style="COLOR: rgb(0,0,204)">.</SPAN>10 sec<SPAN style="COLOR: rgb(0,0,204)">)</SPAN><BR><BR><BR>mysql<SPAN style="COLOR: rgb(0,0,204)">&gt;</SPAN> load <SPAN style="COLOR: rgb(0,0,255)">data</SPAN> infile <SPAN style="COLOR: rgb(255,0,255)">'/tmp/test.dat'</SPAN> <SPAN style="COLOR: rgb(0,0,255)">into</SPAN> <SPAN style="COLOR: rgb(0,0,255)">table</SPAN> category<SPAN style="COLOR: rgb(0,0,204)">;</SPAN><BR>Query OK<SPAN style="COLOR: rgb(0,0,204)">,</SPAN> 2048005 <SPAN style="COLOR: rgb(0,0,255)">rows</SPAN> affected <SPAN style="COLOR: rgb(0,0,204)">(</SPAN>17<SPAN style="COLOR: rgb(0,0,204)">.</SPAN>67 sec<SPAN style="COLOR: rgb(0,0,204)">)</SPAN><BR>Records<SPAN style="COLOR: rgb(0,0,204)">:</SPAN> 2048005 Deleted<SPAN style="COLOR: rgb(0,0,204)">:</SPAN> 0 Skipped<SPAN style="COLOR: rgb(0,0,204)">:</SPAN> 0 Warnings<SPAN style="COLOR: rgb(0,0,204)">:</SPAN> 0<BR><BR>mysql<SPAN style="COLOR: rgb(0,0,204)">&gt;</SPAN> load <SPAN style="COLOR: rgb(0,0,255)">data</SPAN> infile <SPAN style="COLOR: rgb(255,0,255)">'/tmp/test.dat'</SPAN> <SPAN style="COLOR: rgb(0,0,255)">into</SPAN> <SPAN style="COLOR: rgb(0,0,255)">table</SPAN> category_part<SPAN style="COLOR: rgb(0,0,204)">;</SPAN><BR>Query OK<SPAN style="COLOR: rgb(0,0,204)">,</SPAN> 2048005 <SPAN style="COLOR: rgb(0,0,255)">rows</SPAN> affected <SPAN style="COLOR: rgb(0,0,204)">(</SPAN>21<SPAN style="COLOR: rgb(0,0,204)">.</SPAN>62 sec<SPAN style="COLOR: rgb(0,0,204)">)</SPAN><BR>Records<SPAN style="COLOR: rgb(0,0,204)">:</SPAN> 2048005 Deleted<SPAN style="COLOR: rgb(0,0,204)">:</SPAN> 0 Skipped<SPAN style="COLOR: rgb(0,0,204)">:</SPAN> 0 Warnings<SPAN style="COLOR: rgb(0,0,204)">:</SPAN> 0<BR><BR><BR><SPAN style="COLOR: rgb(0,153,2)">可以看出，写性能损失不了多少。<BR>牺牲了少许写的性能却大幅度提高了查询的性能，这个是值得的。<BR>如果我有什么说的不对的地方，欢迎各位提意见！<BR></SPAN></SPAN></CODE></DIV>]]></description>
</item><item>
<title><![CDATA[mysql 5.0 集群负载均衡—经过测试]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=lhwork&amp;id=32442</link>
<author>lhwork</author>
<pubDate>2008/3/13 21:01:46</pubDate>
<description><![CDATA[一、介绍<BR>========<BR>测试环境：<BR>Server1:ndbd 192.168.0.11<BR>Server2:ndbd 192.168.0.12<BR>Server3:mysqld --ndb-cluster 192.168.0.13 (ndbd_mgm ndbd_mgmd也在本机)<BR><BR>操作系统均为<BR>RH ES3<BR>kernel-2.4.21-9.EL<BR>glibc-2.3.2-95.6<BR><BR>所需软件包：<BR>mysql-max-5.0.22-linux-i686-icc-glibc23.tar.gz<BR>下载地址：<A href="http://dev.mysql.com/downloads/mysql/5.0.html" target=_blank>http://dev.mysql.com/downloads/mysql/5.0.html</A><BR>下载时注意系统环境和软件包版本，MySQL是max版的。<BR><BR>首先，明确几个概念（参照下图）：<BR>ndbd： 数据库节点。<BR>mysqld --ndb-cluster： MySQL服务器节点，程序直接访问的是这台机器的IP。默认端口仍是3306。<BR>ndbd_mgm ndbd_mgmd： 管理节点。管理／查看各库节点和服务器节点的状态。<BR><BR><IMG onmousewheel="return imgzoom(this);" onmouseover="if(this.width>screen.width*0.7) {this.resized=true; this.width=screen.width*0.7; this.style.cursor='hand'; this.alt='Click here to open new window\nCTRL+Mouse wheel to zoom in/out';}" onclick="if(!this.resized) {return true;} else {window.open(this.src);}" alt="" src="http://hiphotos.baidu.com/lihangel/pic/item/b2c1c31f5023f0f3e0fe0b24.jpg" onload="if(this.width>screen.width*0.7) {this.resized=true; this.width=screen.width*0.7; this.alt='Click here to open new window\nCTRL+Mouse wheel to zoom in/out';}" border=0><BR><BR><BR><BR><BR>二、在Server1、Server2、Server3上安装MySQL<BR>=================================<BR>1.安装：<BR># mv mysql-max-4.1.9-pc-linux-gnu-i686.tar.gz /usr/local/<BR># cd /usr/local/<BR># tar -zxvf mysql-max-4.1.9-pc-linux-gnu-i686.tar.gz<BR># ln -s mysql-max-4.1.9-pc-linux-gnu-i686 mysql<BR># groupadd mysql<BR># useradd -g mysql mysql<BR># cd mysql<BR># scripts/mysql_install_db --user=mysql<BR># chown -R mysql:mysql .<BR><BR>2.编辑配置文件：<BR># cp /usr/local/mysql/support-files/my-medium.cnf /etc/my.cnf<BR># vi /etc/my.cnf 在文件尾加入<BR><BR># my.cnf<BR># example additions to my.cnf for MySQL Cluster<BR># (valid in MySQL 5.0)<BR><BR># enable ndbcluster storage engine, and provide connectstring for<BR># management Server host (default port is 1186)<BR>[mysqld]<BR>ndbcluster<BR>ndb-connectstring=192.168.0.13<BR><BR># provide connectstring for management Server host (default port: 1186)<BR>[ndbd]<BR>connect-string=192.168.0.13<BR><BR># provide connectstring for management Server host (default port: 1186)<BR>[ndb_mgm]<BR>connect-string=192.168.0.13<BR><BR># provide location of cluster configuration file<BR>[ndb_mgmd]<BR>config-file=/var/lib/mysql-cluster<BR>保存＆退出<BR><BR>3.在Server1、Server2上创建日志文件夹，默认<BR># mkdir /var/lib/mysql-cluster<BR><BR>4.在Server3上创建ndb_mgmd启动配置文件：<BR># mkdir /var/lib/mysql-cluster<BR># cd /var/lib/mysql-cluster<BR># vi config.ini<BR>内容如下：<BR># file "config.ini" - 2 data nodes and 2 SQL nodes<BR># This file is placed in the startup directory of ndb_mgmd (the<BR># management server)<BR># The first MySQL Server can be started from any host. The second<BR># can be started only on the host mysqld_5.mysql.com<BR><BR>[NDBD DEFAULT]<BR>NoOfReplicas= 2<BR>DataDir= /var/lib/mysql-cluster<BR><BR>[NDB_MGMD]<BR>Hostname= 192.168.0.13<BR>DataDir= /var/lib/mysql-cluster<BR><BR>[NDBD]<BR>HostName= 192.168.0.11<BR><BR>[NDBD]<BR>HostName= 192.168.0.12<BR><BR>[MYSQLD]<BR>[MYSQLD]<BR>[MYSQLD]<BR>保存＆退出<BR><BR>[MYSQLD]<BR>[MYSQLD]<BR>[MYSQLD]<BR>表示允许有三台MySQL服务器从任何IP访问数据库结点。<BR><BR>各参数功能，请参考<A href="http://dev.mysql.com/doc/refman/5.0/en/mysql-cluster-config-example.html" target=_blank>http://dev.mysql.com/doc/refman/ ... config-example.html</A><BR><BR><BR><BR><BR>三、启动服务<BR>============<BR>Server3 /usr/local/mysql/bin/ndb_mgmd -f /var/lib/mysql-cluster/config.ini<BR>Server1 /usr/local/mysql/bin/ndbd --initial #只在第一次启动ndbd时使用--initial参数<BR>Server2 /usr/local/mysql/bin/ndbd --initial<BR>Server3 /usr/local/mysql/support-files/mysql.Server start<BR><BR><BR><BR>四、检查工作状态<BR>================<BR>回到管理节点服务器Server3上，并启动管理终端：<BR><BR># /usr/bin/ndb_mgm<BR>键入show命令查看当前工作状态：（下面是一个状态输出示例）<BR><BR>ndb_mgm&gt; show<BR>Cluster Configuration<BR>---------------------<BR>[ndbd(NDB)]&nbsp; &nbsp;&nbsp;&nbsp;2 node(s)<BR>id=2 (not connected, accepting connect from 192.168.0.11)<BR>id=3&nbsp; &nbsp; @192.168.0.12&nbsp;&nbsp;(Version: 5.0.22, Nodegroup: 0, Master)<BR><BR>[ndb_mgmd(MGM)] 1 node(s)<BR>id=1&nbsp; &nbsp; @192.168.0.13&nbsp;&nbsp;(Version: 5.0.22)<BR><BR>[mysqld(API)]&nbsp; &nbsp;3 node(s)<BR>id=4&nbsp; &nbsp; @192.168.0.13&nbsp;&nbsp;(Version: 5.0.22)<BR>id=5 (not connected, accepting connect from any host)<BR>id=6 (not connected, accepting connect from any host)<BR><BR>mysqld(API)即mysqld --ndb-cluster，MySQL服务器节点。当前只有Server3 MySQL启动。<BR><BR>如果上面没有问题，现在开始测试MySQL：<BR>注意，这篇文档对于MySQL并没有设置root密码，推荐你自己设置Server1、Server2、Server3的MySQL root密码。<BR><BR>在Server3中：<BR># /usr/local/mysql/bin/mysql<BR>&gt; use test;<BR>&gt; CREATE TABLE ctest (i INT) ENGINE=NDBCLUSTER;<BR>&gt; INSERT INTO ctest () VALUES (1);<BR>&gt; SELECT * FROM ctest;<BR><BR>应该可以看到1 row returned信息（返回数值1）。<BR><BR>如果上述正常，则换到Server1、Server2上重复上面的测试，观察效果，数据库应该是同步刷新的。但首先要启动这两台机器的MySQL服务<BR># /usr/local/mysql/support-files/mysql.Server start<BR>如果都没有问题，那么恭喜成功！<BR><BR>FAQ:<BR>失败原因，可能是启动顺序不对。<BR>查找所有ndb和sql相关进程，杀掉，重新按顺序来。<BR>ps -aux |grep ndb<BR>ps -aux |grep sql<BR>kill -9 &lt;PID&gt; &lt;PID&gt; ...&lt;PID&gt;<BR><BR><BR><BR>五、破坏性测试<BR>==============<BR>将Server1或Server2的网线拔掉，观察另外一台集群服务器工作是否正常（可以使用SELECT查询测试）。测试完毕后，重新插入网线即可。<BR><BR>如果你接触不到物理服务器，也就是说不能拔掉网线，那也可以这样测试：<BR>在Server1或Server2上：<BR>ifconfig eth0 down&nbsp;&nbsp;#如果只有一块网卡，默认是eth0<BR><BR>之后在Server3上使用SELECT查询测试。并且在管理节点服务器的管理终端中执行show命令会看到被破坏的那台服务器的状态。<BR>测试完成后，只需要重新启动被破坏服务器的ndbd进程即可：<BR># ndbd<BR>注意！前面说过了，此时是不用加--inital参数的！<BR>至此，MySQL集群就配置完成，MySQL负载均衡功能完成！ <BR><BR><BR>如想实现Apache+PHP+MySQL集群负载均衡，只需Server3上安装Apache+PHP，并添加Server4，与其做LVS即可！]]></description>
</item><item>
<title><![CDATA[MySQL-Cluster集群研究]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=lhwork&amp;id=32441</link>
<author>lhwork</author>
<pubDate>2008/3/13 20:58:09</pubDate>
<description><![CDATA[
<H1 class=firstHeading>MySQL-Cluster集群研究</H1>
<DIV id=bodyContent>
<H3 id=siteSub>Wikipedia，自由的百科全书</H3>
<DIV id=contentSub></DIV><!-- start content -->
<TABLE id=toc border=0>
<TBODY>
<TR id=toctitle>
<TD align=middle><B>目录</B>
<SCRIPT type=text/javascript>showTocToggle("显示","隐藏")</SCRIPT>
 <SPAN class=toctoggle>[<A class=internal href="javascript:toggleToc()"><SPAN id=showlink style="DISPLAY: none">显示</SPAN><SPAN id=hidelink>隐藏</SPAN></A>]</SPAN> </TD></TR>
<TR id=tocinside>
<TD>
<DIV class=tocline><A href="http://kb.discuz.net/index.php?title=MySQL-Cluster%E9%9B%86%E7%BE%A4%E7%A0%94%E7%A9%B6#.E4.B8.80.E3.80.81.E4.BB.8B.E7.BB.8D">1 一、介绍</A><BR></DIV>
<DIV class=tocline><A href="http://kb.discuz.net/index.php?title=MySQL-Cluster%E9%9B%86%E7%BE%A4%E7%A0%94%E7%A9%B6#.E4.BA.8C.E3.80.81.E5.9C.A8Server1.E5.92.8CServer2.E4.B8.8A.E5.AE.89.E8.A3.85MySQL">2 二、在Server1和Server2上安装MySQL</A><BR></DIV>
<DIV class=tocline><A href="http://kb.discuz.net/index.php?title=MySQL-Cluster%E9%9B%86%E7%BE%A4%E7%A0%94%E7%A9%B6#.E4.B8.89.E3.80.81.E5.AE.89.E8.A3.85.E5.B9.B6.E9.85.8D.E7.BD.AE.E7.AE.A1.E7.90.86.E8.8A.82.E7.82.B9.E6.9C.8D.E5.8A.A1.E5.99.A8.28Server3.29">3 三、安装并配置管理节点服务器(Server3)</A><BR></DIV>
<DIV class=tocline><A href="http://kb.discuz.net/index.php?title=MySQL-Cluster%E9%9B%86%E7%BE%A4%E7%A0%94%E7%A9%B6#.E5.9B.9B.E3.80.81.E9.85.8D.E7.BD.AE.E9.9B.86.E7.BE.A4.E6.9C.8D.E5.8A.A1.E5.99.A8.E5.B9.B6.E5.90.AF.E5.8A.A8MySQL">4 四、配置集群服务器并启动MySQL</A><BR></DIV>
<DIV class=tocline><A href="http://kb.discuz.net/index.php?title=MySQL-Cluster%E9%9B%86%E7%BE%A4%E7%A0%94%E7%A9%B6#.E4.BA.94.E3.80.81.E6.A3.80.E6.9F.A5.E5.B7.A5.E4.BD.9C.E7.8A.B6.E6.80.81">5 五、检查工作状态</A><BR></DIV>
<DIV class=tocline><A href="http://kb.discuz.net/index.php?title=MySQL-Cluster%E9%9B%86%E7%BE%A4%E7%A0%94%E7%A9%B6#.E5.85.AD.E3.80.81.E7.A0.B4.E5.9D.8F.E6.80.A7.E6.B5.8B.E8.AF.95">6 六、破坏性测试</A><BR></DIV></TD></TR></TBODY></TABLE>
<DIV class=editsection style="FLOAT: right; MARGIN-LEFT: 5px">[<A title=MySQL-Cluster集群研究 href="http://kb.discuz.net/index.php?title=MySQL-Cluster%E9%9B%86%E7%BE%A4%E7%A0%94%E7%A9%B6&amp;action=edit&amp;section=1">编辑</A>]</DIV><A name=.E4.B8.80.E3.80.81.E4.BB.8B.E7.BB.8D></A>
<H2>一、介绍</H2>
<P>这篇文档旨在介绍如何安装配置基于2台服务器的MySQL集群。并且实现任意一台服务器出现问题或宕机时MySQL依然能够继续运行。 </P>
<P>注意！ </P>
<P>虽然这是基于2台服务器的MySQL集群，但也必须有额外的第三台服务器作为管理节点，但这台服务器可以在集群启动完成后关闭。同时需要注意的是并不推荐在集群启动完成后关闭作为管理节点的服务器。尽管理论上可以建立基于只有2台服务器的MySQL集群，但是这样的架构，一旦一台服务器宕机之后集群就无法继续正常工作了，这样也就失去了集群的意义了。出于这个原因，就需要有第三台服务器作为管理节点运行。 </P>
<P>另外，可能很多朋友都没有3台服务器的实际环境，可以考虑在VMWare或其他虚拟机中进行实验。 </P>
<P>下面假设这3台服务的情况： </P><PRE> Server1: mysql1.vmtest.net 192.168.0.1
 Server2: mysql2.vmtest.net 192.168.0.2
 Server3: mysql3.vmtest.net 192.168.0.3
</PRE>
<P>Servers1和Server2作为实际配置MySQL集群的服务器。对于作为管理节点的Server3则要求较低，只需对Server3的系统进行很小的调整并且无需安装MySQL，Server3可以使用一台配置较低的计算机并且可以在Server3同时运行其他服务。 </P>
<P><BR></P>
<DIV class=editsection style="FLOAT: right; MARGIN-LEFT: 5px">[<A title=MySQL-Cluster集群研究 href="http://kb.discuz.net/index.php?title=MySQL-Cluster%E9%9B%86%E7%BE%A4%E7%A0%94%E7%A9%B6&amp;action=edit&amp;section=2">编辑</A>]</DIV><A name=.E4.BA.8C.E3.80.81.E5.9C.A8Server1.E5.92.8CServer2.E4.B8.8A.E5.AE.89.E8.A3.85MySQL></A>
<H2>二、在Server1和Server2上安装MySQL</H2>
<P>从<A class=external href="http://www.mysql.com上下载mysql-max-4.1.9-pc-linux-gnu-i686.tar.gz/" rel=nofollow>http://www.mysql.com上下载mysql-max-4.1.9-pc-linux-gnu-i686.tar.gz</A> </P>
<P>注意：必须是max版本的MySQL，Standard版本不支持集群部署！ </P>
<P>以下步骤需要在Server1和Server2上各做一次 </P><PRE> # mv mysql-max-4.1.9-pc-linux-gnu-i686.tar.gz /usr/local/
 # cd /usr/local/
 # groupadd mysql
 # useradd -g mysql mysql
 # tar -zxvf mysql-max-4.1.9-pc-linux-gnu-i686.tar.gz
 # rm -f mysql-max-4.1.9-pc-linux-gnu-i686.tar.gz
 # mv mysql-max-4.1.9-pc-linux-gnu-i686 mysql
 # cd mysql
 # scripts/mysql_install_db --user=mysql
 # chown -R root  .
 # chown -R mysql data
 # chgrp -R mysql .
 # cp support-files/mysql.server /etc/rc.d/init.d/mysqld
 # chmod +x /etc/rc.d/init.d/mysqld
 # chkconfig --add mysqld
</PRE>
<P>此时不要启动MySQL！ </P>
<P><BR></P>
<DIV class=editsection style="FLOAT: right; MARGIN-LEFT: 5px">[<A title=MySQL-Cluster集群研究 href="http://kb.discuz.net/index.php?title=MySQL-Cluster%E9%9B%86%E7%BE%A4%E7%A0%94%E7%A9%B6&amp;action=edit&amp;section=3">编辑</A>]</DIV><A name=.E4.B8.89.E3.80.81.E5.AE.89.E8.A3.85.E5.B9.B6.E9.85.8D.E7.BD.AE.E7.AE.A1.E7.90.86.E8.8A.82.E7.82.B9.E6.9C.8D.E5.8A.A1.E5.99.A8.28Server3.29></A>
<H2>三、安装并配置管理节点服务器(Server3)</H2>
<P>作为管理节点服务器，Server3需要ndb_mgm和ndb_mgmd两个文件： </P>
<P>从<A class=external href="http://www.mysql.com上下载mysql-max-4.1.9-pc-linux-gnu-i686.tar.gz/" rel=nofollow>http://www.mysql.com上下载mysql-max-4.1.9-pc-linux-gnu-i686.tar.gz</A> </P><PRE> # mkdir /usr/src/mysql-mgm
 # cd /usr/src/mysql-mgm
 # tar -zxvf mysql-max-4.1.9-pc-linux-gnu-i686.tar.gz
 # rm mysql-max-4.1.9-pc-linux-gnu-i686.tar.gz
 # cd mysql-max-4.1.9-pc-linux-gnu-i686
 # mv bin/ndb_mgm .
 # mv bin/ndb_mgmd .
 # chmod +x ndb_mg*
 # mv ndb_mg* /usr/bin/
 # cd
 # rm -rf /usr/src/mysql-mgm
</PRE>
<P>现在开始为这台管理节点服务器建立配置文件： </P><PRE> # mkdir /var/lib/mysql-cluster
 # cd /var/lib/mysql-cluster
 # vi config.ini
</PRE>
<P>在config.ini中添加如下内容： </P><PRE> [NDBD DEFAULT]
 NoOfReplicas=2
 [MYSQLD DEFAULT]
 [NDB_MGMD DEFAULT]
 [TCP DEFAULT]
 # Managment Server
 [NDB_MGMD]
 HostName=192.168.0.3 #管理节点服务器Server3的IP地址
 # Storage Engines
 [NDBD]
 HostName=192.168.0.1 #MySQL集群Server1的IP地址
 DataDir= /var/lib/mysql-cluster
 [NDBD]
 HostName=192.168.0.2 #MySQL集群Server2的IP地址
 DataDir=/var/lib/mysql-cluster
 # 以下2个[MYSQLD]可以填写Server1和Server2的主机名。
 # 但为了能够更快的更换集群中的服务器，推荐留空，否则更换服务器后必须对这个配置进行更改。
 [MYSQLD]
 [MYSQLD]
</PRE>
<P>保存退出后，启动管理节点服务器Server3： </P><PRE> # ndb_mgmd
</PRE>
<P>启动管理节点后应该注意，这只是管理节点服务，并不是管理终端。因而你看不到任何关于启动后的输出信息。 </P>
<DIV class=editsection style="FLOAT: right; MARGIN-LEFT: 5px">[<A title=MySQL-Cluster集群研究 href="http://kb.discuz.net/index.php?title=MySQL-Cluster%E9%9B%86%E7%BE%A4%E7%A0%94%E7%A9%B6&amp;action=edit&amp;section=4">编辑</A>]</DIV><A name=.E5.9B.9B.E3.80.81.E9.85.8D.E7.BD.AE.E9.9B.86.E7.BE.A4.E6.9C.8D.E5.8A.A1.E5.99.A8.E5.B9.B6.E5.90.AF.E5.8A.A8MySQL></A>
<H2>四、配置集群服务器并启动MySQL</H2>
<P>在Server1和Server2中都需要进行如下改动： </P><PRE> # vi /etc/my.cnf
</PRE><PRE> [mysqld]
 ndbcluster
 ndb-connectstring=192.168.0.3 #Server3的IP地址
 [mysql_cluster]
 ndb-connectstring=192.168.0.3 #Server3的IP地址
</PRE>
<P>保存退出后，建立数据目录并启动MySQL： </P><PRE> # mkdir /var/lib/mysql-cluster
 # cd /var/lib/mysql-cluster
 # /usr/local/mysql/bin/ndbd --initial
 # /etc/rc.d/init.d/mysqld start
</PRE>
<P>可以把/usr/local/mysql/bin/ndbd加到/etc/rc.local中实现开机启动。 </P>
<P>注意：只有在第一次启动ndbd时或者对Server3的config.ini进行改动后才需要使用--initial参数！ </P>
<P><BR></P>
<DIV class=editsection style="FLOAT: right; MARGIN-LEFT: 5px">[<A title=MySQL-Cluster集群研究 href="http://kb.discuz.net/index.php?title=MySQL-Cluster%E9%9B%86%E7%BE%A4%E7%A0%94%E7%A9%B6&amp;action=edit&amp;section=5">编辑</A>]</DIV><A name=.E4.BA.94.E3.80.81.E6.A3.80.E6.9F.A5.E5.B7.A5.E4.BD.9C.E7.8A.B6.E6.80.81></A>
<H2>五、检查工作状态</H2>
<P>回到管理节点服务器Server3上，并启动管理终端： </P><PRE> # /usr/bin/ndb_mgm
</PRE>
<P>键入show命令查看当前工作状态：（下面是一个状态输出示例） </P><PRE> [root@mysql3 root]# /usr/bin/ndb_mgm
 -- NDB Cluster -- Management Client --
 ndb_mgm&gt; show
 Connected to Management Server at: localhost:1186
 Cluster Configuration
 ---------------------
 [ndbd(NDB)]     2 node(s)
 id=2    @192.168.0.1  (Version: 4.1.9, Nodegroup: 0, Master)
 id=3    @192.168.0.2  (Version: 4.1.9, Nodegroup: 0)
 [ndb_mgmd(MGM)] 1 node(s)
 id=1    @192.168.0.3  (Version: 4.1.9)
 [mysqld(API)]   2 node(s)
 id=4   (Version: 4.1.9)
 id=5   (Version: 4.1.9)
 ndb_mgm&gt;
</PRE>
<P>如果上面没有问题，现在开始测试MySQL： </P>
<P>注意，这篇文档对于MySQL并没有设置root密码，推荐你自己设置Server1和Server2的MySQL root密码。 </P>
<P>在Server1中： </P><PRE> # /usr/local/mysql/bin/mysql -u root -p
 &gt; use test;
 &gt; CREATE TABLE ctest (i INT) ENGINE=NDBCLUSTER;
 &gt; INSERT INTO ctest () VALUES (1);
 &gt; SELECT * FROM ctest;
</PRE>
<P>应该可以看到1 row returned信息（返回数值1）。 </P>
<P>如果上述正常，则换到Server2上重复上面的测试，观察效果。如果成功，则在Server2中执行INSERT再换回到Server1观察是否工作正常。 </P>
<P>如果都没有问题，那么恭喜成功！ </P>
<P><BR></P>
<DIV class=editsection style="FLOAT: right; MARGIN-LEFT: 5px">[<A title=MySQL-Cluster集群研究 href="http://kb.discuz.net/index.php?title=MySQL-Cluster%E9%9B%86%E7%BE%A4%E7%A0%94%E7%A9%B6&amp;action=edit&amp;section=6">编辑</A>]</DIV><A name=.E5.85.AD.E3.80.81.E7.A0.B4.E5.9D.8F.E6.80.A7.E6.B5.8B.E8.AF.95></A>
<H2>六、破坏性测试</H2>
<P>将Server1或Server2的网线拔掉，观察另外一台集群服务器工作是否正常（可以使用SELECT查询测试）。测试完毕后，重新插入网线即可。 </P>
<P>如果你接触不到物理服务器，也就是说不能拔掉网线，那也可以这样测试：在Server1或Server2上： </P><PRE> # ps aux | grep ndbd
</PRE>
<P>将会看到所有ndbd进程信息： </P><PRE> root      5578  0.0  0.3  6220 1964&nbsp;?        S    03:14   0:00 ndbd
 root      5579  0.0 20.4 492072 102828&nbsp;?     R    03:14   0:04 ndbd
 root     23532  0.0  0.1  3680  684 pts/1    S    07:59   0:00 grep ndbd
</PRE>
<P>然后杀掉一个ndbd进程以达到破坏MySQL集群服务器的目的： </P><PRE> # kill -9 5578 5579
</PRE>
<P>之后在另一台集群服务器上使用SELECT查询测试。并且在管理节点服务器的管理终端中执行show命令会看到被破坏的那台服务器的状态。 </P>
<P>测试完成后，只需要重新启动被破坏服务器的ndbd进程即可： </P><PRE> # ndbd
</PRE>
<P>注意！前面说过了，此时是不用加--inital参数的！ </P>
<P>至此，MySQL集群就配置完成了！ </P><!-- end content --></DIV>]]></description>
</item><item>
<title><![CDATA[RHEL4关闭SELinux的方法]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=lhwork&amp;id=32436</link>
<author>lhwork</author>
<pubDate>2008/3/13 17:11:28</pubDate>
<description><![CDATA[<FONT size=2>RHEL4关闭SELinux的方法。</FONT> 
<P>起初是因为Apache不能认到/var/www以外目录的问题才了解到SELinux的。 <BR>在网上找了很多怎么关掉SELinux的文档，如："在system-config-securitylevel把selinux关掉就可以了"。但都不正确。 <BR>RHEL4上关掉SELinux的正确方法为： <BR>修改/etc/selinux/config文件中的SELINUX="" 为 disabled <BR>然后重启。</P>]]></description>
</item><item>
<title><![CDATA[关于 iBATIS 的几点补充]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=lhwork&amp;id=32350</link>
<author>lhwork</author>
<pubDate>2008/3/11 16:24:27</pubDate>
<description><![CDATA[<DIV><FONT size=5><STRONG><FONT color=#ff00ff><SPAN style="FONT-WEIGHT: normal; FONT-SIZE: 10.5pt">14</SPAN><SPAN style="FONT-WEIGHT: normal; FONT-SIZE: 12pt">.</SPAN><SPAN style="FONT-WEIGHT: normal; FONT-SIZE: 10.5pt">6. </SPAN><SPAN style="FONT-WEIGHT: normal; FONT-SIZE: 10.5pt">在</SPAN><SPAN style="FONT-WEIGHT: normal; FONT-SIZE: 10.5pt">iBATIS 2.09</SPAN><SPAN style="FONT-WEIGHT: normal; FONT-SIZE: 10.5pt">以后</SPAN><SPAN style="FONT-WEIGHT: normal; FONT-SIZE: 10.5pt">SQLMap</SPAN><SPAN style="FONT-WEIGHT: normal; FONT-SIZE: 10.5pt">支持动态表名</SPAN></FONT></STRONG></FONT></DIV>
<DIV>&nbsp;Sample :</DIV>
<DIV>&nbsp;&lt;select id ="getRighe"&nbsp;</DIV>
<DIV><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; remapResults ="true" </SPAN></DIV>
<DIV><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; resultMap ="resultRighe"&nbsp;</SPAN></DIV>
<DIV><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: blue">parameterClass ="java.util.Map"</SPAN> &gt; </SPAN></DIV>
<DIV><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; select * from </SPAN></DIV>
<DIV><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $tablePrefix$_righe</SPAN></DIV>
<DIV><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; where IDUser = #IDUser#</SPAN></DIV>
<DIV>&nbsp;&lt;/ select &gt; </DIV>
<DIV>&nbsp;</DIV>
<DIV style="TEXT-INDENT: 10.5pt">java code :</DIV>
<DIV style="TEXT-INDENT: 10.5pt"><SPAN style="COLOR: blue">param.put("tablePrefix", "NAG");</SPAN></DIV>
<DIV style="TEXT-INDENT: 10.5pt"><SPAN style="COLOR: blue">param.put("IDUser", IDUser);</SPAN></DIV>
<DIV style="TEXT-INDENT: 10.5pt">utente = (Riga)getSqlMapClientTemplate().queryForObject("getRighe", param);</DIV>
<DIV>&nbsp;</DIV>
<DIV>&nbsp;</DIV>
<DIV><FONT size=5><FONT color=#ff00ff><STRONG><SPAN style="FONT-WEIGHT: normal; FONT-SIZE: 10.5pt">14</SPAN><SPAN style="FONT-WEIGHT: normal; FONT-SIZE: 12pt">.</SPAN><SPAN style="FONT-WEIGHT: normal; FONT-SIZE: 10.5pt">7. Parameter Map </SPAN><SPAN style="FONT-WEIGHT: normal; FONT-SIZE: 10.5pt">和</SPAN><SPAN style="FONT-WEIGHT: normal; FONT-SIZE: 10.5pt"> Inline Parameter</SPAN></STRONG></FONT></FONT></DIV>
<DIV style="TEXT-JUSTIFY: inter-ideograph; TEXT-INDENT: 21pt">具有 parameterMap 的statement中用?表示变量的占位符;而 Inline Parameter则用#varName#.&nbsp;<SPAN style="FONT-SIZE: 10.5pt; COLOR: black">当使用基本类型包装类代替</SPAN><SPAN style="FONT-SIZE: 10.5pt; COLOR: black">Java Bean</SPAN><SPAN style="FONT-SIZE: 10.5pt; COLOR: black">时，切记要使用</SPAN><SPAN style="FONT-SIZE: 10.5pt; COLOR: black">#value#</SPAN><SPAN style="FONT-SIZE: 10.5pt; COLOR: black">作为参数。</SPAN></DIV>
<DIV><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;parameterMap id=”insert-product-param” class=”com.domain.Product”&gt;</SPAN></DIV>
<DIV><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;parameter property=”id” </SPAN></DIV>
<DIV><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; jdbcType=”NUMERIC” </SPAN></DIV>
<DIV><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;javaType=”int” </SPAN></DIV>
<DIV><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;nullValue=”-9999999”/&gt;</SPAN></DIV>
<DIV><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;parameter property=”description” </SPAN></DIV>
<DIV><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;jdbcType=”VARCHAR” </SPAN></DIV>
<DIV><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;nullValue=”NO_ENTRY”/&gt;</SPAN></DIV>
<DIV style="TEXT-INDENT: 21pt">&lt;/parameterMap&gt;</DIV>
<DIV style="TEXT-INDENT: 21pt">&lt;statement id=”insertProduct” </DIV>
<DIV><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; parameterMap=”insert-product-param”&gt;</SPAN></DIV>
<DIV><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; insert into PRODUCT (PRD_ID, PRD_DESCRIPTION) values (?,?);</SPAN></DIV>
<DIV style="TEXT-INDENT: 21pt">&lt;/statement&gt;</DIV>
<DIV style="TEXT-INDENT: 21pt">&nbsp;</DIV>
<DIV style="TEXT-INDENT: 21pt">&lt;statement id=”insertProduct” </DIV>
<DIV style="TEXT-INDENT: 21pt"><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; parameterClass=”com.domain.Product”&gt;</SPAN></DIV>
<DIV style="TEXT-INDENT: 21pt"><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; insert into PRODUCT (PRD_ID, PRD_DESCRIPTION)</SPAN></DIV>
<DIV style="TEXT-INDENT: 21pt"><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; values (#id:NUMERIC:-999999#, #description:VARCHAR:NO_ENTRY#);</SPAN></DIV>
<DIV style="TEXT-INDENT: 21pt">&lt;/statement&gt;</DIV>
<DIV style="TEXT-INDENT: 21.1pt"><STRONG></STRONG>&nbsp;</DIV>
<DIV><FONT size=5><FONT color=#ff00ff><STRONG><SPAN style="FONT-WEIGHT: normal; FONT-SIZE: 10.5pt">14</SPAN><SPAN style="FONT-WEIGHT: normal; FONT-SIZE: 12pt">.</SPAN><SPAN style="FONT-WEIGHT: normal; FONT-SIZE: 10.5pt">8. </SPAN><SPAN style="FONT-WEIGHT: normal; FONT-SIZE: 10.5pt">复杂类型属性</SPAN></STRONG></FONT></FONT></DIV>
<DIV><STRONG><SPAN style="COLOR: red">&nbsp;&nbsp;&nbsp; </SPAN></STRONG>&lt;resultMap id=”get-product-result” </DIV>
<DIV><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; class=”com.ibatis.example.Product”&gt;</SPAN></DIV>
<DIV><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;result property=”id” column=”PRD_ID”/&gt;</SPAN></DIV>
<DIV><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;result property=”description” column=”PRD_DESCRIPTION”/&gt;</SPAN></DIV>
<DIV><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;result property=”category” </SPAN></DIV>
<DIV><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; column=”PRD_CAT_ID” </SPAN></DIV>
<DIV><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; select=”getCategory”/&gt;</SPAN></DIV>
<DIV style="TEXT-INDENT: 0.1pt">&lt;/resultMap&gt;</DIV>
<DIV style="TEXT-INDENT: -0.1pt">&lt;resultMap id=”get-category-result” </DIV>
<DIV style="TEXT-INDENT: -0.1pt"><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; class=”com.ibatis.example.Category”&gt;</SPAN></DIV>
<DIV style="TEXT-INDENT: -0.1pt"><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;result property=”id” column=”CAT_ID”/&gt;</SPAN></DIV>
<DIV style="TEXT-INDENT: -0.1pt"><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;result property=”description” column=”CAT_DESCRIPTION”/&gt;</SPAN></DIV>
<DIV style="TEXT-INDENT: -0.1pt">&lt;/resultMap&gt;</DIV>
<DIV style="TEXT-INDENT: -0.1pt">&lt;statement id=”getProduct” </DIV>
<DIV style="TEXT-INDENT: -0.1pt"><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; parameterClass=”int” </SPAN></DIV>
<DIV style="TEXT-INDENT: -0.1pt"><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; resultMap=”get-product-result”&gt;</SPAN></DIV>
<DIV style="TEXT-INDENT: -0.1pt"><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; select * from PRODUCT where PRD_ID = #value#</SPAN></DIV>
<DIV style="TEXT-INDENT: -0.1pt">&lt;/statement&gt;</DIV>
<DIV style="TEXT-INDENT: -0.1pt">&lt;statement id=”getCategory” </DIV>
<DIV style="TEXT-INDENT: -0.1pt"><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; parameterClass=”int” </SPAN></DIV>
<DIV style="TEXT-INDENT: -0.1pt"><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; resultMap=”get-category-result”&gt;</SPAN></DIV>
<DIV style="TEXT-INDENT: -0.1pt"><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; select * from CATEGORY where CAT_ID = #value#</SPAN></DIV>
<DIV style="TEXT-INDENT: -0.1pt">&lt;/statement&gt;</DIV>
<DIV style="TEXT-INDENT: 17.95pt">上面的例子中，Product对象拥有一个类型为Category的category属性。因为category是复杂类型（用户定义的类型），JDBC不知道如何给它赋值。通过将category属性值和另一个mapped statement联系起来，为SQL Map引擎如何给它赋值提供了足够的信息。通过执行“getProduct”，“get-product-result”Result Map使用PRD_CAT_ID字段的值去调用“getCategory”。“get-category-result”Result Map将初始化一个Category对象并赋值给它。然后整个Category对象将赋值给Product的category属性。</DIV>
<DIV style="TEXT-INDENT: 17.95pt">使用一个联合查询和嵌套的属性映射来代替两个查询statement。上面例子的解决方案是：</DIV>
<DIV style="TEXT-INDENT: 17.95pt">&lt;resultMap id=”get-product-result” class=”com.ibatis.example.Product”&gt;</DIV>
<DIV style="TEXT-INDENT: 17.95pt"><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;result property=”id” column=”PRD_ID”/&gt;</SPAN></DIV>
<DIV style="TEXT-INDENT: 17.95pt"><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;result property=”description” column=”PRD_DESCRIPTION”/&gt;</SPAN></DIV>
<DIV style="TEXT-INDENT: 17.95pt"><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;result property=”category.id” column=”CAT_ID” /&gt;</SPAN></DIV>
<DIV style="TEXT-INDENT: 17.95pt"><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;result property=”category.description” column=”CAT_DESCRIPTION” /&gt;</SPAN></DIV>
<DIV style="TEXT-INDENT: 17.95pt">&lt;/resultMap&gt;</DIV>
<DIV style="TEXT-INDENT: 17.95pt">&lt;statement id=”getProduct” parameterClass=”int” resultMap=”get-product-result”&gt;</DIV>
<DIV style="TEXT-INDENT: 17.95pt"><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; select *</SPAN></DIV>
<DIV style="TEXT-INDENT: 17.95pt"><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from PRODUCT, CATEGORY</SPAN></DIV>
<DIV style="TEXT-INDENT: 17.95pt"><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; where PRD_CAT_ID=CAT_ID</SPAN></DIV>
<DIV style="TEXT-INDENT: 17.95pt"><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; and PRD_ID = #value#</SPAN></DIV>
<DIV style="TEXT-INDENT: 17.95pt">&lt;/statement&gt;</DIV>
<DIV style="TEXT-INDENT: 17.95pt">&nbsp;</DIV>
<DIV><FONT size=5><FONT color=#ff00ff><STRONG><SPAN style="FONT-WEIGHT: normal; FONT-SIZE: 10.5pt">14</SPAN><SPAN style="FONT-WEIGHT: normal; FONT-SIZE: 12pt">.</SPAN><SPAN style="FONT-WEIGHT: normal; FONT-SIZE: 10.5pt">9. </SPAN><SPAN style="FONT-WEIGHT: normal; FONT-SIZE: 10.5pt">配置</SPAN><SPAN style="FONT-WEIGHT: normal; FONT-SIZE: 10.5pt">Log4J</SPAN></STRONG></FONT></FONT></DIV>
<DIV><STRONG><SPAN style="COLOR: red">&nbsp;</SPAN></STRONG># Global logging configuration</DIV>
<DIV style="TEXT-INDENT: 0.1pt">log4j.rootLogger=ERROR, stdout</DIV>
<DIV style="TEXT-INDENT: 0.1pt">&nbsp;</DIV>
<DIV style="TEXT-INDENT: 0.1pt"># SqlMap logging configuration...</DIV>
<DIV style="TEXT-INDENT: 0.1pt">log4j.logger.com.ibatis=DEBUG</DIV>
<DIV style="TEXT-INDENT: 0.1pt">log4j.logger.com.ibatis.common.jdbc.SimpleDataSource=DEBUG</DIV>
<DIV style="TEXT-INDENT: 0.1pt">log4j.logger.com.ibatis.common.jdbc.ScriptRunner=DEBUG</DIV>
<DIV style="TEXT-INDENT: 0.1pt">log4j.logger.com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate=DEBUG</DIV>
<DIV style="TEXT-INDENT: 0.1pt">log4j.logger.java.sql.Connection=DEBUG</DIV>
<DIV style="TEXT-INDENT: 0.1pt">#log4j.logger.java.sql.Statement=DEBUG</DIV>
<DIV style="TEXT-INDENT: 0.1pt">#log4j.logger.java.sql.PreparedStatement=DEBUG</DIV>
<DIV style="TEXT-INDENT: 0.1pt">#log4j.logger.java.sql.ResultSet=DEBUG</DIV>
<DIV style="TEXT-INDENT: 0.1pt">&nbsp;</DIV>
<DIV style="TEXT-INDENT: 0.1pt"># Console output...</DIV>
<DIV style="TEXT-INDENT: 0.1pt">log4j.appender.stdout=org.apache.log4j.ConsoleAppender</DIV>
<DIV style="TEXT-INDENT: 0.1pt">log4j.appender.stdout.layout=org.apache.log4j.PatternLayout</DIV>
<DIV style="TEXT-INDENT: 0.1pt">log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n</DIV>
<DIV>&nbsp;</DIV>
<DIV><FONT size=5><FONT color=#ff00ff><STRONG><SPAN style="FONT-WEIGHT: normal; FONT-SIZE: 10.5pt">14</SPAN><SPAN style="FONT-WEIGHT: normal; FONT-SIZE: 12pt">.</SPAN><SPAN style="FONT-WEIGHT: normal; FONT-SIZE: 10.5pt">10. </SPAN><SPAN style="FONT-WEIGHT: normal; FONT-SIZE: 10.5pt">动态</SPAN><SPAN style="FONT-WEIGHT: normal; FONT-SIZE: 10.5pt">SQL</SPAN><SPAN style="FONT-WEIGHT: normal; FONT-SIZE: 10.5pt">语句</SPAN></STRONG></FONT></FONT></DIV>
<DIV><SPAN>&nbsp;&nbsp; &lt;statement id="someName" resultMap="account-result" &gt;</SPAN></DIV>
<DIV><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; select * from ACCOUNT</SPAN></DIV>
<DIV><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: blue">&lt;dynamic</SPAN> prepend="where"&gt;</SPAN></DIV>
<DIV><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;<SPAN style="COLOR: blue">isGreaterThan</SPAN> prepend="and" property="id" compareValue="0"&gt;</SPAN></DIV>
<DIV><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ACC_ID = #id#</SPAN></DIV>
<DIV><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;<SPAN style="COLOR: blue">/isGreaterThan</SPAN>&gt;</SPAN></DIV>
<DIV><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;<SPAN style="COLOR: blue">isNotNull </SPAN>prepend=”and" property="lastName"&gt;</SPAN></DIV>
<DIV><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ACC_LAST_NAME = #lastName#</SPAN></DIV>
<DIV><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;<SPAN style="COLOR: blue">/isNotNull</SPAN>&gt;</SPAN></DIV>
<DIV><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: blue">&lt;/dynamic&gt;</SPAN></SPAN></DIV>
<DIV><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; order by ACC_LAST_NAME</SPAN></DIV>
<DIV style="TEXT-INDENT: 21pt">&lt;/statement&gt;</DIV>
<DIV style="TEXT-INDENT: 21pt">对于以上蓝色的单词就是 动态Mapped Statement 元素关系运算符(她包括一元和二元的很多类型,具体参见 注14.1. 点的内容)</DIV>]]></description>
</item><item>
<title><![CDATA[IBatis中的强制刷新缓存]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=lhwork&amp;id=32349</link>
<author>lhwork</author>
<pubDate>2008/3/11 16:24:04</pubDate>
<description><![CDATA[了IBatis内置的缓存作为缓存方案．并使用了spring集成IBatis<BR><BR>我在我的一篇文章＂<A href="http://blog.csdn.net/pwlazy/archive/2006/08/10/1046197.aspx">使用IBatis作数据缓存</A>＂谈到了使用IBaits作缓存，但这或许是不够的，为了给测试人员提供方便，必须提供一个 强制刷新缓存的功能，如何实现？马上进入实战：<BR><BR>我们通过一个jsp搞定 
<DIV style="BORDER-RIGHT: windowtext 0.5pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 0.5pt solid; PADDING-LEFT: 5.4pt; BACKGROUND: rgb(230,230,230) 0% 50%; PADDING-BOTTOM: 4px; BORDER-LEFT: windowtext 0.5pt solid; WIDTH: 95%; PADDING-TOP: 4px; BORDER-BOTTOM: windowtext 0.5pt solid; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial">
<DIV><IMG alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align=top><SPAN style="COLOR: rgb(0,0,0)">&lt;%</SPAN><SPAN style="COLOR: rgb(0,0,0)">@&nbsp;page&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">import</SPAN><SPAN style="COLOR: rgb(0,0,0)">=</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">xxx.common.utils.SpringBeanProxy</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">%&gt;</SPAN><SPAN style="COLOR: rgb(0,0,0)"><BR><IMG alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align=top></SPAN><SPAN style="COLOR: rgb(0,0,0)">&lt;%</SPAN><SPAN style="COLOR: rgb(0,0,0)">@&nbsp;page&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">import</SPAN><SPAN style="COLOR: rgb(0,0,0)">=</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">com.ibatis.sqlmap.client.SqlMapClient</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">%&gt;</SPAN><SPAN style="COLOR: rgb(0,0,0)"><BR><IMG alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align=top></SPAN><SPAN style="COLOR: rgb(0,0,0)">&lt;%</SPAN><SPAN style="COLOR: rgb(0,0,0)"><BR><IMG alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<BR><IMG alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;<BR><IMG alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;cacheModelId&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">=</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;request.getParameter(</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">cacheModelId</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">);<BR><IMG alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<BR><IMG alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SqlMapClient&nbsp;client&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">=</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;(SqlMapClient)&nbsp;SpringBeanProxy<BR><IMG alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.getBean(</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">sqlMapClient</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">);<BR><IMG alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<BR><IMG alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;<BR><IMG alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;client.flushDataCache(cacheModelId);<BR><IMG alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align=top></SPAN><SPAN style="COLOR: rgb(0,0,0)">%&gt;</SPAN><SPAN style="COLOR: rgb(0,0,0)"><BR><IMG alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align=top><BR><IMG alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align=top><BR><IMG alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align=top>ok</SPAN><SPAN style="COLOR: rgb(0,0,0)">!</SPAN></DIV></DIV><BR>首先我们获取需要刷新缓存的id,然后从spring工厂中取出<SPAN style="COLOR: rgb(0,0,0)">SqlMapClient ，然后利用</SPAN><SPAN style="COLOR: rgb(0,0,0)">SqlMapClient刷新缓存<BR><BR>其实你也可以调用</SPAN><SPAN style="COLOR: rgb(0,0,0)">client．</SPAN><SPAN style="COLOR: rgb(0,0,0)">flushDataCache()，这样就刷新了所有的缓存模型而不是某一个．</SPAN><SPAN style="COLOR: rgb(0,0,0)"></SPAN>
<SCRIPT type=text/javascript><!--
google_ad_client = "pub-1534216445189830";
google_alternate_ad_url = "http://www.fish888.com/noad.html";
google_ad_width = 728;
google_ad_height = 90;
google_ad_format = "728x90_as";
google_ad_type = "text_image";
google_ad_channel ="";
google_color_border = "FFFFFF";
google_color_link = "0000FF";
google_color_bg = "FFFFFF";
google_color_text = "000000";
google_color_url = "008000";
//--></SCRIPT>

<SCRIPT src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type=text/javascript>
</SCRIPT>
]]></description>
</item><item>
<title><![CDATA[iBatis对批量update的支持]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=lhwork&amp;id=32348</link>
<author>lhwork</author>
<pubDate>2008/3/11 16:23:33</pubDate>
<description><![CDATA[<P>最近遇到需要批量update数据的问题，一开始用了一个for循环去update，数据量大的时候效率很低。原因是for循环每次update一条语句，都是一次连接过程。遇到大批数据更新的时候，效率就可想而知了。在google上找了一遍，发现iBatis里有对批量update的支持，挺好的东西。</P>
<P>代码如下：<BR>&nbsp;&nbsp;&nbsp; final List tempList = list;<BR>&nbsp;&nbsp;&nbsp; try {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (List tempList != null) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; template.execute(<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new SqlMapClientCallback() {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public Object doInSqlMapClient(SqlMapExecutor executor) throws<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SQLException {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; executor.startBatch();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int i = 0, n = tempList.size(); i &lt; n; i++) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; executor.update("test.batchupdate",(Map)tempList.get(i));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; executor.executeBatch();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return null;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; );<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;用法就是这么简单，但是其工作的原理还没搞懂。</P>
<SCRIPT type=text/javascript><!--
google_ad_client = "pub-1534216445189830";
google_alternate_ad_url = "http://www.fish888.com/noad.html";
google_ad_width = 728;
google_ad_height = 90;
google_ad_format = "728x90_as";
google_ad_type = "text_image";
google_ad_channel ="";
google_color_border = "FFFFFF";
google_color_link = "0000FF";
google_color_bg = "FFFFFF";
google_color_text = "000000";
google_color_url = "008000";
//--></SCRIPT>

<SCRIPT src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type=text/javascript>
</SCRIPT>]]></description>
</item><item>
<title><![CDATA[一个使用ibatis对数据库增删改查的例子]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=lhwork&amp;id=32347</link>
<author>lhwork</author>
<pubDate>2008/3/11 16:20:06</pubDate>
<description><![CDATA[<P><A href="http://www.fish888.com/ibatis-t146338" target=_blank>一个使用ibatis对数据库增删改查的例子</A></P>]]></description>
</item><item>
<title><![CDATA[一个使用ibatis对数据库增删改查的例子]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=lhwork&amp;id=32346</link>
<author>lhwork</author>
<pubDate>2008/3/11 16:18:32</pubDate>
<description><![CDATA[<P>一个使用ibatis对数据库增删改查的例子:<BR>这里用的开发环境是:Eclipse3.2+mysql5.0.20,ibatis包是ibatis-common-2.jar,<BR>ibatis-dao-2.jar,ibatis-sqlmap-2.jar,mysql包是mysql-connector-java-5.0.3-bin.jar.<BR>步骤:<BR>1.创建数据库:<BR>&nbsp;create database itcast;<BR>&nbsp;use itcast;<BR>创建表：<BR>&nbsp;create table student<BR>&nbsp;(<BR>&nbsp;&nbsp;id int primary key auto_increment,<BR>&nbsp;&nbsp;firstname varchar(20) not null,<BR>&nbsp;&nbsp;lastname varchar(20) not null<BR>&nbsp;)</P>
<P>2.创建POJO类,Student.java，此程序中用到的所有类都放在cn.itcast包下面，<BR>&nbsp;其他的配置文件都放在txd.configfile包下面。<BR>&nbsp;package cn.itcast;<BR>&nbsp;<BR>&nbsp;public class Student {<BR>&nbsp;&nbsp;private Integer id;<BR>&nbsp;<BR>&nbsp;&nbsp;private String firstname;<BR>&nbsp;<BR>&nbsp;&nbsp;private String lastname;<BR>&nbsp;<BR>&nbsp;&nbsp;public String getFirstname() {<BR>&nbsp;&nbsp;&nbsp;return firstname;<BR>&nbsp;&nbsp;}<BR>&nbsp;<BR>&nbsp;&nbsp;public void setFirstname(String firstname) {<BR>&nbsp;&nbsp;&nbsp;this.firstname = firstname;<BR>&nbsp;&nbsp;}<BR>&nbsp;<BR>&nbsp;&nbsp;public Integer getId() {<BR>&nbsp;&nbsp;&nbsp;return id;<BR>&nbsp;&nbsp;}<BR>&nbsp;<BR>&nbsp;&nbsp;public void setId(Integer id) {<BR>&nbsp;&nbsp;&nbsp;this.id = id;<BR>&nbsp;&nbsp;}<BR>&nbsp;<BR>&nbsp;&nbsp;public String getLastname() {<BR>&nbsp;&nbsp;&nbsp;return lastname;<BR>&nbsp;&nbsp;}<BR>&nbsp;<BR>&nbsp;&nbsp;public void setLastname(String lastname) {<BR>&nbsp;&nbsp;&nbsp;this.lastname = lastname;<BR>&nbsp;&nbsp;}<BR>&nbsp;}</P>
<P>3.跟Student类对应的xml配置文件Student.xml,<BR>&nbsp;&lt;?xml version="1.0" encoding="UTF-8"?&gt;<BR>&nbsp;&lt;!DOCTYPE sqlMap PUBLIC "-//iBATIS.com//DTD SQL Map 2.0//EN" "<A href="http://www.ibatis.com/dtd/sql-map-2.dtd">http://www.ibatis.com/dtd/sql-map-2.dtd</A>"&gt;<BR>&nbsp;&lt;sqlMap namespace="student"&gt;<BR>&nbsp;&nbsp;&lt;!--insert元素,id属性值作为标识此元素,parameterClass属性是参数的类型,此<BR>&nbsp;&nbsp;属性的值是Java类的全限定名（即包括类的包名）。它是可选的，但强烈建议使用。<BR>&nbsp;&nbsp;它的目的是&nbsp;限制输入参数的类型为指定的Java类，并优化框架的性能。##符号中<BR>&nbsp;&nbsp;间的名字来自此类的属性.--&gt;<BR>&nbsp;&nbsp;&lt;insert id="insert_student" parameterClass="cn.itcast.Student"&gt;<BR>&nbsp;&nbsp;&nbsp;insert into student(firstname,lastname) values<BR>&nbsp;&nbsp;&nbsp;(#firstname#,#lastname#)<BR>&nbsp;&nbsp;&lt;/insert&gt;<BR>&nbsp;<BR>&nbsp;&nbsp;&lt;select id="getStudent" resultClass="cn.itcast.Student"&gt;<BR>&nbsp;&nbsp;&nbsp;select id, firstname, lastname from student<BR>&nbsp;&nbsp;&lt;/select&gt;<BR>&nbsp;<BR>&nbsp;&nbsp;&lt;delete id="delStudent" parameterClass="int"&gt;<BR>&nbsp;&nbsp;&nbsp;delete from student where id=#value#<BR>&nbsp;&nbsp;&lt;/delete&gt;<BR>&nbsp;<BR>&nbsp;&nbsp;&lt;update id="updateStudent" parameterClass="cn.itcast.Student"&gt;<BR>&nbsp;&nbsp;&nbsp;update student set firstname=#firstname#,lastname=#lastname#<BR>&nbsp;&nbsp;&nbsp;where id=#id#<BR>&nbsp;&nbsp;&lt;/update&gt;<BR>&nbsp;&lt;/sqlMap&gt;</P>
<P>4.jdbc.properties文件,存储数据库连接的driver,url,username,password等信息,<BR>&nbsp;driver=com.mysql.jdbc.Driver<BR>&nbsp;url=jdbc:mysql:///itcast<BR>&nbsp;username=root<BR>&nbsp;password=</P>
<P>5. SqlMap的配置文件SqlMapConfigExample.xml,<BR>&nbsp;&lt;?xml version="1.0" encoding="UTF-8"?&gt;<BR>&nbsp;&lt;!DOCTYPE sqlMapConfig<BR>&nbsp;PUBLIC "-//iBATIS.com//DTD SQL Map Config 2.0//EN"<BR>&nbsp;"<A href="http://www.ibatis.com/dtd/sql-map-config-2.dtd">http://www.ibatis.com/dtd/sql-map-config-2.dtd</A>"&gt;<BR>&nbsp;<BR>&nbsp;&lt;sqlMapConfig&gt;<BR>&nbsp;&nbsp;&lt;!--&lt;properties&gt;元素，用于在配置文件中使用标准的Java属性文件（name＝value）--&gt;<BR>&nbsp;&nbsp;&lt;properties resource="txd/configfile/jdbc.properties" /&gt;<BR>&nbsp;&nbsp;&lt;!--<BR>&nbsp;&nbsp;cacheModelsEnabled:全局性地启用或禁用SqlMapClient的所有缓存model。<BR>&nbsp;&nbsp;enhancementEnabled:全局性地启用或禁用运行时字节码增强，以优化访问<BR>&nbsp;&nbsp;&nbsp;Java Bean属性的性能，同时优化延迟加载的性能。<BR>&nbsp;&nbsp;lazyLoadingEnabled:全局性地启用或禁用SqlMapClient的所有延迟加载。<BR>&nbsp;&nbsp;maxRequests:同时执行SQL语句的最大线程数。<BR>&nbsp;&nbsp;maxSessions:同一时间内活动的最大session数。<BR>&nbsp;&nbsp;maxTransactions:同时进入SqlMapClient.startTransaction()的最大线程数。<BR>&nbsp;&nbsp;useStatementNamespaces:如果启用本属性，必须使用全限定名来引用mapped statement。<BR>&nbsp;&nbsp;&nbsp;Mapped statement的全限定名由sql-map的名称和mapped-statement的名称合成。<BR>&nbsp;&nbsp;--&gt;<BR>&nbsp;&nbsp;&lt;settings cacheModelsEnabled="true" enhancementEnabled="true"<BR>&nbsp;&nbsp;&nbsp;lazyLoadingEnabled="true" maxRequests="32" maxSessions="10"<BR>&nbsp;&nbsp;&nbsp;maxTransactions="5" useStatementNamespaces="false" /&gt;<BR>&nbsp;<BR>&nbsp;&nbsp;&lt;!--<BR>&nbsp;&nbsp;&lt;transationManager&gt;元素让您为SQL Map配置事务管理服务。属性type指定所<BR>&nbsp;&nbsp;使用的事务管理器类型。这个属性值可以是一个类名，也可以是一个别名。<BR>&nbsp;&nbsp;包含在框架的三个事务管理器分别是：JDBC，JTA和EXTERNAL。<BR>&nbsp;&nbsp;--&gt;<BR>&nbsp;&nbsp;&lt;transactionManager type="JDBC"&gt;<BR>&nbsp;&nbsp;&nbsp;&lt;!--dataSource元素为SQL Map数据源设置了一系列参数。--&gt;<BR>&nbsp;&nbsp;&nbsp;&lt;dataSource type="SIMPLE"&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&lt;property name="JDBC.Driver" value="${driver}" /&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&lt;property name="JDBC.ConnectionURL" value="${url}" /&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&lt;property name="JDBC.Username" value="${username}" /&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&lt;property name="JDBC.Password" value="${password}" /&gt;<BR>&nbsp;&nbsp;&nbsp;&lt;/dataSource&gt;<BR>&nbsp;&nbsp;&lt;/transactionManager&gt;<BR>&nbsp;&nbsp;&lt;!--&lt;sqlMap&gt;元素用于包括SQL Map映射文件和其他的SQL Map配置文件。--&gt;<BR>&nbsp;&nbsp;&lt;sqlMap resource="txd/configfile/Student.xml" /&gt;<BR>&nbsp;&lt;/sqlMapConfig&gt;</P>
<P>6.MySqlMapClient.java类,用于产生一个SqlMapClient<BR>&nbsp;package cn.itcast;<BR>&nbsp;<BR>&nbsp;import java.io.IOException;<BR>&nbsp;import java.io.Reader;<BR>&nbsp;<BR>&nbsp;import com.ibatis.common.resources.Resources;<BR>&nbsp;import com.ibatis.sqlmap.client.SqlMapClient;<BR>&nbsp;import com.ibatis.sqlmap.client.SqlMapClientBuilder;<BR>&nbsp;<BR>&nbsp;public class MySqlMapClient {<BR>&nbsp;<BR>&nbsp;&nbsp;private static SqlMapClient sqlMapClient;<BR>&nbsp;<BR>&nbsp;&nbsp;static {<BR>&nbsp;&nbsp;&nbsp;String resource = "txd/configfile/SqlMapConfigExample.xml";<BR>&nbsp;&nbsp;&nbsp;Reader reader = null;<BR>&nbsp;&nbsp;&nbsp;try {<BR>&nbsp;&nbsp;&nbsp;&nbsp;reader = Resources.getResourceAsReader(resource);<BR>&nbsp;&nbsp;&nbsp;&nbsp;sqlMapClient = SqlMapClientBuilder.buildSqlMapClient(reader);<BR>&nbsp;&nbsp;&nbsp;} catch (IOException e) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();<BR>&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;}<BR>&nbsp;<BR>&nbsp;&nbsp;public static SqlMapClient getSqlMapInstance() {<BR>&nbsp;&nbsp;&nbsp;return sqlMapClient;<BR>&nbsp;&nbsp;}<BR>&nbsp;<BR>&nbsp;}</P>
<P>7.StudentManager 类测试一下上面的代码,<BR>&nbsp;package cn.itcast;<BR>&nbsp;<BR>&nbsp;import java.sql.SQLException;<BR>&nbsp;import java.util.List;<BR>&nbsp;<BR>&nbsp;import com.ibatis.sqlmap.client.SqlMapClient;<BR>&nbsp;<BR>&nbsp;public class StudentManager {<BR>&nbsp;<BR>&nbsp;&nbsp;public static void main(String[] args) {<BR>&nbsp;&nbsp;&nbsp;SqlMapClient sqlMap = MySqlMapClient.getSqlMapInstance();<BR>&nbsp;<BR>&nbsp;&nbsp;&nbsp;// insert一条记录<BR>&nbsp;<BR>&nbsp;&nbsp;&nbsp;// Student student = new Student();<BR>&nbsp;&nbsp;&nbsp;// student.setFirstname("zhang");<BR>&nbsp;&nbsp;&nbsp;// student.setLastname("san");<BR>&nbsp;&nbsp;&nbsp;// try {<BR>&nbsp;&nbsp;&nbsp;// sqlMap.insert("insert_student", student);<BR>&nbsp;&nbsp;&nbsp;// System.out.println("插入成功!");<BR>&nbsp;&nbsp;&nbsp;// } catch (SQLException e) {<BR>&nbsp;&nbsp;&nbsp;// e.printStackTrace();<BR>&nbsp;&nbsp;&nbsp;// }<BR>&nbsp;<BR>&nbsp;&nbsp;&nbsp;// delete一条记录<BR>&nbsp;<BR>&nbsp;&nbsp;&nbsp;// try {<BR>&nbsp;&nbsp;&nbsp;// int result = sqlMap.delete("delStudent", 5);<BR>&nbsp;&nbsp;&nbsp;// System.out.println(result);<BR>&nbsp;&nbsp;&nbsp;// } catch (SQLException e) {<BR>&nbsp;&nbsp;&nbsp;// e.printStackTrace();<BR>&nbsp;&nbsp;&nbsp;// }<BR>&nbsp;<BR>&nbsp;&nbsp;&nbsp;// update一条已存在的记录<BR>&nbsp;<BR>&nbsp;&nbsp;&nbsp;Student student = new Student();<BR>&nbsp;&nbsp;&nbsp;student.setId(1);<BR>&nbsp;&nbsp;&nbsp;student.setFirstname("jiang");<BR>&nbsp;&nbsp;&nbsp;student.setLastname("zemin");<BR>&nbsp;&nbsp;&nbsp;try {<BR>&nbsp;&nbsp;&nbsp;&nbsp;int result = sqlMap.update("updateStudent", student);<BR>&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(result);<BR>&nbsp;&nbsp;&nbsp;} catch (SQLException e) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();<BR>&nbsp;&nbsp;&nbsp;}<BR>&nbsp;<BR>&nbsp;&nbsp;&nbsp;// query获得多条记录<BR>&nbsp;<BR>&nbsp;&nbsp;&nbsp;// try {<BR>&nbsp;&nbsp;&nbsp;// List&lt;Student&gt; list = sqlMap.queryForList("getStudent", null);<BR>&nbsp;&nbsp;&nbsp;// for (Student student : list) {<BR>&nbsp;&nbsp;&nbsp;// System.out<BR>&nbsp;&nbsp;&nbsp;// .println(student.getId() + "\t"<BR>&nbsp;&nbsp;&nbsp;// + student.getFirstname() + "\t"<BR>&nbsp;&nbsp;&nbsp;// + student.getLastname());<BR>&nbsp;&nbsp;&nbsp;// }<BR>&nbsp;&nbsp;&nbsp;// } catch (SQLException e) {<BR>&nbsp;&nbsp;&nbsp;// e.printStackTrace();<BR>&nbsp;&nbsp;&nbsp;// }<BR>&nbsp;<BR>&nbsp;&nbsp;&nbsp;// query单条记录<BR>&nbsp;<BR>&nbsp;&nbsp;&nbsp;// try {<BR>&nbsp;&nbsp;&nbsp;// Student student = (Student) sqlMap.queryForObject("getStudent", 1);<BR>&nbsp;&nbsp;&nbsp;// System.out.println(student.getId());<BR>&nbsp;&nbsp;&nbsp;// System.out.println(student.getFirstname());<BR>&nbsp;&nbsp;&nbsp;// System.out.println(student.getLastname());<BR>&nbsp;&nbsp;&nbsp;// } catch (SQLException e) {<BR>&nbsp;&nbsp;&nbsp;// e.printStackTrace();<BR>&nbsp;&nbsp;&nbsp;// }<BR>&nbsp;&nbsp;}<BR>&nbsp;<BR>&nbsp;}</P>
<SCRIPT type=text/javascript><!--
google_ad_client = "pub-1534216445189830";
google_alternate_ad_url = "http://www.fish888.com/noad.html";
google_ad_width = 728;
google_ad_height = 90;
google_ad_format = "728x90_as";
google_ad_type = "text_image";
google_ad_channel ="";
google_color_border = "FFFFFF";
google_color_link = "0000FF";
google_color_bg = "FFFFFF";
google_color_text = "000000";
google_color_url = "008000";
//--></SCRIPT>

<SCRIPT src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type=text/javascript>
</SCRIPT>]]></description>
</item><item>
<title><![CDATA[解决Ibatis一对多映射n+1问题]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=lhwork&amp;id=32345</link>
<author>lhwork</author>
<pubDate>2008/3/11 16:17:47</pubDate>
<description><![CDATA[存在一对多的逻辑关系,比如视频和视频标签（严格来讲是多对多的关系）,目前想取出一些视频和该视频包含的标签,传统的做法往往会存在n+1问题,对性能有些影响<BR><BR>在IBatis中如何做?马上进入实战 <BR><BR>配置文件如下: <BR>
<DIV style="BORDER-RIGHT: windowtext 0.5pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 0.5pt solid; PADDING-LEFT: 5.4pt; BACKGROUND: rgb(230,230,230) 0% 50%; PADDING-BOTTOM: 4px; BORDER-LEFT: windowtext 0.5pt solid; WIDTH: 95%; PADDING-TOP: 4px; BORDER-BOTTOM: windowtext 0.5pt solid; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial">
<DIV>&lt;sqlMap namespace="search"&gt;<BR><IMG alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align=top><SPAN style="COLOR: rgb(0,0,255)"><BR>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;</SPAN><SPAN style="COLOR: rgb(128,0,0)">resultMap&nbsp;</SPAN><SPAN style="COLOR: rgb(255,0,0)">id</SPAN><SPAN style="COLOR: rgb(0,0,255)">="video-map"</SPAN><SPAN style="COLOR: rgb(255,0,0)">&nbsp;class</SPAN><SPAN style="COLOR: rgb(0,0,255)">="xx.index.dataset.VideoVO"</SPAN><SPAN style="COLOR: rgb(255,0,0)">&nbsp;groupBy</SPAN><SPAN style="COLOR: rgb(0,0,255)">="videoId"</SPAN><SPAN style="COLOR: rgb(0,0,255)">&gt;</SPAN><SPAN style="COLOR: rgb(0,0,0)"><BR><IMG alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">&lt;</SPAN><SPAN style="COLOR: rgb(128,0,0)">result&nbsp;</SPAN><SPAN style="COLOR: rgb(255,0,0)">property</SPAN><SPAN style="COLOR: rgb(0,0,255)">="videoId"</SPAN><SPAN style="COLOR: rgb(255,0,0)">&nbsp;column</SPAN><SPAN style="COLOR: rgb(0,0,255)">="videoId"</SPAN><SPAN style="COLOR: rgb(255,0,0)">&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">/&gt;</SPAN><SPAN style="COLOR: rgb(0,0,0)"><BR><IMG alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;............................<BR><IMG alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">&lt;</SPAN><SPAN style="COLOR: rgb(128,0,0)">result&nbsp;</SPAN><SPAN style="COLOR: rgb(255,0,0)">property</SPAN><SPAN style="COLOR: rgb(0,0,255)">="tagList"</SPAN><SPAN style="COLOR: rgb(255,0,0)">&nbsp;resultMap</SPAN><SPAN style="COLOR: rgb(0,0,255)">="search.tag-map"</SPAN><SPAN style="COLOR: rgb(255,0,0)">&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">/&gt;</SPAN><SPAN style="COLOR: rgb(0,0,0)"><BR><IMG alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align=top><BR><IMG alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align=top><BR><IMG alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">&lt;/</SPAN><SPAN style="COLOR: rgb(128,0,0)">resultMap</SPAN><SPAN style="COLOR: rgb(0,0,255)">&gt;</SPAN><SPAN style="COLOR: rgb(0,0,0)"><BR><IMG alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;<BR><IMG alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">&lt;</SPAN><SPAN style="COLOR: rgb(128,0,0)">resultMap&nbsp;</SPAN><SPAN style="COLOR: rgb(255,0,0)">id</SPAN><SPAN style="COLOR: rgb(0,0,255)">="tag-map"</SPAN><SPAN style="COLOR: rgb(255,0,0)">&nbsp;class</SPAN><SPAN style="COLOR: rgb(0,0,255)">="java.util.HashMap"</SPAN><SPAN style="COLOR: rgb(0,0,255)">&gt;</SPAN><SPAN style="COLOR: rgb(0,0,0)"><BR><IMG alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">&lt;</SPAN><SPAN style="COLOR: rgb(128,0,0)">result&nbsp;</SPAN><SPAN style="COLOR: rgb(255,0,0)">property</SPAN><SPAN style="COLOR: rgb(0,0,255)">="tagName"</SPAN><SPAN style="COLOR: rgb(255,0,0)">&nbsp;column</SPAN><SPAN style="COLOR: rgb(0,0,255)">="tagName"</SPAN><SPAN style="COLOR: rgb(255,0,0)">&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">/&gt;</SPAN><SPAN style="COLOR: rgb(0,0,0)"><BR><IMG alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">&lt;/</SPAN><SPAN style="COLOR: rgb(128,0,0)">resultMap</SPAN><SPAN style="COLOR: rgb(0,0,255)">&gt;</SPAN><SPAN style="COLOR: rgb(0,0,0)"><BR><IMG alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<BR><IMG alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">&lt;</SPAN><SPAN style="COLOR: rgb(128,0,0)">statement&nbsp;</SPAN><SPAN style="COLOR: rgb(255,0,0)">id</SPAN><SPAN style="COLOR: rgb(0,0,255)">="query"</SPAN><SPAN style="COLOR: rgb(255,0,0)">&nbsp;resultMap</SPAN><SPAN style="COLOR: rgb(0,0,255)">="video-map"</SPAN><SPAN style="COLOR: rgb(255,0,0)">&nbsp;parameterClass</SPAN><SPAN style="COLOR: rgb(0,0,255)">="xx.index.dataset.DataSetVO"</SPAN><SPAN style="COLOR: rgb(255,0,0)">&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">&gt;</SPAN><SPAN style="COLOR: rgb(0,0,0)"><BR><IMG alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;select&nbsp;v.videoId&nbsp;as&nbsp;videoId,&nbsp;<BR><IMG alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .............<BR><IMG alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vtg.name&nbsp;as&nbsp;tagname,&nbsp;<BR><IMG alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ............<BR><IMG alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<BR><IMG alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from&nbsp;video&nbsp;v&nbsp;<BR><IMG alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;inner&nbsp;join&nbsp;videotagrel&nbsp;vtgrel&nbsp;on&nbsp;v.videoId=vtgrel.videoId<BR><IMG alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;inner&nbsp;join&nbsp;videotag&nbsp;vtg&nbsp;on&nbsp;vtgrel.tagId=vtg.tagId&nbsp;<BR><IMG alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ...........</SPAN><SPAN style="COLOR: rgb(0,0,255)"><SPAN style="COLOR: rgb(0,0,0)"><BR><IMG alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<BR><IMG alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<BR><IMG alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">&lt;/</SPAN><SPAN style="COLOR: rgb(128,0,0)">statement</SPAN><SPAN style="COLOR: rgb(0,0,255)">&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ........<BR>&lt;/sqlMap&gt;</SPAN></SPAN></DIV></DIV><BR>我们采用多表关联的方式用一个sql取出所有数据,然后定义我们映射规则(见上面的 resultMap段),从规则中可以看出,我们将查出来的结果根据videoId进行分组,然后相同videoId的标签会归入video的tagList,最后你会得到一个 video列表，其中每个video又包含一个相关的标签列表，整个过程一句sql搞定 避免了n+1问题<BR>
<SCRIPT type=text/javascript><!--
google_ad_client = "pub-1534216445189830";
google_alternate_ad_url = "http://www.fish888.com/noad.html";
google_ad_width = 728;
google_ad_height = 90;
google_ad_format = "728x90_as";
google_ad_type = "text_image";
google_ad_channel ="";
google_color_border = "FFFFFF";
google_color_link = "0000FF";
google_color_bg = "FFFFFF";
google_color_text = "000000";
google_color_url = "008000";
//--></SCRIPT>

<SCRIPT src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type=text/javascript>
</SCRIPT>]]></description>
</item><item>
<title><![CDATA[Subversion权限详解]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=lhwork&amp;id=32320</link>
<author>lhwork</author>
<pubDate>2008/3/10 16:17:04</pubDate>
<description><![CDATA[<DIV class=postbody>
<P><FONT face=Verdana>1&nbsp;&nbsp; 背景假设 <BR>厦门央瞬公司是一家电子元器件设备供应商，其中有个ARM部门，专门负责ARM芯片的方案设计、销售，并在北京、上海各设立了一个办事处。对于工作日志，原先采用邮件方式发给经理，但是这种方式有个缺点，那就是不具备连续性，要看以前的日志必须一封一封邮件去查看，很麻烦。于是就想到利用 Subversion， 让员工在自己电脑上编辑日志，然后利用svn传送回来，既方便员工自己编写日志，又方便对日志的归档处理，而且提交日志的时候只需要执行一下 svn update 即可，比发送邮件还要简单的多。</FONT></P>
<P><FONT face=Verdana>svn服务器相关信息</FONT></P>
<P><FONT face=Verdana>服务器地址： 192.168.0.1 <BR>服务器OS： MS Windows 2000 Server Edition 中文版 <BR>代码库本地目录： D:\svn\arm <BR>arm部门文档的目录结构如下:</FONT></P>
<P><FONT face=Verdana>arm&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 部门名称<BR>├─diary&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 工作日志目录<BR>│&nbsp; ├─headquarters&nbsp;&nbsp;&nbsp; 总部工作日志目录<BR>│&nbsp; ├─beijing&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 北京办日志目录<BR>│&nbsp; └─shanghai&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 上海办日志目录<BR>├─ref&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 公司公共文件参考目录<BR>└─temp&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 临时文件目录<BR>人员情况</FONT></P>
<P><FONT face=Verdana>morson，公司总经理，其实他不必亲自看任何东西，就连部门经理们的每周总结都不一定看。但是为了表示对他的尊敬，以及满足一下他的权力欲，还是给他开放了“阅读所有文档”的权限 <BR>michael，arm事业部的部门经理，没事的时候喜欢弄点儿新技术，用svn来管理日志，就是他相处来的主意 <BR>scofield，北京办人员，老员工，为人油滑难管 <BR>lincon，上海办人员，老员工，大老实人一个 <BR>linda，总部协调员、秘书，文笔不错，长得也不错 <BR>rory，单片机技术员，技术支持 <BR>访问权限需求分析</FONT></P>
<P><FONT face=Verdana>允许总经理读取所有文件 <BR>除部门经理外，所有其他人员，均只能看到本办事处人员工作日志 <BR>不允许匿名访问 <BR>ref目录只允许经理和秘书写，对其他人只读 <BR>temp目录人人都可以写 <BR>2&nbsp;&nbsp; 建立代码库 <BR>在服务器 D:\svn 目录下，建立 arm 代码库，命令如下:</FONT></P>
<P><FONT face=Verdana>D:\svn&gt;svnadmin create arm<BR>在客户机 F:\temp 目录下，建立好上述目录结构</FONT></P>
<P><FONT face=Verdana>用命令 F:\temp&gt;svnimportarmsvn://192.168.0.1/arm 导入结构</FONT></P>
<P><FONT face=Verdana>【注意点：关于导入时候的细微差别】</FONT></P>
<P><FONT face=Verdana>3&nbsp;&nbsp; 编辑代码库基础配置文件 <BR>编辑代码库 arm\conf\svnserve.conf 文件，如下:</FONT></P>
<P><FONT face=Verdana>[general]<BR>password-db = passwd.conf<BR>anon-access = none<BR>auth-access = write<BR>authz-db = authz.conf<BR>4&nbsp;&nbsp; 管理用户帐号 <BR>新建代码库 arm\conf\passwd.conf 文件，如下:</FONT></P>
<P><FONT face=Verdana>[users]<BR>morson = ShowMeTheMoney<BR>michael = mysecretpassword<BR>scofield = hellolittilekiller<BR>lincon = asyouknows111<BR>rory = 8809117<BR>linda = IlikeWorldCup2006<BR>5&nbsp;&nbsp; 建立目录访问权限控制文件 <BR>新建代码库 arm\conf\authz.conf 文件，内容如下:</FONT></P>
<P><FONT face=Verdana>[groups]<BR>g_vip = morson<BR>g_manager = michael<BR>g_beijing = scofield<BR>g_shanghai = lincon<BR>g_headquarters = rory, linda<BR>g_docs = linda<BR>[arm:/]<BR>@g_manager = rw<BR>* = r<BR>[arm:/diary/headquarters]<BR>@g_manager = rw<BR>@g_headquarters = rw<BR>@g_vip = r<BR>* =<BR>[arm:/diary/beijing]<BR>@g_manager = rw<BR>@g_beijing = rw<BR>@g_vip = r<BR>* =<BR>[arm:/diary/shanghai]<BR>@g_manager = rw<BR>@g_shanghai = rw<BR>@g_vip = r<BR>* =<BR>[arm:/ref]<BR>@g_manager = rw<BR>@g_docs = rw<BR>* = r<BR>[arm:/temp]<BR>* = rw<BR>6&nbsp;&nbsp; 测试 <BR>在服务器上，打开一个 DOS Prompt 窗口，输入如下指令:</FONT></P>
<P><FONT face=Verdana>svn co svn://127.0.0.1/arm --no-auth-cache --username rory --password 8809117<BR>我们应该得到如下目录结构:</FONT></P>
<P><FONT face=Verdana>arm<BR>├─diary<BR>│&nbsp; └─headquarters<BR>├─ref<BR>└─temp<BR>然后修改ref目录下任意文件并提交，服务器将会报错“Access deni”</FONT></P>
<P><FONT face=Verdana>深入 <BR>本章将详细介绍前一章所涉及的两个配置文件， svnserve.conf 和 authz.conf，通过对配置逐行的描述，来阐明其中的一些细节含义。</FONT></P>
<P><FONT face=Verdana>这里首先要注意一点，任何配置文件的有效配置行，都不允许存在前置空格，否则程序会无法识别。也就是说，如果你直接从本文的纯文本格式中拷贝了相关的配置行过去，需要手动将前置的4个空格全部删除。当然了，如果你觉得一下子要删除好多行的同样数目的前置空格是一件苦差使，那么也许 UltraEdit 的“Column Mode”编辑模式，可以给你很大帮助呢。</FONT></P>
<P><FONT face=Verdana>1&nbsp;&nbsp; svnserve.conf <BR>arm\conf\svnserve.conf 文件，是 svnserve.exe 这个服务器进程的配置文件，我们逐行解释如下。</FONT></P>
<P><FONT face=Verdana>首先，我们告诉 svnserve.exe，用户名与密码放在 passwd.conf 文件下。当然，你可以改成任意的有效文件名，比如默认的就是 passwd:</FONT></P>
<P><FONT face=Verdana>password-db = passwd.conf<BR>接下来这两行的意思，是说只允许经过验证的用户，方可访问代码库。 那么哪些是“经过验证的”用户呢？噢，当然，就是前面说那些在 passwd.conf 文件里面持有用户名密码的家伙。这两行的等号后面，目前只允许 read write none 三种值，你如果想实现一些特殊的值，比如说“read-once”之类的，建议你自己动手改源代码，反正它也是自由软件:</FONT></P>
<P><FONT face=Verdana>anon-access = none<BR>auth-access = write<BR>接下来就是最关键的一句呢，它告诉 svnserve.exe，项目目录访问权限的相关配置是放在 authz.conf 文件里:</FONT></P>
<P><FONT face=Verdana>authz-db = authz.conf<BR>当然，svn 1.3.2 引入本功能的时候，系统默认使用 authz 而不是 authz.conf 作为配置文件。不过由于鄙人是处女座的，有着强烈的完美主义情结，看着 svnserve.conf 有后缀而 passwd 和 authz 没有就是不爽，硬是要改了。</FONT></P>
<P><FONT face=Verdana>2&nbsp;&nbsp; authz.conf 之用户分组 <BR>arm\conf\authz.conf 文件的配置段，可以分为两类，``[group]`` 是一类，里面放置着所有用户分组信息。其余以 [arm:/] 开头的是另外一类，每一段就是对应着项目的一个目录，其目录相关权限，就在此段内设置。</FONT></P>
<P><FONT face=Verdana>首先，我们将人员分组管理，以便以后由于人员变动而需要重新设置权限时候，尽量少改动东西。我们一共设置了5个用户分组，分组名称统一采用 g_ 前缀，以方便识别。当然了，分组成员之间采用逗号隔开:</FONT></P>
<P><FONT face=Verdana>[groups]<BR># 任何想要查看所有文档的非本部门人士<BR>g_vip = morson<BR># 经理<BR>g_manager = michael<BR># 北京办人员<BR>g_beijing = scofield<BR># 上海办人员<BR>g_shanghai = lincon<BR># 总部一般员工<BR>g_headquarters = rory, linda<BR># 小秘，撰写文档<BR>g_docs = linda<BR>注意到没有， linda 这个帐号同时存在“总部”和“文档员”两个分组里面，这可不是我老眼昏花写错了，是因为 svnserve.exe 允许我这样设置。它意味着，这个家伙所拥有的权限，将会比他的同事 rory 要多一些，这样的确很方便。具体多了哪些呢？请往下看！</FONT></P>
<P><FONT face=Verdana>3&nbsp;&nbsp; authz.conf 之项目根目录 <BR>接着，我们对项目根目录做了限制，该目录只允许arm事业部的经理才能修改，其他人都只能眼巴巴的看着:</FONT></P>
<P><FONT face=Verdana>[arm:/]<BR>@g_manager = rw<BR>* = r<BR>[arm:/] 表示这个目录结构的相对根节点，或者说是 arm 项目的根目录 <BR>这里的 @ 表示接下来的是一个组名，不是用户名。你当然也可以将 @g_manager=rw 这一行替换成 michael=rw ，而表达的意义完全一样。 <BR>* 表示“除了上面提到的那些人之外的其余所有人”，也就是“除了部门经理外的其他所有人”，当然也包括总经理那个怪老头 <BR>* = r 则表示“那些人只能读，不能写” <BR>4&nbsp;&nbsp; authz.conf 之项目子目录 <BR>然后，我们要给总部人员开放日志目录的读写权限:</FONT></P>
<P><FONT face=Verdana>[arm:/diary/headquarters]<BR>@g_manager = rw<BR>@g_headquarters = rw<BR>@g_vip = r<BR>* =<BR>我敢打赌，设计svn的家伙们，大部分都是在 unix/linux 平台下工作，所以他们总喜欢使用 / 来标识子目录，而完全忽视在 MS Windows 下是用 \ 来做同样的事情。所以这儿，为了表示 arm\diary\headquarters 这个目录，我们必须使用 [arm:/diary/headquarters] 这样的格式。 <BR>这里最后一行的 *= 表示，除了经理、总部人员、特别人士之外，任何人都被禁止访问本目录。这一行是否可以省略呢？ <BR>之所以这儿需要将 @g_vip=r 一句加上，就是因为存在上述这个解释。如果说你没有明确地给总经理授予读的权力，则他会和其他人一样，被 * 给排除在外。 <BR>如果众位看官中间，有谁玩过防火墙配置的话，可能会感觉上述的配置很熟悉。不过这里有一点与防火墙配置不一样，那就是各个配置行之间，没有 先后顺序 一说。也就是说，如果我将本段配置的 *= 这一行挪到最前面，完全不影响整个配置的最终效果。 <BR>请注意这儿，我们并没有给 arm\diary 目录设置权限，就直接跳到其子目录下进行设置了。我当然是故意这样的，因为我想在这儿引入“继承”的概念。 <BR>权限具备继承性 任何子目录，均可继承其父目录的所有权限，除非它自己被明确设置了其他的权限。也就是说，在 arm 目录设置权限后， arm\diary 目录没有进行设置，就意味着它的权限与 arm 目录一样，都是只有经理才有权读写，其他人只能干瞪眼。 <BR>【 * = 是否可以省略】【用例子引入覆盖】【单用户权限的继承问题】【父目录权限集成与全面覆盖问题】 <BR>现在来看看</FONT></P>
<P><FONT face=Verdana>好了，我们现在掌握了“继承”的威力，它让我们节省了不少敲键盘的时间。可是现在又有一个问题了，</FONT></P>
<P><FONT face=Verdana>属性具备覆盖性质子目录若设置了属性，则完全覆盖父目录。</FONT></P>
<P><FONT face=Verdana>5&nbsp;&nbsp; authz.conf 的其他注意点 <BR>父目录的 r 权限，对子目录 w 权限的影响 <BR>把这个问题专门提出来，是因为在1.3.1及其以前的版本里面，有个bug，即为了子目录的写权限，项目首目录必须具备读权限。因此现在使用了1.3.2版本，就方便了那些想在一个代码库存放多个相互独立的项目的管理员，来分配权限了。比如说央舜公司建立一个大的代码库用于存放所有员工日志，叫做 diary，而arm事业部只是其中一个部门，则可以这样做:</FONT></P>
<P><FONT face=Verdana>[diary:/]<BR>@g_chief_manager = rw<BR>[diary:/arm]<BR>@g_arm_manager = rw<BR>@g_arm = r<BR>这样，对于所有arm事业部的人员来说，就可以将 svn://192.168.0.1/diary/arm 这个URL当作根目录来进行日常操作，而完全不管它其实只是一个子目录，并且当有少数好奇心比较强的人想试着 checkout 一下 svn://192.168.0.1/diary 的时候，马上就会得到一个警告“Access deni”，哇，太酷了。</FONT></P>
<P><FONT face=Verdana>默认权限 <BR>如果说我对某个目录不设置任何权限，会怎样？马上动手做个试验，将:</FONT></P>
<P><FONT face=Verdana>[diary:/]<BR>@g_chief_manager = rw<BR>改成:</FONT></P>
<P><FONT face=Verdana>[diary:/]<BR># @g_chief_manager = rw<BR>这样就相当于什么都没有设置。在我的 svn 1.3.2 版本上，此时是禁止任何访问。也就是说，如果你想要让某人访问某目录，你一定要显式指明这一点。这个策略，看起来与防火墙的策略是一致的。</FONT></P>
<P><FONT face=Verdana>只读权限带来的一个小副作用 <BR>若设置了:</FONT></P>
<P><FONT face=Verdana>[arm:/diary]<BR>* = r<BR>则svnserve认为，任何人，都不允许改动diary目录，包括删除和改名，和新增。</FONT></P>
<P><FONT face=Verdana>也就是说，如果你在项目初期创建目录时候，一不小心写错目录名称，比如因拼写错误写成 dairy，以后除非你改动 authz.conf 里面的这行设置，否则无法利用 svn mv 命令将错误的目录更正。</FONT></P>
<P><FONT face=Verdana>改进 <BR>1&nbsp;&nbsp; 对中文目录的支持 <BR>上午上班的时候，Morson 来到 Michael 的桌子前面，说道：“你是否可以将我们的北京办、上海办目录，改成用中文的，看着那些拼音我觉得很难受？” Michael 心想，还好这两天刚了解了一些与 unicode 编码相关的知识，于是微笑地回答：“当然可以，你明天下午就可以看到中文目录名称了。”</FONT></P>
<P><FONT face=Verdana>使用 svn mv 指令，将原来的一些目录改名并 commit 入代码库，改名后的目录结构如下:</FONT></P>
<P><FONT face=Verdana>arm<BR>├─工作日志<BR>│&nbsp; ├─总部人员<BR>│&nbsp; ├─北京办<BR>│&nbsp; └─上海办<BR>├─公司公共文件参考目录<BR>└─临时文件存放处<BR>修改代码库的 authz.conf 文件，将相应目录逐一改名</FONT></P>
<P><FONT face=Verdana>使用 UltraEdit 将 authz.conf 文件转换成不带 BOM 的 UTF-8 格式</FONT></P>
<P><FONT face=Verdana>将配置文件转换成 UTF-8 格式之后，Subversion 就能够正确识别中文字符了。但是这里需要注意一点，即必须保证 UTF-8 文件不包含 BOM 。BOM 是 Byte Order Mark 的缩写，指 UNICODE 文件头部用于指明高低字节排列顺序的几个字符，通常是 FFFE ，而将之用 UTF-8 编码之后，就是 EFBBBF 。由于 UTF-8 文件本身不存在字节序问题，所以对 UTF-16 等编码方式有重大意义的 BOM，对于 UTF-8 来说，只有一个作用——表明这个文件是 UTF-8 格式。由于 BOM 会给文本处理带来很多难题，所以现在很多软件都要求使用不带 BOM 的 UTF-8 文件，特别是一些处理文本的软件，如 PHP、 UNIX 脚本文件等，svn 也是如此。</FONT></P>
<P><FONT face=Verdana>目前常用的一些文本编辑工具中，MS Windows 自带的“记事本”里面，“另存为”菜单保存出来的 UTF-8 格式文件，会自动带上 BOM 。新版本 UltraEdit 提供了选项，允许用户选择是否需要 BOM，而老版本的不会添加 BOM。请各位查看一下自己常用的编辑器的说明文件，看看它是否支持这个功能。</FONT></P>
<P><FONT face=Verdana>利用 UltraEdit ，我们可以将 BOM 去掉。方法是，首先利用“UTF-8 TO ASCII”菜单将文件转换成本地编码，通常是GB2312码，然后再使用“ASCII TO UTF-8(UNICODE Editing)”来转换到 UTF-8 即可。</FONT></P></DIV>]]></description>
</item>
</channel>
</rss>