﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-关注基于J2EE的系统设计与实现,总结项目经验与思考。-随笔分类-J2EE</title><link>http://www.blogjava.net/NeonWay/category/7516.html</link><description>spring、hibernate、webwork框架实践与探索。</description><language>zh-cn</language><lastBuildDate>Tue, 27 Feb 2007 14:14:09 GMT</lastBuildDate><pubDate>Tue, 27 Feb 2007 14:14:09 GMT</pubDate><ttl>60</ttl><item><title>解惑 spring 嵌套事务</title><link>http://www.blogjava.net/NeonWay/archive/2006/12/29/90727.html</link><dc:creator>王彦锋的技术实践</dc:creator><author>王彦锋的技术实践</author><pubDate>Fri, 29 Dec 2006 06:06:00 GMT</pubDate><guid>http://www.blogjava.net/NeonWay/archive/2006/12/29/90727.html</guid><wfw:comment>http://www.blogjava.net/NeonWay/comments/90727.html</wfw:comment><comments>http://www.blogjava.net/NeonWay/archive/2006/12/29/90727.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/NeonWay/comments/commentRss/90727.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/NeonWay/services/trackbacks/90727.html</trackback:ping><description><![CDATA[
		<p>
				<a href="http://www.javaeye.com/topic/35907">http://www.javaeye.com/topic/35907</a>
				<br />
				<br />解惑 spring 嵌套事务 </p>
		<p>/** <br />* @author 王政 <br />* @date 2006-11-24 <br />* @note 转载请注明出处 <br />*/ <br /><br />在所有使用 spring 的应用中, 声明式事务管理可能是使用率最高的功能了, 但是, 从我观察到的情况看, <br />绝大多数人并不能深刻理解事务声明中不同事务传播属性配置的的含义, 让我们来看一下 TransactionDefinition 接口中的定义</p>
		<p>
		</p>
		<div class="code_title">代码</div>
		<div class="code_div">
				<div class="dp-highlighter">
						<div class="bar">
						</div>
						<ol class="dp-xml">
								<li class="alt">
										<span>
												<span>/**   </span>
										</span>
								</li>
								<li class="">
										<span>     * Support a current transaction, create a new one if none exists.   </span>
								</li>
								<li class="alt">
										<span>     * Analogous to EJB transaction attribute of the same name.   </span>
								</li>
								<li class="">
										<span>     * </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">p</span>
										<span class="tag">&gt;</span>
										<span>This is typically the default setting of a transaction definition.   </span>
								</li>
								<li class="alt">
										<span>     */   </span>
								</li>
								<li class="">
										<span>    int </span>
										<span class="attribute">PROPAGATION_REQUIRED</span>
										<span> = </span>
										<span class="attribute-value">0</span>
										<span>;   </span>
								</li>
								<li class="alt">
										<span>  </span>
								</li>
								<li class="">
										<span>    /**   </span>
								</li>
								<li class="alt">
										<span>     * Support a current transaction, execute non-transactionally if none exists.   </span>
								</li>
								<li class="">
										<span>     * Analogous to EJB transaction attribute of the same name.   </span>
								</li>
								<li class="alt">
										<span>     * </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">p</span>
										<span class="tag">&gt;</span>
										<span>Note: For transaction managers with transaction synchronization,   </span>
								</li>
								<li class="">
										<span>     * PROPAGATION_SUPPORTS is slightly different from no transaction at all,   </span>
								</li>
								<li class="alt">
										<span>     * as it defines a transaction scopp that synchronization will apply for.   </span>
								</li>
								<li class="">
										<span>     * As a consequence, the same resources (JDBC Connection, Hibernate Session, etc)   </span>
								</li>
								<li class="alt">
										<span>     * will be shared for the entire specified scope. Note that this depends on   </span>
								</li>
								<li class="">
										<span>     * the actual synchronization configuration of the transaction manager.   </span>
								</li>
								<li class="alt">
										<span>     * @see org.springframework.transaction.support.AbstractPlatformTransactionManager#setTransactionSynchronization   </span>
								</li>
								<li class="">
										<span>     */   </span>
								</li>
								<li class="alt">
										<span>    int </span>
										<span class="attribute">PROPAGATION_SUPPORTS</span>
										<span> = </span>
										<span class="attribute-value">1</span>
										<span>;   </span>
								</li>
								<li class="">
										<span>  </span>
								</li>
								<li class="alt">
										<span>    /**   </span>
								</li>
								<li class="">
										<span>     * Support a current transaction, throw an exception if none exists.   </span>
								</li>
								<li class="alt">
										<span>     * Analogous to EJB transaction attribute of the same name.   </span>
								</li>
								<li class="">
										<span>     */   </span>
								</li>
								<li class="alt">
										<span>    int </span>
										<span class="attribute">PROPAGATION_MANDATORY</span>
										<span> = </span>
										<span class="attribute-value">2</span>
										<span>;   </span>
								</li>
								<li class="">
										<span>  </span>
								</li>
								<li class="alt">
										<span>    /**   </span>
								</li>
								<li class="">
										<span>     * Create a new transaction, suspend the current transaction if one exists.   </span>
								</li>
								<li class="alt">
										<span>     * Analogous to EJB transaction attribute of the same name.   </span>
								</li>
								<li class="">
										<span>     * </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">p</span>
										<span class="tag">&gt;</span>
										<span>Note: Actual transaction suspension will not work on out-of-the-box   </span>
								</li>
								<li class="alt">
										<span>     * on all transaction managers. This in particular applies to JtaTransactionManager,   </span>
								</li>
								<li class="">
										<span>     * which requires the </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">code</span>
										<span class="tag">&gt;</span>
										<span>javax.transaction.TransactionManager</span>
										<span class="tag">&lt;/</span>
										<span class="tag-name">code</span>
										<span class="tag">&gt;</span>
										<span> to be   </span>
								</li>
								<li class="alt">
										<span>     * made available it to it (which is server-specific in standard J2EE).   </span>
								</li>
								<li class="">
										<span>     * @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager   </span>
								</li>
								<li class="alt">
										<span>     */   </span>
								</li>
								<li class="">
										<span>    int </span>
										<span class="attribute">PROPAGATION_REQUIRES_NEW</span>
										<span> = </span>
										<span class="attribute-value">3</span>
										<span>;   </span>
								</li>
								<li class="alt">
										<span>  </span>
								</li>
								<li class="">
										<span>    /**   </span>
								</li>
								<li class="alt">
										<span>     * Execute non-transactionally, suspend the current transaction if one exists.   </span>
								</li>
								<li class="">
										<span>     * Analogous to EJB transaction attribute of the same name.   </span>
								</li>
								<li class="alt">
										<span>     * </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">p</span>
										<span class="tag">&gt;</span>
										<span>Note: Actual transaction suspension will not work on out-of-the-box   </span>
								</li>
								<li class="">
										<span>     * on all transaction managers. This in particular applies to JtaTransactionManager,   </span>
								</li>
								<li class="alt">
										<span>     * which requires the </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">code</span>
										<span class="tag">&gt;</span>
										<span>javax.transaction.TransactionManager</span>
										<span class="tag">&lt;/</span>
										<span class="tag-name">code</span>
										<span class="tag">&gt;</span>
										<span> to be   </span>
								</li>
								<li class="">
										<span>     * made available it to it (which is server-specific in standard J2EE).   </span>
								</li>
								<li class="alt">
										<span>     * @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager   </span>
								</li>
								<li class="">
										<span>     */   </span>
								</li>
								<li class="alt">
										<span>    int </span>
										<span class="attribute">PROPAGATION_NOT_SUPPORTED</span>
										<span> = </span>
										<span class="attribute-value">4</span>
										<span>;   </span>
								</li>
								<li class="">
										<span>  </span>
								</li>
								<li class="alt">
										<span>    /**   </span>
								</li>
								<li class="">
										<span>     * Execute non-transactionally, throw an exception if a transaction exists.   </span>
								</li>
								<li class="alt">
										<span>     * Analogous to EJB transaction attribute of the same name.   </span>
								</li>
								<li class="">
										<span>     */   </span>
								</li>
								<li class="alt">
										<span>    int </span>
										<span class="attribute">PROPAGATION_NEVER</span>
										<span> = </span>
										<span class="attribute-value">5</span>
										<span>;   </span>
								</li>
								<li class="">
										<span>  </span>
								</li>
								<li class="alt">
										<span>    /**   </span>
								</li>
								<li class="">
										<span>     * Execute within a nested transaction if a current transaction exists,   </span>
								</li>
								<li class="alt">
										<span>     * behave like PROPAGATION_REQUIRED else. There is no analogous feature in EJB.   </span>
								</li>
								<li class="">
										<span>     * </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">p</span>
										<span class="tag">&gt;</span>
										<span>Note: Actual creation of a nested transaction will only work on specific   </span>
								</li>
								<li class="alt">
										<span>     * transaction managers. Out of the box, this only applies to the JDBC   </span>
								</li>
								<li class="">
										<span>     * DataSourceTransactionManager when working on a JDBC 3.0 driver.   </span>
								</li>
								<li class="alt">
										<span>     * Some JTA providers might support nested transactions as well.   </span>
								</li>
								<li class="">
										<span>     * @see org.springframework.jdbc.datasource.DataSourceTransactionManager   </span>
								</li>
								<li class="alt">
										<span>     */   </span>
								</li>
								<li class="">
										<span>    int </span>
										<span class="attribute">PROPAGATION_NESTED</span>
										<span> = </span>
										<span class="attribute-value">6</span>
										<span>;   </span>
								</li>
						</ol>
				</div>
		</div>
		<script><![CDATA[ender_code();]]&gt;</script>
		<p>
		</p>
		<p>我们可以看到, 在 spring 中一共定义了六种事务传播属性, 如果你觉得看起来不够直观, 那么我来转贴一个满大街都有的翻译</p>
		<p>
		</p>
		<div class="quote_title">引用</div>
		<div class="quote_div">
				<br />PROPAGATION_REQUIRED -- 支持当前事务，如果当前没有事务，就新建一个事务。这是最常见的选择。 <br />PROPAGATION_SUPPORTS -- 支持当前事务，如果当前没有事务，就以非事务方式执行。 <br />PROPAGATION_MANDATORY -- 支持当前事务，如果当前没有事务，就抛出异常。 <br />PROPAGATION_REQUIRES_NEW -- 新建事务，如果当前存在事务，把当前事务挂起。 <br />PROPAGATION_NOT_SUPPORTED -- 以非事务方式执行操作，如果当前存在事务，就把当前事务挂起。 <br />PROPAGATION_NEVER -- 以非事务方式执行，如果当前存在事务，则抛出异常。 <br />PROPAGATION_NESTED -- 如果当前存在事务，则在嵌套事务内执行。如果当前没有事务，则进行与PROPAGATION_REQUIRED类似的操作。 <br />前六个策略类似于EJB CMT，第七个（PROPAGATION_NESTED）是Spring所提供的一个特殊变量。 <br />它要求事务管理器或者使用JDBC 3.0 Savepoint API提供嵌套事务行为（如Spring的DataSourceTransactionManager） <br /></div>
		<p>
		</p>
		<p>在我所见过的误解中, 最常见的是下面这种:</p>
		<p>
		</p>
		<div class="quote_title">引用</div>
		<div class="quote_div">
				<br />假如有两个业务接口 ServiceA 和 ServiceB, 其中 ServiceA 中有一个方法实现如下 
<p></p><p>/** <br />* 事务属性配置为 PROPAGATION_REQUIRED <br />*/ <br />void methodA() { <br />// 调用 ServiceB 的方法 <br />ServiceB.methodB(); <br />}</p><p>那么如果 ServiceB 的 methodB 如果配置了事务, 就必须配置为 PROPAGATION_NESTED <br /></p></div>
		<p>
		</p>
		<p>这种想法可能害了不少人, 认为 Service 之间应该避免互相调用, 其实根本不用担心这点，PROPAGATION_REQUIRED 已经说得很明白, <br />如果当前线程中已经存在事务, 方法调用会加入此事务, 果当前没有事务，就新建一个事务, 所以 ServiceB#methodB() 的事务只要遵循最普通的规则配置为 PROPAGATION_REQUIRED 即可, 如果 ServiceB#methodB (我们称之为内部事务, 为下文打下基础) 抛了异常, 那么 ServiceA#methodA(我们称之为外部事务) 如果没有特殊配置此异常时事务提交 (即 +MyCheckedException的用法), 那么整个事务是一定要 rollback 的, 什么 Service 只能调 Dao 之类的言论纯属无稽之谈, spring 只负责配置了事务属性方法的拦截, 它怎么知道你这个方法是在 Service 还是 Dao 里 ?</p>
		<p>说了这么半天, 那到底什么是真正的事务嵌套呢, 解释之前我们来看一下 Juergen Hoeller 的原话</p>
		<p>
		</p>
		<div class="quote_title">Juergen Hoeller 写道</div>
		<div class="quote_div">
				<br />PROPAGATION_REQUIRES_NEW starts a new, independent "inner" transaction for the given scope. This transaction will be committed or rolled back completely independent from the outer transaction, having its own isolation scope, its own set of locks, etc. The outer transaction will get suspended at the beginning of the inner one, and resumed once the inner one has completed. 
<p></p><p>Such independent inner transactions are for example used for id generation through manual sequences, where the access to the sequence table should happen in its own transactions, to keep the lock there as short as possible. The goal there is to avoid tying the sequence locks to the (potentially much longer running) outer transaction, with the sequence lock not getting released before completion of the outer transaction.</p><p>PROPAGATION_NESTED on the other hand starts a "nested" transaction, which is a true subtransaction of the existing one. What will happen is that a savepoint will be taken at the start of the nested transaction. íf the nested transaction fails, we will roll back to that savepoint. The nested transaction is part of of the outer transaction, so it will only be committed at the end of of the outer transaction.</p><p>Nested transactions essentially allow to try some execution subpaths as subtransactions: rolling back to the state at the beginning of the failed subpath, continuing with another subpath or with the main execution path there - all within one isolated transaction, and not losing any previous work done within the outer transaction.</p><p>For example, consider parsing a very large input file consisting of account transfer blocks: The entire file should essentially be parsed within one transaction, with one single commit at the end. But if a block fails, its transfers need to be rolled back, writing a failure marker somewhere. You could either start over the entire transaction every time a block fails, remembering which blocks to skip - or you mark each block as a nested transaction, only rolling back that specific set of operations, keeping the previous work of the outer transaction. The latter is of course much more efficient, in particular when a block at the end of the file fails. <br /></p></div>
		<p>
		</p>
		<p>
		</p>
		<div class="quote_title">Juergen Hoeller 写道</div>
		<div class="quote_div">
				<br />Rolling back the entire transaction is the choice of the demarcation code/config that started the outer transaction. 
<p></p><p>So if an inner transaction throws an exception and is supposed to be rolled back (according to the rollback rules), the transaction will get rolled back to the savepoint taken at the start of the inner transaction. The immediate calling code can then decide to catch the exception and proceed down some other path within the outer transaction.</p><p>If the code that called the inner transaction lets the exception propagate up the call chain, the exception will eventually reach the demarcation code of the outer transaction. At that point, the rollback rules of the outer transaction decide whether to trigger a rollback. That would be a rollback of the entire outer transaction then.</p><p>So essentially, it depends on your exception handling. If you catch the exception thrown by the inner transaction, you can proceed down some other path within the outer transaction. If you let the exception propagate up the call chain, it's eventually gonna cause a rollback of the entire outer transaction. <br /></p></div>
		<p>
		</p>
		<p>也就是说, 最容易弄混淆的其实是 PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED, 那么这两种方式又有何区别呢? 我简单的翻译一下 Juergen Hoeller 的话 : <br /><br /><span style="COLOR: red">PROPAGATION_REQUIRES_NEW 启动一个新的, 不依赖于环境的 "内部" 事务. 这个事务将被完全 commited 或 rolled back 而不依赖于外部事务, 它拥有自己的隔离范围, 自己的锁, 等等. 当内部事务开始执行时, 外部事务将被挂起, 内务事务结束时, 外部事务将继续执行.</span><br /></p>
		<p>
				<span style="COLOR: red">另一方面, PROPAGATION_NESTED 开始一个 "嵌套的" 事务, 它是已经存在事务的一个真正的子事务. 潜套事务开始执行时, 它将取得一个 savepoint. 如果这个嵌套事务失败, 我们将回滚到此 savepoint. 潜套事务是外部事务的一部分, 只有外部事务结束后它才会被提交.</span>
		</p>
		<p>
				<span style="COLOR: red">由此可见, PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED 的最大区别在于, PROPAGATION_REQUIRES_NEW 完全是一个新的事务, 而 PROPAGATION_NESTED 则是外部事务的子事务, 如果外部事务 commit, 潜套事务也会被 commit, 这个规则同样适用于 roll back.</span>
				<br />
				<br />
				<br />那么外部事务如何利用嵌套事务的 savepoint 特性呢, 我们用代码来说话 <br /><br /></p>
		<div class="code_title">代码</div>
		<div class="code_div">
				<div class="dp-highlighter">
						<div class="bar">
						</div>
						<ol class="dp-j">
								<li class="alt">
										<span>
												<span>ServiceA {   </span>
										</span>
								</li>
								<li class="">
										<span>       </span>
								</li>
								<li class="alt">
										<span>    </span>
										<span class="comment">/** </span> </li>
								<li class="">
										<span>
												<span class="comment">     * 事务属性配置为 PROPAGATION_REQUIRED </span> </span>
								</li>
								<li class="alt">
										<span>
												<span class="comment">     */</span>
												<span>  </span>
										</span>
								</li>
								<li class="">
										<span>    </span>
										<span class="keyword">void</span>
										<span> methodA() {   </span>
								</li>
								<li class="alt">
										<span>        ServiceB.methodB();   </span>
								</li>
								<li class="">
										<span>    }   </span>
								</li>
								<li class="alt">
										<span>  </span>
								</li>
								<li class="">
										<span>}   </span>
								</li>
								<li class="alt">
										<span>  </span>
								</li>
								<li class="">
										<span>ServiceB {   </span>
								</li>
								<li class="alt">
										<span>       </span>
								</li>
								<li class="">
										<span>    </span>
										<span class="comment">/** </span> </li>
								<li class="alt">
										<span>
												<span class="comment">     * 事务属性配置为 PROPAGATION_REQUIRES_NEW </span> </span>
								</li>
								<li class="">
										<span>
												<span class="comment">     */</span>
												<span>    </span>
										</span>
								</li>
								<li class="alt">
										<span>    </span>
										<span class="keyword">void</span>
										<span> methodB() {   </span>
								</li>
								<li class="">
										<span>    }   </span>
								</li>
								<li class="alt">
										<span>       </span>
								</li>
								<li class="">
										<span>}      </span>
								</li>
						</ol>
				</div>
		</div>
		<script><![CDATA[ender_code();]]&gt;</script>
		<p>
		</p>
		<p>这种情况下, 因为 ServiceB#methodB 的事务属性为 PROPAGATION_REQUIRES_NEW, 所以两者不会发生任何关系, ServiceA#methodA 和 ServiceB#methodB 不会因为对方的执行情况而影响事务的结果, 因为它们根本就是两个事务, 在 ServiceB#methodB 执行时 ServiceA#methodA 的事务已经挂起了 (关于事务挂起的内容已经超出了本文的讨论范围, 有时间我会再写一些挂起的文章) .</p>
		<p>那么 PROPAGATION_NESTED 又是怎么回事呢? 继续看代码</p>
		<p>
		</p>
		<div class="code_title">代码</div>
		<div class="code_div">
				<div class="dp-highlighter">
						<div class="bar">
						</div>
						<ol class="dp-j">
								<li class="alt">
										<span>
												<span>ServiceA {   </span>
										</span>
								</li>
								<li class="">
										<span>       </span>
								</li>
								<li class="alt">
										<span>    </span>
										<span class="comment">/** </span> </li>
								<li class="">
										<span>
												<span class="comment">     * 事务属性配置为 PROPAGATION_REQUIRED </span> </span>
								</li>
								<li class="alt">
										<span>
												<span class="comment">     */</span>
												<span>  </span>
										</span>
								</li>
								<li class="">
										<span>    </span>
										<span class="keyword">void</span>
										<span> methodA() {   </span>
								</li>
								<li class="alt">
										<span>        ServiceB.methodB();   </span>
								</li>
								<li class="">
										<span>    }   </span>
								</li>
								<li class="alt">
										<span>  </span>
								</li>
								<li class="">
										<span>}   </span>
								</li>
								<li class="alt">
										<span>  </span>
								</li>
								<li class="">
										<span>ServiceB {   </span>
								</li>
								<li class="alt">
										<span>       </span>
								</li>
								<li class="">
										<span>    </span>
										<span class="comment">/** </span> </li>
								<li class="alt">
										<span>
												<span class="comment">     * 事务属性配置为 PROPAGATION_NESTED </span> </span>
								</li>
								<li class="">
										<span>
												<span class="comment">     */</span>
												<span>    </span>
										</span>
								</li>
								<li class="alt">
										<span>    </span>
										<span class="keyword">void</span>
										<span> methodB() {   </span>
								</li>
								<li class="">
										<span>    }   </span>
								</li>
								<li class="alt">
										<span>       </span>
								</li>
								<li class="">
										<span>}      </span>
								</li>
						</ol>
				</div>
		</div>
		<script><![CDATA[ender_code();]]&gt;</script>
		<p>
		</p>
		<p>现在的情况就变得比较复杂了, ServiceB#methodB 的事务属性被配置为 PROPAGATION_NESTED, 此时两者之间又将如何协作呢? 从 Juergen Hoeller 的原话中我们可以找到答案, ServiceB#methodB 如果 rollback, 那么内部事务(即 ServiceB#methodB) 将回滚到它执行前的 SavePoint(注意, 这是本文中第一次提到它, 潜套事务中最核心的概念), 而外部事务(即 ServiceA#methodA) 可以有以下两种处理方式:</p>
		<p>1. 改写 ServiceA 如下 <br /></p>
		<div class="code_title">代码</div>
		<div class="code_div">
				<div class="dp-highlighter">
						<div class="bar">
						</div>
						<ol class="dp-j">
								<li class="alt">
										<span>
												<span>ServiceA {   </span>
										</span>
								</li>
								<li class="">
										<span>       </span>
								</li>
								<li class="alt">
										<span>    </span>
										<span class="comment">/** </span> </li>
								<li class="">
										<span>
												<span class="comment">     * 事务属性配置为 PROPAGATION_REQUIRED </span> </span>
								</li>
								<li class="alt">
										<span>
												<span class="comment">     */</span>
												<span>  </span>
										</span>
								</li>
								<li class="">
										<span>    </span>
										<span class="keyword">void</span>
										<span> methodA() {   </span>
								</li>
								<li class="alt">
										<span>        </span>
										<span class="keyword">try</span>
										<span> {   </span>
								</li>
								<li class="">
										<span>            ServiceB.methodB();   </span>
								</li>
								<li class="alt">
										<span>        } </span>
										<span class="keyword">catch</span>
										<span> (SomeException) {   </span>
								</li>
								<li class="">
										<span>            </span>
										<span class="comment">// 执行其他业务, 如 ServiceC.methodC(); </span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>        }   </span>
								</li>
								<li class="">
										<span>    }   </span>
								</li>
								<li class="alt">
										<span>  </span>
								</li>
								<li class="">
										<span>}   </span>
								</li>
								<li class="alt">
										<span>  </span>
								</li>
						</ol>
				</div>
		</div>
		<script><![CDATA[ender_code();]]&gt;</script>
		<p>
		</p>
		<p>这种方式也是潜套事务最有价值的地方, 它起到了分支执行的效果, 如果 ServiceB.methodB 失败, 那么执行 ServiceC.methodC(), 而 ServiceB.methodB 已经回滚到它执行之前的 SavePoint, 所以不会产生脏数据(相当于此方法从未执行过), 这种特性可以用在某些特殊的业务中, 而 PROPAGATION_REQUIRED 和 PROPAGATION_REQUIRES_NEW 都没有办法做到这一点. (题外话 : 看到这种代码, 似乎似曾相识, 想起了 prototype.js 中的 Try 函数 )</p>
		<p>2. 代码不做任何修改, 那么如果内部事务(即 ServiceB#methodB) rollback, 那么首先 ServiceB.methodB 回滚到它执行之前的 SavePoint(在任何情况下都会如此), <br />外部事务(即 ServiceA#methodA) 将根据具体的配置决定自己是 commit 还是 rollback (+MyCheckedException). <br /><br /><br />上面大致讲述了潜套事务的使用场景, 下面我们来看如何在 spring 中使用 PROPAGATION_NESTED, 首先来看 AbstractPlatformTransactionManager</p>
		<p>
		</p>
		<div class="code_title">代码</div>
		<div class="code_div">
				<div class="dp-highlighter">
						<div class="bar">
						</div>
						<ol class="dp-j">
								<li class="alt">
										<span>
												<span class="comment">/** </span> </span>
								</li>
								<li class="">
										<span>
												<span class="comment"> * Create a TransactionStatus for an existing transaction. </span> </span>
								</li>
								<li class="alt">
										<span>
												<span class="comment"> */</span>
												<span>  </span>
										</span>
								</li>
								<li class="">
										<span>
										</span>
										<span class="keyword">private</span>
										<span> TransactionStatus handleExistingTransaction(   </span>
								</li>
								<li class="alt">
										<span>        TransactionDefinition definition, Object transaction, </span>
										<span class="keyword">boolean</span>
										<span> debugEnabled)   </span>
								</li>
								<li class="">
										<span>        </span>
										<span class="keyword">throws</span>
										<span> TransactionException {   </span>
								</li>
								<li class="alt">
										<span>  </span>
								</li>
								<li class="">
										<span>   ... 省略   </span>
								</li>
								<li class="alt">
										<span>  </span>
								</li>
								<li class="">
										<span>    </span>
										<span class="keyword">if</span>
										<span> (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {   </span>
								</li>
								<li class="alt">
										<span>        </span>
										<span class="keyword">if</span>
										<span> (!isNestedTransactionAllowed()) {   </span>
								</li>
								<li class="">
										<span>            </span>
										<span class="keyword">throw</span>
										<span> </span>
										<span class="keyword">new</span>
										<span> NestedTransactionNotSupportedException(   </span>
								</li>
								<li class="alt">
										<span>                    </span>
										<span class="string">"Transaction manager does not allow nested transactions by default - "</span>
										<span> +   </span>
								</li>
								<li class="">
										<span>                    </span>
										<span class="string">"specify 'nestedTransactionAllowed' property with value 'true'"</span>
										<span>);   </span>
								</li>
								<li class="alt">
										<span>        }   </span>
								</li>
								<li class="">
										<span>        </span>
										<span class="keyword">if</span>
										<span> (debugEnabled) {   </span>
								</li>
								<li class="alt">
										<span>            logger.debug(</span>
										<span class="string">"Creating nested transaction with name ["</span>
										<span> + definition.getName() + </span>
										<span class="string">"]"</span>
										<span>);   </span>
								</li>
								<li class="">
										<span>        }   </span>
								</li>
								<li class="alt">
										<span>        </span>
										<span class="keyword">if</span>
										<span> (useSavepointForNestedTransaction()) {   </span>
								</li>
								<li class="">
										<span>            </span>
										<span class="comment">// Create savepoint within existing Spring-managed transaction, </span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>            </span>
										<span class="comment">// through the SavepointManager API implemented by TransactionStatus. </span>
										<span>  </span>
								</li>
								<li class="">
										<span>            </span>
										<span class="comment">// Usually uses JDBC 3.0 savepoints. Never activates Spring synchronization. </span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>            DefaultTransactionStatus status =   </span>
								</li>
								<li class="">
										<span>                    newTransactionStatus(definition, transaction, </span>
										<span class="keyword">false</span>
										<span>, </span>
										<span class="keyword">false</span>
										<span>, debugEnabled, </span>
										<span class="keyword">null</span>
										<span>);   </span>
								</li>
								<li class="alt">
										<span>            status.createAndHoldSavepoint();   </span>
								</li>
								<li class="">
										<span>            </span>
										<span class="keyword">return</span>
										<span> status;   </span>
								</li>
								<li class="alt">
										<span>        }   </span>
								</li>
								<li class="">
										<span>        </span>
										<span class="keyword">else</span>
										<span> {   </span>
								</li>
								<li class="alt">
										<span>            </span>
										<span class="comment">// Nested transaction through nested begin and commit/rollback calls. </span>
										<span>  </span>
								</li>
								<li class="">
										<span>            </span>
										<span class="comment">// Usually only for JTA: Spring synchronization might get activated here </span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>            </span>
										<span class="comment">// in case of a pre-existing JTA transaction. </span>
										<span>  </span>
								</li>
								<li class="">
										<span>            doBegin(transaction, definition);   </span>
								</li>
								<li class="alt">
										<span>            </span>
										<span class="keyword">boolean</span>
										<span> newSynchronization = (</span>
										<span class="keyword">this</span>
										<span>.transactionSynchronization != SYNCHRONIZATION_NEVER);   </span>
								</li>
								<li class="">
										<span>            </span>
										<span class="keyword">return</span>
										<span> newTransactionStatus(definition, transaction, </span>
										<span class="keyword">true</span>
										<span>, newSynchronization, debugEnabled, </span>
										<span class="keyword">null</span>
										<span>);   </span>
								</li>
								<li class="alt">
										<span>        }   </span>
								</li>
								<li class="">
										<span>    }   </span>
								</li>
								<li class="alt">
										<span>}   </span>
								</li>
						</ol>
				</div>
		</div>
		<script><![CDATA[ender_code();]]&gt;</script>
		<br />
		<br />一目了然 
<p></p><p><span style="COLOR: red">1. 我们要设置 transactionManager 的 nestedTransactionAllowed 属性为 true, 注意, 此属性默认为 false!!!</span></p><p>再看 AbstractTransactionStatus#createAndHoldSavepoint() 方法</p><p></p><div class="code_title">代码</div><div class="code_div"><div class="dp-highlighter"><div class="bar"></div><ol class="dp-j"><li class="alt"><span><span class="comment">/** </span> </span></li><li class=""><span><span class="comment"> * Create a savepoint and hold it for the transaction. </span> </span></li><li class="alt"><span><span class="comment"> * @throws org.springframework.transaction.NestedTransactionNotSupportedException </span> </span></li><li class=""><span><span class="comment"> * if the underlying transaction does not support savepoints </span> </span></li><li class="alt"><span><span class="comment"> */</span><span>  </span></span></li><li class=""><span></span><span class="keyword">public</span><span> </span><span class="keyword">void</span><span> createAndHoldSavepoint() </span><span class="keyword">throws</span><span> TransactionException {   </span></li><li class="alt"><span>    setSavepoint(getSavepointManager().createSavepoint());   </span></li><li class=""><span>}   </span></li></ol></div></div><script><![CDATA[ender_code();]]&gt;</script><p></p><p>可以看到 Savepoint 是 SavepointManager.createSavepoint 实现的, 再看 SavepointManager 的层次结构, 发现 <br />其 Template 实现是 JdbcTransactionObjectSupport, 常用的 DatasourceTransactionManager, HibernateTransactionManager <br />中的 TransactonObject 都是它的子类 :</p><p><img src="http://www.javaeye.com/upload/attachment/pic/2754/6dfbf7bb-eb70-485c-82d6-a172e7ad8114-thumb.jpg" border="0" /><br /><br />JdbcTransactionObjectSupport 告诉我们必须要满足两个条件才能 createSavepoint : <br /><br /><span style="COLOR: red">2. java.sql.Savepoint 必须存在, 即 jdk 版本要 1.4+ <br />3. Connection.getMetaData().supportsSavepoints() 必须为 true, 即 jdbc drive 必须支持 JDBC 3.0 </span><br />确保以上条件都满足后, 你就可以尝试使用 PROPAGATION_NESTED 了. (全文完) <br /></p><img src ="http://www.blogjava.net/NeonWay/aggbug/90727.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/NeonWay/" target="_blank">王彦锋的技术实践</a> 2006-12-29 14:06 <a href="http://www.blogjava.net/NeonWay/archive/2006/12/29/90727.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Servlet和Filter的url匹配以及url-pattern详解</title><link>http://www.blogjava.net/NeonWay/archive/2006/12/21/89194.html</link><dc:creator>王彦锋的技术实践</dc:creator><author>王彦锋的技术实践</author><pubDate>Thu, 21 Dec 2006 01:23:00 GMT</pubDate><guid>http://www.blogjava.net/NeonWay/archive/2006/12/21/89194.html</guid><wfw:comment>http://www.blogjava.net/NeonWay/comments/89194.html</wfw:comment><comments>http://www.blogjava.net/NeonWay/archive/2006/12/21/89194.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/NeonWay/comments/commentRss/89194.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/NeonWay/services/trackbacks/89194.html</trackback:ping><description><![CDATA[
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td colspan="2">
										<hr />
								</td>
						</tr>
						<tr>
								<td colspan="2">
										<div class="postbodydiv" id="188730_body">
												<table width="100%">
														<tbody>
																<tr>
																		<td>  
<h1 style="LINE-HEIGHT: 150%; TEXT-ALIGN: center" align="center"><font size="4"><span lang="EN-US" style="FONT-FAMILY: \" verdana\?,\?sans-serif\??="">Servlet</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri">和</span><span lang="EN-US" style="FONT-FAMILY: \" verdana\?,\?sans-serif\??="">Filter</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri">的</span><span lang="EN-US" style="FONT-FAMILY: \" verdana\?,\?sans-serif\??="">url</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri">匹配以及</span><span lang="EN-US" style="FONT-FAMILY: \" verdana\?,\?sans-serif\??="">url-pattern</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri">详解</span><span lang="EN-US" style="FONT-FAMILY: \" verdana\?,\?sans-serif\??=""><?XML:NAMESPACE PREFIX = O /?><o:p></o:p></span></font></h1><p class="MsoNormal" style="LINE-HEIGHT: 150%"><span lang="EN-US" style="FONT-FAMILY: \" verdana\?,\?sans-serif\??=""><span style="mso-tab-count: 1">      </span>Servlet</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri">和</span><span lang="EN-US" style="FONT-FAMILY: \" verdana\?,\?sans-serif\??="">filter</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri">是</span><span lang="EN-US" style="FONT-FAMILY: \" verdana\?,\?sans-serif\??="">J2EE</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri">开发中常用的技术，使用方便，配置简单，老少皆宜。估计大多数朋友都是直接配置用，也没有关心过具体的细节，今天遇到一个问题，上网查了</span><span lang="EN-US" style="FONT-FAMILY: \" verdana\?,\?sans-serif\??="">servlet</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri">的规范才发现，</span><span lang="EN-US" style="FONT-FAMILY: \" verdana\?,\?sans-serif\??="">servlet</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri">和</span><span lang="EN-US" style="FONT-FAMILY: \" verdana\?,\?sans-serif\??="">filter</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri">中的</span><span lang="EN-US" style="FONT-FAMILY: \" verdana\?,\?sans-serif\??="">url-pattern</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri">还是有一些文章在里面的，总结了一些东西，放出来供大家参考，以免遇到问题又要浪费时间。</span><span lang="EN-US" style="FONT-FAMILY: \" verdana\?,\?sans-serif\??=""><o:p></o:p></span></p><h2 style="LINE-HEIGHT: 150%"><span lang="EN-US" style="FONT-FAMILY: \" verdana\?,\?sans-serif\??=""><span style="mso-tab-count: 1">   <font size="3"> 一，</font></span><font size="3">servlet</font></span><font size="3"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Cambria">容器对</span><span lang="EN-US" style="FONT-FAMILY: \" verdana\?,\?sans-serif\??="">url</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Cambria">的匹配过程：</span><span lang="EN-US" style="FONT-FAMILY: \" verdana\?,\?sans-serif\??=""><o:p></o:p></span></font></h2><p class="MsoNormal" style="LINE-HEIGHT: 150%"><span lang="EN-US" style="FONT-FAMILY: \" verdana\?,\?sans-serif\??=""><span style="mso-tab-count: 1">      </span><o:p></o:p></span></p><table class="MsoNormalTable" style="BORDER-RIGHT: medium none; BORDER-TOP: medium none; BACKGROUND: #f2f2f2; BORDER-LEFT: medium none; BORDER-BOTTOM: medium none; BORDER-COLLAPSE: collapse; mso-shading: windowtext; mso-pattern: gray-5 auto; mso-border-alt: solid #9BBB59 1.0pt; mso-yfti-tbllook: 1184; mso-padding-alt: 0cm 5.4pt 0cm 5.4pt; mso-border-insideh: 1.0pt solid #9BBB59; mso-border-insidev: 1.0pt solid #9BBB59" cellspacing="0" cellpadding="0" border="1"><tbody><tr style="mso-yfti-irow: 0; mso-yfti-firstrow: yes; mso-yfti-lastrow: yes"><td style="BORDER-RIGHT: #9bbb59 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: #9bbb59 1pt solid; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: #9bbb59 1pt solid; WIDTH: 426.1pt; PADDING-TOP: 0cm; BORDER-BOTTOM: #9bbb59 1pt solid" valign="top" width="568"><p class="MsoNormal" style="TEXT-INDENT: 21pt; LINE-HEIGHT: 150%"><span style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold">当一个请求发送到</span><span lang="EN-US" style="COLOR: black; FONT-FAMILY: \" verdana\?,\?sans-serif\?;="" mso-bidi-font-weight:="" bold?="">servlet</span><span style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold">容器的时候，容器先会将请求的</span><span lang="EN-US" style="COLOR: black; FONT-FAMILY: \" verdana\?,\?sans-serif\?;="" mso-bidi-font-weight:="" bold?="">url</span><span style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold">减去当前应用上下文的</span><span style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana; mso-bidi-font-weight: bold">路径</span><span style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold">作为</span><span lang="EN-US" style="COLOR: black; FONT-FAMILY: \" verdana\?,\?sans-serif\?;="" mso-bidi-font-weight:="" bold?="">servlet</span><span style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold">的映射</span><span lang="EN-US" style="COLOR: black; FONT-FAMILY: \" verdana\?,\?sans-serif\?;="" mso-bidi-font-weight:="" bold?="">url</span><span style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold">，比如我访问的是</span><span lang="EN-US" style="COLOR: black; FONT-FAMILY: \" verdana\?,\?sans-serif\?;="" mso-bidi-font-weight:="" bold?=""><a href="http://localhost/test/aaa.html">http://localhost/test/aaa.html</a></span><span style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold">，我的应用上下文是</span><span lang="EN-US" style="COLOR: black; FONT-FAMILY: \" verdana\?,\?sans-serif\?;="" mso-bidi-font-weight:="" bold?="" mso-hansi-font-family:="" calibri;="">test</span><span style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold">，容器会将</span><span lang="EN-US" style="COLOR: black; FONT-FAMILY: \" verdana\?,\?sans-serif\?;="" mso-bidi-font-weight:="" bold?=""><a href="http://localhost/test">http://localhost/test</a></span><span style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold">去掉，剩下的</span><span lang="EN-US" style="COLOR: black; FONT-FAMILY: \" verdana\?,\?sans-serif\?;="" mso-bidi-font-weight:="" bold?="">/aaa.html</span><span style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold">部分拿来做</span><span lang="EN-US" style="COLOR: black; FONT-FAMILY: \" verdana\?,\?sans-serif\?;="" mso-bidi-font-weight:="" bold?="">servlet</span><span style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold">的映射匹配。这个映射匹配过程是有顺序的，而且当有一个</span><span lang="EN-US" style="COLOR: black; FONT-FAMILY: \" verdana\?,\?sans-serif\?;="" mso-bidi-font-weight:="" bold?="">servlet</span><span style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold">匹配成功以后，就不会去理会剩下的</span><span lang="EN-US" style="COLOR: black; FONT-FAMILY: \" verdana\?,\?sans-serif\?;="" mso-bidi-font-weight:="" bold?="">servlet</span><span style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold">了（</span><span lang="EN-US" style="COLOR: black; FONT-FAMILY: \" verdana\?,\?sans-serif\?;="" mso-bidi-font-weight:="" bold?="">filter</span><span style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold">不同，后文会提到）。其匹配规则和顺序如下：</span><span lang="EN-US" style="COLOR: black; FONT-FAMILY: \" verdana\?,\?sans-serif\?;="" mso-bidi-font-weight:="" bold?=""><o:p></o:p></span></p><p class="MsoListParagraph" style="MARGIN-LEFT: 42pt; TEXT-INDENT: -21pt; LINE-HEIGHT: 150%; mso-char-indent-count: 0; mso-list: l1 level1 lfo1"><span lang="EN-US" style="COLOR: black; FONT-FAMILY: \" verdana\?,\?sans-serif\?;="" mso-bidi-font-weight:="" bold;="" mso-fareast-font-family:="" verdana;="" mso-bidi-font-family:="" verdana?=""><span style="mso-list: Ignore">1.<span style="FONT: 7pt \" times="" new="" roman\??="">     </span></span></span><span style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold">精确路径匹配。例子：比如</span><span lang="EN-US" style="COLOR: black; FONT-FAMILY: \" verdana\?,\?sans-serif\?;="" mso-bidi-font-weight:="" bold?="">servletA </span><span style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold">的</span><span lang="EN-US" style="COLOR: black; FONT-FAMILY: \" verdana\?,\?sans-serif\?;="" mso-bidi-font-weight:="" bold?="">url-pattern</span><span style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold">为</span><span lang="EN-US" style="COLOR: black; FONT-FAMILY: \" verdana\?,\?sans-serif\?;="" mso-bidi-font-weight:="" bold?=""> /test</span><span style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold">，</span><span lang="EN-US" style="COLOR: black; FONT-FAMILY: \" verdana\?,\?sans-serif\?;="" mso-bidi-font-weight:="" bold?="">servletB</span><span style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold">的</span><span lang="EN-US" style="COLOR: black; FONT-FAMILY: \" verdana\?,\?sans-serif\?;="" mso-bidi-font-weight:="" bold?="">url-pattern</span><span style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold">为</span><span style="COLOR: black; FONT-FAMILY: \" verdana\?,\?sans-serif\?;="" mso-bidi-font-weight:="" bold?=""><span lang="EN-US">/* </span></span><span style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold">，这个时候，如果我访问的</span><span lang="EN-US" style="COLOR: black; FONT-FAMILY: \" verdana\?,\?sans-serif\?;="" mso-bidi-font-weight:="" bold?="">url</span><span style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold">为</span><span lang="EN-US" style="COLOR: black; FONT-FAMILY: \" verdana\?,\?sans-serif\?;="" mso-bidi-font-weight:="" bold?=""><a href="http://localhost/test">http://localhost/test</a></span><span style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold">，这个时候容器就会先</span><span style="COLOR: black; FONT-FAMILY: \" verdana\?,\?sans-serif\?;="" mso-bidi-font-weight:="" bold?=""></span><span style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold">进行精确路径匹配，发现</span><span lang="EN-US" style="COLOR: black; FONT-FAMILY: \" verdana\?,\?sans-serif\?;="" mso-bidi-font-weight:="" bold?="">/test</span><span style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold">正好被</span><span lang="EN-US" style="COLOR: black; FONT-FAMILY: \" verdana\?,\?sans-serif\?;="" mso-bidi-font-weight:="" bold?="">servletA</span><span style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold">精确匹配，那么就去调用</span><span lang="EN-US" style="COLOR: black; FONT-FAMILY: \" verdana\?,\?sans-serif\?;="" mso-bidi-font-weight:="" bold?="">servletA</span><span style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold">，也不会去理会其他的</span><span lang="EN-US" style="COLOR: black; FONT-FAMILY: \" verdana\?,\?sans-serif\?;="" mso-bidi-font-weight:="" bold?="">servlet</span><span style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold">了。</span><span lang="EN-US" style="COLOR: black; FONT-FAMILY: \" verdana\?,\?sans-serif\?;="" mso-bidi-font-weight:="" bold?=""><o:p></o:p></span></p><p class="MsoListParagraph" style="MARGIN-LEFT: 42pt; TEXT-INDENT: -21pt; LINE-HEIGHT: 150%; mso-char-indent-count: 0; mso-list: l1 level1 lfo1"><span lang="EN-US" style="COLOR: black; FONT-FAMILY: \" verdana\?,\?sans-serif\?;="" mso-bidi-font-weight:="" bold;="" mso-fareast-font-family:="" verdana;="" mso-bidi-font-family:="" verdana?=""><span style="mso-list: Ignore">2.<span style="FONT: 7pt \" times="" new="" roman\??="">     </span></span></span><span style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold">最长路径匹配。例子：</span><span lang="EN-US" style="COLOR: black; FONT-FAMILY: \" verdana\?,\?sans-serif\?;="" mso-bidi-font-weight:="" bold?="">servletA</span><span style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold">的</span><span lang="EN-US" style="COLOR: black; FONT-FAMILY: \" verdana\?,\?sans-serif\?;="" mso-bidi-font-weight:="" bold?="">url-pattern</span><span style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold">为</span><span lang="EN-US" style="COLOR: black; FONT-FAMILY: \" verdana\?,\?sans-serif\?;="" mso-bidi-font-weight:="" bold?="">/test/*</span><span style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold">，而</span><span lang="EN-US" style="COLOR: black; FONT-FAMILY: \" verdana\?,\?sans-serif\?;="" mso-bidi-font-weight:="" bold?="">servletB</span><span style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold">的</span><span lang="EN-US" style="COLOR: black; FONT-FAMILY: \" verdana\?,\?sans-serif\?;="" mso-bidi-font-weight:="" bold?="">url-pattern</span><span style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold">为</span><span lang="EN-US" style="COLOR: black; FONT-FAMILY: \" verdana\?,\?sans-serif\?;="" mso-bidi-font-weight:="" bold?="">/test/a/*</span><span style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold">，此时访问</span><span lang="EN-US" style="COLOR: black; FONT-FAMILY: \" verdana\?,\?sans-serif\?;="" mso-bidi-font-weight:="" bold?=""><a href="http://localhost/test/a">http://localhost/test/a</a></span><span style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold">时，容器会选择路径最长的</span><span lang="EN-US" style="COLOR: black; FONT-FAMILY: \" verdana\?,\?sans-serif\?;="" mso-bidi-font-weight:="" bold?="">servlet</span><span style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold">来匹配，也就是这里的</span><span lang="EN-US" style="COLOR: black; FONT-FAMILY: \" verdana\?,\?sans-serif\?;="" mso-bidi-font-weight:="" bold?="">servletB</span><span style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold">。</span><span lang="EN-US" style="COLOR: black; FONT-FAMILY: \" verdana\?,\?sans-serif\?;="" mso-bidi-font-weight:="" bold?=""><o:p></o:p></span></p><p class="MsoListParagraph" style="MARGIN-LEFT: 42pt; TEXT-INDENT: -21pt; LINE-HEIGHT: 150%; mso-char-indent-count: 0; mso-list: l1 level1 lfo1"><span lang="EN-US" style="COLOR: black; FONT-FAMILY: \" verdana\?,\?sans-serif\?;="" mso-bidi-font-weight:="" bold;="" mso-fareast-font-family:="" verdana;="" mso-bidi-font-family:="" verdana?=""><span style="mso-list: Ignore">3.<span style="FONT: 7pt \" times="" new="" roman\??="">     </span></span></span><span style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold">扩展匹配，如果</span><span lang="EN-US" style="COLOR: black; FONT-FAMILY: \" verdana\?,\?sans-serif\?;="" mso-bidi-font-weight:="" bold?="">url</span><span style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold">最后一段包含扩展，容器将会根据扩展选择合适的</span><span lang="EN-US" style="COLOR: black; FONT-FAMILY: \" verdana\?,\?sans-serif\?;="" mso-bidi-font-weight:="" bold?="">servlet</span><span style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold">。例子：</span><span lang="EN-US" style="COLOR: black; FONT-FAMILY: \" verdana\?,\?sans-serif\?;="" mso-bidi-font-weight:="" bold?="">servletA</span><span style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold">的</span><span lang="EN-US" style="COLOR: black; FONT-FAMILY: \" verdana\?,\?sans-serif\?;="" mso-bidi-font-weight:="" bold?="">url-pattern</span><span style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold">：</span><span lang="EN-US" style="COLOR: black; FONT-FAMILY: \" verdana\?,\?sans-serif\?;="" mso-bidi-font-weight:="" bold?="">*.action<o:p></o:p></span></p><p class="MsoListParagraph" style="MARGIN-LEFT: 42pt; TEXT-INDENT: -21pt; LINE-HEIGHT: 150%; mso-char-indent-count: 0; mso-list: l1 level1 lfo1"><strong><span lang="EN-US" style="COLOR: black; FONT-FAMILY: \" verdana\?,\?sans-serif\?;="" mso-fareast-font-family:="" verdana;="" mso-bidi-font-family:="" verdana?=""><span style="mso-list: Ignore">4.<span style="FONT: 7pt \" times="" new="" roman\??="">     </span></span></span></strong><span style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold">如果前面三条规则都没有找到一个</span><span lang="EN-US" style="COLOR: black; FONT-FAMILY: \" verdana\?,\?sans-serif\?;="" mso-bidi-font-weight:="" bold?="">servlet</span><span style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold">，容器会根据</span><span lang="EN-US" style="COLOR: black; FONT-FAMILY: \" verdana\?,\?sans-serif\?;="" mso-bidi-font-weight:="" bold?="">url</span><span style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold">选择对应的请求资源。如果应用定义了一个</span><span lang="EN-US" style="COLOR: black; FONT-FAMILY: \" verdana\?,\?sans-serif\?;="" mso-bidi-font-weight:="" bold?="">default servlet</span><span style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold">，则容器会将请求丢给</span><span lang="EN-US" style="COLOR: black; FONT-FAMILY: \" verdana\?,\?sans-serif\?;="" mso-bidi-font-weight:="" bold?="">default servlet</span><span style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana; mso-bidi-font-weight: bold">（什么是</span><span lang="EN-US" style="COLOR: black; FONT-FAMILY: \" verdana\?,\?sans-serif\?;="" mso-bidi-font-weight:="" bold?="">default servlet</span><span style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana; mso-bidi-font-weight: bold">？后面会讲）</span><span style="COLOR: black; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri; mso-bidi-font-weight: bold">。</span><strong><span lang="EN-US" style="COLOR: black; FONT-FAMILY: \" verdana\?,\?sans-serif\??=""><o:p></o:p></span></strong></p></td></tr></tbody></table><p class="MsoNormal" style="LINE-HEIGHT: 150%"><span lang="EN-US" style="FONT-FAMILY: \" verdana\?,\?sans-serif\??=""><span style="mso-spacerun: yes"> </span><span style="mso-tab-count: 1">    </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri">根据这个规则表，就能很清楚的知道</span><span lang="EN-US" style="FONT-FAMILY: \" verdana\?,\?sans-serif\??="">servlet</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri">的匹配过程，所以定义</span><span lang="EN-US" style="FONT-FAMILY: \" verdana\?,\?sans-serif\??="">servlet</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri">的时候也要考虑</span><span lang="EN-US" style="FONT-FAMILY: \" verdana\?,\?sans-serif\??="">url-pattern</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri">的写法，以免出错。</span><span lang="EN-US" style="FONT-FAMILY: \" verdana\?,\?sans-serif\??=""><o:p></o:p></span></p><p class="MsoNormal" style="LINE-HEIGHT: 150%"><span lang="EN-US" style="FONT-FAMILY: \" verdana\?,\?sans-serif\??=""><span style="mso-tab-count: 1">      </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri">对于</span><span lang="EN-US" style="FONT-FAMILY: \" verdana\?,\?sans-serif\??="">filter</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri">，不会像</span><span lang="EN-US" style="FONT-FAMILY: \" verdana\?,\?sans-serif\??="">servlet</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri">那样只匹配一个</span><span lang="EN-US" style="FONT-FAMILY: \" verdana\?,\?sans-serif\??="">servlet</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri">，因为</span><span lang="EN-US" style="FONT-FAMILY: \" verdana\?,\?sans-serif\??="">filter</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri">的集合是一个链，所以只会有处理的顺序不同，而不会出现只选择一个</span><span lang="EN-US" style="FONT-FAMILY: \" verdana\?,\?sans-serif\??="">filter</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri">。</span><span lang="EN-US" style="FONT-FAMILY: \" verdana\?,\?sans-serif\??="">Filter</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri">的处理顺序和</span><span lang="EN-US" style="FONT-FAMILY: \" verdana\?,\?sans-serif\??="">filter-mapping</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri">在</span><span lang="EN-US" style="FONT-FAMILY: \" verdana\?,\?sans-serif\??="">web.xml</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Calibri">中定义的顺序相同。</span><span lang="EN-US" style="FONT-FAMILY: \" verdana\?,\?sans-serif\??=""><o:p></o:p></span></p><h2 style="LINE-HEIGHT: 150%"><font size="3"><span lang="EN-US" style="FONT-FAMILY: \" verdana\?,\?sans-serif\??="">    二，url-pattern</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Cambria">详解</span><span lang="EN-US" style="FONT-FAMILY: \" verdana\?,\?sans-serif\?;="" mso-hansi-font-family:="" cambria?=""><o:p></o:p></span></font></h2><p class="MsoNormal" style="LINE-HEIGHT: 150%"><span lang="EN-US"><span style="mso-tab-count: 1">         </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Calibri; mso-hansi-font-family: Calibri">在</span><span lang="EN-US">web.xml</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Calibri; mso-hansi-font-family: Calibri">文件中，以下语法用于定义映射：</span></p><p class="MsoListParagraph" style="MARGIN-LEFT: 41.9pt; TEXT-INDENT: -21pt; LINE-HEIGHT: 150%; mso-char-indent-count: 0; mso-list: l0 level1 lfo2"><span lang="EN-US" style="FONT-FAMILY: Wingdings; mso-fareast-font-family: Wingdings; mso-bidi-font-family: Wingdings"><span style="mso-list: Ignore">l<span style="FONT: 7pt \" times="" new="" roman\??="">  </span></span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Calibri; mso-hansi-font-family: Calibri">以</span><span lang="EN-US">”/’</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Calibri; mso-hansi-font-family: Calibri">开头和以</span><span lang="EN-US">”/*”</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Calibri; mso-hansi-font-family: Calibri">结尾的是用来做路径映射的。</span></p><p class="MsoListParagraph" style="MARGIN-LEFT: 41.9pt; TEXT-INDENT: -21pt; LINE-HEIGHT: 150%; mso-char-indent-count: 0; mso-list: l0 level1 lfo2"><span lang="EN-US" style="FONT-FAMILY: Wingdings; mso-fareast-font-family: Wingdings; mso-bidi-font-family: Wingdings"><span style="mso-list: Ignore">l<span style="FONT: 7pt \" times="" new="" roman\??="">  </span></span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Calibri; mso-hansi-font-family: Calibri">以前缀</span><span lang="EN-US">”*.”</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Calibri; mso-hansi-font-family: Calibri">开头的是用来做扩展映射的。</span></p><p class="MsoListParagraph" style="MARGIN-LEFT: 41.9pt; TEXT-INDENT: -21pt; LINE-HEIGHT: 150%; mso-char-indent-count: 0; mso-list: l0 level1 lfo2"><span lang="EN-US" style="FONT-FAMILY: Wingdings; mso-fareast-font-family: Wingdings; mso-bidi-font-family: Wingdings"><span style="mso-list: Ignore">l<span style="FONT: 7pt \" times="" new="" roman\??="">  </span></span></span><span lang="EN-US">“/” </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Calibri; mso-hansi-font-family: Calibri">是用来定义</span><span lang="EN-US">default servlet</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Calibri; mso-hansi-font-family: Calibri">映射的。</span></p><p class="MsoListParagraph" style="MARGIN-LEFT: 41.9pt; TEXT-INDENT: -21pt; LINE-HEIGHT: 150%; mso-char-indent-count: 0; mso-list: l0 level1 lfo2"><span lang="EN-US" style="FONT-FAMILY: Wingdings; mso-fareast-font-family: Wingdings; mso-bidi-font-family: Wingdings"><span style="mso-list: Ignore">l<span style="FONT: 7pt \" times="" new="" roman\??="">  </span></span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Calibri; mso-hansi-font-family: Calibri">剩下的都是用来定义详细映射的。比如：</span><span lang="EN-US"> /aa/bb/cc.action</span></p><p class="MsoNormal" style="TEXT-INDENT: 20.9pt; LINE-HEIGHT: 150%"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Calibri; mso-hansi-font-family: Calibri">所以，为什么定义</span><span lang="EN-US">”/*.action”</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Calibri; mso-hansi-font-family: Calibri">这样一个看起来很正常的匹配会错？因为这个匹配即属于路径映射，也属于扩展映射，导致容器无法判断。</span></p><p class="MsoNormal" style="TEXT-INDENT: 20.9pt; LINE-HEIGHT: 150%"><span lang="EN-US"><o:p> </o:p></span></p><p class="MsoNormal" style="TEXT-INDENT: 20.9pt; LINE-HEIGHT: 150%"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Calibri; mso-hansi-font-family: Calibri">【参考内容】</span></p><p class="MsoNormal" style="TEXT-INDENT: 20.9pt; LINE-HEIGHT: 150%"><span lang="EN-US"><span style="mso-tab-count: 3">                            </span></span><strong style="mso-bidi-font-weight: normal"><span lang="EN-US" style="FONT-SIZE: 14pt; LINE-HEIGHT: 150%">Java <span style="mso-spacerun: yes"> </span>Servlet 2.4 Specification<o:p></o:p></span></strong></p></td>
																</tr>
														</tbody>
												</table>
										</div>
								</td>
						</tr>
				</tbody>
		</table>
		<a href="http://www.javaeye.com/topic/39332?page=1">http://www.javaeye.com/topic/39332?page=1</a>
<img src ="http://www.blogjava.net/NeonWay/aggbug/89194.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/NeonWay/" target="_blank">王彦锋的技术实践</a> 2006-12-21 09:23 <a href="http://www.blogjava.net/NeonWay/archive/2006/12/21/89194.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>引： HttpClient POST 的 UTF-8 编码问题</title><link>http://www.blogjava.net/NeonWay/archive/2006/11/01/78413.html</link><dc:creator>王彦锋的技术实践</dc:creator><author>王彦锋的技术实践</author><pubDate>Wed, 01 Nov 2006 01:59:00 GMT</pubDate><guid>http://www.blogjava.net/NeonWay/archive/2006/11/01/78413.html</guid><wfw:comment>http://www.blogjava.net/NeonWay/comments/78413.html</wfw:comment><comments>http://www.blogjava.net/NeonWay/archive/2006/11/01/78413.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/NeonWay/comments/commentRss/78413.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/NeonWay/services/trackbacks/78413.html</trackback:ping><description><![CDATA[
		<h1 class="block_title">
				<a id="viewpost1_TitleUrl" href="/thinkbase/archive/2006/10/31/HttpClientPOST_UTF8.html">
				</a>
		</h1>
		<div class="post">
				<div class="postcontent">原文来自: <a href="http://thinkbase.net/w/main/Wiki?HttpClient+POST+%E7%9A%84+UTF-8+%E7%BC%96%E7%A0%81%E9%97%AE%E9%A2%98">HttpClient POST 的 UTF-8 编码问题</a><div class="tagsList" id="tagsList" align="right"><hr width="100%" size="2" />
类别标签: <span><a class="tagsItem" href="http://thinkbase.net/w/main/Wiki?TagIndex&amp;tag=UTF-8">UTF-8  </a><a class="tagsItem" href="http://thinkbase.net/w/main/Wiki?TagIndex&amp;tag=encoding">encoding  </a><a class="tagsItem" href="http://thinkbase.net/w/main/Wiki?TagIndex&amp;tag=http-client">http-client  </a><a class="tagsItem" href="http://thinkbase.net/w/main/Wiki?TagIndex&amp;tag=java">java</a></span></div><span class="pageHeader"><a href="http://thinkbase.net/w/main/Wiki?action=action_search&amp;text=%22HttpClient+POST+%E7%9A%84+UTF-8+%E7%BC%96%E7%A0%81%E9%97%AE%E9%A2%98%22"></a></span><p>Apache HttpClient ( <a class="externallink" style="BORDER-BOTTOM: 1px dotted" href="http://jakarta.apache.org/commons/httpclient/">http://jakarta.apache.org/commons/httpclient/</a> ) 是一个纯 Java 的HTTP 协议的客户端编程工具包, 对 HTTP 协议的支持相当全面, 更多细节也可以参考IBM 网站上的这篇文章 <a href="http://thinkbase.net/w/main/Wiki?HttpClient+POST+%E7%9A%84+UTF-8+%E7%BC%96%E7%A0%81%E9%97%AE%E9%A2%98-Ref-IBM">HttpClient入门</a> ( <a class="externallink" style="BORDER-BOTTOM: 1px dotted" href="http://www-128.ibm.com/developerworks/cn/opensource/os-httpclient/">http://www-128.ibm.com/developerworks/cn/opensource/os-httpclient/</a> ).<br /><br /></p><h3>问题分析</h3>不过在实际使用中, 还是发现按照最基本的方式调用 HttpClient 时, 并不支持 UTF-8 编码, 在网络上找过一些文章, 也不得要领, 于是查看了 commons-httpclient-3.0.1 的一些代码, 首先在 PostMethod 中找到了 generateRequestEntity() 方法:<br /><!-- ======================================================== --><!-- = Java Sourcecode to HTML automatically converted code = --><!-- =   Java to HTML Converter V3.0 2003 by Markus Gebhard  markus@jave.de   = --><!-- =     Further information: http://www.java2html.de     = --><center><table cellspacing="0" cellpadding="3" align="center" bgcolor="#ffffff" border="2"><tbody><tr><!-- start source code --><td valign="top" nowrap="" align="left"><code><font color="#ffffff">    </font><font color="#008000">/**</font><br /><font color="#ffffff">     </font><font color="#008000">* Generates a request entity from the post parameters, if present.  Calls</font><br /><font color="#ffffff">     </font><font color="#008000">* </font><font color="#008000">{@link EntityEnclosingMethod#generateRequestBody()} </font><font color="#008000">if parameters have not been set.</font><br /><font color="#ffffff">     </font><font color="#008000">* </font><br /><font color="#ffffff">     </font><font color="#008000">* </font><font color="#005500">@since </font><font color="#008000">3.0</font><br /><font color="#ffffff">     </font><font color="#008000">*/</font><br /><font color="#ffffff">    </font><font color="#0000c0"><b>protected </b></font><font color="#000000">RequestEntity generateRequestEntity</font><font color="#000000">() {</font><br /><font color="#ffffff">        </font><font color="#0000c0"><b>if </b></font><font color="#000000">(</font><font color="#000000">!</font><font color="#0000c0"><b>this</b></font><font color="#000000">.params.isEmpty</font><font color="#000000">()) {</font><br /><font color="#ffffff">            </font><font color="#008000">// Use a ByteArrayRequestEntity instead of a StringRequestEntity.</font><br /><font color="#ffffff">            </font><font color="#008000">// This is to avoid potential encoding issues.  Form url encoded strings</font><br /><font color="#ffffff">            </font><font color="#008000">// are ASCII by definition but the content type may not be.  Treating the content</font><br /><font color="#ffffff">            </font><font color="#008000">// as bytes allows us to keep the current charset without worrying about how</font><br /><font color="#ffffff">            </font><font color="#008000">// this charset will effect the encoding of the form url encoded string.</font><br /><font color="#ffffff">            </font><font color="#000000">String content = EncodingUtil.formUrlEncode</font><font color="#000000">(</font><font color="#000000">getParameters</font><font color="#000000">()</font><font color="#000000">, getRequestCharSet</font><font color="#000000">())</font><font color="#000000">;</font><br /><font color="#ffffff">            </font><font color="#000000">ByteArrayRequestEntity entity = </font><font color="#0000c0"><b>new </b></font><font color="#000000">ByteArrayRequestEntity</font><font color="#000000">(</font><br /><font color="#ffffff">                </font><font color="#000000">EncodingUtil.getAsciiBytes</font><font color="#000000">(</font><font color="#000000">content</font><font color="#000000">)</font><font color="#000000">,</font><br /><font color="#ffffff">                </font><font color="#000000">FORM_URL_ENCODED_CONTENT_TYPE</font><br /><font color="#ffffff">            </font><font color="#000000">)</font><font color="#000000">;</font><br /><font color="#ffffff">            </font><font color="#0000c0"><b>return </b></font><font color="#000000">entity;</font><br /><font color="#ffffff">        </font><font color="#000000">} </font><font color="#0000c0"><b>else </b></font><font color="#000000">{</font><br /><font color="#ffffff">            </font><font color="#0000c0"><b>return super</b></font><font color="#000000">.generateRequestEntity</font><font color="#000000">()</font><font color="#000000">;</font><br /><font color="#ffffff">        </font><font color="#000000">}</font><br /><font color="#ffffff">    </font><font color="#000000">}</font></code></td><!-- end source code --></tr></tbody></table></center><!-- =       END of automatically generated HTML code       = --><!-- ======================================================== --><br />原来使用 NameValuePair 加入的 HTTP 请求的参数最终都会转化为 RequestEntity 提交到 HTTP 服务器, 接着在 PostMethod 的父类 EntityEnclosingMethod 中找到了如下的代码:<br /><!-- ======================================================== --><!-- = Java Sourcecode to HTML automatically converted code = --><!-- =   Java to HTML Converter V3.0 2003 by Markus Gebhard  markus@jave.de   = --><!-- =     Further information: http://www.java2html.de     = --><center><table cellspacing="0" cellpadding="3" align="center" bgcolor="#ffffff" border="2"><tbody><tr><!-- start source code --><td valign="top" nowrap="" align="left"><code><font color="#ffffff">    </font><font color="#008000">/**</font><br /><font color="#ffffff">     </font><font color="#008000">* Returns the request's charset.  The charset is parsed from the request entity's </font><br /><font color="#ffffff">     </font><font color="#008000">* content type, unless the content type header has been set manually. </font><br /><font color="#ffffff">     </font><font color="#008000">* </font><br /><font color="#ffffff">     </font><font color="#008000">* </font><font color="#005500">@see </font><font color="#008000">RequestEntity#getContentType()</font><br /><font color="#ffffff">     </font><font color="#008000">* </font><br /><font color="#ffffff">     </font><font color="#008000">* </font><font color="#005500">@since </font><font color="#008000">3.0</font><br /><font color="#ffffff">     </font><font color="#008000">*/</font><br /><font color="#ffffff">    </font><font color="#0000c0"><b>public </b></font><font color="#000000">String getRequestCharSet</font><font color="#000000">() {</font><br /><font color="#ffffff">        </font><font color="#0000c0"><b>if </b></font><font color="#000000">(</font><font color="#000000">getRequestHeader</font><font color="#000000">(</font><font color="#990000">"Content-Type"</font><font color="#000000">) </font><font color="#000000">== </font><font color="#0000c0"><b>null</b></font><font color="#000000">) {</font><br /><font color="#ffffff">            </font><font color="#008000">// check the content type from request entity</font><br /><font color="#ffffff">            </font><font color="#008000">// We can't call getRequestEntity() since it will probably call</font><br /><font color="#ffffff">            </font><font color="#008000">// this method.</font><br /><font color="#ffffff">            </font><font color="#0000c0"><b>if </b></font><font color="#000000">(</font><font color="#0000c0"><b>this</b></font><font color="#000000">.requestEntity != </font><font color="#0000c0"><b>null</b></font><font color="#000000">) {</font><br /><font color="#ffffff">                </font><font color="#0000c0"><b>return </b></font><font color="#000000">getContentCharSet</font><font color="#000000">(</font><br /><font color="#ffffff">                    </font><font color="#0000c0"><b>new </b></font><font color="#000000">Header</font><font color="#000000">(</font><font color="#990000">"Content-Type"</font><font color="#000000">, requestEntity.getContentType</font><font color="#000000">()))</font><font color="#000000">;</font><br /><font color="#ffffff">            </font><font color="#000000">} </font><font color="#0000c0"><b>else </b></font><font color="#000000">{</font><br /><font color="#ffffff">                </font><font color="#0000c0"><b>return super</b></font><font color="#000000">.getRequestCharSet</font><font color="#000000">()</font><font color="#000000">;</font><br /><font color="#ffffff">            </font><font color="#000000">}</font><br /><font color="#ffffff">        </font><font color="#000000">} </font><font color="#0000c0"><b>else </b></font><font color="#000000">{</font><br /><font color="#ffffff">            </font><font color="#0000c0"><b>return super</b></font><font color="#000000">.getRequestCharSet</font><font color="#000000">()</font><font color="#000000">;</font><br /><font color="#ffffff">        </font><font color="#000000">}</font><br /><font color="#ffffff">    </font><font color="#000000">}</font></code></td><!-- end source code --></tr></tbody></table></center><!-- =       END of automatically generated HTML code       = --><!-- ======================================================== --><br /><br /><h3>解决方案</h3>从上面两段代码可以看出是 HttpClient 是如何依据 "Content-Type" 获得请求的编码(字符集), 而这个编码又是如何应用到提交内容的编码过程中去的. 按照这个原来, 其实我们只需要重载 getRequestCharSet() 方法, 返回我们需要的编码(字符集)名称, 就可以解决 UTF-8 或者其它非默认编码提交 POST 请求时的乱码问题了.<br /><br /><h3>测试</h3>首先在 Tomcat 的 ROOT WebApp 下部署一个页面 test.jsp, 作为测试页面, 主要代码片段如下:<br /><!-- ======================================================== --><!-- = Java Sourcecode to HTML automatically converted code = --><!-- =   Java to HTML Converter V3.0 2003 by Markus Gebhard  markus@jave.de   = --><!-- =     Further information: http://www.java2html.de     = --><center><table cellspacing="0" cellpadding="3" align="center" bgcolor="#ffffff" border="2"><tbody><tr><!-- start source code --><td valign="top" nowrap="" align="left"><code><font color="#000000">&lt;%@ page contentType=</font><font color="#990000">"text/html;charset=UTF-8"</font><font color="#000000">%&gt;</font><br /><font color="#000000">&lt;%@ page session=</font><font color="#990000">"false" </font><font color="#000000">%&gt;</font><br /><font color="#000000">&lt;%</font><br /><font color="#000000">request.setCharacterEncoding</font><font color="#000000">(</font><font color="#990000">"UTF-8"</font><font color="#000000">)</font><font color="#000000">;</font><br /><font color="#000000">String val = request.getParameter</font><font color="#000000">(</font><font color="#990000">"TEXT"</font><font color="#000000">)</font><font color="#000000">;</font><br /><font color="#000000">System.out.println</font><font color="#000000">(</font><font color="#990000">"&gt;&gt;&gt;&gt; The result is " </font><font color="#000000">+ val</font><font color="#000000">)</font><font color="#000000">;</font><br /><font color="#000000">%&gt;</font></code></td><!-- end source code --></tr></tbody></table></center><!-- =       END of automatically generated HTML code       = --><!-- ======================================================== --><br /><br />接着写一个测试类, 主要代码如下:<br /><!-- ======================================================== --><!-- = Java Sourcecode to HTML automatically converted code = --><!-- =   Java to HTML Converter V3.0 2003 by Markus Gebhard  markus@jave.de   = --><!-- =     Further information: http://www.java2html.de     = --><center><table cellspacing="0" cellpadding="3" align="center" bgcolor="#ffffff" border="2"><tbody><tr><!-- start source code --><td valign="top" nowrap="" align="left"><code><font color="#ffffff">    </font><font color="#0000c0"><b>public static </b></font><font color="#c00000"><b>void </b></font><font color="#000000">main</font><font color="#000000">(</font><font color="#000000">String</font><font color="#000000">[] </font><font color="#000000">args</font><font color="#000000">) </font><font color="#0000c0"><b>throws </b></font><font color="#000000">Exception, IOException </font><font color="#000000">{</font><br /><font color="#ffffff">        </font><font color="#000000">String url = </font><font color="#990000">"http://localhost:8080/test.jsp"</font><font color="#000000">;</font><br /><font color="#ffffff">        </font><font color="#000000">PostMethod postMethod = </font><font color="#0000c0"><b>new </b></font><font color="#000000">UTF8PostMethod</font><font color="#000000">(</font><font color="#000000">url</font><font color="#000000">)</font><font color="#000000">;</font><br /><font color="#ffffff">        </font><font color="#008000">//填入各个表单域的值</font><br /><font color="#ffffff">        </font><font color="#000000">NameValuePair</font><font color="#000000">[] </font><font color="#000000">data = </font><font color="#000000">{</font><br /><font color="#ffffff">                </font><font color="#0000c0"><b>new </b></font><font color="#000000">NameValuePair</font><font color="#000000">(</font><font color="#990000">"TEXT"</font><font color="#000000">, </font><font color="#990000">"中文"</font><font color="#000000">)</font><font color="#000000">,</font><br /><font color="#ffffff">        </font><font color="#000000">}</font><font color="#000000">;</font><br /><font color="#ffffff">        </font><font color="#008000">//将表单的值放入postMethod中</font><br /><font color="#ffffff">        </font><font color="#000000">postMethod.setRequestBody</font><font color="#000000">(</font><font color="#000000">data</font><font color="#000000">)</font><font color="#000000">;</font><br /><font color="#ffffff">        </font><font color="#008000">//执行postMethod</font><br /><font color="#ffffff">        </font><font color="#000000">HttpClient httpClient = </font><font color="#0000c0"><b>new </b></font><font color="#000000">HttpClient</font><font color="#000000">()</font><font color="#000000">;</font><br /><font color="#ffffff">        </font><font color="#000000">httpClient.executeMethod</font><font color="#000000">(</font><font color="#000000">postMethod</font><font color="#000000">)</font><font color="#000000">;</font><br /><font color="#ffffff">    </font><font color="#000000">}</font><br /><font color="#ffffff">    </font><br /><font color="#ffffff">    </font><font color="#008000">//Inner class for UTF-8 support</font><br /><font color="#ffffff">    </font><font color="#0000c0"><b>public static class </b></font><font color="#000000">UTF8PostMethod </font><font color="#0000c0"><b>extends </b></font><font color="#000000">PostMethod</font><font color="#000000">{</font><br /><font color="#ffffff">        </font><font color="#0000c0"><b>public </b></font><font color="#000000">UTF8PostMethod</font><font color="#000000">(</font><font color="#000000">String url</font><font color="#000000">){</font><br /><font color="#ffffff">            </font><font color="#0000c0"><b>super</b></font><font color="#000000">(</font><font color="#000000">url</font><font color="#000000">)</font><font color="#000000">;</font><br /><font color="#ffffff">        </font><font color="#000000">}</font><br /><font color="#ffffff">        </font><font color="#000000">@Override</font><br /><font color="#ffffff">        </font><font color="#0000c0"><b>public </b></font><font color="#000000">String getRequestCharSet</font><font color="#000000">() {</font><br /><font color="#ffffff">            </font><font color="#008000">//return super.getRequestCharSet();</font><br /><font color="#ffffff">            </font><font color="#0000c0"><b>return </b></font><font color="#990000">"UTF-8"</font><font color="#000000">;</font><br /><font color="#ffffff">        </font><font color="#000000">}</font><br /><font color="#ffffff">    </font><font color="#000000">}</font></code></td><!-- end source code --></tr></tbody></table></center><!-- =       END of automatically generated HTML code       = --><!-- ======================================================== --><br /><br />运行这个测试程序, 在 Tomcat 的后台输出中可以正确打印出 "&gt;&gt;&gt;&gt; The result is 中文" .<br /><br /><h3>代码下载</h3>本文所提到的所有代码, 以及测试程序(可直接导入 eclipse)提供打包下载: <a class="attachmentlink" href="http://thinkbase.net/w/main/Wiki/httpClientUTF8.tar.bz2?action=action_view_attachment&amp;attachment=HttpClient+POST+%E7%9A%84+UTF-8+%E7%BC%96%E7%A0%81%E9%97%AE%E9%A2%98.httpClientUTF8.tar.bz2" target="_blank">att:HttpClient POST 的 UTF-8 编码问题.httpClientUTF8.tar.bz2</a><br /><br /><h3>END</h3><p>引：<a href="/thinkbase/archive/2006/10/31/httpclientpost_utf8.html">http://www.blogjava.net/thinkbase/archive/2006/10/31/httpclientpost_utf8.html</a></p></div>
		</div>
<img src ="http://www.blogjava.net/NeonWay/aggbug/78413.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/NeonWay/" target="_blank">王彦锋的技术实践</a> 2006-11-01 09:59 <a href="http://www.blogjava.net/NeonWay/archive/2006/11/01/78413.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hibernate中对Session管理</title><link>http://www.blogjava.net/NeonWay/archive/2006/09/09/68662.html</link><dc:creator>王彦锋的技术实践</dc:creator><author>王彦锋的技术实践</author><pubDate>Sat, 09 Sep 2006 02:04:00 GMT</pubDate><guid>http://www.blogjava.net/NeonWay/archive/2006/09/09/68662.html</guid><wfw:comment>http://www.blogjava.net/NeonWay/comments/68662.html</wfw:comment><comments>http://www.blogjava.net/NeonWay/archive/2006/09/09/68662.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/NeonWay/comments/commentRss/68662.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/NeonWay/services/trackbacks/68662.html</trackback:ping><description><![CDATA[
		<strong>
				<font size="2">
						<span class="tpc_title">Hibernate中对Session管理</span>
						<br />
						<br />
				</font>
		</strong>
		<font size="2">
				<span class="tpc_content">在各种Session 管理方案中， ThreadLocal 模式得到了大量使用。ThreadLocal 是Java中一种较为特殊的线程绑定机制。通过ThreadLocal存取的数据，总是与当前线程相关，也就是说，JVM 为每个运行的线程，绑定了私有的本地实例存取空间，从而为多线程环境常出现的并发访问问题提供了一种隔离机制。首先，我们需要知道，SessionFactory负责创建Session，SessionFactory是线程<br />安全的，多个并发线程可以同时访问一个SessionFactory 并从中获取Session 实例。而<br />Session并非线程安全，也就是说，如果多个线程同时使用一个Session实例进行数据存取，<br />则将会导致Session 数据存取逻辑混乱。下面是一个典型的Servlet，我们试图通过一个类<br />变量session实现Session的重用，以避免每次操作都要重新创建：<br />public class TestServlet extends HttpServlet {<br />private Session session;<br />public void doGet( HttpServletRequest request,<br />HttpServletResponse response)<br />throws ServletException, IOException {<br />session = getSession();<br />doSomething();<br />session.flush();<br />}<br />public void doSomething(){<br />......//基于session的存取操作<br />}<br />}<br />代码看上去正确无误，甚至在我们单机测试的时候可能也不会发生什么问题，但这样的代<br />Hibernate Developer's Guide Version 1.0<br />September 2, 2004 So many open source projects. Why not Open your Documents?<br />码一旦编译部署到实际运行环境中，接踵而来的莫名其妙的错误很可能会使得我们摸不找头脑。<br />问题出在哪里？<br />首先，Servlet 运行是多线程的，而应用服务器并不会为每个线程都创建一个Servlet<br />实例，也就是说，TestServlet在应用服务器中只有一个实例（在Tomcat中是这样，其他的<br />应用服务器可能有不同的实现），而这个实例会被许多个线程并发调用，doGet 方法也将被不<br />同的线程反复调用，可想而知，每次调用doGet 方法，这个唯一的TestServlet 实例的<br />session 变量都会被重置，线程A 的运行过程中，其他的线程如果也被执行，那么session<br />的引用将发生改变，之后线程A 再调用session，可能此时的session 与其之前所用的<br />session就不再一致，显然，错误也就不期而至。<br />ThreadLocal的出现，使得这个问题迎刃而解。<br />我们对上面的例子进行一些小小的修改：<br />public class TestServlet extends HttpServlet {<br />private ThreadLocal localSession = new ThreadLocal();<br />public void doGet( HttpServletRequest request,<br />HttpServletResponse response)<br />throws ServletException, IOException {<br />localSession.set(getSession());<br />doSomething();<br />session.flush();<br />}<br />public void doSomething(){<br />Session session = (Session)localSession.get();<br />......//基于session的存取操作<br />}<br />}<br />可以看到，localSession 是一个ThreadLocal 类型的对象，在doGet 方法中，我们<br />通过其set 方法将获取的session 实例保存，而在doSomething 方法中，通过get 方法取<br />出session实例。<br />这也就是ThreadLocal的独特之处，它会为每个线程维护一个私有的变量空间。实际上，<br />其实现原理是在JVM 中维护一个Map，这个Map的key 就是当前的线程对象，而value则是<br />线程通过ThreadLocal.set方法保存的对象实例。当线程调用ThreadLocal.get方法时，<br />ThreadLocal会根据当前线程对象的引用，取出Map中对应的对象返回。<br />这样，ThreadLocal通过以各个线程对象的引用作为区分，从而将不同线程的变量隔离开<br />来。 <br />Hibernate官方开发手册的示例中，提供了一个通过ThreadLocal维护Session的好<br />榜样： <br /><br />public class HibernateUtil {<br />private static SessionFactory sessionFactory;<br />static {<br />try {<br />// Create the SessionFactory<br />sessionFactory = new<br />Configuration().configure().buildSessionFactory();<br />} catch (HibernateException ex) {<br />throw new RuntimeException(<br />"Configuration problem: " + ex.getMessage(),<br />ex<br />);<br />}<br />}<br />public static final ThreadLocal session = new ThreadLocal();<br />public static Session currentSession() throws HibernateException<br />{<br />Session s = (Session) session.get();<br />// Open a new Session, if this Thread has none yet<br />if (s == null) {<br />s = sessionFactory.openSession();<br />session.set(s);<br />}<br />return s;<br />}<br />public static void closeSession() throws HibernateException {<br />Session s = (Session) session.get();<br />session.set(null);<br />if (s != null)<br />s.close();<br />}<br />}<br />在代码中，只要借助上面这个工具类获取Session 实例，我们就可以实现线程范围内的<br />Session 共享，从而避免了在线程中频繁的创建和销毁Session 实例。不过注意在线程结束<br />时关闭Session。<br /><br />同时值得一提的是，新版本的Hibernate在处理Session的时候已经内置了延迟加载机<br />制，只有在真正发生数据库操作的时候，才会从数据库连接池获取数据库连接，我们不必过于担<br />心Session的共享会导致整个线程生命周期内数据库连接被持续占用。<br /><br /><br /><br />对于Web程序<br />而言，我们可以借助Servlet2.3规范中新引入的Filter机制，轻松实现线程生命周期内的<br />Session管理（关于Filter的具体描述，请参考Servlet2.3规范）。<br />Filter的生命周期贯穿了其所覆盖的Servlet（JSP也可以看作是一种特殊的Servlet）<br />及其底层对象。Filter在Servlet被调用之前执行，在Servlet调用结束之后结束。因此，<br />在Filter 中管理Session 对于Web 程序而言就显得水到渠成。下面是一个通过Filter 进<br />行Session管理的典型案例：<br />public class PersistenceFilter implements Filter<br />{<br />protected static ThreadLocal hibernateHolder = new ThreadLocal();<br />public void doFilter(ServletRequest request, ServletResponse<br />response, FilterChain chain)<br />throws IOException, ServletException<br />{<br />hibernateHolder.set(getSession());<br />try<br />{<br />......<br />chain.doFilter(request, response);<br />......<br />}<br />finally<br />{<br />Session sess = (Session)hibernateHolder.get();<br />if (sess != null)<br />{<br />hibernateHolder.set(null);<br />try<br />{<br />sess.close();<br />}<br />catch (HibernateException ex) {<br />throw new ServletException(ex);<br />}<br />}<br />}<br />}<br />......<br />Hibernate Developer's Guide Version 1.0<br />September 2, 2004 So many open source projects. Why not Open your Documents?<br />}<br />通过在doFilter中获取和关闭Session，并在周期内运行的所有对象（Filter链中其<br />余的Filter，及其覆盖的Servlet 和其他对象）对此Session 实例进行重用，保证了一个<br />Http Request处理过程中只占用一个Session，提高了整体性能表现。<br />在实际设计中，Session的重用做到线程级别一般已经足够，企图通过HttpSession实<br />现用户级的Session重用反而可能导致其他的问题。凡事不能过火，Session重用也一样。<br /></span>
				<br /> 转自:http://bbs.tech.ccidnet.com/read.php?tid=147661</font>
<img src ="http://www.blogjava.net/NeonWay/aggbug/68662.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/NeonWay/" target="_blank">王彦锋的技术实践</a> 2006-09-09 10:04 <a href="http://www.blogjava.net/NeonWay/archive/2006/09/09/68662.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>hibernate集合映射inverse和cascade详解 （转载）</title><link>http://www.blogjava.net/NeonWay/archive/2006/09/09/68659.html</link><dc:creator>王彦锋的技术实践</dc:creator><author>王彦锋的技术实践</author><pubDate>Sat, 09 Sep 2006 02:00:00 GMT</pubDate><guid>http://www.blogjava.net/NeonWay/archive/2006/09/09/68659.html</guid><wfw:comment>http://www.blogjava.net/NeonWay/comments/68659.html</wfw:comment><comments>http://www.blogjava.net/NeonWay/archive/2006/09/09/68659.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/NeonWay/comments/commentRss/68659.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/NeonWay/services/trackbacks/68659.html</trackback:ping><description><![CDATA[
		<font size="2">﻿4. hibernate如何根据pojo来更新数据库<br /><br />4.0 在commit/flush之前，hibernate不会对pojo对象作神秘的处理。<br />4.0.1 在select查询出pojo时，hibernate根据“字段--属性”的对应关系，用字段的值填充pojo的属性；<br />然后根据“关系标记”生成sql语句从relationTable中查询出满足条件的relationPojo，并把这些relatinPojo<br />放到“关系属性”中。这个过程是机械的。<br /><br />4.0.2 在pojo对象被查出来后，到commit(或flush)之前，它将是一个普通的java对象，hibernate不会做额外的手脚。<br />比如，不会限制你设置一个属性的值为null或其它任何值<br />在集合类Set的add(object)操作时， 不会改变object的值，不会检查参数object是否是一个pojo对象<br />设置mainPojo的一个“桥属性”的值，不会自动设置relationPojo的对应的“桥属性”的值。<br />执行session.delete(pojo)时，pojo本身没有变化，他的属性值也没有变化。<br />执行session.save(pojo)时，如果pojo的id不是hibernate或数据库生成,则它的值没有变化。<br />如果pojo的id是hibernate或数据库生成，则hibernate会把id给pojo设上去。<br /><br />extend: 对lazy=true的set，hibernate在进行set的操作(调用java.util.Set中声明的方法)时<br />会先inialize这个set，仅此而已。而inialize仅仅是从数据库中捞出set的数据。 <br />如果一个set已经被inialize了，那么对它进行的操作就是java.util.Set接口中定义的语义。<br /><br />另外，如果id由hibernate来生成，那么在save(pojo)时，hibernate会改变该pojo，会设置它的id，这<br />可能改变该pojo的hashCode，详细地讨论见帖《》<br /><br />mapping文件中标记的某些属性及pojo对象的操作会对数据库操作产生影响，这些影响都是在commit时才会起作用。<br />而在commit前pojo的状态不受它们的影响。<br /><br />不过，待commit之时，将由hibernate完全掌控，它好像知道pojo对象从创建到commit这中间的所有变化。<br /><br /><br />4.01. 关联更新<br />"关系标记"对应的属性是一个pojo或一个pojo的集合，修改“关系属性”的值能会导致更新mainTable表，也可能会更新relationTable表。<br /><br />这种更新暂叫“关联更新”。<br /><br /><br />4.1.inverse属性的作用（假定没有设置cascade属性） <br />4.1.1 “只有集合标记（set/map/list/array/bag）才有inverse属性”。<br />————不妨以标记set为例，具体为“一个地区（Address表）的学校（School表）” -- address.schoolSet。<br /><br />4.1.2 “set的inverse属性决定是否把对set的改动反映到数据库中去。<br />inverse=false————反映；inverse=true————不反映”<br />inverse属性默认为false<br /><br />对&lt;one-to-many&gt;和&lt;many-to-many&gt;子标记，这两条都适用。<br />不管是对set做什么操作，4.1.2都适用。<br /><br />4.1.3当inverse=false时，hibernate如何将对set的改动反映到数据库中：<br /><br />对set的操作主要有：（1）新增元素 address.getSchoolSet().add(oneSchool);<br />（2）删除元素 address.getSchoolSet().remove(oneSchool);<br />（3）删除set address.setSchoolSet(null);<br />（4）设新set address.setSchoolSet( newSchoolSet);<br />（5）转移set otherSchoolSet = otherAddress.getSchoolSet();<br />otherAddress.setSchoolSet(null);<br />address.setSchoolSet(otherSchoolSet);<br />（6）改变set中元素的属性的值 如果是改变key属性，这会导致异常<br />如果改变的是普通的属性，则hibernate认为set没有变化（在后面可以看出缘由）。<br />所以这种情形不予考虑。<br /><br />改变set后，hibernate对数据库的操作根据是&lt;one-to-many&gt;关系还是&lt;many-to-many&gt;关系而有不同。<br /><br />对one-to-many，对school set的改动，会改变表SCHOOL中的数据:<br />#SCHOOL_ID是school表的主键，SCHOOL_ADDRESS是school表中的地址栏位<br />#表School的外键为SCHOOL_ADDRESS，它对应表Address的主键ADDRESS_ID<br />（11）insert oneSchool———— sqlInsertRowString: <br />update SCHOOL set SCHOOL_ADDRESS=? where SCHOOL_ID=? <br />(仅仅update foreign-key的值。)<br />（22）delete oneSchool———— sqlDeleteRowString: <br />update SCHOOL set SCHOOL_ADDRESS=null where SCHOOL_ID=?<br />（很奇怪，把foreign-key设置为null不知道有什么实际意义？）<br />（33）delete 属于某一address的所有school ————sqlDeleteString：<br />update SCHOOL set SCHOOL_ADDRESS=null where SCHOOL_ADDRESS=?<br />（44）update ————sqlUpdateRowString：""， no need<br /><br />对many-to-many，对school set的改动，会改变关系表ADDRESS_SCHOOL中的数据:<br />#“地区————学校”的关系为多对多的关系有点牵强，只是为了方便与上面的one-to-many作比较<br />#假设有一个关系表ADDRESS_SCHOOL，有两个字段ADDRESS_ID, SCHOOL_ID，<br />#这两个字段分别对应ADDRESS和SCHOOL两表的key<br />（11）insert的SQL语句为： insert into ADDRESS_SCHOOL(ADDRESS_ID, SCHOOL_ID) <br />values(?,?)<br />（22）delete的SQL语句为： delete from ADDRESS_SCHOOL <br />where ADDRESS_ID=? AND SCHOOL_ID=?<br />（33）delete all的SQL语句为： delete from ADDRESS_SCHOOL<br />where ADDRESS_ID=?<br />（44）update的sql语句为 ————sqlUpdateRowString：<br />update ADDRESS_SCHOOL set ADDRESS_ID=?<br />where ADDRESS_ID=? AND SCHOOL_ID=?<br /><br />对set的操作(1),hibernate会执行(11)sqlInsertRowString<br />对set的操作(2),hibernate会执行(22)sqlDeleteRowString<br />对set的操作(3),hibernate会执行(33)sqlDeleteString<br />对set的操作(4),老的schoolSet因为没有所属的address,所以被全部delete掉，即先执行(33)sqlDeleteString<br />然后新增新的schoolSet,即再执行sqlInsertRowString<br />对set的操作(5)，实际上就是将set从一个pojo转移到另一pojo：<br />首先，执行sqlDeleteString，删除掉otherAddress所属的school<br />然后，执行sqlDeleteString，删除掉address原先的school<br />最后，执行sqlInsertRowString，将otherSchoolSet新增给address<br /><br />总结：（1）对one-to-many而言，改变set，会让hibernate执行一系列的update语句， 不会delete/insert数据<br />（2）对many-to-many而言，改变set,只修改关系表的数据，不会影响many-to-many的另一方。<br />（3）虽然one-to-many和many-to-many的数据库操作不一样，但目的都是一个：维护数据的一致性。执行的sql都<br />只涉及到“桥字段”，不会考虑或改变其他的字段，所以对set的操作(6)是没有效果地。<br />extend:对list,可能还会维护index字段。<br /><br />4.1.4 “inverse与cascade没有什么关系，互无牵扯。”<br />commit后，这两个属性发挥作用的时机不同，hibernate会根据对pojo对象的改动，及cascade属性的设置，<br />生成一系列的Action，比如UpdateAction,DeleteAction,InsertAction等，每个Action都有execute方法以执行对应的sql语句。<br />待所有这些Action都生成好了后，hibernate再一起执行它们，在执行sql前，inverse属性起作用，<br />当inverse=true时，不执行sql；当inverse=false时，执行sql。<br /><br />4.1.5 inverse的默认值为false，所以inverse属性默认会进行“关联更新”。<br /><br />4.1.6 建议：只对set + many-to-many设置inverse=false，其他的标记不考虑inverse属性。<br />  糟糕的是，不设置inverse属性时，inverse默认为false。<br /><br />4.2. 级联（cascade）属性的作用： <br />4.2.1 只有“关系标记”才有cascade属性：many-to-one，one-to-one ，any, <br />set(map, bag, idbag, list, array) + one-to-many(many-to-many)<br /><br />4.2.2 级联指的是当主控方执行操作时，关联对象（被动方）是否同步执行同一操作。<br />pojo和它的关系属性的关系就是“主控方 -- 被动方”的关系，如果关系属性是一个set，那么被动方就是set中的一个一个元素，。<br />比如：学校（School）有三个属性：地区(Address),校长（TheMaster）和学生(Set， 元素为Student)<br />执行session.delete(school)时，级联决定是否执行session.delete(Address),session.delete(theMaster)，<br />是否对每个aStudent执行session.delete(aStudent)。<br /><br />extend:这点和inverse属性是有区别的。见4.3.<br /><br />4.2.3 一个操作因级联cascade可能触发多个关联操作。前一个操作叫“主控操作”，后一个操作叫“关联操作”。<br />cascade属性的可选值：<br />all : 所有情况下均进行关联操作。<br />none：所有情况下均不进行关联操作。这是默认值。<br />save-update:在执行save/update/saveOrUpdate时进行关联操作。<br />delete：在执行delete时进行关联操作。 <br /><br />具体执行什么“关联操作”是根据“主控操作”来的：<br />“主控操作”       “关联操作”<br />session.saveOrUpdate --&gt; session.saveOrUpdate (执行saveOrUpdate实际上会执行save或者update)<br />session.save ----&gt; session.saveOrUpdate<br />session.udpate --&gt; session.saveOrUpdate<br />session.delete --&gt; session.delete<br /><br />4.2.4 主控操作和关联操作的先后顺序是“先保存one，再保存many；先删除many，再删除one；先update主控方，再update被动方”<br />对于one-to-one，当其属性constrained="false"（默认值）时，它可看作one-to-many关系；<br />  当其属性constrained="true"时，它可看作many-to-one关系；<br />对many-to-many，它可看作one-to-many。<br /><br />比如：学校（School）有三个属性：地区(Address),校长（TheMaster，其constrained="false"）和学生(Set， 元素为Student) <br />当执行session.save(school)时，<br />实际的执行顺序为：session.save(Address);<br />session.save(school);<br />session.save(theMaster);<br />for( 对每一个student ){<br />session.save(aStudent);<br />}<br /><br />当执行session.delete(school)时，<br />实际的执行顺序为：session.delete(theMaster);<br />for( 对每一个student ){<br />session.delete(aStudent);<br />}<br />session.delete(school);<br />session.delete(Address);<br /><br />当执行session.update(school)时，<br />实际的执行顺序为：session.update(school);<br />session.saveOrUpdate(Address);<br />session.saveOrUpdate(theMaster);<br />for( 对每一个student ){<br />session.saveOrUpdate(aStudent);<br />}<br />注意：update操作因级联引发的关联操作为saveOrUpdate操作，而不是update操作。<br />saveOrUpdate与update的区别是：前者根据操作对象是保存了还是没有保存，而决定执行update还是save<br /><br />extends: 实际中，删除学校不会删除地区，即地区的cascade一般设为false<br />另外，many-to-many关系很少设置cascade=true，而是设置inverse=false。这个反映了cascade和inverse的区别。见4.3<br /><br />4.2.6 cascade的默认值为false，所以inverse属性默认会进行“关联更新”。<br /><br />4.2.7 总结：级联（cascade）就是操作一个对象时，对它的属性（其cascade=true）也进行这个操作。<br /><br /><br />4.3 inverse和cascade的比较<br />这两个属性本身互不影响，但起的作用有些类似，都能引发对关系表的更新。<br /><br />4.3.1 inverse只对set+one-to-many(或many-to-many)有效，对many-to-one, one-to-one无效。<br />cascade对关系标记都有效。<br /><br />4.3.2 inverse对集合对象整体起作用，cascade对集合对象中的一个一个元素起作用，如果集合为空，那么cascade不会引发关联操作。<br />比如将集合对象置为null， school.setStudentSet(null)<br />inverse导致hibernate执行:udpate STUDENT set SCHOOL_ID=null where SCHOOL_ID=?<br />cascade则不会执行对STUDENT表的关联更新， 因为集合中没有元素。<br /><br />再比新增一个school, session.save(school)<br />inverse导致hibernate执行：<br />for( 对(school的每一个student ){<br />udpate STUDENT set SCHOOL_ID=? where STUDENT_ID=? //将学生的school_id改为新的school的id<br />}<br />cascade导致hibernate执行：<br />for( 对school的每一个student ){<br />session.save(aStudent); //对学生执行save操作<br />}<br /><br />extends:如果改变集合中的部分元素（比如新增一个元素），<br />inverse: hibernate先判断哪些元素改变了，对改变的元素执行相应的sql<br />cascade: 它总是对集合中的每个元素执行关联操作。<br />（在关联操作中，hibernate会判断操作的对象是否改变）<br /><br />4.3.2 两个起作用的时机不同：<br />cascade：在对主控方操作时，级联发生。<br />inverse: 在flush时（commit会自动执行flush)，对session中的所有set，hibernate判断每个set是否有变化，<br />对有变化的set执行相应的sql，执行之前，会有个判断：if( inverse == true ) return;<br /><br />可以看出cascade在先，inverse在后。<br /><br />4.3.3 inverse 对set + one-to-many 和 set + many-to-many 起的作用不同。hibernate生成的sql不同。<br />对one-to-many，hibernate对many方的数据库表执行update语句。<br />对many-to-many, hibernate对关系表执行insert/update/delte语句，注意不是对many方的数据库表而是关系表。<br /><br />cascase 对set都是一致的，不管one-to-many还是many-to-many。都简单地把操作传递到set中的每个元素。所以它总是更新many<br />方的数据库表。<br /><br />4.3.4 建议：只对set + many-to-many设置inverse=false，其他的标记不考虑inverse属性，都设为inverse=true。<br />  <br />  对cascade，一般对many-to-one，many-to-many，constrained=true的one-to-one 不设置级联删除。<br /><br />引自：<a href="http://bbs.tech.ccidnet.com/simple/index.php?t144447.html">http://bbs.tech.ccidnet.com/simple/index.php?t144447.html</a></font>
<img src ="http://www.blogjava.net/NeonWay/aggbug/68659.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/NeonWay/" target="_blank">王彦锋的技术实践</a> 2006-09-09 10:00 <a href="http://www.blogjava.net/NeonWay/archive/2006/09/09/68659.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>正确优雅的解决用户退出问题——JSP和Struts解决方案 </title><link>http://www.blogjava.net/NeonWay/archive/2006/09/08/68519.html</link><dc:creator>王彦锋的技术实践</dc:creator><author>王彦锋的技术实践</author><pubDate>Fri, 08 Sep 2006 07:11:00 GMT</pubDate><guid>http://www.blogjava.net/NeonWay/archive/2006/09/08/68519.html</guid><wfw:comment>http://www.blogjava.net/NeonWay/comments/68519.html</wfw:comment><comments>http://www.blogjava.net/NeonWay/archive/2006/09/08/68519.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/NeonWay/comments/commentRss/68519.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/NeonWay/services/trackbacks/68519.html</trackback:ping><description><![CDATA[
		<p>如下：<br /><a href="/majianan/archive/2006/08/24/65147.html">http://www.blogjava.net/majianan/archive/2006/08/24/65147.html</a></p>
<img src ="http://www.blogjava.net/NeonWay/aggbug/68519.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/NeonWay/" target="_blank">王彦锋的技术实践</a> 2006-09-08 15:11 <a href="http://www.blogjava.net/NeonWay/archive/2006/09/08/68519.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>昨天发现的关于servlet部署和jdbc异常的问题</title><link>http://www.blogjava.net/NeonWay/archive/2006/08/30/66573.html</link><dc:creator>王彦锋的技术实践</dc:creator><author>王彦锋的技术实践</author><pubDate>Wed, 30 Aug 2006 01:55:00 GMT</pubDate><guid>http://www.blogjava.net/NeonWay/archive/2006/08/30/66573.html</guid><wfw:comment>http://www.blogjava.net/NeonWay/comments/66573.html</wfw:comment><comments>http://www.blogjava.net/NeonWay/archive/2006/08/30/66573.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/NeonWay/comments/commentRss/66573.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/NeonWay/services/trackbacks/66573.html</trackback:ping><description><![CDATA[
		<font size="2">一、servlet部署问题：<br />       在已经正常运行的系统中，如果添加一个新的servlet时，在拷贝类文件时要注意，一定要定该servlet关联的所有类都拷贝到相应目录下，否则，servlet在部署时不提示任何错误，但却不能部署成功。<br /><br />二、关于jdbc的"[org.hibernate.util.JDBCExceptionReporter] - 对象名 '*******' 无效"异常问题: <br />       出现该异常，毫无疑问是在数据库中找不到对应的表，其实不是Hibernbate异常，Hibernate只不过是把Jdbc异常给抛了处来，出现这样的情况，请先检查映射文件的数据库表是否正确。</font>
<img src ="http://www.blogjava.net/NeonWay/aggbug/66573.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/NeonWay/" target="_blank">王彦锋的技术实践</a> 2006-08-30 09:55 <a href="http://www.blogjava.net/NeonWay/archive/2006/08/30/66573.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>tomcat中的几点配置说明</title><link>http://www.blogjava.net/NeonWay/archive/2006/05/09/45175.html</link><dc:creator>王彦锋的技术实践</dc:creator><author>王彦锋的技术实践</author><pubDate>Tue, 09 May 2006 04:08:00 GMT</pubDate><guid>http://www.blogjava.net/NeonWay/archive/2006/05/09/45175.html</guid><wfw:comment>http://www.blogjava.net/NeonWay/comments/45175.html</wfw:comment><comments>http://www.blogjava.net/NeonWay/archive/2006/05/09/45175.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/NeonWay/comments/commentRss/45175.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/NeonWay/services/trackbacks/45175.html</trackback:ping><description><![CDATA[
		<div>
				<h2>
						<a name="0">
						</a>
						<b style="COLOR: black; BACKGROUND-COLOR: #ffff66">tomcat</b>中的几点配置说明 </h2>
				<div class="postbody">
						<font class="f14" id="zoom">
								<b>1. 如何加大<b style="COLOR: black; BACKGROUND-COLOR: #ffff66">tomcat</b><a name="1"></a><b style="COLOR: black; BACKGROUND-COLOR: #a0ffff">连接数</b></b>
								<br />
								<p style="LINE-HEIGHT: 150%">在<b style="COLOR: black; BACKGROUND-COLOR: #ffff66">tomcat</b>配置文件server.xml中的<connector ...="" />配置中，和<b style="COLOR: black; BACKGROUND-COLOR: #a0ffff">连接数</b>相关的参数有：<br />minProcessors：最小空闲连接线程数，用于提高系统处理性能，默认值为10<br />maxProcessors：最大连接线程数，即：并发处理的最大请求数，默认值为75<br />acceptCount：允许的最大<b style="COLOR: black; BACKGROUND-COLOR: #a0ffff">连接数</b>，应大于等于maxProcessors，默认值为100<br />enableLookups：是否反查域名，取值为：true或false。为了提高处理能力，应设置为false<br />connectionTimeout：网络连接超时，单位：毫秒。设置为0表示永不超时，这样设置有隐患的。通常可设置为30000毫秒。<br /><br />其中和最大<b style="COLOR: black; BACKGROUND-COLOR: #a0ffff">连接数</b>相关的参数为maxProcessors和acceptCount。如果要加大并发<b style="COLOR: black; BACKGROUND-COLOR: #a0ffff">连接数</b>，应同时加大这两个参数。<br /></p>
								<p style="LINE-HEIGHT: 150%">web server允许的最大<b style="COLOR: black; BACKGROUND-COLOR: #a0ffff">连接数</b>还受制于操作系统的内核参数设置，通常Windows是2000个左右，Linux是<a name="3"></a><b style="COLOR: black; BACKGROUND-COLOR: #ff9999">1000</b>个左右。Unix中如何设置这些参数，请参阅<a href="http://www.ee2ee.com/tech_art/2/30.html" target="_blank">Unix常用监控和管理命令</a></p>
								<b style="COLOR: black; BACKGROUND-COLOR: #ffff66">tomcat</b>4中的配置示例：<br /><connector><br classname="org.apache.coyote.tomcat4.CoyoteConnector" />port="8080" minProcessors="10" maxProcessors="1024"<br />enableLookups="false" redirectPort="8443"<br />acceptCount="1024" debug="0" connectionTimeout="30000" /&gt; <br /><br />对于其他端口的侦听配置，以此类推。<br /><br /><b>2. <b style="COLOR: black; BACKGROUND-COLOR: #ffff66">tomcat</b>中如何禁止列目录下的文件</b><br />在{<b style="COLOR: black; BACKGROUND-COLOR: #ffff66">tomcat</b>_home}/conf/web.xml中，把listings参数设置成false即可，如下：<br /><servlet><br />...<br /><init-param><br /><param-name>listings</param-name><br /><param-value>false</param-value><br /></init-param><br />...<br /></servlet><br /><br /><b>3. 如何加大<b style="COLOR: black; BACKGROUND-COLOR: #ffff66">tomcat</b>可以使用的内存</b><br /><p style="LINE-HEIGHT: 150%"><b style="COLOR: black; BACKGROUND-COLOR: #ffff66">tomcat</b>默认可以使用的内存为128MB，在较大型的应用项目中，这点内存是不够的，需要调大。<br /><br />Unix下，在文件{<b style="COLOR: black; BACKGROUND-COLOR: #ffff66">tomcat</b>_home}/bin/catalina.sh的前面，增加如下设置：<br />JAVA_OPTS='-Xms【初始化内存大小】 -Xmx【可以使用的最大内存】'<br />需要把这个两个参数值调大。例如：<br />JAVA_OPTS='-Xms256m -Xmx512m'<br />表示初始化内存为256MB，可以使用的最大内存为512MB <br />摘自：<a href="http://blog.sina.com.cn/u/40d8d6f8010002ra">http://blog.sina.com.cn/u/40d8d6f8010002ra</a></p></connector></font>
				</div>
		</div>
<img src ="http://www.blogjava.net/NeonWay/aggbug/45175.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/NeonWay/" target="_blank">王彦锋的技术实践</a> 2006-05-09 12:08 <a href="http://www.blogjava.net/NeonWay/archive/2006/05/09/45175.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>解决Hibernate的如下错误 JDBC error: Unsupported method: Connection.prepareStatement</title><link>http://www.blogjava.net/NeonWay/archive/2006/03/17/35853.html</link><dc:creator>王彦锋的技术实践</dc:creator><author>王彦锋的技术实践</author><pubDate>Fri, 17 Mar 2006 10:23:00 GMT</pubDate><guid>http://www.blogjava.net/NeonWay/archive/2006/03/17/35853.html</guid><wfw:comment>http://www.blogjava.net/NeonWay/comments/35853.html</wfw:comment><comments>http://www.blogjava.net/NeonWay/archive/2006/03/17/35853.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/NeonWay/comments/commentRss/35853.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/NeonWay/services/trackbacks/35853.html</trackback:ping><description><![CDATA[
		<p>
				<font size="2">在配置weblogic数据源和连接池时，由于建立连接池采用的weblogic的默认sqlserver jdbc驱动程序weblogic.jdbc.sqlserver.SQLServerDriver,这给我下面的工作带来很大的麻烦。我在进行session.save()时，提示错误 JDBC error: Unsupported method: Connection.prepareStatement ,很是让我纳闷，百思不得其解，后google一下，得到了bea 工程师的解答，如下:<br /> Well, that's clearly one of them. I would contact Hibernate/Plum Tree<br /> about this, and ask how many JDBC drivers they've tested this with.<br /> I would venture an educated guess that many JDBC drivers will not<br /> be able to completely implement all the JDBC 3.0 methods in the<br /> spec's wishlist.... MHO,<br /> Joe Weinstein at BEA Systems </font>
		</p>
		<p>
				<font size="2">    可以看出，bea提供的sqlserver驱动没有完全实现 jdbc的方法，而hibernate3却调用了Connection.prepareStatement 方法，碰巧该方法不实现，就出现上述错误。</font>
		</p>
<img src ="http://www.blogjava.net/NeonWay/aggbug/35853.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/NeonWay/" target="_blank">王彦锋的技术实践</a> 2006-03-17 18:23 <a href="http://www.blogjava.net/NeonWay/archive/2006/03/17/35853.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>配置hibernate为weblogic上的JNDI</title><link>http://www.blogjava.net/NeonWay/archive/2006/03/17/35852.html</link><dc:creator>王彦锋的技术实践</dc:creator><author>王彦锋的技术实践</author><pubDate>Fri, 17 Mar 2006 10:20:00 GMT</pubDate><guid>http://www.blogjava.net/NeonWay/archive/2006/03/17/35852.html</guid><wfw:comment>http://www.blogjava.net/NeonWay/comments/35852.html</wfw:comment><comments>http://www.blogjava.net/NeonWay/archive/2006/03/17/35852.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/NeonWay/comments/commentRss/35852.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/NeonWay/services/trackbacks/35852.html</trackback:ping><description><![CDATA[
		<p>
				<font size="2">今天成功配置hibernate为weblogic上的JNDI,具体实现参考了robbin的教程，实现步骤如下:</font>
		</p>
		<p>
				<font size="2">前提如下：</font>
		</p>
		<p>
				<font size="2">我的hibernate项目结构如下:<br />  E:\eclipse_workspace\hibernateJndi\lib        hibernate用到的包及其他系统使用的包,包括weblogic.jar，已通过下面要编写的启动类<br />  E:\eclipse_workspace\hibernateJndi\src        源文件<br />  E:\eclipse_workspace\hibernateJndi\classes    系统编译后的类文件，存放hibernate.cfg.xml、log4j.properties等文件</font>
		</p>
		<p>
				<font size="2">  具体步骤如下：<br />  一、修改weblogic的ClassPath<br />      现在需要把E:\eclipse_workspace\hibernateJndi\lib目录下那些与hibernate相关jar文件和E:\eclipse_workspace\hibernateJndi\classes 目录都放置到Weblogic的 CLASSPATH里面去，所以修改mydomain里面的Weblogic启动脚本startWeblogic.cmd，在启动Weblogic之前，插入设置CLASSPATH的命令，如下： </font>
		</p>
		<p>
				<font size="2">      @rem set hibernate classpath <br />      set HIBERNATE_LIB=E:\eclipse_workspace\hibernateJndi\lib <br />      set HIBERNATE_CLASSES=E:\eclipse_workspace\hibernateJndi\classes<br />      set CLASSPATH=%HIBERNATE_LIB%\asm.jar;%HIBERNATE_LIB%\asm-attrs.jar;%HIBERNATE_LIB%\c3p0-0.9.0.jar;%HIBERNATE_LIB%\cglib-2.1.3.jar;%HIBERNATE_LIB%\commons-beanutils.jar;%HIBERNATE_LIB%\commons-collections.jar;%HIBERNATE_LIB%\commons-lang-2.0.jar;%HIBERNATE_LIB%\commons-logging.jar;%HIBERNATE_LIB%\dom4j-1.6.1.jar;%HIBERNATE_LIB%\hibernate3.jar;%HIBERNATE_LIB%\log4j-1.2.11.jar;%HIBERNATE_CLASSES%;%CLASSPATH%;</font>
		</p>
		<p>
				<font size="2">     下面就是启动weblogic了,不用修改<br />     <br />      @REM Call WebLogic Server<br />      ...</font>
		</p>
		<p>
				<font size="2">   二、添加weblogic的数据库连接池和数据源<br />       我用的是sqlserver 2000,建立数据库连接池，建立数据源sqlserverSource,使用刚才建立的连接池。<br />   </font>
		</p>
		<p>
				<font size="2">   三、修改classes目录下的hibernate.cfg.xml。该文件放到classes下，发布web应时，把mapping文件加上去，使用Weblogic的连接池，而不是自带的连接池,以后访问的jndi名为hhibernate/session_factory 如下:<br />       &lt;?xml version='1.0' encoding='UTF-8'?&gt;<br /> &lt;!DOCTYPE hibernate-configuration PUBLIC<br />          "-//Hibernate/Hibernate Configuration DTD 3.0//EN"<br />          "</font>
				<a href="http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
						<font size="2">http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd</font>
				</a>
				<font size="2">"&gt;<br /> &lt;hibernate-configuration&gt;</font>
		</p>
		<p>
				<font size="2"> &lt;session-factory&gt;<br />  &lt;property name="hibernate.connection.datasource"&gt;sqlserverSource&lt;/property&gt;<br />  &lt;property name="hibernate.connection.provider_class"&gt;org.hibernate.connection.DatasourceConnectionProvider&lt;/property&gt;<br />  &lt;property name="hibernate.session_factory_name"&gt;hibernate.session_factory&lt;/property&gt;<br />  &lt;property name="hibernate.show_sql"&gt;true&lt;/property&gt;<br />  &lt;property name="hibernate.jdbc.fetch_size"&gt;100&lt;/property&gt;<br />  &lt;property name="hibernate.jdbc.batch_size"&gt;50&lt;/property&gt;<br />  &lt;property name="hibernate.dialect"&gt;org.hibernate.dialect.SQLServerDialect&lt;/property&gt;<br />  &lt;mapping resource="zx/common/model/User.hbm.xml" /&gt;<br /> &lt;/session-factory&gt;</font>
		</p>
		<p>
				<font size="2"> &lt;/hibernate-configuration&gt;</font>
		</p>
		<p>
				<font size="2">      这是使用 Hibernate来绑定JNDI ,给JNDI起的名称，本来应该是hibernate/session_factory，但是Weblogic要求改为. 号，不过在程序中lookup的时候还是要写hibernate/session_factory </font>
		</p>
		<p>
				<font size="2">  四、建立启动类，并编译<br /> package zx.util;<br /> import java.util.Hashtable; <br /> import weblogic.common.T3StartupDef; <br /> import weblogic.common.T3ServicesDef; <br /> import org.hibernate.cfg.Configuration; <br /> import org.hibernate.SessionFactory; </font>
		</p>
		<p>
				<font size="2"> /**<br />  * 郑州市正信科技发展有限公司 版权所有 2006<br />  * &lt;p/&gt;创 建 人：Robbin,王彦锋<br />  * &lt;p/&gt;创建日期：2006-3-17<br />  * &lt;p/&gt;创建时间：10:17:56<br />  * &lt;p/&gt;功能描述：Hibernate启动类<br />  * &lt;p/&gt;==============================================================<br />  * &lt;p/&gt;修改历史<br />  * &lt;p/&gt;修改人                修改时间                修改原因<br />  * &lt;p/&gt;==============================================================<br />  */</font>
		</p>
		<p>
				<font size="2"> public class HibernateStartUp implements T3StartupDef { </font>
		</p>
		<p>
				<font size="2">   public void setServices(T3ServicesDef services) {} </font>
		</p>
		<p>
				<font size="2">   public String startup(String name, Hashtable args) throws Exception { <br />     SessionFactory sf =  new Configuration().configure().buildSessionFactory(); <br />     return "Hibernate Startup completed successfully"; <br />   } <br /> }</font>
		</p>
		<p>
				<br />
				<font size="2">   五、配置StartUp类 <br /> 启动Weblogic，打开Console控制台，在左边的Applet树上找到StartUp &amp; Shutdown，然后在右边点击“Configure a new Startup Class...”，在Name框里面随便填写，在ClassName里面填写你编写的StartUp类，zx.util.HibernateStartUp ，然后点击“Apply”。然后切换到Target这选项卡，在Target-Server左边的 Avaiable框里面选择“myserver”，点击右箭头，把它挪到右边的“Chosen”框里面去，最后再点击一下“Apply"按钮。如果此时 Weblogic的DOS窗口里面没有出错信息，那么应该已经配置成功了。 </font>
		</p>
		<p>
				<br />
				<font size="2">    六、重启wblogic<br />       关闭Weblogic，再重新运行 startWelogic.cmd，启动Weblogic，观察DOS窗口的输出信息，可以看到Hibernate的初始化信息一屏屏的滚动输出，证明已    经配置成功。现在再打开Console控制台，点击左边Applet树中的Servers|myserver，然后可以在右边最下面找到“View JNDI tree ”，点击它，会打开一    个浏览器窗口，显示JNDI树，这时你可以看到一个名称为hibernate的JNDI对象，在左边的Applet树中点击它，看右边的详细信息，我的机器上的信息如下： <br /> <br />    绑定名称: session_factory <br />    对象类: org.hibernate.impl.SessionFactoryImpl <br />    对象散列代码: 10578812 <br />    对象转换成字符串: </font>
				<a href="mailto:org.hibernate.impl.SessionFactoryImpl@a16b7c">
						<font size="2">org.hibernate.impl.SessionFactoryImpl@a16b7c</font>
				</a>
				<font size="2">
				</font>
		</p>
		<p>
				<font size="2">  <br />  七、调用方法,获得SessionFactory</font>
		</p>
		<p>
				<font size="2">        try {<br />            Context ctx = new InitialContext();<br />            String jndiName = "hibernate/session_factory";<br />            sessionFactory = (SessionFactory) ctx.lookup(jndiName);<br />        } catch (Exception ex) {<br />            throw ex;<br />        }</font>
		</p>
		<p>
				<br />
				<font size="2">  配置成功！ </font>
		</p>
		<p>
				<font size="2">注：如果要随同web应用一块发布，修改相应目录即可：</font>
		</p>
		<p>
				<font size="2">      set HIBERNATE_LIB=%bea_home%\user_projects\domains\mydomain\applications\myapp\WEB-INF\lib<br />      set HIBERNATE_CLASSES=%bea_home%\user_projects\domains\mydomain\applications\myapp\WEB-INF\classes<br /></font>
		</p>
<img src ="http://www.blogjava.net/NeonWay/aggbug/35852.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/NeonWay/" target="_blank">王彦锋的技术实践</a> 2006-03-17 18:20 <a href="http://www.blogjava.net/NeonWay/archive/2006/03/17/35852.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hibernate使用Weblogic的数据源</title><link>http://www.blogjava.net/NeonWay/archive/2006/03/16/35700.html</link><dc:creator>王彦锋的技术实践</dc:creator><author>王彦锋的技术实践</author><pubDate>Thu, 16 Mar 2006 10:40:00 GMT</pubDate><guid>http://www.blogjava.net/NeonWay/archive/2006/03/16/35700.html</guid><wfw:comment>http://www.blogjava.net/NeonWay/comments/35700.html</wfw:comment><comments>http://www.blogjava.net/NeonWay/archive/2006/03/16/35700.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/NeonWay/comments/commentRss/35700.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/NeonWay/services/trackbacks/35700.html</trackback:ping><description><![CDATA[
		<p>
				<font style="BACKGROUND-COLOR: #ffffff" color="#000000" size="2">今日经过几个小时的测试与调试，成功完成Hibernate调用Weblogic的数据源，其实不是什么大问题，如果有Spirng来做这事，就简单多了，现在的项目没有利用Spring,而是Struts + Hibernate,在weblogic上运行，不罗嗦了，具体步骤如下:<br />一、安装weblogic,配置数据库连接池和数据源。我使用的是SqlServer 2000 ,数据源名称为myDataSource;<br />二、Hibernate的配置文件如下:<br /> &lt;?xml version='1.0' encoding='UTF-8'?&gt;<br /> &lt;!DOCTYPE hibernate-configuration PUBLIC<br />    "-//Hibernate/Hibernate Configuration DTD 3.0//EN"<br />    "</font>
				<a href="http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
						<font style="BACKGROUND-COLOR: #ffffff" color="#000000" size="2">http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd</font>
				</a>
				<font style="BACKGROUND-COLOR: #ffffff" color="#000000" size="2">"&gt;</font>
		</p>
		<p>
				<font style="BACKGROUND-COLOR: #ffffff" color="#000000" size="2"> &lt;hibernate-configuration&gt;</font>
		</p>
		<p>
				<font style="BACKGROUND-COLOR: #ffffff" color="#000000" size="2"> &lt;session-factory&gt;<br />  &lt;property name="hibernate.connection.datasource"&gt;myDataSource&lt;/property&gt;<br />  &lt;property name="hibernate.connection.provider_class"&gt;org.hibernate.connection.DatasourceConnectionProvider&lt;/property&gt;<br />  &lt;property name="hibernate.jndi.class"&gt;weblogic.jndi.WLInitialContextFactory&lt;/property&gt;<br />  &lt;property name="hibernate.show_sql"&gt;true&lt;/property&gt;<br />  &lt;property name="hibernate.jdbc.fetch_size"&gt;100&lt;/property&gt;<br />  &lt;property name="hibernate.jdbc.batch_size"&gt;50&lt;/property&gt;<br />  &lt;property name="hibernate.dialect"&gt;org.hibernate.dialect.SQLServerDialect&lt;/property&gt;<br />  <br />  <br />  &lt;property name="hibernate.query.factory_class"&gt;org.hibernate.hql.classic.ClassicQueryTranslatorFactory&lt;/property&gt;<br />     <br />      <br />      &lt;mapping resource="zx/common/model/User.hbm.xml" /&gt;</font>
		</p>
		<p>
				<font style="BACKGROUND-COLOR: #ffffff" color="#000000" size="2"> &lt;/session-factory&gt;</font>
		</p>
		<p>
				<font style="BACKGROUND-COLOR: #ffffff" color="#000000" size="2"> &lt;/hibernate-configuration&gt;</font>
		</p>
		<p>
				<font style="BACKGROUND-COLOR: #ffffff" color="#000000" size="2">   注意: 在运行过程中出现ClassNotFoundException: org.hibernate.hql.ast.HqlToken，则配置hibernate.query.factory_class就可以解决了.</font>
		</p>
		<p>
				<font style="BACKGROUND-COLOR: #ffffff" color="#000000" size="2">三、相关持久类、映射文件 省略</font>
		</p>
		<p>
				<font style="BACKGROUND-COLOR: #ffffff" color="#000000" size="2">四、调用<br />             //SessionFactory sessions =  new Configuration().buildSessionFactory();          <br />           SessionFactory sessions = new Configuration().configure().buildSessionFactory();<br />           Session session = sessions.openSession(); <br />           Query query =  session.createQuery(" from User as t ");           <br />           List list = query.list();</font>
		</p>
		<p>
				<font style="BACKGROUND-COLOR: #ffffff" color="#000000" size="2">五、一切ok!</font>
		</p>
		<p>
				<font style="BACKGROUND-COLOR: #ffffff" color="#000000" size="2">
				</font> </p>
<img src ="http://www.blogjava.net/NeonWay/aggbug/35700.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/NeonWay/" target="_blank">王彦锋的技术实践</a> 2006-03-16 18:40 <a href="http://www.blogjava.net/NeonWay/archive/2006/03/16/35700.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java面试的一些常见问题总结</title><link>http://www.blogjava.net/NeonWay/archive/2006/02/18/31382.html</link><dc:creator>王彦锋的技术实践</dc:creator><author>王彦锋的技术实践</author><pubDate>Sat, 18 Feb 2006 08:54:00 GMT</pubDate><guid>http://www.blogjava.net/NeonWay/archive/2006/02/18/31382.html</guid><wfw:comment>http://www.blogjava.net/NeonWay/comments/31382.html</wfw:comment><comments>http://www.blogjava.net/NeonWay/archive/2006/02/18/31382.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/NeonWay/comments/commentRss/31382.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/NeonWay/services/trackbacks/31382.html</trackback:ping><description><![CDATA[<P>Java基础方面:</P>
<P>1,作用域public,protected,private,以及不写时的区别</P>
<P>2,ArrayList和Vector的区别,HashMap和Hashtable的区别</P>
<P>3,char型变量能不能定义为一个中文?为什么?</P>
<P>4,多线程有几种表示方法,都是什么?同步有几种实现方法,都是什么?</P>
<P>5,继承时候类的执行顺序问题,一般都是选择题,问你将会打印出什么?</P>
<P>6,内部类的实现方式?</P>
<P>7,垃圾回收机制,如何优化程序?</P>
<P>8,float型float f=3.4是否正确?</P>
<P>Jsp方面</P>
<P>1,jsp有哪些内置对象?作用分别是什么?</P>
<P>2,jsp有哪些动作?作用分别是什么?</P>
<P>3,include的两种实现方式的区别?</P>
<P>4,两种跳转方式分别是什么?有什么区别?</P>
<P>Servlet方面</P>
<P>1,说一说Servlet的生命周期?</P>
<P>2,Servlet版本间(忘了问的是哪两个版本了)的不同?</P>
<P>Jdbc,Jdo方面</P>
<P>1,可能会让你写一段Jdbc连Oracle的程序.</P>
<P>2,Class.forName的作用?为什么要用?</P>
<P>3,Jdo是什么?</P>
<P>Xml方面</P>
<P>1,xml有哪些解析技术?区别是什么?</P>
<P>2,你在项目中用到了xml技术的哪些方面?如何实现的?</P>
<P>3,用jdom解析xml文件时如何解决中文问题?如何解析?</P>
<P>EJB方面</P>
<P>1,EJB2.0有哪些内容?分别用在什么场合? EJB2.0和EJB1.1的区别?</P>
<P>MVC方面</P>
<P>1,MVC的各个部分都有那些技术来实现?如何实现?</P>
<P>设计模式方面:</P>
<P>1,开发中都用到了那些设计模式?用在什么场合?</P>
<P>JavaScript方面</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1,如何校验数字型?</P>
<P>CORBA</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1,CORBA是什么?用途是什么?</P>
<P><BR>谁来做出解答阿！<BR>-------------------------------------------------------------<BR>回答一部分。<BR>1,作用域public,protected,private,以及不写时的区别<BR>public 在其他的包中的类也可以引用，protected只限于同一个包内的类，private只有自己可以使用。不写的时候和protected一样。<BR>2,ArrayList和Vector的区别,HashMap和Hashtable的区别<BR>ArrayList需要预先定义大小，Vector不用。HashMap和Hashtable的默认初始化容量（default initial capacity）不同 HashMap是16，Hashtable为11。<BR>3,char型变量能不能定义为一个中文?为什么?<BR>可以定义。因为中文也是16bit的。<BR>4,多线程有几种表示方法,都是什么?同步有几种实现方法,都是什么?<BR>查看jdk文档。<BR>5,继承时候类的执行顺序问题,一般都是选择题,问你将会打印出什么?<BR>这个具体的去看。<BR>6,内部类的实现方式?<BR>内部类”是在另一个类的内部声明的类。从Java 1.1开始，你可在一个类中声明另一个类，这与声明字段和方法非常相似。<BR>7,垃圾回收机制,如何优化程序?<BR>在变量不使用的时候将其赋值为null。<BR>8,float型float f=3.4是否正确?<BR>不行。类型不匹配。改为float f=3.4f。</P>
<P>Servlet方面</P>
<P>1,说一说Servlet的生命周期?<BR>Servlet的生命周期是当服务器装载运行servlets，接收来自客户端的多个请求并且返回数据给客户端，然后再删除移开servlets的时间。<BR>2,Servlet版本间(忘了问的是哪两个版本了)的不同?<BR>我个人认为这个问题没有什么实际意义。<BR>Jdbc,Jdo方面</P>
<P>1,可能会让你写一段Jdbc连Oracle的程序.<BR>有通式。Connection conn = null;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String driver = "oracle.jdbc.driver.OracleDriver";<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String url = "jdbc:oracle:thin:@xxx:1521:xxx";<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String user = "xxx";<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String password = "xxx";<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Class.forName("oracle.jdbc.driver.OracleDriver");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; conn = DriverManager.getConnection(url, user, password);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch (ClassNotFoundException e)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.err.print("ClassNotFoundException: Load jdbc-driver failure!");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.err.println(e.getMessage());<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch (SQLException e)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; e.printStackTrace();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try<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;&nbsp; if (conn != null)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; conn.close();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; conn = null;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch (SQLException se)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>2,Class.forName的作用?为什么要用?<BR>返回一个指定名称的class对象。用它是为了load你指定名称的class。<BR>3,Jdo是什么?<BR>全称Java Data Objects。提供了在事务处理数据库中Java对象模型的明显的持久性，直接支持了Java类的实例，应用程序不用处理任何其它的数据模型。</P>
<P>Xml方面</P>
<P>1,xml有哪些解析技术?区别是什么?<BR>1） CSS是Cascading Style Sheet的缩写，即“层叠样式表”，在1997年W3C颁布HTML4标准的同时也公布了有关样式单的第一个标准CSS1。<BR>2）XSL（eXtensible Style Language，可扩展的样式语言）是最强大和灵活的样式语言，是特别为应用XML而设计的，它完全遵循XML规则，进一步完善了XML本身。<BR>3）Data-Island。还有几个，但是主要是第二个，其他的我认为不是主流。<BR>2,你在项目中用到了xml技术的哪些方面?如何实现的?<BR>xslt,fo,html解析，xml数据封装和解析。使用第三方软件包实现。<BR>3,用jdom解析xml文件时如何解决中文问题?如何解析?<BR>没用过，不太清楚。我使用的castor。（jbuilder9中有）</P>
<P>JavaScript方面</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1,如何校验数字型?<BR>isNaN(parseFloat(xxx))如果为true，则不是数字。<BR>---<BR>做点力所能及的补充：<BR>&nbsp; （1）Vector的方法都是同步的(Synchronized),是线程安全的(thread-safe)，而<BR>ArrayList的方法不是，由于线程的同步必然要影响性能，因此,ArrayList的性能比<BR>Vector好。<BR>&nbsp; （2）当Vector或ArrayList中的元素超过它的初始大小时,Vector会将它的容量翻倍,而<BR>ArrayList只增加50%的大小，这样,ArrayList就有利于节约内存空间。<BR>&nbsp; （3）Hashtable是基于陈旧的Dictionary类的，HashMap是Java 1.2引进的Map接口的一<BR>个实现。<BR>&nbsp; （4）性能方面的比较类似 Vector和ArrayList，比如Hashtable的方法是同步的,而<BR>HashMap的不是。<BR>（5）只有HashMap可以让你将空值作为一个表的条目的key或value<BR>---<BR>1,xml有哪些解析技术?区别是什么?</P>
<P>有两种:DOM和SAX.</P>
<P>DOM:可以得到一个包含文档中所有元素的树结构.<BR>SAX:在文档的不同治点产生事件,应用程序可以决定如何处理这些事件以从解析器中得到信息.<BR>---<BR>Java基础方面:(未写的是已经有人回答或我自己也未知或不确定)</P>
<P>4,多线程有几种表示方法,都是什么?同步有几种实现方法,都是什么?<BR>&nbsp; :::<BR>&nbsp; 我所知道的有两种实现方法:<BR>&nbsp;&nbsp;&nbsp; 一种是将方法同步:public synchronized methodName(...){....}<BR>&nbsp;&nbsp;&nbsp; 另一种是将对象同步(此对象不能是null值): synchronized (object) { ..... }</P>
<P>5,继承时候类的执行顺序问题,一般都是选择题,问你将会打印出什么?<BR>&nbsp; 继承时候类的执行顺序是:<BR>&nbsp;&nbsp;&nbsp; 父类中被static关键字定义的部分是按所定义的顺序而最先被初始化的;<BR>&nbsp;&nbsp;&nbsp; 父类构造函数(按调用顺序);</P>
<P>&nbsp;&nbsp;&nbsp; 子类中被static关键字定义的部分是按所定义的顺序而最先被初始化的;<BR>&nbsp;&nbsp;&nbsp; 子类构造函数(按调用顺序);<BR>&nbsp;&nbsp;&nbsp; 其他则按方法的调用顺序.</P>
<P>6,内部类的实现方式?<BR>&nbsp; public class XXXXX{ // 只有一个public类</P>
<P>&nbsp;&nbsp;&nbsp; ...<BR>&nbsp; <BR>&nbsp;&nbsp;&nbsp; class YYYYY{ // 可以有的访问类型是[ protected | private | 无 ]<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ...<BR>&nbsp;&nbsp;&nbsp; }</P>
<P>&nbsp; }</P>
<P>8,float型float f=3.4是否正确?<BR>&nbsp; 我也不知道是否正确.<BR>&nbsp; 我一般是这样:float f=3.4F; 或 float f=3.4f;// 后面跟一个英文大写或小写字母F<BR>---<BR>JavaScript方面</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1,如何校验数字型?<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var v = document.all.Telephone.value;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(isNan(v)){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; alert("全是数字");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>---<BR>yangtaylor的解释有一半以上是错误的，大家不要作标准答案背哦<BR>noisysilence的解释很不错，说明你已经是高手了，不过说明一点，Vector的精妙设置是在于第二个参数的设置，其余的都基本正确。</P>
<P>关于“作用域public,protected,private,以及不写时的区别”的说明---<BR>前三个常用，就不用说了，关于不写时的情况我来说明一下：<BR>JAVA的作用域其实有5种，除了上面的3种外还有:private protected,default<BR>public--------------不说了<BR>protected-----------除了所有的子类可访问外，同包的非子类也可以访问<BR>private-------------也不说了<BR>private protected---只有子类可以访问(这才是我们理解意义上的protected)<BR>default-------------只有同包的类可以访问，即使是子类但不同包仍不能访问</P>
<P>我也是看了很多参考书才最终得到的结果，在此献给大家了。<BR>---<BR>ArrayList和Vector的区别上面已说，我说说它们会带来得影响吧。<BR>同为对象集合，ArrayList可由编译器检查而Vector则不会，所以如果用Vector返回对象集合，编译器是无法查错得，只有在运行时才能才能发现。例如：<BR>********采用Vector*************<BR>server side：<BR>public Vector getCustomDataSet(int num)<BR>{<BR>&nbsp;&nbsp; Vector v = new Vector();<BR>&nbsp;&nbsp; for(int i=0; i&lt;num; i++)<BR>&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CustomData customData = new CustomData(i);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; v.add(customData)&nbsp; //此处加入自定义的数据结构CustomData <BR>&nbsp;&nbsp; }<BR>&nbsp;&nbsp; return v; <BR>}<BR>client side:<BR>&nbsp; <BR>&nbsp; Vector v = getCustomDataSet(5);<BR>&nbsp; for(int i=0; i&lt;v.size(); i++)<BR>&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp; OtherData data = (OtherData)v.get(i);//此处取出的是customData却转换为OtherData，编译器通过&nbsp;&nbsp;&nbsp; <BR>&nbsp; }</P>
<P>********采用ArrayList*************<BR>server side：<BR>public CustomData[] getCustomDataSet(int num)<BR>{<BR>&nbsp;&nbsp; CustomData[] customData = new CustomData[5];<BR>&nbsp;&nbsp; for(int i=0; i&lt;num; i++)<BR>&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; customData[i] = new CustomData(i);<BR>&nbsp;&nbsp; }<BR>&nbsp;&nbsp; return customData; <BR>}<BR>client side:<BR>&nbsp; <BR>&nbsp; CustomData[] datas = getCustomDataSet(5);<BR>&nbsp; for(int i=0; i&lt;datas.length; i++)<BR>&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp; OtherData data = datas[i];//编译不通过，类型不匹配<BR>&nbsp; }</P>
<P>---<BR>下边是以前我找的关于Hashtable和HashMap的不同之处。</P>
<P><BR>Hashtable和HashMap<BR>Hashtable和HashMap类有三个重要的不同之处。第一个不同主要是历史原因。Hashtable是基于陈旧的Dictionary类的，HashMap是Java 1.2引进的Map接口的一个实现。<BR>也许最重要的不同是Hashtable的方法是同步的，而HashMap的方法不是。这就意味着，虽然你可以不用采取任何特殊的行为就可以在一个多线程的应用程序中用一个Hashtable，但你必须同样地为一个HashMap提供外同步。一个方便的方法就是利用Collections类的静态的synchronizedMap()方法，它创建一个线程安全的Map对象，并把它作为一个封装的对象来返回。这个对象的方法可以让你同步访问潜在的HashMap。这么做的结果就是当你不需要同步时，你不能切断Hashtable中的同步（比如在一个单线程的应用程序中），而且同步增加了很多处理费用。<BR>第三点不同是，只有HashMap可以让你将空值作为一个表的条目的key或value。HashMap中只有一条记录可以是一个空的key，但任意数量的条目可以是空的value。这就是说，如果在表中没有发现搜索键，或者如果发现了搜索键，但它是一个空的值，那么get()将返回null。如果有必要，用containKey()方法来区别这两种情况。<BR>一些资料建议，当需要同步时，用Hashtable，反之用HashMap。但是，因为在需要时，HashMap可以被同步，HashMap的功能比Hashtable的功能更多，而且它不是基于一个陈旧的类的，所以有人认为，在各种情况下，HashMap都优先于Hashtable。<BR>---<BR>XML 的编程接口:&nbsp; DOM&nbsp;&nbsp;&nbsp; SAX&nbsp;&nbsp; JDOM&nbsp;&nbsp; JAXP</P>
<P>文档对象模型（通常称为 DOM）为 XML 文档的已解析版本定义了一组接口。解析器读入整个文档，然后构建一个驻留内存的树结构，然后您的代码就可以使用 DOM 接口来操作这个树结构。您可以遍历树以了解原始文档包含了什么，您可以删除树的几个部分，还可以重新排列树和添加新的分支<BR>DOM 提供了一组丰富的功能，您可以用这些功能来解释和操作 XML 文档，但使用它们是有代价的。<BR>DOM 构建整个文档驻留内存的树。如果文档很大，就会要求有极大的内存。 <BR>DOM 创建表示原始文档中每个东西的对象，包括元素、文本、属性和空格。如果您只需关注原始文档的一小部分，那么创建那些永远不被使用的对象是极其浪费的。 <BR>DOM 解析器必须在您的代码取得控制权之前读取整个文档。对于非常大的文档，这会引起显著的延迟</P>
<P><BR>为了解决 DOM 问题，XML-DEV 参与者们（由 David Megginson 领导）创建了 SAX 接口。SAX 的几个特征解决了 DOM 的问题：</P>
<P>SAX 解析器向您的代码发送事件。当解析器发现元素开始、元素结束、文本、文档的开始或结束等时，它会告诉您。您可以决定什么事件对您重要，而且可以决定要创建什么类型的数据结构以保存来自这些事件的数据。如果您没有显式地保存来自某个事件的数据，它就被丢弃。 <BR>SAX 解析器根本不创建任何对象，它只是将事件传递给您的应用程序。如果希望基于那些事件创建对象，这将由您来完成。 <BR>SAX 解析器在解析开始的时候就开始发送事件。当解析器发现文档开始、元素开始和文本等时，代码会收到一个事件。您的应用程序可以立即开始生成结果；您不必一直等到整个文档被解析完毕。更妙的是，如果您只查找文档中某些内容，代码一旦找到所要找的东西就可以抛出一个异常。该异常会停止 SAX 解析器，然后代码用它找到的数据做它需要做的任何事。 <BR>SAX 解析器也有些问题引人关注：</P>
<P>SAX 事件是无状态的。当 SAX 解析器在 XML 文档中发现文本时，它就向您的代码发送一个事件。该事件仅仅给您发现的文本；它不告诉您什么元素包含那个文本。如果您想知道这一点，则必须自己编写状态管理代码。 <BR>SAX 事件不是持久的。如果应用程序需要一个数据结构来对 XML 文档建模，则必须自己编写那样的代码。如果您需要从 SAX 事件访问数据，并且没有把那个数据存储在代码中，那么您不得不再次解析该文档。 </P>
<P>JDOM 是基于 Java 技术的开放源码项目，它试图遵循 80/20 规则：用 DOM 和 SAX 20% 的功能来满足 80% 的用户需求。JDOM 使用 SAX 和 DOM 解析器，因此它是作为一组相对较小的 Java 类被实现的。</P>
<P>JDOM 的主要特性是它极大地减少了您必须编写的代码数量。尽管本篇介绍性教程并不深入讨论编程主题，但 JDOM 应用程序的长度通常是 DOM 应用程序的三分之一，大约是 SAX 应用程序的一半。（当然，坚持使用 DOM 的纯粹主义者会建议说：从长远来看，学习和使用 DOM 终会有所回报）。JDOM 并不做所有的事，但对于大多数您要做的解析，它可能正好适合您。</P>
<P>尽管 DOM、SAX 和 JDOM 为大多数常见任务提供了标准接口，但仍有些事情是它们不能解决的。例如，在 Java 程序中创建 DOMParser 对象的过程因 DOM 解析器的不同而不同。为了修正这个问题，Sun 发布了 JAXP（用于 XML 解析的 Java API，Java API for XML Parsing）。该 API 为使用 DOM、SAX 和 XSLT 处理 XML 文档提供了公共接口。</P>
<P>JAXP 提供的诸如 DocumentBuilderFactory 和 DocumentBuilder 之类的接口为不同的解析器提供了一个标准接口。还有一些方法可以允许您控制底层的解析器是否可以识别名称空间以及是否使用 DTD 或模式来验证 XML 文档。<BR>为了确定哪种接口适合您，您需要理解所有接口的设计要点，而且需要理解应用程序用您将要处理的 XML 文档来做什么。考虑下面的问题将有助于您找到正确的方法。</P>
<P>要用 Java 编写应用程序吗？JAXP 使用 DOM、SAX 和 JDOM；如果您用 Java 编写代码，那么您应使用 JAXP 将您的代码与各种解析器实现的细节隔离。 <BR>应用程序将如何部署？如果您的应用程序将要作为 Java applet 部署，那么您会希望使要下载的代码数量最小，别忘了 SAX 解析器比 DOM 解析器小。还要知道使用 JDOM 时，除了 SAX 或 DOM 解析器之外还要求编写少量的代码。 <BR>一旦解析了 XML 文档，还需要多次访问那些数据吗？如果您需要回过头来访问 XML 文件的已解析版本，DOM 可能是正确的选择。而 SAX 事件被触发时，如果您以后需要它，则由您（开发人员）自己决定以某种方式保存它。如果您需要访问不曾保存的事件，则必须再次解析该文件。而 DOM 自动保存所有的数据。 <BR>只需要 XML 源文件的少量内容吗？如果您只需要 XML 源文件的少量内容，那么 SAX 可能是正确的选择。SAX 不会为源文件中的每个东西创建对象；您要确定什么是重要的。使用 SAX，您要检查每个事件以了解它是否与您的需要有关，然后相应地处理它。更妙的是，一旦找到您正在寻找的东西，您的代码就会抛出一个异常来完全停止 SAX 解析器。 <BR>您正在一台内存很少的机器上工作吗？若是的话，不管您可能考虑到的其它因素是什么，SAX 是您的最佳选择。</P><img src ="http://www.blogjava.net/NeonWay/aggbug/31382.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/NeonWay/" target="_blank">王彦锋的技术实践</a> 2006-02-18 16:54 <a href="http://www.blogjava.net/NeonWay/archive/2006/02/18/31382.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>