<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Java豆技术站点 &#187; Hibernate</title>
	<atom:link href="http://javadou.com/framework/hibernate-framework/feed/" rel="self" type="application/rss+xml" />
	<link>http://javadou.com</link>
	<description>Java</description>
	<lastBuildDate>Wed, 21 Jul 2010 08:08:04 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>连接池泄露的问题：Timeout waiting for idle object</title>
		<link>http://javadou.com/org-apache-commons-dbcp-sqlnestedexception-cannot-get-a-connection-pool-exhausted-causejava-util-nosuchelementexcep-638/</link>
		<comments>http://javadou.com/org-apache-commons-dbcp-sqlnestedexception-cannot-get-a-connection-pool-exhausted-causejava-util-nosuchelementexcep-638/#comments</comments>
		<pubDate>Tue, 13 Jul 2010 10:58:47 +0000</pubDate>
		<dc:creator>阿超</dc:creator>
				<category><![CDATA[Hibernate]]></category>
		<category><![CDATA[Java核心类]]></category>
		<category><![CDATA[Spring]]></category>
		<category><![CDATA[Timeout waiting for idle object]]></category>

		<guid isPermaLink="false">http://javadou.com/?p=638</guid>
		<description><![CDATA[问题描述:连接池泄露的问题：org.apache.commons.dbcp.SQLNestedException: Cannot get a connection, pool exhausted, cause:java.util.NoSuchElementException: Timeout waiting for idle object 问题同样适用于其他服务器,使用spring配置文件的可以加下面的参... ]]></description>
			<content:encoded><![CDATA[<p>问题描述:<strong>连接池泄露的问题：org.apache.commons.dbcp.SQLNestedException: Cannot get a connection, pool exhausted, cause:java.util.NoSuchElementException: Timeout waiting for idle object</strong><br />
问题同样适用于其他服务器,使用spring配置文件的可以加下面的参数<br />
&lt;property name=&#8221;removeAbandoned&#8221; value=&#8221;true&#8221;/&gt;<br />
&lt;property name=&#8221;removeAbandonedTimeout&#8221; value=&#8221;60&#8243;/&gt;<br />
&lt;property name=&#8221;logAbandoned&#8221; value=&#8221;true&#8221;/&gt;</p>
<p>1 问题描述<br />
Web程序在tomcat刚开始运行时速度很快，但过一段时间后发现速度变得很慢。<br />
检查日志输出，发现异常如下:<br />
org.apache.commons.dbcp.SQLNestedException: Cannot get a connection, pool exhausted, cause:<br />
java.util.NoSuchElementException: Timeout waiting for idle object<br />
同时在SQLServer事件探查器中发现，每执行一次sql语句都要产生Audit login事件，语句执行后产生<br />
Audit logout事件。说明每一次tomcat都是重新打开新的连接。<br />
2 问题解决<br />
tomcat 的数据源定义提供了三个参数：<br />
a. 如果设为true则tomcat自动检查恢复重新利用，没有正常关闭的Connection.（默认是false）<br />
&lt;parameter&gt;<br />
&lt;name&gt;removeAbandoned&lt;/name&gt;<br />
&lt;value&gt;true&lt;/value&gt;<br />
&lt;/parameter&gt;<br />
b. 设定连接在多少秒内被认为是放弃的连接，即可进行恢复利用。<br />
&lt;parameter&gt;<br />
&lt;name&gt;removeAbandonedTimeout&lt;/name&gt;<br />
&lt;value&gt;60&lt;/value&gt;<br />
&lt;/parameter&gt;<br />
c. 输出回收的日志，可以详细打印出异常从而发现是在那里发生了泄漏<br />
&lt;parameter&gt;<br />
&lt;name&gt;logAbandoned&lt;/name&gt;<br />
&lt;value&gt;true&lt;/value&gt;<br />
&lt;/parameter&gt;</p>
]]></content:encoded>
			<wfw:commentRss>http://javadou.com/org-apache-commons-dbcp-sqlnestedexception-cannot-get-a-connection-pool-exhausted-causejava-util-nosuchelementexcep-638/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>hibernate C3P0连接池详细配置</title>
		<link>http://javadou.com/hibernate-c3p0-config-634/</link>
		<comments>http://javadou.com/hibernate-c3p0-config-634/#comments</comments>
		<pubDate>Tue, 06 Jul 2010 12:30:18 +0000</pubDate>
		<dc:creator>阿超</dc:creator>
				<category><![CDATA[Hibernate]]></category>
		<category><![CDATA[c3p0]]></category>
		<category><![CDATA[hibernate]]></category>

		<guid isPermaLink="false">http://javadou.com/?p=634</guid>
		<description><![CDATA[&60;c3p0-config&62; &60;default-config&62; &60;!&8211;当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 &8211;&62; &60;property name=&8221;acquireIncrement&8221;&62;3&60;/property&62; &60;!&8211;定义在从数据库获取新连接... ]]></description>
			<content:encoded><![CDATA[<p>&lt;c3p0-config&gt;<br />
&lt;default-config&gt;<br />
&lt;!&#8211;当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 &#8211;&gt;<br />
&lt;property name=&#8221;acquireIncrement&#8221;&gt;3&lt;/property&gt;</p>
<p>&lt;!&#8211;定义在从数据库获取新连接失败后重复尝试的次数。Default: 30 &#8211;&gt;<br />
&lt;property name=&#8221;acquireRetryAttempts&#8221;&gt;30&lt;/property&gt;</p>
<p>&lt;!&#8211;两次连接中间隔时间，单位毫秒。Default: 1000 &#8211;&gt;<br />
&lt;property name=&#8221;acquireRetryDelay&#8221;&gt;1000&lt;/property&gt;</p>
<p>&lt;!&#8211;连接关闭时默认将所有未提交的操作回滚。Default: false &#8211;&gt;<br />
&lt;property name=&#8221;autoCommitOnClose&#8221;&gt;false&lt;/property&gt;</p>
<p>&lt;!&#8211;c3p0将建一张名为Test的空表，并使用其自带的查询语句进行测试。如果定义了这个参数那么<br />
属性preferredTestQuery将被忽略。你不能在这张Test表上进行任何操作，它将只供c3p0测试<br />
使用。Default: null&#8211;&gt;<br />
&lt;property name=&#8221;automaticTestTable&#8221;&gt;Test&lt;/property&gt;</p>
<p>&lt;!&#8211;获取连接失败将会引起所有等待连接池来获取连接的线程抛出异常。但是数据源仍有效<br />
保留，并在下次调用getConnection()的时候继续尝试获取连接。如果设为true，那么在尝试<br />
获取连接失败后该数据源将申明已断开并永久关闭。Default: false&#8211;&gt;<br />
&lt;property name=&#8221;breakAfterAcquireFailure&#8221;&gt;false&lt;/property&gt;</p>
<p>&lt;!&#8211;当连接池用完时客户端调用getConnection()后等待获取新连接的时间，超时后将抛出<br />
SQLException,如设为0则无限期等待。单位毫秒。Default: 0 &#8211;&gt;<br />
&lt;property name=&#8221;checkoutTimeout&#8221;&gt;100&lt;/property&gt;</p>
<p>&lt;!&#8211;通过实现ConnectionTester或QueryConnectionTester的类来测试连接。类名需制定全路径。<br />
Default: com.mchange.v2.c3p0.impl.DefaultConnectionTester&#8211;&gt;<br />
&lt;property name=&#8221;connectionTesterClassName&#8221;&gt;&lt;/property&gt;</p>
<p>&lt;!&#8211;指定c3p0 libraries的路径，如果（通常都是这样）在本地即可获得那么无需设置，默认null即可<br />
Default: null&#8211;&gt;<br />
&lt;property name=&#8221;factoryClassLocation&#8221;&gt;null&lt;/property&gt;</p>
<p>&lt;!&#8211;Strongly disrecommended. Setting this to true may lead to subtle and bizarre bugs.<br />
（文档原文）作者强烈建议不使用的一个属性&#8211;&gt;<br />
&lt;property name=&#8221;forceIgnoreUnresolvedTransactions&#8221;&gt;false&lt;/property&gt;</p>
<p>&lt;!&#8211;每60秒检查所有连接池中的空闲连接。Default: 0 &#8211;&gt;<br />
&lt;property name=&#8221;idleConnectionTestPeriod&#8221;&gt;60&lt;/property&gt;</p>
<p>&lt;!&#8211;初始化时获取三个连接，取值应在minPoolSize与maxPoolSize之间。Default: 3 &#8211;&gt;<br />
&lt;property name=&#8221;initialPoolSize&#8221;&gt;3&lt;/property&gt;</p>
<p>&lt;!&#8211;最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0 &#8211;&gt;<br />
&lt;property name=&#8221;maxIdleTime&#8221;&gt;60&lt;/property&gt;</p>
<p>&lt;!&#8211;连接池中保留的最大连接数。Default: 15 &#8211;&gt;<br />
&lt;property name=&#8221;maxPoolSize&#8221;&gt;15&lt;/property&gt;</p>
<p>&lt;!&#8211;JDBC的标准参数，用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements<br />
属于单个connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素。<br />
如果maxStatements与maxStatementsPerConnection均为0，则缓存被关闭。Default: 0&#8211;&gt;<br />
&lt;property name=&#8221;maxStatements&#8221;&gt;100&lt;/property&gt;</p>
<p>&lt;!&#8211;maxStatementsPerConnection定义了连接池内单个连接所拥有的最大缓存statements数。Default: 0  &#8211;&gt;<br />
&lt;property name=&#8221;maxStatementsPerConnection&#8221;&gt;&lt;/property&gt;</p>
<p>&lt;!&#8211;c3p0是异步操作的，缓慢的JDBC操作通过帮助进程完成。扩展这些操作可以有效的提升性能<br />
通过多线程实现多个操作同时被执行。Default: 3&#8211;&gt;<br />
&lt;property name=&#8221;numHelperThreads&#8221;&gt;3&lt;/property&gt;</p>
<p>&lt;!&#8211;当用户调用getConnection()时使root用户成为去获取连接的用户。主要用于连接池连接非c3p0<br />
的数据源时。Default: null&#8211;&gt;<br />
&lt;property name=&#8221;overrideDefaultUser&#8221;&gt;root&lt;/property&gt;</p>
<p>&lt;!&#8211;与overrideDefaultUser参数对应使用的一个参数。Default: null&#8211;&gt;<br />
&lt;property name=&#8221;overrideDefaultPassword&#8221;&gt;password&lt;/property&gt;</p>
<p>&lt;!&#8211;密码。Default: null&#8211;&gt;<br />
&lt;property name=&#8221;password&#8221;&gt;&lt;/property&gt;</p>
<p>&lt;!&#8211;定义所有连接测试都执行的测试语句。在使用连接测试的情况下这个一显著提高测试速度。注意：<br />
测试的表必须在初始数据源的时候就存在。Default: null&#8211;&gt;<br />
&lt;property name=&#8221;preferredTestQuery&#8221;&gt;select id from test where id=1&lt;/property&gt;</p>
<p>&lt;!&#8211;用户修改系统配置参数执行前最多等待300秒。Default: 300 &#8211;&gt;<br />
&lt;property name=&#8221;propertyCycle&#8221;&gt;300&lt;/property&gt;</p>
<p>&lt;!&#8211;因性能消耗大请只在需要的时候使用它。如果设为true那么在每个connection提交的<br />
时候都将校验其有效性。建议使用idleConnectionTestPeriod或automaticTestTable<br />
等方法来提升连接测试的性能。Default: false &#8211;&gt;<br />
&lt;property name=&#8221;testConnectionOnCheckout&#8221;&gt;false&lt;/property&gt;</p>
<p>&lt;!&#8211;如果设为true那么在取得连接的同时将校验连接的有效性。Default: false &#8211;&gt;<br />
&lt;property name=&#8221;testConnectionOnCheckin&#8221;&gt;true&lt;/property&gt;</p>
<p>&lt;!&#8211;用户名。Default: null&#8211;&gt;<br />
&lt;property name=&#8221;user&#8221;&gt;root&lt;/property&gt;</p>
<p>&lt;!&#8211;早期的c3p0版本对JDBC接口采用动态反射代理。在早期版本用途广泛的情况下这个参数<br />
允许用户恢复到动态反射代理以解决不稳定的故障。最新的非反射代理更快并且已经开始<br />
广泛的被使用，所以这个参数未必有用。现在原先的动态反射与新的非反射代理同时受到<br />
支持，但今后可能的版本可能不支持动态反射代理。Default: false&#8211;&gt;<br />
&lt;property name=&#8221;usesTraditionalReflectiveProxies&#8221;&gt;false&lt;/property&gt;</p>
<p>&lt;property name=&#8221;automaticTestTable&#8221;&gt;con_test&lt;/property&gt;<br />
&lt;property name=&#8221;checkoutTimeout&#8221;&gt;30000&lt;/property&gt;<br />
&lt;property name=&#8221;idleConnectionTestPeriod&#8221;&gt;30&lt;/property&gt;<br />
&lt;property name=&#8221;initialPoolSize&#8221;&gt;10&lt;/property&gt;<br />
&lt;property name=&#8221;maxIdleTime&#8221;&gt;30&lt;/property&gt;<br />
&lt;property name=&#8221;maxPoolSize&#8221;&gt;25&lt;/property&gt;<br />
&lt;property name=&#8221;minPoolSize&#8221;&gt;10&lt;/property&gt;<br />
&lt;property name=&#8221;maxStatements&#8221;&gt;0&lt;/property&gt;<br />
&lt;user-overrides user=&#8221;swaldman&#8221;&gt;<br />
&lt;/user-overrides&gt;<br />
&lt;/default-config&gt;<br />
&lt;named-config name=&#8221;dumbTestConfig&#8221;&gt;<br />
&lt;property name=&#8221;maxStatements&#8221;&gt;200&lt;/property&gt;<br />
&lt;user-overrides user=&#8221;poop&#8221;&gt;<br />
&lt;property name=&#8221;maxStatements&#8221;&gt;300&lt;/property&gt;<br />
&lt;/user-overrides&gt;<br />
&lt;/named-config&gt;<br />
&lt;/c3p0-config&gt;</p>
]]></content:encoded>
			<wfw:commentRss>http://javadou.com/hibernate-c3p0-config-634/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>你所不知道的提高spring+hibernate性能的一个方法</title>
		<link>http://javadou.com/spring-hibernate-autocommit-xing-neng-504/</link>
		<comments>http://javadou.com/spring-hibernate-autocommit-xing-neng-504/#comments</comments>
		<pubDate>Fri, 05 Feb 2010 09:13:56 +0000</pubDate>
		<dc:creator>阿超</dc:creator>
				<category><![CDATA[Hibernate]]></category>
		<category><![CDATA[autocommit]]></category>
		<category><![CDATA[hibernate]]></category>

		<guid isPermaLink="false">http://javadou.com/?p=504</guid>
		<description><![CDATA[在spring + hibernate的应用中，你监控mysql日志，你会发现大量的log如下： 1. 158268 Query       SET autocommit=1 2. 158268 Query       SET autocommit=1 3. 158268 Query       SET autocommit=1 4. 158268 Query       SET autocommit=0 5. 158268 Q... ]]></description>
			<content:encoded><![CDATA[<p>在spring + hibernate的应用中，你监控mysql日志，你会发现大量的log如下：</p>
<p>1. 158268 Query       SET autocommit=1<br />
2. 158268 Query       SET autocommit=1<br />
3. 158268 Query       SET autocommit=1<br />
4. 158268 Query       SET autocommit=0<br />
5. 158268 Query       commit<br />
6. 158268 Query       SET autocommit=1<br />
7. 158268 Query       SET autocommit=1<br />
8. 158268 Query       SET autocommit=1<br />
9. 158268 Query       SET autocommit=0<br />
10. 158268 Query       commit</p>
<p>158268 Query       SET autocommit=1<br />
158268 Query       SET autocommit=1<br />
158268 Query       SET autocommit=1<br />
158268 Query       SET autocommit=0<br />
158268 Query       commit<br />
158268 Query       SET autocommit=1<br />
158268 Query       SET autocommit=1<br />
158268 Query       SET autocommit=1<br />
158268 Query       SET autocommit=0<br />
158268 Query       commit</p>
<p>另外，你如果看mysqlreport，你会发现set_option和commt几乎占了mysql query的一半！！</p>
<p>原因是？</p>
<p>我们先看第一个问题：</p>
<p>1. 158268 Query       SET autocommit=0<br />
2. 158268 Query       commit</p>
<p>158268 Query       SET autocommit=0<br />
158268 Query       commit</p>
<p>这种日志产生的原因是hibernate查询时，如果所请求的对象在cache中，那么hibernate仍然会向数据库发出这样的两个sql语句。</p>
<p>再来看第二个问题</p>
<p>1. 158268 Query       SET autocommit=1</p>
<p>158268 Query       SET autocommit=1</p>
<p>这是因为当connection 被放回conn pool时，conn pool会恢复此连接取出时的autocommit状态。一般连接池里面的autocommit状态为true，所以每个查询都会紧跟着一个set autocommit＝1。</p>
<p>对第一个问题我们的解决方案：</p>
<p>那就是利用LazyConnectionDataSourceProxy</p>
<p>这个conn 代理的作用就是，只有当确实有必要时，他它向DB发出查询。一切没有必要的set autocommit=0 commit语句都不会发向数据库。</p>
<p>此class的详细作用请参见spring 文档</p>
<p>example配置如下:</p>
<p>1. &lt;bean id=&#8221;dataSourceTarget&#8221; destroy-method=&#8221;close&#8221;&gt;<br />
2.   &lt;property name=&#8221;driverClass&#8221;&gt;&lt;value&gt;com.mysql.jdbc.Driver&lt;/value&gt;&lt;/property&gt;<br />
3.   &lt;property name=&#8221;jdbcUrl&#8221;&gt;&lt;value&gt;jdbc:mysql<br />
4. ://localhost:3306/imagedb&lt;/value&gt;&lt;/property&gt;<br />
5.   &lt;property name=&#8221;user&#8221;&gt;&lt;value&gt;admin&lt;/value&gt;&lt;/property&gt;<br />
6.   &lt;property name=&#8221;password&#8221;&gt;&lt;value&gt;&lt;/value&gt;&lt;/property&gt;<br />
7.<br />
8.  &lt;property name=&#8221;initialPoolSize&#8221; value=&#8221;60&#8243; /&gt;<br />
9.         &lt;property name=&#8221;minPoolSize&#8221; value=&#8221;50&#8243; /&gt;<br />
10.         &lt;property name=&#8221;maxPoolSize&#8221; value=&#8221;80&#8243; /&gt;<br />
11.         &lt;property name=&#8221;maxIdleTime&#8221; value=&#8221;7200&#8243; /&gt;<br />
12.<br />
13.         &lt;property name=&#8221;idleConnectionTestPeriod&#8221; value=&#8221;360&#8243; /&gt;<br />
14.         &lt;property name=&#8221;preferredTestQuery&#8221; value=&#8221;select 1&#8243; /&gt;<br />
15.         &lt;property name=&#8221;acquireIncrement&#8221; value=&#8221;5&#8243; /&gt;<br />
16.         &lt;property name=&#8221;acquireRetryAttempts&#8221; value=&#8221;50&#8243; /&gt;<br />
17.         &lt;property name=&#8221;acquireRetryDelay&#8221; value=&#8221;1000&#8243; /&gt;<br />
18.         &lt;property name=&#8221;breakAfterAcquireFailure&#8221; value=&#8221;true&#8221; /&gt;<br />
19.<br />
20.         &lt;!&#8211;property name=&#8221;checkoutTimeout&#8221; value=&#8221;1000&#8243; /&#8211;&gt;<br />
21.<br />
22.         &lt;property name=&#8221;autoCommitOnClose&#8221; value=&#8221;false&#8221; /&gt;<br />
23.         &lt;property name=&#8221;forceIgnoreUnresolvedTransactions&#8221; value=&#8221;false&#8221; /&gt;<br />
24.         &lt;property name=&#8221;unreturnedConnectionTimeout&#8221; value=&#8221;1000&#8243; /&gt;<br />
25.<br />
26.         &lt;property name=&#8221;maxStatements&#8221; value=&#8221;0&#8243; /&gt;<br />
27.         &lt;property name=&#8221;maxStatementsPerConnection&#8221; value=&#8221;0&#8243; /&gt;<br />
28.<br />
29.         &lt;property name=&#8221;testConnectionOnCheckin&#8221; value=&#8221;true&#8221; /&gt;<br />
30.         &lt;property name=&#8221;testConnectionOnCheckout&#8221; value=&#8221;false&#8221; /&gt;<br />
31.         &lt;property name=&#8221;usesTraditionalReflectiveProxies&#8221; value=&#8221;false&#8221; /&gt;<br />
32.<br />
33.         &lt;property name=&#8221;numHelperThreads&#8221; value=&#8221;5&#8243; /&gt;<br />
34. &lt;/bean&gt;<br />
35.<br />
36. &lt;bean id=&#8221;dataSource&#8221;&gt;<br />
37.   &lt;property name=&#8221;targetDataSource&#8221;&gt;&lt;ref local=&#8221;dataSource&#8221;/&gt;&lt;/property&gt;<br />
38. &lt;/bean&gt;</p>
<p>&lt;bean id=&#8221;dataSourceTarget&#8221; destroy-method=&#8221;close&#8221;&gt;<br />
&lt;property name=&#8221;driverClass&#8221;&gt;&lt;value&gt;com.mysql.jdbc.Driver&lt;/value&gt;&lt;/property&gt;<br />
&lt;property name=&#8221;jdbcUrl&#8221;&gt;&lt;value&gt;jdbc:mysql<br />
://localhost:3306/imagedb&lt;/value&gt;&lt;/property&gt;<br />
&lt;property name=&#8221;user&#8221;&gt;&lt;value&gt;admin&lt;/value&gt;&lt;/property&gt;<br />
&lt;property name=&#8221;password&#8221;&gt;&lt;value&gt;&lt;/value&gt;&lt;/property&gt;</p>
<p>&lt;property name=&#8221;initialPoolSize&#8221; value=&#8221;60&#8243; /&gt;<br />
&lt;property name=&#8221;minPoolSize&#8221; value=&#8221;50&#8243; /&gt;<br />
&lt;property name=&#8221;maxPoolSize&#8221; value=&#8221;80&#8243; /&gt;<br />
&lt;property name=&#8221;maxIdleTime&#8221; value=&#8221;7200&#8243; /&gt;</p>
<p>&lt;property name=&#8221;idleConnectionTestPeriod&#8221; value=&#8221;360&#8243; /&gt;<br />
&lt;property name=&#8221;preferredTestQuery&#8221; value=&#8221;select 1&#8243; /&gt;<br />
&lt;property name=&#8221;acquireIncrement&#8221; value=&#8221;5&#8243; /&gt;<br />
&lt;property name=&#8221;acquireRetryAttempts&#8221; value=&#8221;50&#8243; /&gt;<br />
&lt;property name=&#8221;acquireRetryDelay&#8221; value=&#8221;1000&#8243; /&gt;<br />
&lt;property name=&#8221;breakAfterAcquireFailure&#8221; value=&#8221;true&#8221; /&gt;</p>
<p>&lt;!&#8211;property name=&#8221;checkoutTimeout&#8221; value=&#8221;1000&#8243; /&#8211;&gt;</p>
<p>&lt;property name=&#8221;autoCommitOnClose&#8221; value=&#8221;false&#8221; /&gt;<br />
&lt;property name=&#8221;forceIgnoreUnresolvedTransactions&#8221; value=&#8221;false&#8221; /&gt;<br />
&lt;property name=&#8221;unreturnedConnectionTimeout&#8221; value=&#8221;1000&#8243; /&gt;</p>
<p>&lt;property name=&#8221;maxStatements&#8221; value=&#8221;0&#8243; /&gt;<br />
&lt;property name=&#8221;maxStatementsPerConnection&#8221; value=&#8221;0&#8243; /&gt;</p>
<p>&lt;property name=&#8221;testConnectionOnCheckin&#8221; value=&#8221;true&#8221; /&gt;<br />
&lt;property name=&#8221;testConnectionOnCheckout&#8221; value=&#8221;false&#8221; /&gt;<br />
&lt;property name=&#8221;usesTraditionalReflectiveProxies&#8221; value=&#8221;false&#8221; /&gt;</p>
<p>&lt;property name=&#8221;numHelperThreads&#8221; value=&#8221;5&#8243; /&gt;<br />
&lt;/bean&gt;</p>
<p>&lt;bean id=&#8221;dataSource&#8221;&gt;<br />
&lt;property name=&#8221;targetDataSource&#8221;&gt;&lt;ref local=&#8221;dataSource&#8221;/&gt;&lt;/property&gt;<br />
&lt;/bean&gt;</p>
<p>第二个问题的解决方案：</p>
<p>通过conn pool 的jdbc url把autocommit设为false来解决，不过mysql driver好像不支持这个设置。</p>
<p>另外，如果你使用的是mysql，那么第一个问题还有一个更简单的解决方案，那就是在jdbcUrl中加入</p>
<p>useLocalSessionState=true</p>
<p>这可以达到和</p>
<p>1. LazyConnectionDataSourceProxy</p>
<p>LazyConnectionDataSourceProxy</p>
<p>一样的效果</p>
]]></content:encoded>
			<wfw:commentRss>http://javadou.com/spring-hibernate-autocommit-xing-neng-504/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Struts2 json session close no session 异常解决</title>
		<link>http://javadou.com/struts2-json-session-close-no-session-exception-489/</link>
		<comments>http://javadou.com/struts2-json-session-close-no-session-exception-489/#comments</comments>
		<pubDate>Tue, 05 Jan 2010 06:16:56 +0000</pubDate>
		<dc:creator>阿超</dc:creator>
				<category><![CDATA[Ajax]]></category>
		<category><![CDATA[Hibernate]]></category>
		<category><![CDATA[Struts2]]></category>
		<category><![CDATA[json]]></category>
		<category><![CDATA[OpenSessionInViewFilter]]></category>
		<category><![CDATA[session]]></category>
		<category><![CDATA[struts2]]></category>

		<guid isPermaLink="false">http://javadou.com/?p=489</guid>
		<description><![CDATA[异常信息： ERROR – failed to lazily initialize a collection of role: com.dudu.pojo.User.roles, no session or session was closed org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.dudu.pojo.User.roles, no session or session was clos... ]]></description>
			<content:encoded><![CDATA[<p>异常信息：</p>
<p>ERROR – failed to lazily initialize a collection of role: com.dudu.pojo.User.roles, no session or session was closed</p>
<p>org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.dudu.pojo.User.roles, no session or session was closed</p>
<p>异常说明：session已关闭，无法初始化懒加载数据集role</p>
<p>异常原因：Hibernate映射文件中配置了lazy=&#8221;true&#8221;，同时也启用了OpenSessionInViewFilter。当实现ajax检测role名称是否可用时报以上异常，我这里检测role名称是利用json格式返回数据的。json返回数据的特点是：如果action中的属性有get()方法并且该属性没有transient修饰，那么json就会将其返回。在我的TrackSmsExpertAction中有private User  role;并且role有get()方法，所以在检测名称是否可用后返回的json数据中会将这一属性返回，但是检测名称的可用性根本不需要用到这个属性，异常就是由于启用懒加载机制下json中返回role这个属性需要查询数据库，而这时session已经关闭，因此报异常。</p>
<p>解决方法：用transient对role属性进行修饰，即：private transient User  role;这样json就不会将其返回，因为也不用再次查询关联数据不会出现session已关闭的异常。</p>
<p>如果还是不行的话 请检查你的Action中是否有多余的get set方法 把不用的全部去掉 就可以解决问题了 最后感谢下<a href="http://imleeo.com" target="_blank">IT北瓜</a>的提醒帮我解决问题</p>
]]></content:encoded>
			<wfw:commentRss>http://javadou.com/struts2-json-session-close-no-session-exception-489/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>用hibernate的hql查询查询成map或list</title>
		<link>http://javadou.com/hibernate-hql-select-map-or-list-488/</link>
		<comments>http://javadou.com/hibernate-hql-select-map-or-list-488/#comments</comments>
		<pubDate>Mon, 04 Jan 2010 07:43:21 +0000</pubDate>
		<dc:creator>阿超</dc:creator>
				<category><![CDATA[Hibernate]]></category>
		<category><![CDATA[hibernante]]></category>
		<category><![CDATA[List]]></category>
		<category><![CDATA[map]]></category>

		<guid isPermaLink="false">http://javadou.com/?p=488</guid>
		<description><![CDATA[      这里制作一个引子，具体内容比较多，而且hibernate文档里的hql篇写的很详细 可以这么用： List list = getHibernateTemplate().find(&8220;select new map(t1.c1,t2.c3) from table1 t1 ,table2 t2 where t1.c1=t2.c2&8243;); 这样的话list里的每... ]]></description>
			<content:encoded><![CDATA[<p>      这里制作一个引子，具体内容比较多，而且hibernate文档里的hql篇写的很详细<br />
可以这么用：<br />
List list = getHibernateTemplate().find(&#8220;select new map(t1.c1,t2.c3) from table1 t1 ,table2 t2 where t1.c1=t2.c2&#8243;);<br />
这样的话list里的每个元素都是一个map，每个map里包含两个元素<br />
注意：这里的table1和table2都是class名并不是真的表名，毕竟这是hql。除了可以用map还还支持list和自定义的bean。</p>
<p>//HQL-Associations<br />
String hql = &#8220;select s.name, p.name, p.price from Product p inner join p.supplier as s&#8221;;<br />
Query query = session.createQuery(hql);<br />
List results = query.list();</p>
<p>//HQL-Delete<br />
String hql = &#8220;delete from Product where name = :name&#8221;;<br />
Query query = session.createQuery(hql);<br />
query.setString(&#8220;name&#8221;,&#8221;Product 1&#8243;);<br />
int rowCount = query.executeUpdate();</p>
<p>//HQL-Function<br />
String hql = &#8220;select min(product.price), max(product.price) from Product product&#8221;;<br />
Query query = session.createQuery(hql);<br />
List results = query.list();</p>
<p>//HQL-Fetch Associations HQL Inner Join<br />
String hql = &#8220;from Supplier s inner join fetch s.products as p&#8221;;<br />
Query query = session.createQuery(hql);<br />
List results = query.list();</p>
<p>//HQL-Named Parameters<br />
String hql = &#8220;from Product where price &gt; :price&#8221;;<br />
Query query = session.createQuery(hql);<br />
query.setDouble(&#8220;price&#8221;,2.0);<br />
List results = query.list();<br />
String hql = &#8220;from Product as product where product.supplier=:supplier&#8221;;<br />
Query query = session.createQuery(hql);<br />
query.setEntity(&#8220;supplier&#8221;,supplier);<br />
List results = query.list();</p>
<p>//HQL-Update<br />
String hql = &#8220;update Supplier set name = :newName where name = :name&#8221;;<br />
Query query = session.createQuery(hql);<br />
query.setString(&#8220;name&#8221;,&#8221;Supplier Name 1&#8243;);<br />
query.setString(&#8220;newName&#8221;,&#8221;s1&#8243;);<br />
int rowCount = query.executeUpdate();</p>
<p>//HQL-where<br />
String hql = &#8220;from Product where price &gt; 2.0 and name like &#8216;P%&#8217;&#8221;;<br />
Query query = session.createQuery(hql);<br />
List results = query.list();</p>
<p>//HQL-Map<br />
String hql = &#8221; select new map(usr.name as userName, usr.password as password) from User usr&#8221;;<br />
Query query = session.createQuery(hql);<br />
List list = query.list();<br />
Map goods =(Map)list.get(0);</p>
<p>【注】<br />
String hql = &#8221; select new map(usr.name as userName, usr.password as password)　from com.jason.User usr&#8221;;<br />
String hql = &#8221; select new map(usr.name as userName, usr.password as password) from com.jason.User usr&#8221;;<br />
由于from之前的空格，引起unexpected token: 　from</p>
<p>//select new</p>
<p>给一个构建函数：<br />
public class Department(Department d, Integer employeeSize)</p>
]]></content:encoded>
			<wfw:commentRss>http://javadou.com/hibernate-hql-select-map-or-list-488/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>使 Hibernate Tools生成注释</title>
		<link>http://javadou.com/hibernate-tools-create-marke-430/</link>
		<comments>http://javadou.com/hibernate-tools-create-marke-430/#comments</comments>
		<pubDate>Sat, 14 Nov 2009 12:24:09 +0000</pubDate>
		<dc:creator>阿超</dc:creator>
				<category><![CDATA[Freemarker]]></category>
		<category><![CDATA[Hibernate]]></category>
		<category><![CDATA[hibernate]]></category>

		<guid isPermaLink="false">http://javadou.com/?p=430</guid>
		<description><![CDATA[&160;&160;&160; 最近做项目时，使用Hibernate Tools 3.2.4生成entity和hbm.xml，但默认情况下，DB中的comments没法生成到javadoc和xml中，改了templates倒是有注释了，但却是乱码，心里一直耿耿于怀&8230;（这不符合咱一直强调的编... ]]></description>
			<content:encoded><![CDATA[<p>&#160;&#160;&#160; 最近做项目时，使用Hibernate Tools 3.2.4生成entity和hbm.xml，但默认情况下，DB中的comments没法生成到javadoc和xml中，改了templates倒是有注释了，但却是乱码，心里一直耿耿于怀&#8230;（这不符合咱一直强调的编码规范不是？最主要的是人懒，有时用entity不想再找文档）。在网上找了半天，大多说是freemarker编码设置问题，但不管怎么设置，都没一点效果，决定自己动手。下了源码，查到原因，人家压根就没处理中文问题。记录一下处理过程。<br />
  <br />ftl是freemarker模板，可以通过在jar包外使用，java和properties重新打包替换hibernate-tools.jar，如果是eclipse-plugins，jar包在plugins\org.hibernate.eclipse_3.2.4.GA-R200905070146-H18\lib\tools\hibernate-tools.jar </p>
<p>pojo\PojoFields.ftl</p>
<pre class="html">&lt;#-- // Fields --&gt;

&lt;#foreach field in pojo.getAllPropertiesIterator()&gt;&lt;#if pojo.getMetaAttribAsBool(field, &quot;gen-property&quot;, true)&gt;    /** *//** *//** *//**
&lt;#if pojo.hasMetaAttribute(field, &quot;field-description&quot;)&gt;
     ${pojo.getFieldJavaDoc(field, 0)}
&lt;/#IF&gt;
&lt;#foreach column in field.columnIterator&gt;&lt;#if column.comment?exists &amp;&amp; column.comment?trim?length!=0&gt;     * ${column.comment}.
&lt;/#IF&gt;
&lt;/#FOREACH&gt;
     */
    ${pojo.getFieldModifiers(field)} ${pojo.getJavaTypeName(field, jdk5)} ${field.name}&lt;#if pojo.hasFieldInitializor(field, jdk5)&gt; = ${pojo.getFieldInitialization(field, jdk5)}&lt;/#IF&gt;;
&lt;/#IF&gt;
&lt;/#FOREACH&gt;</pre>
<p>pojo\PojoPropertyAccessors.ftl </p>
<pre class="html">&lt;#-- // Property accessors --&gt;
&lt;#foreach property in pojo.getAllPropertiesIterator()&gt;
&lt;#if pojo.getMetaAttribAsBool(property, &quot;gen-property&quot;, true)&gt;
    /** *//**
&lt;#if pojo.hasFieldJavaDoc(property)&gt;
     * ${pojo.getFieldJavaDoc(property, 4)}
&lt;/#IF&gt;
&lt;#foreach column in property.columnIterator&gt;&lt;#if column.comment?exists &amp;&amp; column.comment?trim?length!=0&gt;     * 取得 ${column.comment}.
&lt;/#IF&gt;
&lt;/#FOREACH&gt;
     */
    &lt;#include &quot;GetPropertyAnnotation.ftl&quot;/&gt;
    ${pojo.getPropertyGetModifiers(property)} ${pojo.getJavaTypeName(property, jdk5)} ${pojo.getGetterSignature(property)}() {
        return this.${property.name};
    }

    /** *//**
&lt;#if pojo.hasFieldJavaDoc(property)&gt;
     * ${pojo.getFieldJavaDoc(property, 4)}
&lt;/#IF&gt;
&lt;#foreach column in property.columnIterator&gt;&lt;#if column.comment?exists &amp;&amp; column.comment?trim?length!=0&gt;     * 设置 ${column.comment}.
&lt;/#IF&gt;
&lt;/#FOREACH&gt;
     */
    ${pojo.getPropertySetModifiers(property)} void set${pojo.getPropertyName(property)}(${pojo.getJavaTypeName(property, jdk5)} ${property.name}) {
        this.${property.name} = ${property.name};
    }
&lt;/#IF&gt;
&lt;/#FOREACH&gt;</pre>
<p>org\hibernate\tool\hbm2x\TemplateProducer.java </p>
<pre class="java">public void produce(Map additionalContext, String templateName, File destination, String identifier, String fileType, String rootContext) {

        String tempResult = produceToString( additionalContext, templateName, rootContext );

        if(tempResult.trim().length()==0) {
            log.warn(&quot;Generated output is empty. Skipped creation for file &quot; + destination);
            return;
        }
        FileWriter fileWriter = null;
        Writer fileWriter = null;
        try {

            th.ensureExistence( destination );    

            ac.addFile(destination, fileType);
            log.debug(&quot;Writing &quot; + identifier + &quot; to &quot; + destination.getAbsolutePath() );
            fileWriter = new FileWriter(destination);
            fileWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(destination), &quot;UTF-8&quot;));

            fileWriter.write(tempResult);
        }
        catch (Exception e) {
            throw new ExporterException(&quot;Error while writing result to file&quot;, e);
        } finally {
            if(fileWriter!=null) {
                try {
                    fileWriter.flush();
                    fileWriter.close();
                }
                catch (IOException e) {
                    log.warn(&quot;Exception while flushing/closing &quot; + destination,e);
                }
            }
        }

    }</pre>
<p>org\hibernate\tool\hbm2x\jtidy.properties </p>
<pre class="html">indent=auto
indent-spaces=4
#indent-attributes=yes
    wrap=180
markup=yes
clean=yes
output-xml=yes
input-xml=yes
show-warnings=yes
trim-empty-elements=yes
input-encoding=utf-8
output-encoding=utf-8</pre>
]]></content:encoded>
			<wfw:commentRss>http://javadou.com/hibernate-tools-create-marke-430/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Hibernate dao单元测试</title>
		<link>http://javadou.com/hibernate-dao-union-test-248/</link>
		<comments>http://javadou.com/hibernate-dao-union-test-248/#comments</comments>
		<pubDate>Thu, 10 Sep 2009 23:35:00 +0000</pubDate>
		<dc:creator>阿超</dc:creator>
				<category><![CDATA[Hibernate]]></category>
		<category><![CDATA[dao]]></category>
		<category><![CDATA[hibernate]]></category>

		<guid isPermaLink="false">http://javadou.com/hibernate-dao-union-test-248/</guid>
		<description><![CDATA[单元测试作为保证软件质量及重构的基础，早已获得广大开发人员的认可。单元测试是一种细粒度的测试，越来越多的开发人员在提交功能模块时也同时提交相应的单元测试。对于大多数开发人员来讲，编写单元测... ]]></description>
			<content:encoded><![CDATA[<p>&#160;&#160;&#160;&#160; 单元测试作为保证软件质量及重构的基础，早已获得广大开发人员的认可。单元测试是一种细粒度的测试，越来越多的开发人员在提交功能模块时也同时提交相应的单元测试。对于大多数开发人员来讲，编写单元测试已经成为开发过程中必须的流程和最佳实践。</p>
<p>对普通的逻辑组件编写单元测试是一件容易的事情，由于逻辑组件通常只需要内存资源，因此，设置好输入输出即可编写有效的单元测试。对于稍微复杂一点的组件，例如Servlet，我们可以自行编写模拟对象，以便模拟HttpRequest和HttpResponse等对象，或者，使用 EasyMock之类的动态模拟库，可以对任意接口实现相应的模拟对象，从而对依赖接口的组件进行有效的单元测试。</p>
<p>在J2EE开发中，对DAO组件编写单元测试往往是一件非常复杂的任务。和其他组件不通，DAO组件通常依赖于底层数据库，以及JDBC接口或者某个ORM框架（如Hibernate），对DAO组件的测试往往还需引入事务，这更增加了编写单元测试的复杂性。虽然使用EasyMock也可以模拟出任意的JDBC接口对象，或者ORM框架的主要接口，但其复杂性往往非常高，需要编写大量的模拟代码，且代码复用度很低，甚至不如直接在真实的数据库环境下测试。不过，使用真实数据库环境也有一个明显的弊端，我们需要准备数据库环境，准备初始数据，并且每次运行单元测试后，其数据库现有的数据将直接影响到下一次测试，难以实现“即时运行，反复运行”单元测试的良好实践。</p>
<p>本文针对DAO组件给出一种较为合适的单元测试的编写策略。在JavaEE开发网（<a href="http://javadou.com">http://javadou.com</a>）的开发过程中，为了对DAO组件进行有效的单元测试，我们采用HSQLDB这一小巧的纯Java数据库作为测试时期的数据库环境，配合Ant，实现了自动生成数据库脚本，测试前自动初始化数据库，极大地简化了DAO组件的单元测试的编写。     <br />在Java领域，JUnit作为第一个单元测试框架已经获得了最广泛的应用，无可争议地成为Java领域单元测试的标准框架。本文以最新的JUnit 4版本为例，演示如何创建对DAO组件的单元测试用例。</p>
<p>javadou的持久层使用Hibernate 3.2，底层数据库为MySQL。为了演示如何对DAO进行单元测试，我们将其简化为一个DAOTest工程：</p>
<p>由于将Hibernate的Transaction绑定在Thread上，因此，HibernateUtil类负责初始化SessionFactory以及获取当前的Session：    </p>
<pre class="java">public class HibernateUtil {
  private static final  SessionFactory sessionFactory;
  static {
  try {
  sessionFactory =  new AnnotationConfiguration()
  .configure()
  .buildSessionFactory();
  }
  catch(Exception e) {
  throw new  ExceptionInInitializerError(e);
  }
  }&#160;&#160; public static Session  getCurrentSession() {
  return  sessionFactory.getCurrentSession();
  }
  }
  </pre>
<p>HibernateUtil还包含了一些辅助方法，如：</p>
<pre class="java">　public static Object query(Class clazz, Serializable id);
  public static void createEntity(Object entity);
  public static Object queryForObject(String hql, Object[] params);
  public static List queryForList(String hql, Object[] params);
  </pre>
<p>在此不再多述。实体类User使用JPA注解，代表一个用户： </p>
<pre class="java">@Entity

  @Table(name=&quot;T_USER&quot;)

  public class User {

  public static final  String REGEX_USERNAME = &quot;[a-z0-9][a-z0-9\\-]{1,18}[a-z0-9]&quot;;

  public static final  String REGEX_PASSWORD = &quot;[a-f0-9]{32}&quot;;

  public static final  String REGEX_EMAIL = &quot;([0-9a-zA-Z]([-.\\w]*[0-9a-zA-Z])*@([0-9a-zA-Z][-\\w]*[0-9a-zA-Z]\\.)+[a-zA-Z]{2,9})&quot;;
  private String  username;     // 用户名 

  private String  password;     // MD5口令 

  private boolean  admin;       // 是否是管理员 

  private String  email;        // 电子邮件 

  private int  emailValidation; // 电子邮件验证码 

  private long  createdDate;    // 创建时间 

  private long  lockDate;       // 锁定时间
  public User() {}
  public User(String  username, String password, boolean admin, long lastSignOnDate) {

  this.username = username;

  this.password =  password;

  this.admin = admin;

  }
  @Id

  @Column(updatable=false,  length=20)

  @Pattern(regex=REGEX_USERNAME)

  public String  getUsername() { return username; }

  public void setUsername(String  username) { this.username = username; }
  @Column(nullable=false,  length=32)

  @Pattern(regex=REGEX_PASSWORD)

  public String  getPassword() { return password; }

  public void  setPassword(String password) { this.password = password; }
  @Column(nullable=false,  length=50)

  @Pattern(regex=REGEX_EMAIL)

  public String getEmail()  { return email; }

  public void  setEmail(String email) { this.email = email; }
  @Column(nullable=false)

  public boolean getAdmin()  { return admin; }

  public void  setAdmin(boolean admin) { this.admin = admin; }
  @Column(nullable=false,  updatable=false)

  public long  getCreatedDate() { return createdDate; }

  public void  setCreatedDate(long createdDate) { this.createdDate = createdDate; }
  @Column(nullable=false)

  public int  getEmailValidation() { return emailValidation; }

  public void  setEmailValidation(int emailValidation) { this.emailValidation =  emailValidation; }
  @Column(nullable=false)

  public long getLockDate()  { return lockDate; }

  public void  setLockDate(long lockDate) { this.lockDate = lockDate; }
  @Transient

  public boolean  getEmailValidated() { return emailValidation==0; }
  @Transient

  public boolean  getLocked() {

  return !admin  &amp;&amp; lockDate&gt;0 &amp;&amp; lockDate&gt;System.currentTimeMillis();

  }

  }
  </pre>
<p>实体类PasswordTicket代表一个重置口令的请求： </p>
<pre class="java">@Entity

  @Table(name=&quot;T_PWDT&quot;)

  public class PasswordTicket {

  private String id;

  private User user;

  private String ticket;

  private long createdDate;
  @Id

  @Column(nullable=false, updatable=false,  length=32)

  @GeneratedValue(generator=&quot;system-uuid&quot;)

  @GenericGenerator(name=&quot;system-uuid&quot;,  strategy=&quot;uuid&quot;)

  public String getId() {  return id; }

  protected void  setId(String id) { this.id = id; }
  @ManyToOne

  @JoinColumn(nullable=false, updatable=false)

  public User getUser() {  return user; }

  public void setUser(User  user) { this.user = user; }
  @Column(nullable=false,  updatable=false, length=32)

  public String getTicket()  { return ticket; }

  public void  setTicket(String ticket) { this.ticket = ticket; }
  @Column(nullable=false,  updatable=false)

  public long  getCreatedDate() { return createdDate; }

  public void  setCreatedDate(long createdDate) { this.createdDate = createdDate; }

  }</pre>
<p>UserDao接口定义了对用户的相关操作： </p>
<pre class="java">public interface UserDao {
  User  queryForSignOn(String username);
  User queryUser(String  username);
  void createUser(User  user);
  void updateUser(User  user);
  boolean  updateEmailValidation(String username, int ticket);
  String  createPasswordTicket(User user);
  boolean  updatePassword(String username, String oldPassword, String newPassword);
  boolean  queryResetPassword(User user, String ticket);
  boolean  updateResetPassword(User user, String ticket, String password);
  void updateLock(User  user, long lockTime);
  void updateUnlock(User  user);
  }</pre>
<p>UserDaoImpl是其实现类：</p>
<pre>　public class UserDaoImpl implements UserDao {
  public User  queryForSignOn(String username) {
  User user =  queryUser(username);
  if(user.getLocked())
  throw new  LockException(user.getLockDate());
  return user;
  }
　public User  queryUser(String username) {
  return (User)  HibernateUtil.query(User.class, username);
  }
　public void  createUser(User user) {
  user.setEmailValidation((int)(Math.random() * 1000000) + 0xf);
  HibernateUtil.createEntity(user);
  }
  // 其余方法略 
  ...
  }
  </pre>
<p>由于将Hibernate事务绑定在Thread上，因此，实际的客户端调用DAO组件时，还必须加入事务代码：</p>
<pre class="java">Transaction tx =  HibernateUtil.getCurrentSession().beginTransaction();
  try {
  dao.xxx();
  tx.commit();
  }
  catch(Exception e) {
  tx.rollback();
  throw e;
  }
  </pre>
<p>下面，我们开始对DAO组件编写单元测试。前面提到了HSQLDB这一小巧的纯Java数据库。HSQLDB除了提供完整的JDBC驱动以及事务支持外，HSQLDB还提供了进程外模式（与普通数据库类似）和进程内模式（In-Process），以及文件和内存两种存储模式。我们将HSQLDB 设定为进程内模式及仅使用内存存储，这样，在运行JUnit测试时，可以直接在测试代码中启动HSQLDB。测试完毕后，由于测试数据并没有保存在文件上，因此，不必清理数据库。</p>
<p>此外，为了执行批量测试，在每个独立的DAO单元测试运行前，我们都执行一个初始化脚本，重新建立所有的表。该初始化脚本是通过HibernateTool自动生成的，稍后我们还会讨论。下图是单元测试的执行顺序：<br />
  <br /><img alt="对DAO编写单元测试 图-2" src="http://dev2dev.bea.com.cn/images/070820/image070820002.jpg" align="middle" border="0" /></p>
<p>在编写测试类之前，我们首先准备了一个TransactionCallback抽象类，该类通过Template模式将DAO调用代码通过事务包装起来：</p>
<pre class="java">　public abstract class TransactionCallback {
  public final Object  execute() throws Exception {
  Transaction tx =  HibernateUtil.getCurrentSession().beginTransaction();
  try {
  Object r =  doInTransaction();
  tx.commit();
  return r;
  }
  catch(Exception e) {
  tx.rollback();
  throw e;
  }
  }
  // 模板方法： 
  protected abstract Object  doInTransaction() throws Exception;
  }
  </pre>
<p>其原理是使用JDK提供的动态代理。由于JDK的动态代理只能对接口代理，因此，要求DAO组件必须实现接口。如果只有具体的实现类，则只能考虑CGLIB之类的第三方库，在此我们不作更多讨论。</p>
<p>下面我们需要编写DatabaseFixture，负责启动HSQLDB数据库，并在@Before方法中初始化数据库表。该DatabaseFixture可以在所有的DAO组件的单元测试类中复用：</p>
<pre class="java">　public class DatabaseFixture {
  private static Server  server = null; // 持有HSQLDB的实例 
  private static final  String DATABASE_NAME = &quot;javaeedev&quot;; // 数据库名称 
  private static final  String SCHEMA_FILE = &quot;schema.sql&quot;; // 数据库初始化脚本 
  private static final  List&lt;String&gt; initSqls = new ArrayList&lt;String&gt;();
　@BeforeClass // 启动HSQLDB数据库 
  public static void  startDatabase() throws Exception {
  if(server!=null)
  return;
  server = new  Server();
  server.setDatabaseName(0,  DATABASE_NAME);
  server.setDatabasePath(0, &quot;mem:&quot; + DATABASE_NAME);
  server.setSilent(true);
  server.start();
  try {
  Class.forName(&quot;org.hsqldb.jdbcDriver&quot;);
  }
  catch(ClassNotFoundException cnfe) {
  throw new  RuntimeException(cnfe);
  }
  LineNumberReader  reader = null;
  try {
  reader = new  LineNumberReader(new  　　　InputStreamReader(DatabaseFixture.class.getClassLoader().getResourceAsStream(SCHEMA_FILE)));
  for(;;) {
  String line =  reader.readLine();
  if(line==null) break;
  // 将text类型的字段改为varchar(2000)，因为HSQLDB不支持text： 
  line =  line.trim().replace(&quot; text &quot;, &quot; varchar(2000)  &quot;).replace(&quot; 　text,&quot;, &quot; varchar(2000),&quot;);
  if(!line.equals(&quot;&quot;))
  initSqls.add(line);
  }
  }
  catch(IOException e)  {
  throw new  RuntimeException(e);
  }
  finally {
  if(reader!=null)  {
  try {  reader.close(); } catch(IOException e) {}
  }
  }
  }
　@Before // 执行初始化脚本 
  public void initTables()  {
  for(String sql :  initSqls) {
  executeSQL(sql);
  }
  }
static Connection  getConnection() throws SQLException {
  return  DriverManager.getConnection(&quot;jdbc:hsqldb:mem:&quot; + DATABASE_NAME,  &quot;sa&quot;, &quot;&quot;);
  }
static void  close(Statement stmt) {
  if(stmt!=null) {
  try {
  stmt.close();
  }
  catch(SQLException e) {}
  }
  }
static void  close(Connection conn) {
  if(conn!=null) {
  try {
  conn.close();
  }
  catch(SQLException e) {}
  }
  }
static void  executeSQL(String sql) {
  Connection conn =  null;
  Statement stmt =  null;
  try {
  conn =  getConnection();
  boolean  autoCommit = conn.getAutoCommit();
  conn.setAutoCommit(true);
  stmt = conn.createStatement();
  stmt.execute(sql);
  conn.setAutoCommit(autoCommit);
  }
  catch(SQLException e)  {
  log.warn(&quot;Execute failed: &quot; + sql + &quot;\nException: &quot;  + e.getMessage());
  }
  finally {
  close(stmt);
  close(conn);
  }
  }
public static Object  createProxy(final Object target) {
  return  Proxy.newProxyInstance(
  target.getClass().getClassLoader(),
  target.getClass().getInterfaces(),
  new  InvocationHandler() {
  public  Object invoke(Object proxy, final Method method, final Object[] args) throws  Throwable {
  return new TransactionCallback() {
  @Override
  protected Object doInTransaction() throws Exception {
  return method.invoke(target, args);
  }
  }.execute();
  }
  }
  );
  }
  }
  </pre>
<p>注意DatabaseFixture的createProxy()方法，它将一个普通的DAO对象包装为在事务范围内执行的代理对象，即对于一个普通的DAO对象的方法调用前后，自动地开启事务并根据异常情况提交或回滚事务。</p>
<p>下面是UserDaoImpl的单元测试类：</p>
<pre class="java">　public class UserDaoImplTest extends DatabaseFixture {
  private UserDao userDao =  new UserDaoImpl();
  private UserDao proxy =  (UserDao)createProxy(userDao);
　@Test
  public void  testQueryUser() {
  User user =  newUser(&quot;test&quot;);
  proxy.createUser(user);
  User t =  proxy.queryUser(&quot;test&quot;);
  assertEquals(user.getEmail(), t.getEmail());
  }
  }
  </pre>
<p>注意到UserDaoImplTest持有两个UserDao引用，userDao是普通的UserDaoImpl对象，而proxy则是将userDao进行了事务封装的对象。</p>
<p>由于UserDaoImplTest从DatabaseFixture继承，因此，@Before方法在每个@Test方法调用前自动调用，这样，每个@Test方法执行前，数据库都是一个经过初始化的“干净”的表。</p>
<p>对于普通的测试，如UserDao.queryUser()方法，直接调用proxy.queryUser()即可在事务内执行查询，获得返回结果。</p>
<p>对于异常测试，例如期待一个ResourceNotFoundException，就不能直接调用proxy.queryUser()方法，否则，将得到一个UndeclaredThrowableException：</p>
<p><img alt="对DAO编写单元测试 图-3" src="http://dev2dev.bea.com.cn/images/070820/image070820003.jpg" align="middle" border="0" /></p>
<p>这是因为通过反射调用抛出的异常被代理类包装为UndeclaredThrowableException，因此，对于异常测试，只能使用原始的userDao对象配合TransactionCallback实现：</p>
<pre class="java">　@Test(expected=ResourceNotFoundException.class)
  public void testQueryNonExistUser() throws Exception {
  new TransactionCallback()  {
  protected Object  doInTransaction() throws Exception {
  userDao.queryUser(&quot;nonexist&quot;);
  return null;
  }
  }.execute();
  }
  </pre>
<p>到此为止，对DAO组件的单元测试已经实现完毕。下一步，我们需要使用HibernateTool自动生成数据库脚本，免去维护SQL语句的麻烦。相关的Ant脚本片段如下：</p>
<pre class="java">　&lt;target name=&quot;make-schema&quot; depends=&quot;build&quot;  description=&quot;create schema&quot;&gt;
  &lt;taskdef  name=&quot;hibernatetool&quot; classname=&quot;org.hibernate.tool.ant.HibernateToolTask&quot;&gt;
  &lt;classpath  refid=&quot;build-classpath&quot;/&gt;
  &lt;/taskdef&gt;
  &lt;taskdef  name=&quot;annotationconfiguration&quot;  classname=&quot;org.hibernate.tool.ant.AnnotationConfigurationTask&quot;&gt;
  &lt;classpath  refid=&quot;build-classpath&quot;/&gt;
  &lt;/taskdef&gt;
  &lt;annotationconfiguration  configurationfile=&quot;${src.dir}/hibernate.cfg.xml&quot;/&gt;
  &lt;hibernatetool  destdir=&quot;${gen.dir}&quot;&gt;
  &lt;classpath  refid=&quot;build-classpath&quot;/&gt;
  &lt;annotationconfiguration  configurationfile=&quot;${src.dir}/hibernate.cfg.xml&quot;/&gt;
  &lt;hbm2ddl
  export=&quot;false&quot;
  drop=&quot;true&quot;
  create=&quot;true&quot;
  delimiter=&quot;;&quot;
  outputfilename=&quot;schema.sql&quot;
  destdir=&quot;${src.dir}&quot;
  /&gt;
  &lt;/hibernatetool&gt;
  &lt;/target&gt;
  </pre>
<p>完整的Ant脚本以及Hibernate配置文件请参考项目工程源代码。</p>
<p>利用HSQLDB，我们已经成功地简化了对DAO组件进行单元测试。我发现这种方式能够找出许多常见的bug：</p>
<ul>
<li>HQL语句的语法错误，包括SQL关键字和实体类属性的错误拼写，反复运行单元测试就可以不断地修复许多这类错误，而不需要等到通过Web页面请求而调用DAO时才发现问题； </li>
<li>传入了不一致或者顺序错误的HQL参数数组，导致Hibernate在运行期报错； </li>
<li>一些逻辑错误，包括不允许的null属性（常常由于忘记设置实体类的属性），更新实体时引发的数据逻辑状态不一致。 </li>
</ul>
<p>总之，单元测试需要根据被测试类的实际情况，编写最简单最有效的测试用例。本文旨在给出一种编写DAO组件单元测试的有效方法。</p>
]]></content:encoded>
			<wfw:commentRss>http://javadou.com/hibernate-dao-union-test-248/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MyEclipse生成的Spring+Hibernate无法保存数据问题2</title>
		<link>http://javadou.com/myeclipse-spring-hibernate-save-database-2-241/</link>
		<comments>http://javadou.com/myeclipse-spring-hibernate-save-database-2-241/#comments</comments>
		<pubDate>Wed, 09 Sep 2009 02:41:00 +0000</pubDate>
		<dc:creator>阿超</dc:creator>
				<category><![CDATA[Hibernate]]></category>
		<category><![CDATA[MyEclipse]]></category>
		<category><![CDATA[Spring]]></category>
		<category><![CDATA[hibernate]]></category>
		<category><![CDATA[myeclipse]]></category>
		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://javadou.com/myeclipse-spring-hibernate-save-database-2-241/</guid>
		<description><![CDATA[MyEclipse生成的Spring+Hibernate无法保存数据问题的解决方法2 - 用 CGLIB 来实现事务管理

  上一小节讨论了用 JDK 的代理机制来实现事务管理的解决方案, 相比起来它有一个麻烦的地方就是必须需要生成一个 DAO 的接口才能... ]]></description>
			<content:encoded><![CDATA[<p>&#160; MyEclipse生成的Spring+Hibernate无法保存数据问题的解决方法2 &#8211; 用 CGLIB 来实现事务管理</p>
<p>&#160; 上一小节讨论了用 JDK 的代理机制来实现事务管理的解决方案, 相比起来它有一个麻烦的地方就是必须需要生成一个 DAO 的接口才能工作. 那么另一种比较简单的解决方案就是用 CGBLIB, 可以不用编写接口, 那么下面是 Spring 参考文档中的内容:   <br />7.5.3. 基于JDK和CGLIB的代理    <br />这个小节作为说明性文档，解释了对于一个目标对象（需要被代理的对象），ProxyFactryBean是如何决定究竟创建一个基于JDK还是CGLIB的代理的。 </p>
<p>注意   <br />ProxyFactoryBean需要创建基于JDK还是CGLIB代理的具体行为在版本1.2.x和2.0中有所不同。现在ProxyFactoryBean在关于自动检测接口方面使用了与TransactionProxyFactoryBean相似的语义。 </p>
<p>如果一个需要被代理的目标对象的类（后面将简单地称它为目标类）没有实现任何接口，那么一个基于CGLIB的代理将被创建。这是最简单的场景，因为 JDK代理是基于接口的，没有接口意味着没有使用JDK进行代理的可能。在目标bean里将被插入探测代码，通过interceptorNames属性给出了拦截器的列表。注意一个基于CGLIB的代理将被创建即使 ProxyFactoryBean的proxyTargetClass属性被设置为false。（很明显这种情况下对这个属性进行设置是没有意义的，最好把它从bean的定义中移除，因为虽然这只是个多余的属性，但在许多情况下会引起混淆。） </p>
<p>如果目标类实现了一个（或者更多）接口，那么创建代理的类型将根据ProxyFactoryBean的配置来决定。 </p>
<p>如果ProxyFactoryBean的proxyTargetClass属性被设为true，那么一个基于CGLIB的代理将创建。这样的规定是有意义的，遵循了最小惊讶法则（保证了设定的一致性）。甚至当ProxyFactoryBean的proxyInterfaces属性被设置为一个或者多个全限定接口名，而proxyTargetClass属性被设置为true仍然将实际使用基于CGLIB的代理。 </p>
<p>如果ProxyFactoryBean的proxyInterfaces属性被设置为一个或者多个全限定接口名，一个基于JDK的代理将被创建。被创建的代理将实现所有在proxyInterfaces属性里被说明的接口；如果目标类实现了全部在proxyInterfaces属性里说明的接口以及一些额外接口，返回的代理将只实现说明的接口而不会实现那些额外接口。 </p>
<p>如果ProxyFactoryBean的proxyInterfaces属性没有被设置，但是目标类实现了一个（或者更多）接口，那么 ProxyFactoryBean将自动检测到这个目标类已经实现了至少一个接口，一个基于JDK的代理将被创建。被实际代理的接口将是目标类所实现的全部接口；实际上，这和在proxyInterfaces属性中列出目标类实现的每个接口的情况是一样的。然而，这将显著地减少工作量以及输入错误的可能性。 </p>
<p>好了, 详细阐述这个解决方案.</p>
<p>用 MyEclipse 的自动生成功能产生的 Spring + Hibernate 的 DAO 有时候会出现不能保存数据但是可以查询数据的问题, 这是因为默认生成的 Spring 配置文件里面没有包含对事务的操作, 也就是没有 commit Hibernate transaction 的调用所以无法保存数据. 也就是正确的调用需要 beginTran, save, commit, 但是现在就少了 tran 的调用代码部分. 因为刚刚接触 Spring 这个 &quot;轻量级&quot; 非侵入框架不久, 所以好多问题不是太熟悉, 最近收集了一些资料看了看总算解决了问题. 有问题不要紧, 只要能通过学习来解决它就可以了, 我个人并不很喜欢没事去精通 XXX 框架, 而是喜欢做一些解决问题和查资料能力的锻炼, 有了后面所提的能力, 不管改天是不是出了个 Winter 框架, 也不会担心落伍, 当然前提是基础知识要牢固, 否则很容易看不懂. </p>
<p>解决方法是在配置文件里&quot;侵入性&quot;(必须这样做, 做额外的配置, 否则就无法正常工作, 所以是侵入性的)的加入事务配置后就可以正常的保存数据到 Derby, Oracle 等数据了:</p>
<p>1. 修改配置文件给原来的 UsersDAO 加入代理类来进行事务管理:   <br />&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;    <br />&lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;    <br /> xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;    <br /> xsi:schemaLocation=&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd&quot;&gt;</p>
<p> &lt;bean id=&quot;sessionFactory&quot;   <br />&#160; class=&quot;org.springframework.orm.hibernate3.LocalSessionFactoryBean&quot;&gt;    <br />&#160; &lt;property name=&quot;configLocation&quot;    <br />&#160;&#160; value=&quot;file:src/hibernate.cfg.xml&quot;&gt;    <br />&#160; &lt;/property&gt;    <br /> &lt;/bean&gt;</p>
<p> &lt;!&#8211; UsersDAO &#8211;&gt;   <br /> &lt;bean id=&quot;UsersDAO&quot; class=&quot;dao.UsersDAO&quot;&gt;    <br />&#160; &lt;property name=&quot;sessionFactory&quot;&gt;    <br />&#160;&#160; &lt;ref bean=&quot;sessionFactory&quot; /&gt;    <br />&#160; &lt;/property&gt;    <br /> &lt;/bean&gt;</p>
<p> &lt;!&#8211; 以下两个 Bean transactionManager 和 userDAOProxy 是新加入的内容, 用来配置事务 &#8211;&gt;</p>
<p> &lt;!&#8211; 声明一个 Hibernate 3 的 事务管理器供代理类自动管理事务用 &#8211;&gt;   <br /> &lt;bean id=&quot;transactionManager&quot;    <br />&#160; class=&quot;org.springframework.orm.hibernate3.HibernateTransactionManager&quot;&gt;    <br />&#160; &lt;property name=&quot;sessionFactory&quot;&gt;    <br />&#160;&#160; &lt;ref local=&quot;sessionFactory&quot; /&gt;    <br />&#160; &lt;/property&gt;    <br /> &lt;/bean&gt;</p>
<p> &lt;!&#8211; 这个代理类是最后对外公开的类, 否则因为没有进行事务操作,    <br /> 保存时没有提交 hibernate 的事务, 这将无法对数据库进行改动, 也就是原来要调用 UsersDAO 的地方都要转而调用这个代理对象 userDAOProxy; 具体的属性配置在 target 参数那里指定了这个对象对原来的 UsersDAO 对象进行代理;    <br /> 也因为要使用代理, 只有通过它来作为原来配置的 UsersDAO 的代理工作, 才能让 Spring 在保存数据的时候自动打开 Hibernate 的 Transaction 并提交, 即属性 transactionManager 配置的 HibernateTransactionManager &#8211;&gt;    <br /> &lt;bean id=&quot;userDAOProxy&quot;    <br />&#160; class=&quot;org.springframework.transaction.interceptor.TransactionProxyFactoryBean&quot;&gt;</p>
<p>&#160; &lt;!&#8211; 注意这个属性, 详细意义请参考文章开头的参考资料, 必须为 true 使用CGLIB才不用强制编写DAO接口 &#8211;&gt;   <br />&#160; &lt;property name=&quot;proxyTargetClass&quot;&gt;    <br />&#160;&#160; &lt;value&gt;true&lt;/value&gt;    <br />&#160; &lt;/property&gt;</p>
<p>&#160; &lt;property name=&quot;transactionManager&quot;&gt;   <br />&#160;&#160; &lt;ref bean=&quot;transactionManager&quot; /&gt;    <br />&#160; &lt;/property&gt;    <br />&#160; &lt;property name=&quot;target&quot;&gt;    <br />&#160;&#160; &lt;ref local=&quot;UsersDAO&quot; /&gt;    <br />&#160; &lt;/property&gt;    <br />&#160; &lt;property name=&quot;transactionAttributes&quot;&gt;    <br />&#160;&#160; &lt;props&gt;    <br />&#160;&#160;&#160; &lt;!&#8211; 这里的方法签名可以精确到方法, 先懒惰一下全配置上 &#8211;&gt;    <br />&#160;&#160;&#160; &lt;prop key=&quot;*&quot;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;    <br />&#160;&#160; &lt;/props&gt;    <br />&#160; &lt;/property&gt;    <br /> &lt;/bean&gt;</p>
<p>&lt;/beans&gt;</p>
<p>2. 修改调用代码, 原来调用 UsersDAO 的地方都要转而调用 userDAOProxy, 因为用了 CGLIB, 所以类型转换不会发生异常.   <br />&#160; 原始代码:    <br />&#160; UsersDAO dao = applicationContext.getBean(&quot;UsersDAO&quot;);    <br />&#160; dao.save(users);// 可能无法保存数据, 因为没有事务管理    <br />&#160; 修改为:    <br />&#160; UsersDAO dao = applicationContext.getBean(&quot;userDAOProxy&quot;);    <br />&#160; dao.save(users);// 现在应该 OK 了, 因为事务提交了</p>
]]></content:encoded>
			<wfw:commentRss>http://javadou.com/myeclipse-spring-hibernate-save-database-2-241/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MyEclipse生成Spring+Hibernate无法保存数据问题解决方法</title>
		<link>http://javadou.com/myeclipse-spring-hibernate-save-database-240/</link>
		<comments>http://javadou.com/myeclipse-spring-hibernate-save-database-240/#comments</comments>
		<pubDate>Wed, 09 Sep 2009 01:40:00 +0000</pubDate>
		<dc:creator>阿超</dc:creator>
				<category><![CDATA[Hibernate]]></category>
		<category><![CDATA[MyEclipse]]></category>
		<category><![CDATA[Spring]]></category>
		<category><![CDATA[hibernate]]></category>
		<category><![CDATA[myeclipse]]></category>
		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://javadou.com/myeclipse-spring-hibernate-save-database-240/</guid>
		<description><![CDATA[用 MyEclipse 的自动生成功能产生的 Spring + Hibernate 的 DAO 有时候会出现不能保存数据但是可以查询数据的问题, 这是因为默认生成的 Spring 配置文件里面没有包含对事务的操作, 也就是没有 commit Hibernate transaction 的调用... ]]></description>
			<content:encoded><![CDATA[<p>MyEclipse生成的Spring+Hibernate无法保存数据问题的解决方法</p>
<p>用 MyEclipse 的自动生成功能产生的 Spring + Hibernate 的 DAO 有时候会出现不能保存数据但是可以查询数据的问题, 这是因为默认生成的 Spring 配置文件里面没有包含对事务的操作, 也就是没有 commit Hibernate transaction 的调用所以无法保存数据. 也就是正确的调用需要 beginTran, save, commit, 但是现在就少了 tran 的调用代码部分. 因为刚刚接触 Spring 这个 &#8220;轻量级&#8221; 非侵入框架不久, 所以好多问题不是太熟悉, 最近收集了一些资料看了看总算解决了问题. 有问题不要紧, 只要能通过学习来解决它就可以了, 我个人并不很喜欢没事去精通 XXX 框架, 而是喜欢做一些解决问题和查资料能力的锻炼, 有了后面所提的能力, 不管改天是不是出了个 Winter 框架, 也不会担心落伍, 当然前提是基础知识要牢固, 否则很容易看不懂.</p>
<p>解决方法是在配置文件里&#8221;侵入性&#8221;(必须这样做, 做额外的配置和修改, 否则就无法正常工作, 所以是侵入性的)的加入事务配置后就可以正常的保存数据到 Derby, Oracle 等数据了, 也有其它的解决办法, 希望用 Spring 比较早的经验多的人提出建议:</p>
<p>1. 用 Ecipse 的重构给自动生成的 UsersDAO 类添加一个接口, 里面包含所有的方法声明, 例如 IUsersDAO, 加入接口的目的是为了使用 JDK 的动态代理方式实现的 Spring AOP 来工作, 也有另一种解决方案使用 CGLIB 的话就不需要这一步了, 这种方式下一次讨论.</p>
<p>public interface IUsersDAO {</p>
<p>public abstract void save(Users transientInstance);<br />
}</p>
<p>public class UsersDAO extends HibernateDaoSupport implements IUsersDAO {<br />
&#8230;<br />
public void save(Users transientInstance) {<br />
log.debug(&#8220;saving Users instance&#8221;);<br />
try {<br />
getHibernateTemplate().save(transientInstance);<br />
log.debug(&#8220;save successful&#8221;);<br />
} catch (RuntimeException re) {<br />
log.error(&#8220;save failed&#8221;, re);<br />
throw re;<br />
}<br />
&#8230;<br />
}</p>
<p>2. 修改配置文件给原来的 UsersDAO 加入代理类来进行事务管理:<br />
&lt;?xml version=&#8221;1.0&#8243; encoding=&#8221;UTF-8&#8243;?&gt;<br />
&lt;beans xmlns=&#8221;http://www.springframework.org/schema/beans&#8221;<br />
xmlns:xsi=&#8221;http://www.w3.org/2001/XMLSchema-instance&#8221;<br />
xsi:schemaLocation=&#8221;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd&#8221;&gt;</p>
<p>&lt;bean id=&#8221;sessionFactory&#8221;<br />
class=&#8221;org.springframework.orm.hibernate3.LocalSessionFactoryBean&#8221;&gt;<br />
&lt;property name=&#8221;configLocation&#8221;<br />
value=&#8221;file:src/hibernate.cfg.xml&#8221;&gt;<br />
&lt;/property&gt;<br />
&lt;/bean&gt;</p>
<p>&lt;!&#8211; UsersDAO implements IUsersDAO 接口 &#8211;&gt;<br />
&lt;bean id=&#8221;UsersDAO&#8221; class=&#8221;dao.UsersDAO&#8221;&gt;<br />
&lt;property name=&#8221;sessionFactory&#8221;&gt;<br />
&lt;ref bean=&#8221;sessionFactory&#8221; /&gt;<br />
&lt;/property&gt;<br />
&lt;/bean&gt;</p>
<p>&lt;!&#8211; 以下两个 Bean transactionManager 和 userDAOProxy 是新加入的内容, 用来配置事务 &#8211;&gt;</p>
<p>&lt;!&#8211; 声明一个 Hibernate 3 的 事务管理器供代理类自动管理事务用 &#8211;&gt;<br />
&lt;bean id=&#8221;transactionManager&#8221;<br />
class=&#8221;org.springframework.orm.hibernate3.HibernateTransactionManager&#8221;&gt;<br />
&lt;property name=&#8221;sessionFactory&#8221;&gt;<br />
&lt;ref local=&#8221;sessionFactory&#8221; /&gt;<br />
&lt;/property&gt;<br />
&lt;/bean&gt;</p>
<p>&lt;!&#8211; 这个代理类是最后对外公开的类, 否则因为没有进行事务操作,<br />
保存时没有提交 hibernate 的事务, 这将无法对数据库进行改动, 也就是原来要调用 UsersDAO 的地方都要转而调用这个代理对象 userDAOProxy; 具体的属性配置在 target 参数那里指定了这个对象对原来的 UsersDAO 对象进行代理;<br />
也因为要使用动态代理, 所以这里必须给 UsersDAO 抽象一个接口 IUsersDAO, 只有通过它来作为原来配置的 UsersDAO 的代理工作, 才能让 Spring 在保存数据的时候自动打开 Hibernate 的 Transaction 并提交, 即属性 transactionManager 配置的 HibernateTransactionManager &#8211;&gt;<br />
&lt;bean id=&#8221;userDAOProxy&#8221;<br />
class=&#8221;org.springframework.transaction.interceptor.TransactionProxyFactoryBean&#8221;&gt;<br />
&lt;property name=&#8221;transactionManager&#8221;&gt;<br />
&lt;ref bean=&#8221;transactionManager&#8221; /&gt;<br />
&lt;/property&gt;<br />
&lt;property name=&#8221;target&#8221;&gt;<br />
&lt;ref local=&#8221;UsersDAO&#8221; /&gt;<br />
&lt;/property&gt;<br />
&lt;property name=&#8221;transactionAttributes&#8221;&gt;<br />
&lt;props&gt;<br />
&lt;!&#8211; 这里的方法签名可以精确到方法, 先懒惰一下全配置上 &#8211;&gt;<br />
&lt;prop key=&#8221;*&#8221;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />
&lt;/props&gt;<br />
&lt;/property&gt;<br />
&lt;/bean&gt;</p>
<p>&lt;/beans&gt;</p>
<p>3. 修改调用代码, 原来调用 UsersDAO 的地方都要转而调用 userDAOProxy, 而且转换后的目标要修改为 IUsersDAO, 否则就会报 ClassCastException, 具体原因参考 Spring 的 AOP 实现部分的内容, 也可以用 cglib 来解决.<br />
原始代码:<br />
UsersDAO dao = applicationContext.getBean(&#8220;UsersDAO&#8221;);<br />
dao.save(users);// 可能无法保存数据, 因为没有事务管理<br />
修改为:<br />
IUsersDAO dao = applicationContext.getBean(&#8220;userDAOProxy&#8221;);<br />
dao.save(users);// 现在应该 OK 了, 因为事务提交了</p>
]]></content:encoded>
			<wfw:commentRss>http://javadou.com/myeclipse-spring-hibernate-save-database-240/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Spring 整合 Hibernate + Mysql 的代码</title>
		<link>http://javadou.com/spring-hibernate-mysql-code-239/</link>
		<comments>http://javadou.com/spring-hibernate-mysql-code-239/#comments</comments>
		<pubDate>Tue, 08 Sep 2009 22:38:00 +0000</pubDate>
		<dc:creator>阿超</dc:creator>
				<category><![CDATA[Hibernate]]></category>
		<category><![CDATA[Spring]]></category>
		<category><![CDATA[hibernate]]></category>
		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://javadou.com/spring-hibernate-mysql-code-239/</guid>
		<description><![CDATA[开始用的是 MyEclipse 自带的 Derby 数据库,  发现单独的 Hibernate DAO 没有问题, 一整合 Spring 就插入不了数据, 甚至按照参考资料上的将 HibernateTransactionManager 的加进去也无济于事. 今天换成了 Mysql 就好了, 调试信息全打开... ]]></description>
			<content:encoded><![CDATA[<p>开始用的是 MyEclipse 自带的 Derby 数据库,  发现单独的 Hibernate DAO 没有问题, 一整合 Spring 就插入不了数据, 甚至按照参考资料上的将 HibernateTransactionManager 的加进去也无济于事. 今天换成了 Mysql 就好了, 调试信息全打开也没看到什么出错, 不知原因, 甚是郁闷.</p>
<p><strong>原因已经找到, 事务管理器没加对.具体解决方案请参考:</strong></p>
<p><strong><a href="http://javadou.com/myeclipse-spring-hibernate-save-database-240/" target="_blank">MyEclipse生成的Spring+Hibernate无法保存数据问题的解决方法</a></strong></p>
<p><strong><a href="http://myeclipse-spring-hibernate-save-database-2-241/" target="_blank">MyEclipse生成的Spring+Hibernate无法保存数据问题的解决方法2 &#8211; 用 CGLIB 来实现事务管理</a></strong></p>
<p>可以新建一个 Java Project 然后添加 Hibernate 和 Spring 开发功能就能测试本文提到的代码了.</p>
<p>建表的 SQL:</p>
<pre class="sql">CREATE TABLE `usertable` (
  `id` int(11) NOT NULL,
  `username` varchar(200) NOT NULL,
  `password` varchar(20) NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=GBK;</pre>
<p>src/TestSpringHibernateDAO.java</p>
<pre class="java">import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import entity.Usertable;

import spring_hibernate_dao.UsertableDAO;

public class TestSpringHibernateDAO {

    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext(
        "applicationContext.xml");

        UsertableDAO dao = UsertableDAO.getFromApplicationContext(ctx);

        Usertable user = new Usertable();
        user.setId(5);
        user.setUsername("5");
        user.setPassword("5");

        dao.save(user);
    }

}</pre>
<p>src/entity/Usertable.java</p>
<pre class="java">package entity;

public class Usertable implements java.io.Serializable {

    // Fields

    private Integer id;

    private String username;

    private String password;

    // Constructors

    /** default constructor */
    public Usertable() {
    }

    /** full constructor */
    public Usertable(Integer id, String username, String password) {
        this.id = id;
        this.username = username;
        this.password = password;
    }

    // Property accessors

    public Integer getId() {
        return this.id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return this.username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return this.password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

}</pre>
<p>src/entity/Usertable.hbm.xml</p>
<pre class="xml">
&lt;?xml version="1.0" encoding="utf-8"?&gt;&lt;!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"&gt;&lt;hibernate-mapping&gt;&lt;class name="entity.Usertable" table="usertable" catalog="test"&gt;&lt;id name="id" type="java.lang.Integer"&gt;&lt;column name="id" /&gt;&lt;generator class="assigned" /&gt;&lt;/id&gt;&lt;property name="username" type="java.lang.String"&gt;&lt;column name="username" length="200" not-null="true" /&gt;&lt;/property&gt;&lt;property name="password" type="java.lang.String"&gt;&lt;column name="password" length="20" not-null="true" /&gt;&lt;/property&gt;&lt;/class&gt;&lt;/hibernate-mapping&gt;</pre>
<p>src/spring_hibernate_dao/UsertableDAO.java</p>
<pre class="java">package spring_hibernate_dao;

import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.LockMode;
import org.springframework.context.ApplicationContext;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import entity.Usertable;

/**
 * Data access object (DAO) for domain model class Usertable.
 *
 * @see spring_hibernate_dao.Usertable
 * @author MyEclipse Persistence Tools
 */

public class UsertableDAO extends HibernateDaoSupport {
    private static final Log log = LogFactory.getLog(UsertableDAO.class);

    // property constants
    public static final String USERNAME = "username";

    public static final String PASSWORD = "password";

    protected void initDao() {
        // do nothing
    }

    public void save(Usertable transientInstance) {
        log.debug("saving Usertable instance");
        try {
            getHibernateTemplate().save(transientInstance);
            log.debug("save successful");
        } catch (RuntimeException re) {
            log.error("save failed", re);
            throw re;
        }
    }

    public void delete(Usertable persistentInstance) {
        log.debug("deleting Usertable instance");
        try {
            getHibernateTemplate().delete(persistentInstance);
            log.debug("delete successful");
        } catch (RuntimeException re) {
            log.error("delete failed", re);
            throw re;
        }
    }

    public Usertable findById(java.lang.Integer id) {
        log.debug("getting Usertable instance with id: " + id);
        try {
            Usertable instance = (Usertable) getHibernateTemplate().get(
                    "spring_hibernate.Usertable", id);
            return instance;
        } catch (RuntimeException re) {
            log.error("get failed", re);
            throw re;
        }
    }

    public List findByExample(Usertable instance) {
        log.debug("finding Usertable instance by example");
        try {
            List results = getHibernateTemplate().findByExample(instance);
            log.debug("find by example successful, result size: "
                    + results.size());
            return results;
        } catch (RuntimeException re) {
            log.error("find by example failed", re);
            throw re;
        }
    }

    public List findByProperty(String propertyName, Object value) {
        log.debug("finding Usertable instance with property: " + propertyName
                + ", value: " + value);
        try {
            String queryString = "from Usertable as model where model."
                    + propertyName + "= ?";
            return getHibernateTemplate().find(queryString, value);
        } catch (RuntimeException re) {
            log.error("find by property name failed", re);
            throw re;
        }
    }

    public List findByUsername(Object username) {
        return findByProperty(USERNAME, username);
    }

    public List findByPassword(Object password) {
        return findByProperty(PASSWORD, password);
    }

    public List findAll() {
        log.debug("finding all Usertable instances");
        try {
            String queryString = "from Usertable";
            return getHibernateTemplate().find(queryString);
        } catch (RuntimeException re) {
            log.error("find all failed", re);
            throw re;
        }
    }

    public Usertable merge(Usertable detachedInstance) {
        log.debug("merging Usertable instance");
        try {
            Usertable result = (Usertable) getHibernateTemplate().merge(
                    detachedInstance);
            log.debug("merge successful");
            return result;
        } catch (RuntimeException re) {
            log.error("merge failed", re);
            throw re;
        }
    }

    public void attachDirty(Usertable instance) {
        log.debug("attaching dirty Usertable instance");
        try {
            getHibernateTemplate().saveOrUpdate(instance);
            log.debug("attach successful");
        } catch (RuntimeException re) {
            log.error("attach failed", re);
            throw re;
        }
    }

    public void attachClean(Usertable instance) {
        log.debug("attaching clean Usertable instance");
        try {
            getHibernateTemplate().lock(instance, LockMode.NONE);
            log.debug("attach successful");
        } catch (RuntimeException re) {
            log.error("attach failed", re);
            throw re;
        }
    }

    public static UsertableDAO getFromApplicationContext(ApplicationContext ctx) {
        return (UsertableDAO) ctx.getBean("UsertableDAO");
    }
}</pre>
<p>src/applicationContext.xml</p>
<pre class="xml">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
  &lt;beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"&gt;

&lt;bean id="sessionFactory"

        class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"&gt;

&lt;property name="configLocation"

            value="file:src/hibernate.cfg.xml"&gt;

&lt;/property&gt;

&lt;/bean&gt;

&lt;bean id="UsertableDAO" class="spring_hibernate_dao.UsertableDAO"&gt;

&lt;property name="sessionFactory"&gt;

&lt;ref bean="sessionFactory" /&gt;

&lt;/property&gt;

&lt;/bean&gt;

&lt;/beans&gt;</pre>
<pre class="xml">src/hibernate.cfg.xml

&lt;?xml version='1.0' encoding='UTF-8'?&gt;
  &lt;!DOCTYPE hibernate-configuration PUBLIC

          "-//Hibernate/Hibernate Configuration DTD 3.0//EN"

          "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"&gt;

&lt;hibernate-configuration&gt;

&lt;session-factory&gt;

&lt;property name="connection.username"&gt;root&lt;/property&gt;

&lt;property name="connection.url"&gt;

            jdbc:mysql://localhost/test

&lt;/property&gt;

&lt;property name="dialect"&gt;

            org.hibernate.dialect.MySQLDialect

&lt;/property&gt;

&lt;property name="myeclipse.connection.profile"&gt;

            mysql localhost

&lt;/property&gt;

&lt;property name="connection.driver_class"&gt;

            com.mysql.jdbc.Driver

&lt;/property&gt;

&lt;mapping resource="entity/Usertable.hbm.xml" /&gt;

&lt;/session-factory&gt;

&lt;/hibernate-configuration&gt;</pre>
]]></content:encoded>
			<wfw:commentRss>http://javadou.com/spring-hibernate-mysql-code-239/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>2 分钟用MyEclipse 开发一个 Hibernate 应用</title>
		<link>http://javadou.com/two-min-myeclipse-hibernate-215/</link>
		<comments>http://javadou.com/two-min-myeclipse-hibernate-215/#comments</comments>
		<pubDate>Sat, 05 Sep 2009 11:21:00 +0000</pubDate>
		<dc:creator>阿超</dc:creator>
				<category><![CDATA[Hibernate]]></category>
		<category><![CDATA[MyEclipse]]></category>
		<category><![CDATA[hibernate]]></category>
		<category><![CDATA[myeclipse]]></category>

		<guid isPermaLink="false">http://javadou.com/two-min-myeclipse-hibernate-215/</guid>
		<description><![CDATA[用 MyEclipse, 就有必要把 MyEclipse 快速开发的功能熟悉一下. 当我们熟悉了基本的开发过程之后, 就需要考虑用顺手的 IDE 来让我们的开发速度有个飞跃了.

这次讨论的主题包括: Hibernate 快速开发, Spring 快速开发, Struts 登... ]]></description>
			<content:encoded><![CDATA[<p>用 MyEclipse, 就有必要把 MyEclipse 快速开发的功能熟悉一下. 当我们熟悉了基本的开发过程之后, 就需要考虑用顺手的 IDE 来让我们的开发速度有个飞跃了.</p>
<p>这次讨论的主题包括: Hibernate 快速开发, Spring 快速开发, Struts 登录应用开发, UML 建模, 可视化Swing界面开发这些个内容.</p>
<p>首先就是大家可以看 MyEclipse 的帮助文档进行学习了, 里面很全, 图文并茂, 唯一缺点呢就是文档是英文的. 具体方法:   <br />菜单 Help -&gt; Help Contents, 然后会在浏览器里打开 MyEclipse 帮助文档, 展开左边的 MyEclipse Learning Center, 就能看到详细的开发教程了. 其中 &quot;JEE Application Development&quot; 的部分是我们重点关注的内容.</p>
<p>使用的开发工具是 MyEclipse 5.5.1 GA,&#160; Windows/Linux 版本均可.</p>
<p>好了, 现在简单介绍一下 用 MyEclipse 2 分钟开发一个 Hibernate 应用的步骤.   <br />1. 在 MyEclipse 视图下的 Servers 面板上, 启动 MyEclipse Derby 这个服务器. 相信大家都很熟悉这个过程了.    <br />2. 选择菜单 Window -&gt; Open Persipective -&gt; MyEclipse Database Explorer, 打开新的数据库浏览视图.    <br />3. 在最左边的 DB Browser 面板下选中 MyEclipse Derby 项, 点击右键并选择弹出菜单中的菜单项 Open Connection 来打开数据库连接并显示所有的数据库和表格.    <br />4. 展开 MyEclipse Derby&#160; 节点, 单击选中第一项 Connected to MyEclipse Derby, 点击右键并选择弹出菜单中的菜单项 New SQL Editor.    <br />5. 在 SQL 编辑器里键入下列建表语句:    <br />create table testUser(    <br />id int not null,    <br />username varchar(200),    <br />age int,    <br />primary key (&quot;ID&quot;)    <br />)    <br />, 然后点击编辑器上面的绿色的运行向右箭头按钮来创建表格.    <br />6. 新建一个 Java Project 名字为 MyHibernateTest, 这个过程无需赘述了, 建议建项目的时候将 src 目录和 bin(或者classes)目录分开, 另外提示你切换透视图的时候一定要切换过去到 Java 透视图, 此时默认会在 Package Explorer 中选中刚才已经建好的 Java Project, 但是背景为灰色.    <br />7. 首先单击一下左边的 Package Explorer 中新建的 MyHibernateTest 项目来使其高亮选中, 接着点击菜单项 MyEclipse -&gt; Add Hibernate Capabilities&#8230;, 接着会弹出对话框 New Hibernate Project 提示你设置当前项目的 Hibernate 属性.    <br />对话框的第一页选择 Hibernate 3.1, 其它保持默认;    <br />第二页同样如此, 保持默认来创建新的 Hibernate 配置文件;    <br />第三页Specify Hibernate database connection details则点击 DB Driver 下拉框选择 MyEclipse Derby, 这时候下面的输入框会自动填好数据库连接对应的值.    <br />第四页 Define SessionFactory properties 则先点击 Java Package 一行最右侧的 New&#8230; 按钮来新建一个名字为 dao 的包. 这时候你可以看到 Finish 按钮终于不为灰色了,&#160; 点击它完成给项目加入 Hibernate 开发功能的操作, 包括 Hibernate 类库, jdbc 驱动和 Hibernate 配置文件都已经设置完毕了.    <br />8. 选择菜单 Window -&gt; Open Persipective -&gt; MyEclipse Database Explorer, 打开数据库浏览视图. 展开 Connected to MyEclipse Derby 下面的 APP 节点, 再选中下面的 TABLE 目录,&#160;&#160; 点击右键并选择弹出菜单中的菜单项 Refresh 来刷新数据库表格列表, 这时候展开此节点可以看到下面出现了一个名为 TESTUSER 的表.    <br />9. OK, 最关键的操作即将开始了. 请在 TESTUSER 节点上点击右键并选择弹出菜单中的菜单项 Hibernate Reverse Engineering&#8230;, 弹出一个对话框提示你 Save All Modified Resources, 点击 OK 并且选中 MyHibernateTest, 在 File name 右侧的文件名输入框中输入 create.sql 来保存我们最开始所写的那个建表的 SQL 文件.    <br />10. 接着 Hibernate Reverse Engineering 对话框弹出了.    <br />点击 Java src folder 一行最右侧的 Browser.. 按钮来选择源码目录,&#160; 并把下面的 Java package 右侧的输入框中输入包名 dao, 我们选择 /MyHibernateTest/src 目录并点击完成,&#160; 接着选中下面的三个复选框:    <br />[x] Hibernate mapping file (*.hbm.xml) for each database table    <br />[x] Java Data Object (POJO &lt;&gt; DB Table)    <br />[x] Java Data Access Object (DAO) (Hibernate 3 only)</p>
<p>好了, 点击 Finish 按钮, 就可以看到反向工程的忙碌对话框. 最后当一切结束后弹出对话框提示切换视图到 MyEclipse Hibernate perspective 的时候点击 &quot;OK&quot; 按钮, 您就可以看到工作成果了, 包括下列文件:   <br />HibernateSessionFactory.java    <br />Testuser.hbm.xml    <br />BaseHibernateDAO.java    <br />IBaseHibernateDAO.java    <br />Testuser.java    <br />TestuserDAO.java    <br />hibernate.cfg.xml    <br />. 那么, 我们的 POJO 已经生成了, 就是 Testuser.java,&#160; DAO 的代码也已经生成, 就是 TestuserDAO, 这些代码都已经帮我们写好, 当然我们可以做进一步的修改来适应我们的要求. 当你用工具生成代码的时候, 请确保您已经了解了 Hibernate 手工开发的步骤. 好了, 接下来的事情, 我们就可以    <br />11. 修改 Testuser.hbm.xml 里面的主键生成方式为合适的方式(默认的是 &lt;generator class=&quot;assigned&quot; /&gt;),&#160; 或者一些属性映射关系, 这些仍然要求开发人员对 Hibernate 的配置文件有一定的了解;    <br />或者    <br />12. 继续重复 1, 3, 5, 8, 9, 10 来生成更多的 POJO 或者 DAO.    <br />13. 编写测试代码来运行测试.</p>
<p>小结: 虽然这些步骤很繁琐,&#160; 但是当你熟练之后完全可以在2分钟内完成所有操作, 这样就省去了手工编写大量 Java 代码和 XML 配置文件的痛苦, 这也是实际中程序员采取的偷懒的步骤.   <br />前提: 您一定要理解 Hibernate 手工开发的步骤和 JDBC 驱动的概念, 否则生成的文件有时候是有潜在的问题的, 工具只能帮你完成部分工作, 不能完成全部工作.</p>
<p>更多提示: 当你执行 第 9 步的时候, 还可以看到弹出的菜单中有 JPA 和 EJB 3 反向工程的选项, 这个就留给大家做练习了, 同样也能生成类似的 JPA 或者 EJB&#160; 3 实体类, 当然您实现要建好支持 JPA 或者 EJB 的项目.</p>
]]></content:encoded>
			<wfw:commentRss>http://javadou.com/two-min-myeclipse-hibernate-215/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Hibernate 分页的设计和编码</title>
		<link>http://javadou.com/hibernate-fenye-code-214/</link>
		<comments>http://javadou.com/hibernate-fenye-code-214/#comments</comments>
		<pubDate>Sat, 05 Sep 2009 10:19:00 +0000</pubDate>
		<dc:creator>阿超</dc:creator>
				<category><![CDATA[Hibernate]]></category>
		<category><![CDATA[hibernate]]></category>

		<guid isPermaLink="false">http://javadou.com/hibernate-fenye-code-214/</guid>
		<description><![CDATA[1. 当前页码的表单参数 listuser.do?page=2
    同时转换成一个 int 类型的页码变量
    int currentPage = Integer.parseInt(
        request.getParameter("page");// 当前页 

2. 下一页 listuser.do?page=${currentPage+1}
   上一页 listuser.do?page=${currentPage... ]]></description>
			<content:encoded><![CDATA[<p>分页的设计和编码, 代码下载请访问: <a href="http://javadou.com/hibernate-jsp-pageno-212/" target="_blank">Hibernate + JSP 分页代码</a></p>
<p>1. 当前页码的表单参数 listuser.do?page=2   <br />&#160;&#160;&#160; 同时转换成一个 int 类型的页码变量    <br />&#160;&#160;&#160; int currentPage = Integer.parseInt(    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; request.getParameter(&quot;page&quot;);// 当前页 </p>
<p>2. 下一页 listuser.do?page=${currentPage+1}   <br />&#160;&#160; 上一页 listuser.do?page=${currentPage-1}    <br />3. 一页显示多少数据    <br />&#160;&#160;&#160; int pageSize = 5;//每页显示的数据数    <br />4. 总页数 totalPage    <br />&#160;&#160;&#160; 1) 先从数据库取得总记录数    <br />&#160;&#160;&#160; dao.UserDAO#getUserTotalCount()    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; int totalCount = executeQuery(&quot;select count(*) from Users&quot;);    <br />&#160;&#160;&#160; 2) 根据一页的数据类计算出总页数    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; dao.UserManager#getTotalPage(int pageSize)    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; // 得到页面总数    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; int totalPageCount = ((totalCount + pageSize) &#8211; 1) / pageSize; </p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160; if(totalPageCount == 0) {   <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; totalPageCount = 1;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; }    <br />5. 从数据库里把第currentPage页的数据读取出来(Hibernate), DAO 层的代码    <br />dao.UserDAO#findPagedAll(int currentPage, int pageSize) </p>
<p>&#160;&#160;&#160; 两个参数: currentPage 当前页(从1开始的) </p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; pageSize 取多少数据   <br />&#160;&#160;&#160; String queryString = &quot;from User&quot;;    <br />&#160;&#160;&#160; Query queryObject = getSession().createQuery(queryString); </p>
<p>&#160;&#160;&#160; queryObject.setFirstResult((currentPage &#8211; 1) * pageSize);   <br />&#160;&#160;&#160; queryObject.setMaxResults(pageSize); </p>
<p>&#160;&#160;&#160; List result = queryObject.list(); </p>
<p>6. 在前台显示上下页的链接,并根据总页数的上下限来避免让用户跳到第-1页或者比最大页数还大的页码哪里   <br />&#160;&#160;&#160; &lt;c:if test=&quot;${currentPage &gt; 1}&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160; [ 上一页的链接 ]     <br />&#160;&#160;&#160; &lt;/c:if&gt;    <br />&#160;&#160;&#160; &lt;c:if test=&quot;${currentPage &lt;= 1}&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160; [ 上一页的文本 ]     <br />&#160;&#160;&#160; &lt;/c:if&gt; </p>
<p>7. 通过 forEach 来显示数据   <br />&lt;c:forEach items=&quot;${users}&quot; var=&quot;user&quot; &gt;    <br />&#160; ${user.id}    <br />&#160; ${user.username}    <br />&lt;c:/forEach&gt; </p>
<p>8. 通过下拉菜单来跳转页面 </p>
<p>转到   <br />&#160;&#160;&#160; &lt;script&gt;    <br />&#160;&#160;&#160; // 页面跳转函数    <br />&#160;&#160;&#160; // 参数: 包含网址的选择框(SELECT元素)    <br />&#160;&#160;&#160; function jumpPage(select) {    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; var newUrl = &quot;/hibernate_page/index.jsp?page=&quot; + select.value;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; //alert(newUrl);    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; document.location = newUrl;    <br />&#160;&#160;&#160; }    <br />&#160;&#160;&#160; &lt;/script&gt; </p>
<p>&#160;&#160;&#160;&#160;&#160; &lt;!&#8211; 输出 HTML SELECT 元素, 并选中当前页面编码 &#8211;&gt;   <br />&#160;&#160;&#160;&#160;&#160; &lt;select onchange=&#8217;jumpPage(this);&#8217;&gt;    <br />&#160;&#160;&#160;&#160;&#160; &lt;option value=&quot;1&quot; selected&gt;1页&lt;/option&gt;    <br />&#160;&#160;&#160;&#160;&#160; &lt;option value=&quot;2&quot;&#160; &gt;2页&lt;/option&gt;    <br />&#160;&#160;&#160;&#160;&#160; &lt;/select&gt;</p>
]]></content:encoded>
			<wfw:commentRss>http://javadou.com/hibernate-fenye-code-214/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Hibernate + JSP 分页代码开发</title>
		<link>http://javadou.com/hibernate-jsp-pageno-212/</link>
		<comments>http://javadou.com/hibernate-jsp-pageno-212/#comments</comments>
		<pubDate>Sat, 05 Sep 2009 09:15:00 +0000</pubDate>
		<dc:creator>阿超</dc:creator>
				<category><![CDATA[Hibernate]]></category>
		<category><![CDATA[hibernate]]></category>
		<category><![CDATA[jsp]]></category>

		<guid isPermaLink="false">http://javadou.com/hibernate-jsp-pageno-212/</guid>
		<description><![CDATA[下载后导入项目到 MyEclipse , 然后修改数据库连接参数即可测试. 我这用的是 MySQL 数据库. 用 JSP 是因为 Hibernate 可以配合各种框架, 因此在代码里我已经尽量的把页面和后台的直接变量耦合分隔开了. 
部分代码显示... ]]></description>
			<content:encoded><![CDATA[<p>下载后导入项目到 MyEclipse , 然后修改数据库连接参数即可测试. 我这用的是 MySQL 数据库. 用 JSP 是因为 Hibernate 可以配合各种框架, 因此在代码里我已经尽量的把页面和后台的直接变量耦合分隔开了.<br />
<a href="http://javadou.com/wordpress/wp-content/uploads/2009/09/hibernate_page.zip">hibernate_page</a><br />
部分代码显示:</p>
<p>相关 SQL:</p>
<pre class="sql">CREATE TABLE `user` (
  `id` int(11) NOT NULL,
  `username` varchar(200) NOT NULL,
  `password` varchar(20) NOT NULL,
   `age` int,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=GBK;

-- JDBC Driver Name: com.mysql.jdbc.Driver
-- JDBC Driver URL: jdbc:mysql://hostname/dbname?useUnicode=true&amp;characterEncoding=GBK

insert into user values(1, '中文', 'beansoft', 1);
insert into user values(2, 'BeanSoft', 'beansoft', 2);
insert into user values(3, '张三', 'beansoft', 3);
insert into user values(4, '李四', 'beansoft', 4);
insert into user values(5, '王五', 'beansoft', 5);
insert into user values(6, '马六', 'beansoft', 6);
insert into user values(7, '黑七', 'beansoft', 7);
insert into user values(8, '腊八', 'beansoft', 8);
insert into user values(9, '陆九', 'beansoft', 9);
insert into user values(10, '茅十八', 'beansoft', 10);</pre>
<p>前台 JSP 代码:</p>
<pre class="html">&lt;%@ page language="java" import="manager.*,java.util.*" pageEncoding="GBK"%&gt;
&lt;%@ page contentType="text/html;charset=GBK"%&gt;
&lt;%-- 我们使用 JSTL 来访问数据 --%&gt;
&lt;%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %&gt;
&lt;%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%&gt;

&lt;%
// 以下代码为业务逻辑代码, 应该放在 Servlet 或者 Struts 的 Action 或者其它框架的业务代码部分, 这些代码和当前页面是独立的
// {{{

// 分析当前页码
String pageString=request.getParameter("page");
if(pageString == null || pageString.length() == 0) {
    pageString = "1";
}
int currentPage= 0 ;
try {
    currentPage = Integer.parseInt(pageString);// 当前页码
} catch(Exception e) {}

if(currentPage == 0) {
    currentPage = 1;
}

int pageSize = 3;//每页显示的数据数
// 读取数据
UserManager manager = new UserManager();
List users = manager.findPagedAll(currentPage, pageSize);

request.setAttribute("users",users);// 保存用户列表

request.setAttribute("totalPage", manager.getTotalPage(pageSize));// 保存总页数
request.setAttribute("totalCount", manager.getUserTotalCount());// 保存记录总数
request.setAttribute("currentPage", currentPage);// 保存当前页码
// }}}
%&gt;

  用户列表
  &lt;%-- 输出用户列表 --%&gt;
  总用户:${totalCount}个用户
<table border="0" width="80%">
<tbody>
<tr>
<td><strong>用户ID</strong></td>
<td><strong>用户名</strong></td>
<td><strong>操作</strong></td>
</tr>
<tr>
<td>${user.id}</td>
<td>${user.username}</td>
<td><a href="edit.jsp?id=${user.id}">修改</a></td>
</tr>
</tbody>
</table>

第${currentPage}页/共${totalPage}页
    &lt;%-- 输出页面跳转代码, 分链接和静态文字两种 --%&gt;

       [ <a href="${pageContext.request.contextPath}/index.jsp?page=${currentPage-1}">上一页</a> ]

       [ 上一页 ]

       [ <a href="${pageContext.request.contextPath}/index.jsp?page=${currentPage+1}">下一页</a> ]

       [ 下一页 ]

    &lt;%-- 输出 JavaScript 跳转代码 --%&gt;
    转到
    <script type="text/javascript"><!--mce:0--></script>

      <!-- 输出 HTML SELECT 元素, 并选中当前页面编码 -->
<select>
<option value="${i}">selected &gt;第${i}页</option>
</select>
</pre>
<p>后台 DAO:</p>
<pre class="java&gt; package dao;  import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.hibernate.LockMode; import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.criterion.Example;  import util.HibernateSessionFactory;  /**  * Data access object (DAO) for domain model class User.  *   * @see dao.User  * @author MyEclipse Persistence Tools  */  public class UserDAO {     private static final Log log = LogFactory.getLog(UserDAO.class);      // property constants     public static final String USERNAME = ">&lt;="&lt;" }="}" re;="re;" throw="throw" re);="re);" failed?,="failed?," log.error(?attach="log.error(?attach" {="{" re)="re)" (RuntimeException="(RuntimeException" catch="catch" successful?);="successful?);" log.debug(?attach="log.debug(?attach" LockMode.NONE);="LockMode.NONE);" getSession().lock(instance,="getSession().lock(instance," try="try" instance?);="instance?);" User="User" clean="clean" log.debug(?attaching="log.debug(?attaching" instance)="instance)" attachClean(User="attachClean(User" void="void" public="public" getSession().saveOrUpdate(instance);="getSession().saveOrUpdate(instance);" dirty="dirty" attachDirty(User="attachDirty(User" log.error(?merge="log.error(?merge" result;="result;" return="return" log.debug(?merge="log.debug(?merge" getSession().merge(detachedInstance);="getSession().merge(detachedInstance);" result="result" log.debug(?merging="log.debug(?merging" detachedInstance)="detachedInstance)" merge(User="merge(User" all="all" log.error(?find="log.error(?find" queryObject.list();="queryObject.list();" queryObject="getSession().createQuery(queryString);" Query="Query" ;=";" queryString="from User" String="String" instances?);="instances?);" log.debug(?finding="log.debug(?finding" findAll()="findAll()" List="List" age);="age);" findByProperty(AGE,="findByProperty(AGE," age)="age)" findByAge(Object="findByAge(Object" password);="password);" findByProperty(PASSWORD,="findByProperty(PASSWORD," password)="password)" findByPassword(Object="findByPassword(Object" username);="username);" findByProperty(USERNAME,="findByProperty(USERNAME," username)="username)" findByUsername(Object="findByUsername(Object" name="name" property="property" by="by" value);="value);" queryObject.setParameter(0,="queryObject.setParameter(0," ?="?" +="+" propertyName="propertyName" value:="value:" ?,="?," property:="property:" with="with" instance="instance" value)="value)" Object="Object" propertyName,="propertyName," findByProperty(String="findByProperty(String" example="example" results;="results;" results.size());="results.size());" size:="size:" successful,="successful," log.debug(?find="log.debug(?find" Example.create(instance)).list();="Example.create(instance)).list();" results="getSession().createCriteria("dao.User").add(" example?);="example?);" findByExample(User="findByExample(User" log.error(?get="log.error(?get" instance;="instance;" id);="id);" getSession().get(?dao.User?,="getSession().get(?dao.User?," id:="id:" log.debug(?getting="log.debug(?getting" id)="id)" findById(java.lang.Integer="findById(java.lang.Integer" log.error(?delete="log.error(?delete" log.debug(?delete="log.debug(?delete" getSession().delete(persistentInstance);="getSession().delete(persistentInstance);" log.debug(?deleting="log.debug(?deleting" persistentInstance)="persistentInstance)" delete(User="delete(User" log.error(?save="log.error(?save" log.debug(?save="log.debug(?save" getSession().save(transientInstance);="getSession().save(transientInstance);" log.debug(?saving="log.debug(?saving" transientInstance)="transientInstance)" save(User="save(User" queryObject.setMaxResults(pageSize);="queryObject.setMaxResults(pageSize);" pageSize);="pageSize);" *="*" 1)="1)" -="-" queryObject.setFirstResult((currentPage="queryObject.setFirstResult((currentPage" currentPage="currentPage" 0)="0)" (currentPage="=" if="if" log.debug(?分页查找?);="log.debug(?分页查找?);" pageSize)="pageSize)" int="int" currentPage,="currentPage," findPagedAll(int="findPagedAll(int" 用户数据="用户数据" @return="@return" 每页显示数据量="每页显示数据量" pageSize="pageSize" @param="@param" 开始="开始" 1="1" 从="从" 当前页码,="当前页码," 分页显示用户数据.="分页显示用户数据." **="**" a.intValue();="a.intValue();" cc.get(0);="cc.get(0);" a="(Integer)" Integer="Integer" cc="q.list();" User?);="User?);" from="from" count(*)="count(*)" q="getSession().createQuery("select" getUserTotalCount()="getUserTotalCount()" 用户记录总数="用户记录总数" 得到用户总数="得到用户总数" HibernateSessionFactory.getSession();="HibernateSessionFactory.getSession();" getSession()="getSession()" Session="Session" AGE="age" final="final" static="static" PASSWORD="password" username?;="username?;"&gt;后台 Manager:
<pre class="java">&lt; } { public return List + pageSize); * 1) - currentPage pageSize) int currentPage, findPagedAll(int 用户数据 @return 每页显示数据量 pageSize @param 开始 1 从 当前页码, 分页显示用户数据. ** 用户记录总数 得到用户总数 userDAO.findPagedAll(currentPage, totalPageCount; pageSize; totalPageCount="((totalCount" 得到页面总数 totalCount="userDAO.getUserTotalCount();" getTotalPage(int 页面总数 一页显示数据量 获取总页面数. userDAO.getUserTotalCount(); getUserTotalCount(){ dao.UserDAO(); userDAO="new" dao.UserDAO private DAO 用户管理 UserManager Administrator @author 用户管理类 java.util.List; import manager; package&gt;</pre>
</pre>
]]></content:encoded>
			<wfw:commentRss>http://javadou.com/hibernate-jsp-pageno-212/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>spring+hibernate避免延迟加载异常OpenSessionInViewFilter(no session)</title>
		<link>http://javadou.com/spring-hibernate-opensessioninviewfilter-211/</link>
		<comments>http://javadou.com/spring-hibernate-opensessioninviewfilter-211/#comments</comments>
		<pubDate>Sat, 05 Sep 2009 08:09:00 +0000</pubDate>
		<dc:creator>阿超</dc:creator>
				<category><![CDATA[Hibernate]]></category>
		<category><![CDATA[Spring]]></category>
		<category><![CDATA[hibernate]]></category>
		<category><![CDATA[OpenSessionInViewFilter]]></category>
		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://javadou.com/spring-hibernate-opensessioninviewfilter-211/</guid>
		<description><![CDATA[在hibernate中，延迟加载是1个非常大的优点，但有时候却给我们带来一些小麻烦，在后台查询结束后，session已经关闭，但在前台显示的时候，如果存在关联关系就会产生延迟加载异常。 
解决办法是客户端每次请求就... ]]></description>
			<content:encoded><![CDATA[<p>&#160;&#160;&#160;&#160;&#160; 在hibernate中，延迟加载是1个非常大的优点，但有时候却给我们带来一些小麻烦，在后台查询结束后，session已经关闭，但在前台显示的时候，如果存在关联关系就会产生延迟加载异常。    <br />解决办法是客户端每次请求就分配1个session,将请求结果返回给客户端，并完成展现后关闭session。     <br />实现这个功能非常简单，在web.xml中加入以下配置</p>
<pre class="xml">&lt;filter&gt;
  &#160;&#160;&#160;&#160;&#160; &lt;filter-name&gt;hibernateFilter&lt;/filter-name&gt;

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;filter-class&gt;org.springframework.orm.hibernate3.support.OpenSessionInViewFilter &lt;/filter-class&gt;

&#160;&#160;&#160;&#160;&#160; &lt;init-param&gt;

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;param-name&gt;singleSession&lt;/param-name&gt;

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;param-value&gt;true&lt;/param-value&gt;

&#160;&#160;&#160;&#160;&#160; &lt;/init-param&gt;

&lt;/filter&gt;

&lt;filter-mapping&gt;

&#160;&#160;&#160;&#160;&#160; &lt;filter-name&gt;hibernateFilter&lt;/filter-name&gt;

&#160;&#160;&#160;&#160;&#160; &lt;url-pattern&gt;*.do&lt;/url-pattern&gt;

&#160; &lt;/filter-mapping&gt;</pre>
<p>使用spring提供这个过滤器就可以实现session的集中管理了，所有以.do结尾的请求都自动分配了1个session,并且在这个请求过程中都使用这个session.</p>
]]></content:encoded>
			<wfw:commentRss>http://javadou.com/spring-hibernate-opensessioninviewfilter-211/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>hibernate3出现could not initialize proxy &#8211; no Session</title>
		<link>http://javadou.com/hibernate-could-not-initialize-proxy-no-session-181/</link>
		<comments>http://javadou.com/hibernate-could-not-initialize-proxy-no-session-181/#comments</comments>
		<pubDate>Wed, 02 Sep 2009 11:37:00 +0000</pubDate>
		<dc:creator>阿超</dc:creator>
				<category><![CDATA[Hibernate]]></category>
		<category><![CDATA[recommend]]></category>
		<category><![CDATA[hibernate]]></category>
		<category><![CDATA[session]]></category>

		<guid isPermaLink="false">http://javadou.com/hibernate-could-not-initialize-proxy-no-session-181/</guid>
		<description><![CDATA[延迟加载, 也就是用到的时候才去加载.这样可以提高一些性能. 
Hibernate的lazy loading 采用了一个HibernateSession来管理session，它的逻辑是每进行一次数据库操作，就开新的session，操作完成后立即关闭该session。这样做的好... ]]></description>
			<content:encoded><![CDATA[<p>hibernate3出现could not initialize proxy &#8211; no Session 错误的解决办法以及lazy load的介绍   </p>
<p>异常：   <br />org.hibernate.LazyInitializationException: could not initialize proxy &#8211; no Session    <br />at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:57)    <br />at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:111)    <br /><strong>原因：</strong>hibernate3 many-to-one的默认选项是 lazy = &quot;proxy&quot;    <br /><strong>解决方法：</strong>&lt;many-to-one&gt;&#160; &amp; &lt;set&gt; 中设置 lazy=&quot;false&quot;</p>
<p>HIBERNATE的持久化对象加载策略。&#160; <br />延迟加载, 也就是用到的时候才去加载.这样可以提高一些性能.&#160; <br />Hibernate的lazy loading 采用了一个HibernateSession来管理session，它的逻辑是每进行一次数据库操作，就开新的session，操作完成后立即关闭该session。这样做的好处是可以严格关闭session，避免菜鸟级的错误，但是hibernate.org并不推荐这么做。因为这不适合lazy loading，也不适合跨方法的事务。    <br />比如在我们的应用中，user-&gt;post形成一对多的映射，User中有一个包含post的List。    <br />在User中，有多个属性：name，password，phone等，还有一个List类型的posts。当我们对posts使用lazy laoding的时候，hibernate会在获得User对象的时候，仅仅返回name,password,phone等基本属性，当你访问posts的时候，它才会从数据库中提取posts需要的数据，这就是所谓lazy laoding。但是在我们的系统中，session是被立即关闭的，也就是在读取了name,password,phone等基本属性后，session已经close了，再进行lazy loaiding就会有异常。    <br />解决办法是在close session之前，调用Hibernate.initialize(user.getPosts())，告诉系统，user.getPosts()是需要lazy laoding的。但是这样做会破坏HibernateSession类的封装.    <br />后来采用所谓的OpenSessionInView模式，把session的周期交给servlet filter来管理，每当有request进来，就打开一个session，response结束之后再关闭它，这样可以让session存在于整个请求周期中。</p>
<p>Hibernate中Lazy延迟加载&#160; <br />Hibernate有关one-to-one和many-to-one在查询中的父亲端lazy问题&#160; <br />Hibernate3 在关联上有lazy这个属性，如果是Hibernate2，应该是设置outer-join=&quot;false&quot;，然后被关联的对象，在class那个地方设置lazy=&quot;true&quot;.首先，对于many-to-one的问题，可以在父亲端的class标签中设置lazy来解决，这样，在查询儿子的时候，不会发送多余的sql .    <br />对于one-to-one，在hibernate2里面，由于one-to-one里面没有lazy的选项，所以只能通过设置outer-join=&quot;false&quot;来解决。而hibernate3已经加入了lazy，所以不会有这个问题。&#160; <br />总体来说，如果你发现你查询儿子的时候，有多余的sql发送，那一定是你对hibernate的误用..</p>
<p>在hibernate 的one-to-many,many-to-one,many-to-many中，为了效率的提高，我们一般都采用lazy机制，但使用spring的 getHibernateTemplate().save(Object)时，HibernateTemplate试图每次在execute之前去获得 Session，执行完就力争关闭Session 。也就是说Hibernate的Lazy初始化1:n关系时，你必须保证是在同一个Session内部使用这个关系集合，不然Hiernate将抛出 Failed to lazily initialize a collection &#8211; no session or session was closed的例外。</p>
<p>Hibernate 中的对象的关联(association)的设置还是不够灵活，实际应用中有的地方需要lazy load，有的地方又不需要，其实还有的地方就根本不需要使用association。而在Hibernate中，只能在影射文件中设置一种方式，像我们这样的应用，我是不敢轻易使用open session in view的(慢点总比lock住要好)，只能是要么不设置association，要么就是lazy=true的。以前的分类信息只用了一个many to one的关系，代价还可以忍受，但现在关系越来越复杂了，再多加几个的话，所要付出的performance，带宽等方面的代价恐怕就不能忽略了,即使使用cache提高一点performance，对带宽的浪费也还是不可原谅的。</p>
]]></content:encoded>
			<wfw:commentRss>http://javadou.com/hibernate-could-not-initialize-proxy-no-session-181/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Spring hibernate使用方法整理@Component(五)</title>
		<link>http://javadou.com/spring-jpa-hibernate-five-180/</link>
		<comments>http://javadou.com/spring-jpa-hibernate-five-180/#comments</comments>
		<pubDate>Wed, 02 Sep 2009 10:31:00 +0000</pubDate>
		<dc:creator>阿超</dc:creator>
				<category><![CDATA[Hibernate]]></category>
		<category><![CDATA[Spring]]></category>
		<category><![CDATA[hibernate]]></category>
		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://javadou.com/spring-jpa-hibernate-five-180/</guid>
		<description><![CDATA[虽然我们可以通过 Autowired 在 Bean 类中使用自动注入功能，但是 Bean 还是在 applicatonContext.xml 文件中通过  进行定义 —— 在前面的例子中，我们还是在配置文件中定义 Bean，通过 Autowired为 Bean 的成员变量、方法... ]]></description>
			<content:encoded><![CDATA[<p>虽然我们可以通过 @Autowired 在 Bean 类中使用自动注入功能，但是 Bean 还是在 applicatonContext.xml 文件中通过 &lt;bean&gt; 进行定义 —— 在前面的例子中，我们还是在配置文件中定义 Bean，通过 @Autowired为 Bean 的成员变量、方法形参或构造函数形参提供自动注入的功能。<br />
那么能不是也可以通过注解定义 Bean，从 XML 配置文件中完全移除 Bean 定义的配置呢？<br />
答案是肯定的，我们通过 Spring 5 提供的 @Component 注释就可以达到这个目标了。<br />
修改Bean的java类的代码如下，在类名前面加上 @Component注解</p>
<pre class="java">    package com.firemax.test.service;
      import java.util.ArrayList;

    import java.util.Iterator;

    import java.util.List;

    import org.apache.commons.logging.Log;

    import org.apache.commons.logging.LogFactory;

    import org.dom4j.Document;

   import org.dom4j.DocumentHelper;

   import org.dom4j.Element;

   import org.springframework.beans.factory.annotation.Autowired;

   import org.springframework.stereotype.Component;

   import com.firemax.test.hibernate.AlcorTCitys;

   import com.firemax.test.hibernate.AlcorTCitysDAO;

   import com.firemax.test.hibernate.AlcorTCountries;

   import com.firemax.test.hibernate.AlcorTCountriesDAO;

   import com.firemax.test.hibernate.AlcorTProvinces;

   import com.firemax.test.hibernate.AlcorTProvincesDAO;

   import com.firemax.test.hibernate.AlcotTDistrict;

   import com.firemax.test.hibernate.AlcotTDistrictDAO;

   @Component

   public class CountryService {

       private static Log logger = LogFactory.getLog(CountryService.class);

       @Autowired

       private AlcorTCountriesDAO  alcorTCountriesDAO;

       @Autowired

       private AlcorTProvincesDAO  alcorTProvincesDAO;

       @Autowired

       private AlcorTCitysDAO          alcorTCitysDAO;

       @Autowired

       private AlcotTDistrictDAO       alcotTDistrictDAO;

       public CountryService(){

       }

        //这里是业务逻辑的方法

        。。。。。

   }</pre>
<p>然后，我们修改配置文件applicatonContext.xml中，启用自动注入的功能，而放弃原来的&lt;bean&gt;方式的配置</p>
<p>&lt;?xml version=&#8221;0&#8243; encoding=&#8221;UTF-8&#8243;?&gt;</p>
<p>&lt;beans xmlns=&#8221;<a href="http://www.springframework.org/schema/beans&quot;">http://www.springframework.org/schema/beans&#8221;</a></p>
<p>xmlns:context=&#8221;<a href="http://www.springframework.org/schema/context&quot;">http://www.springframework.org/schema/context&#8221;</a></p>
<p>xmlns:xsi=&#8221;<a href="http://www.worg/2001/XMLSchema-instance&quot;">http://www.worg/2001/XMLSchema-instance&#8221;</a></p>
<p>xmlns:tx=&#8221;<a href="http://www.springframework.org/schema/tx&quot;">http://www.springframework.org/schema/tx&#8221;</a></p>
<p>xsi:schemaLocation=&#8221;<a href="http://www.springframework.org/schema/beans">http://www.springframework.org/schema/beans</a> <a href="http://www.springframework.org/schema/beans/spring-beans-xsd">http://www.springframework.org/schema/beans/spring-beans-xsd</a></p>
<p><a href="http://www.springframework.org/schema/context">http://www.springframework.org/schema/context</a> <a href="http://www.springframework.org/schema/context/spring-context-xsd">http://www.springframework.org/schema/context/spring-context-xsd</a></p>
<p><a href="http://www.springframework.org/schema/tx">http://www.springframework.org/schema/tx</a> <a href="http://www.springframework.org/schema/tx/spring-tx-xsd&quot;">http://www.springframework.org/schema/tx/spring-tx-xsd&#8221;</a></p>
<p>default-autowire=&#8221;autodetect&#8221;&gt;</p>
<p>&lt;bean id=&#8221;entityManagerFactory&#8221;</p>
<p>class=&#8221;org.springframework.orm.jpa.LocalEntityManagerFactoryBean&#8221;&gt;</p>
<p>&lt;property name=&#8221;persistenceUnitName&#8221; value=&#8221;testerPU&#8221; /&gt;</p>
<p>&lt;/bean&gt;</p>
<p>&lt;bean id=&#8221;transactionManager&#8221; class=&#8221;org.springframework.orm.jpa.JpaTransactionManager&#8221;&gt;</p>
<p>&lt;property name=&#8221;entityManagerFactory&#8221; ref=&#8221;entityManagerFactory&#8221; /&gt;</p>
<p>&lt;/bean&gt;</p>
<p>&lt;tx:annotation-driven transaction-manager=&#8221;transactionManager&#8221; /&gt;</p>
<p>&lt;bean id=&#8221;transactionInterceptor&#8221;</p>
<p>class=&#8221;org.springframework.transaction.interceptor.TransactionInterceptor&#8221;&gt;</p>
<p>&lt;!&#8211; 事务拦截器bean需要依赖注入一个事务管理器 &#8211;&gt;</p>
<p>&lt;property name=&#8221;transactionManager&#8221;&gt;</p>
<p>&lt;ref local=&#8221;transactionManager&#8221; /&gt;</p>
<p>&lt;/property&gt;</p>
<p>&lt;property name=&#8221;transactionAttributes&#8221;&gt;</p>
<p>&lt;!&#8211; 下面定义事务（指service里面的方法）传播属性 &#8211;&gt;</p>
<p>&lt;props&gt;</p>
<p>&lt;prop key=&#8221;insert*&#8221;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;</p>
<p>&lt;prop key=&#8221;update*&#8221;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;</p>
<p>&lt;prop key=&#8221;save*&#8221;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;</p>
<p>&lt;prop key=&#8221;add*&#8221;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;</p>
<p>&lt;prop key=&#8221;update*&#8221;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;</p>
<p>&lt;prop key=&#8221;remove*&#8221;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;</p>
<p>&lt;prop key=&#8221;delete*&#8221;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;</p>
<p>&lt;prop key=&#8221;get*&#8221;&gt;PROPAGATION_REQUIRED,readOnly</p>
<p>&lt;/prop&gt;</p>
<p>&lt;prop key=&#8221;find*&#8221;&gt;PROPAGATION_REQUIRED,readOnly</p>
<p>&lt;/prop&gt;</p>
<p>&lt;prop key=&#8221;load*&#8221;&gt;PROPAGATION_REQUIRED,readOnly</p>
<p>&lt;/prop&gt;</p>
<p>&lt;prop key=&#8221;change*&#8221;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;</p>
<p>&lt;prop key=&#8221;count*&#8221;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;</p>
<p>&lt;prop key=&#8221;*&#8221;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;</p>
<p>&lt;/props&gt;</p>
<p>&lt;/property&gt;</p>
<p>&lt;/bean&gt;</p>
<p>&lt;!&#8211; 该 BeanPostProcessor 将自动对标注 @Autowired 的 Bean 进行注入 &#8211;&gt;</p>
<p>&lt;!&#8211;  这个Processor 已经被 &lt;context:annotation-config/&gt; 所简化<br />
&lt;bean class=&#8221;org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor&#8221;/&gt;</p>
<p>&#8211;&gt;</p>
<p>&lt;!&#8211; &lt;context:component- scan/&gt; 配置项不但启用了对类包进行扫描以实施注释驱动 Bean 定义的功能，同时还启用了注释驱动自动注入的功能（即还隐式地在内部注册了 AutowiredAnnotationBeanPostProcessor 和 CommonAnnotationBeanPostProcessor），因此当使用 &lt;context:component-scan/&gt; 后，就可以将 &lt;context:annotation- config/&gt; 移除了。 &#8211;&gt;</p>
<p>&lt;context:component-scan base-package =&#8221;com.firemax&#8221;/&gt;<br />
&lt;!&#8211; 定义自动代理BeanNameAutoProxyCreator &#8211;&gt;</p>
<p>&lt;bean id=&#8221;beanNameAutoProxyCreator&#8221;</p>
<p>class=&#8221;org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator&#8221;&gt;</p>
<p>&lt;!&#8211; 指定对满足哪些bean name的bean自动生成业务代理 &#8211;&gt;</p>
<p>&lt;property name=&#8221;beanNames&#8221;&gt;</p>
<p>&lt;list&gt;</p>
<p>&lt;value&gt;*Service&lt;/value&gt;</p>
<p>&lt;/list&gt;</p>
<p>&lt;/property&gt;</p>
<p>&lt;!&#8211; 下面定义BeanNameAutoProxyCreator所需的事务拦截器  &#8211;&gt;</p>
<p>&lt;property name=&#8221;interceptorNames&#8221;&gt;</p>
<p>&lt;list&gt;</p>
<p>&lt;!&#8211; 此处可增加其他新的Interceptor &#8211;&gt;</p>
<p>&lt;value&gt;transactionInterceptor&lt;/value&gt;</p>
<p>&lt;/list&gt;</p>
<p>&lt;/property&gt;</p>
<p>&lt;/bean&gt;</p>
<p>&lt;!&#8211;</p>
<p>&lt;bean id=&#8221;AlcorTCountriesDAO&#8221; class=&#8221;com.firemax.test.hibernate.AlcorTCountriesDAO&#8221;&gt;</p>
<p>&lt;property name=&#8221;entityManagerFactory&#8221; ref=&#8221;entityManagerFactory&#8221; /&gt;</p>
<p>&lt;/bean&gt;</p>
<p>&lt;bean id=&#8221;AlcorTProvincesDAO&#8221; class=&#8221;com.firemax.test.hibernate.AlcorTProvincesDAO&#8221;&gt;</p>
<p>&lt;property name=&#8221;entityManagerFactory&#8221; ref=&#8221;entityManagerFactory&#8221; /&gt;</p>
<p>&lt;/bean&gt;</p>
<p>&lt;bean id=&#8221;AlcotTDistrictDAO&#8221; class=&#8221;com.firemax.test.hibernate.AlcotTDistrictDAO&#8221;&gt;</p>
<p>&lt;property name=&#8221;entityManagerFactory&#8221; ref=&#8221;entityManagerFactory&#8221; /&gt;</p>
<p>&lt;/bean&gt;</p>
<p>&lt;bean id=&#8221;AlcorTCitysDAO&#8221; class=&#8221;com.firemax.test.hibernate.AlcorTCitysDAO&#8221;&gt;</p>
<p>&lt;property name=&#8221;entityManagerFactory&#8221; ref=&#8221;entityManagerFactory&#8221; /&gt;</p>
<p>&lt;/bean&gt;</p>
<p>&lt;bean id=&#8221;CountryService&#8221; class=&#8221;com.firemax.test.service.CountryService&#8221;/&gt;</p>
<p>&#8211;&gt;</p>
<p>&lt;/beans&gt;</p>
<p>新的applicaitonContext.xml 配置文件中蓝色的部分就是原来的&lt;bean&gt;的注入方式，现在已经给屏蔽了。不需要再写。而红色部分就是使用了&lt;context:component-scan base-package =&#8221;com.firemax&#8221;/&gt; ，让spirng自动搜索，然后注入。</p>
<p>注意：</p>
<p>* 这里注入的bean 的名称是按照类的名称，把第一个字母改成小写来命名的。比如例子中的CountryService的bean的名称就是countryService.</p>
<p>* 我们也可以通过@Component(&#8220;countryService&#8221;) 这种方式来显示的定义一个bean的注入名称。但是在大多数情况下没有必要。</p>
<p>&lt;context:component-scan/&gt; 的 base-package 属性指定了需要扫描的类包，类包及其递归子包中所有的类都会被处理。</p>
<p>&lt;context:component-scan/&gt; 还允许定义过滤器将基包下的某些类纳入或排除。Spring 支持以下 4 种类型的过滤方式，通过下表说明：</p>
<p><strong>扫描过滤方式</p>
<p></strong>过滤器类型          说明</p>
<p>注释                   假如 com.firemax.test.SomeAnnotation 是一个注释类，我们可以将使用该注释的类过滤出来。</p>
<p>类名指定             通过全限定类名进行过滤，如您可以指定将 com.firemax.test.IncludeService纳入扫描，而将 com.firemax.test.NotIncludeService 排除。</p>
<p>正则表达式          通过正则表达式定义过滤的类，如下所示： com\.firemax\.test\.Default.*</p>
<p>AspectJ 表达式    通过 AspectJ 表达式定义过滤的类，如下所示： com. firemax.test..*Service+</p>
<p>下面是一个简单的例子：</p>
<pre class="java">    &lt;context:component-scan base-package="com.firemax"&gt;
          &lt;context:include-filter type="regex" 

            expression="com\.firemax\.test\.service\..*"/&gt;

        &lt;context:exclude-filter type="aspectj" 

            expression="com.firemax.test.util..*"/&gt;

    &lt;/context:component-scan&gt;</pre>
<p>默认情况下通过 @Component 定义的 Bean 都是 singleton 的，如果需要使用其它作用范围的 Bean，可以通过 @Scope 注释来达到目标，如以下代码所示：</p>
<p>通过 @Scope 指定 Bean 的作用范围</p>
<pre class="java">    package com.firemax.tester.service;
      import org.springframework.context.annotation.Scope;

    …

    @Scope("prototype")

    @Component("countryService")

    public class CountryService{

        …

    }</pre>
<p>这样，当从 Spring 容器中获取 boss Bean 时，每次返回的都是新的实例了。</p>
<p>在Spring5中引入了更多的典型化注解，@Repository ，@Service，@Controler是@Component的细化。分别表示持久层，服务层，控制层。建议使用这个注解来取代@Component</p>
<p>附上一个java Applicaiton的简单测试程序</p>
<pre class="java">    /*
       * Created on 2008-9-28

     *

     */

    package com.firemax.test.tester;

    import java.util.Iterator;

   import org.springframework.context.ApplicationContext;

   import org.springframework.context.support.FileSystemXmlApplicationContext;

   import com.firemax.test.hibernate.AlcorTCitys;

   import com.firemax.test.hibernate.AlcorTCitysDAO;

   import com.firemax.test.hibernate.AlcorTCountries;

   import com.firemax.test.hibernate.AlcorTProvinces;

   import com.firemax.test.hibernate.AlcotTDistrict;

   import com.firemax.test.hibernate.AlcotTDistrictDAO;

   import com.firemax.test.service.CountryService;

   public class Tester {

       /**

        * @param args

        */

       public static void main(String[] args) throws Exception{

           // TODO Auto-generated method stub

           ApplicationContext ctx =     new FileSystemXmlApplicationContext("/WebContent/WEB-INF/classes/applicationContext*.xml");

           String[] beans = ctx.getBeanDefinitionNames();

           for (int i = 0 ; i &lt; beans.length;i++)

           {

               System.out.println(beans[i]);

           }

           CountryService countryService= (CountryService)ctx.getBean("countryService");

           AlcorTCountries  alcorTCountries= countryService.getCountriesInfo("CN");

           System.out.println(alcorTCountries.getCountry());

           System.out.println("开始调用子类");

           System.out.println(alcorTCountries.getAlcorTProvinceses().size());

           Iterator&lt;AlcorTProvinces&gt; it = alcorTCountries.getAlcorTProvinceses().iterator();

           while (it.hasNext()){

               AlcorTProvinces  alcorTProvinces= (AlcorTProvinces)it.next();

               System.out.println(alcorTProvinces.getProvinceName());

           }

           AlcotTDistrict alcotTDistrict= new AlcotTDistrict();

           alcotTDistrict.setDistrictCode("22");

           alcotTDistrict.setDistrictName("浦东");

           AlcorTCitys alcorTCitys =countryService.getCityInfo("021");

           alcotTDistrict.setAlcorTCitys(alcorTCitys);

           countryService.saveProvinces(alcotTDistrict);

       }

   }</pre>
<p>在所有的JPOPO中，我们可以使用@Entity 这个注解来注入 JOPO。这样我们在 Persistent.xml中就不需要在 定义哪些POJO的类了。</p>
<p>感谢 JPA 感谢Spring ，终于不要频繁的去定义和修改这些Bean了</p>
]]></content:encoded>
			<wfw:commentRss>http://javadou.com/spring-jpa-hibernate-five-180/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Spring JPA hibernate 使用方法整理（四)命名空间</title>
		<link>http://javadou.com/spring-hibernate-jpa-foure-179/</link>
		<comments>http://javadou.com/spring-hibernate-jpa-foure-179/#comments</comments>
		<pubDate>Wed, 02 Sep 2009 09:27:00 +0000</pubDate>
		<dc:creator>阿超</dc:creator>
				<category><![CDATA[Hibernate]]></category>
		<category><![CDATA[Spring]]></category>
		<category><![CDATA[hibernate]]></category>
		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://javadou.com/spring-hibernate-jpa-foure-179/</guid>
		<description><![CDATA[在（三）里面。我们引入了 <bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/& gt;这个bean 来处理Autowired注解。
其实在spring 里面还有其他三个BeanPostProcessor 。总共有四个，分别是：
AutowiredAnn... ]]></description>
			<content:encoded><![CDATA[<p><a href="http://javadou.com/spring-jpa-hibernate-three-178/" target="_blank">在（三）里面</a>。我们引入了 &lt;bean class=&#8221;org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor&#8221;/&amp; gt;这个bean 来处理@Autowired注解。<br />
其实在spring 里面还有其他三个BeanPostProcessor 。总共有四个，分别是：<br />
AutowiredAnnotationBeanPostProcessor<br />
CommonAnnotationBeanPostProcessor<br />
PersistenceAnnotationBeanPostProcessor<br />
equiredAnnotationBeanPostProcessor</p>
<p>但是直接在 Spring 配置文件中定义这些 Bean 显得比较笨拙。Spring 为我们提供了一种方便的注册这些 BeanPostProcessor 的方式，这就是 &lt;context:annotation-config/&gt;</p>
<p>Spring 1 添加了一个新的 context 的 Schema 命名空间，该命名空间对注释驱动、属性文件引入、加载期织入等功能提供了便捷的配置。我们知道注释本身是不会做任何事情的，它仅提供元数据信息。要使元数据信息真正起作用，必须让负责处理这些元数据的处理器工作起来。</p>
<p>这段代码就是 启用了这个命名空间后的applicationContext.xml文件</p>
<p>&lt;?xml version=&#8221;0&#8243; encoding=&#8221;UTF-8&#8243;?&gt;<br />
&lt;beans xmlns=&#8221;http://www.springframework.org/schema/beans&#8221;<br />
xmlns:context=&#8221;http://www.springframework.org/schema/context&#8221;<br />
xmlns:xsi=&#8221;http://www.worg/2001/XMLSchema-instance&#8221;<br />
xmlns:tx=&#8221;http://www.springframework.org/schema/tx&#8221;<br />
xsi:schemaLocation=&#8221;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-xsd<br />
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-xsd<br />
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-xsd&#8221;<br />
&gt;<br />
&lt;bean id=&#8221;entityManagerFactory&#8221;<br />
class=&#8221;org.springframework.orm.jpa.LocalEntityManagerFactoryBean&#8221;&gt;<br />
&lt;property name=&#8221;persistenceUnitName&#8221; value=&#8221;testerPU&#8221; /&gt;<br />
&lt;/bean&gt;<br />
&lt;bean id=&#8221;transactionManager&#8221; class=&#8221;org.springframework.orm.jpa.JpaTransactionManager&#8221;&gt;<br />
&lt;property name=&#8221;entityManagerFactory&#8221; ref=&#8221;entityManagerFactory&#8221; /&gt;<br />
&lt;/bean&gt;<br />
&lt;tx:annotation-driven transaction-manager=&#8221;transactionManager&#8221; /&gt;<br />
&lt;bean id=&#8221;transactionInterceptor&#8221;<br />
class=&#8221;org.springframework.transaction.interceptor.TransactionInterceptor&#8221;&gt;<br />
&lt;!&#8211; 事务拦截器bean需要依赖注入一个事务管理器 &#8211;&gt;<br />
&lt;property name=&#8221;transactionManager&#8221;&gt;<br />
&lt;ref local=&#8221;transactionManager&#8221; /&gt;<br />
&lt;/property&gt;<br />
&lt;property name=&#8221;transactionAttributes&#8221;&gt;<br />
&lt;!&#8211; 下面定义事务（指service里面的方法）传播属性 &#8211;&gt;<br />
&lt;props&gt;<br />
&lt;prop key=&#8221;insert*&#8221;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />
&lt;prop key=&#8221;update*&#8221;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />
&lt;prop key=&#8221;save*&#8221;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />
&lt;prop key=&#8221;add*&#8221;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />
&lt;prop key=&#8221;update*&#8221;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />
&lt;prop key=&#8221;remove*&#8221;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />
&lt;prop key=&#8221;delete*&#8221;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />
&lt;prop key=&#8221;get*&#8221;&gt;PROPAGATION_REQUIRED,readOnly<br />
&lt;/prop&gt;<br />
&lt;prop key=&#8221;find*&#8221;&gt;PROPAGATION_REQUIRED,readOnly<br />
&lt;/prop&gt;<br />
&lt;prop key=&#8221;load*&#8221;&gt;PROPAGATION_REQUIRED,readOnly<br />
&lt;/prop&gt;<br />
&lt;prop key=&#8221;change*&#8221;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />
&lt;prop key=&#8221;count*&#8221;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />
&lt;prop key=&#8221;*&#8221;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />
&lt;/props&gt;<br />
&lt;/property&gt;<br />
&lt;/bean&gt;<br />
&lt;!&#8211; 该 BeanPostProcessor 将自动对标注 @Autowired 的 Bean 进行注入 &#8211;&gt;<br />
&lt;!&#8211;  这个Processor 已经被 &lt;context:annotation-config/&gt; 所简化<br />
&lt;bean class=&#8221;org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor&#8221;/&gt;<br />
&#8211;&gt;<br />
&lt;context:annotation-config/&gt;<br />
&lt;!&#8211; 定义自动代理BeanNameAutoProxyCreator &#8211;&gt;<br />
&lt;bean id=&#8221;beanNameAutoProxyCreator&#8221;<br />
class=&#8221;org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator&#8221;&gt;<br />
&lt;!&#8211; 指定对满足哪些bean name的bean自动生成业务代理 &#8211;&gt;<br />
&lt;property name=&#8221;beanNames&#8221;&gt;<br />
&lt;list&gt;<br />
&lt;value&gt;*Service&lt;/value&gt;<br />
&lt;/list&gt;<br />
&lt;/property&gt;<br />
&lt;!&#8211; 下面定义BeanNameAutoProxyCreator所需的事务拦截器  &#8211;&gt;<br />
&lt;property name=&#8221;interceptorNames&#8221;&gt;<br />
&lt;list&gt;<br />
&lt;!&#8211; 此处可增加其他新的Interceptor &#8211;&gt;<br />
&lt;value&gt;transactionInterceptor&lt;/value&gt;<br />
&lt;/list&gt;<br />
&lt;/property&gt;<br />
&lt;/bean&gt;<br />
&lt;bean id=&#8221;AlcorTCountriesDAO&#8221; class=&#8221;com.firemax.test.hibernate.AlcorTCountriesDAO&#8221;&gt;<br />
&lt;property name=&#8221;entityManagerFactory&#8221; ref=&#8221;entityManagerFactory&#8221; /&gt;<br />
&lt;/bean&gt;<br />
&lt;bean id=&#8221;AlcorTProvincesDAO&#8221; class=&#8221;com.firemax.test.hibernate.AlcorTProvincesDAO&#8221;&gt;<br />
&lt;property name=&#8221;entityManagerFactory&#8221; ref=&#8221;entityManagerFactory&#8221; /&gt;<br />
&lt;/bean&gt;<br />
&lt;bean id=&#8221;AlcotTDistrictDAO&#8221; class=&#8221;com.firemax.test.hibernate.AlcotTDistrictDAO&#8221;&gt;<br />
&lt;property name=&#8221;entityManagerFactory&#8221; ref=&#8221;entityManagerFactory&#8221; /&gt;<br />
&lt;/bean&gt;<br />
&lt;bean id=&#8221;AlcorTCitysDAO&#8221; class=&#8221;com.firemax.test.hibernate.AlcorTCitysDAO&#8221;&gt;<br />
&lt;property name=&#8221;entityManagerFactory&#8221; ref=&#8221;entityManagerFactory&#8221; /&gt;<br />
&lt;/bean&gt;<br />
&lt;bean id=&#8221;CountryService&#8221; class=&#8221;com.firemax.test.service.CountryService&#8221;/&gt;<br />
&lt;/beans&gt;</p>
<p>注意2段标红的内容，就是这次更新的配置内容。在配置文件中使用 context 命名空间之前，必须在 &lt;beans&gt; 元素中声明 context 命名空间。</p>
]]></content:encoded>
			<wfw:commentRss>http://javadou.com/spring-hibernate-jpa-foure-179/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Spring hibernate使用方法整理@Autowired(三)</title>
		<link>http://javadou.com/spring-jpa-hibernate-three-178/</link>
		<comments>http://javadou.com/spring-jpa-hibernate-three-178/#comments</comments>
		<pubDate>Wed, 02 Sep 2009 08:25:00 +0000</pubDate>
		<dc:creator>阿超</dc:creator>
				<category><![CDATA[Hibernate]]></category>
		<category><![CDATA[Spring]]></category>
		<category><![CDATA[hibernate]]></category>
		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://javadou.com/spring-jpa-hibernate-three-178/</guid>
		<description><![CDATA[是在我们编写spring 框架的代码时候。一直遵循是这样一个规则：所有在spring中注入的bean 都建议定义成私有的域变量。并且要配套写上 get 和 set方法。虽然可以通过eclipse等工具来自动生成。但是还是会引起程序阅读... ]]></description>
			<content:encoded><![CDATA[<p>通过 前两篇文章的介绍。我们已经做了初步的简化程序。<br />
但是在我们编写spring 框架的代码时候。一直遵循是这样一个规则：所有在spring中注入的bean 都建议定义成私有的域变量。并且要配套写上 get 和 set方法。虽然可以通过eclipse等工具来自动生成。但是还是会引起程序阅读性上的不便。那么既然注解这么强大。是否可以也把他精简掉呢？</p>
<p>当然可以。这个标签就是@Autowired</p>
<p>Spring 5 引入了 @Autowired 注释，它可以对类成员变量、方法及构造函数进行标注，完成自动装配的工作。</p>
<p>要实现我们要精简程序的目的。需要这样来处理：</p>
<p>* 在applicationContext.xml中加入：</p>
<p>&lt;!&#8211; 该 BeanPostProcessor 将自动对标注 @Autowired 的 Bean 进行注入 &#8211;&gt;<br />
&lt;bean class=&#8221;org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor&#8221;/&gt;</p>
<p>* 修改在原来注入spirng容器中的bean的方法。在域变量上加上标签@Autowired,并且去掉 相应的get 和set方法<br />
/*国家，省份，城市，城区信息维护服务<br />
* Created on 2008-9-26<br />
*<br />
* 徐泽宇 roamer<br />
*/<br />
package com.firemax.test.service;<br />
import java.util.ArrayList;<br />
import java.util.Iterator;<br />
import java.util.List;<br />
import org.apache.commons.logging.Log;<br />
import org.apache.commons.logging.LogFactory;<br />
import org.dom4j.Document;<br />
import org.dom4j.DocumentHelper;<br />
import org.dom4j.Element;<br />
import org.springframework.beans.factory.annotation.Autowired;<br />
import com.firemax.test.hibernate.AlcorTCitys;<br />
import com.firemax.test.hibernate.AlcorTCitysDAO;<br />
import com.firemax.test.hibernate.AlcorTCountries;<br />
import com.firemax.test.hibernate.AlcorTCountriesDAO;<br />
import com.firemax.test.hibernate.AlcorTProvinces;<br />
import com.firemax.test.hibernate.AlcorTProvincesDAO;<br />
import com.firemax.test.hibernate.AlcotTDistrict;<br />
import com.firemax.test.hibernate.AlcotTDistrictDAO;<br />
public class CountryService {<br />
private static Log logger = LogFactory.getLog(CountryService.class);<br />
@Autowired<br />
private AlcorTCountriesDAO  alcorTCountriesDAO;<br />
@Autowired<br />
private AlcorTProvincesDAO  alcorTProvincesDAO;<br />
@Autowired<br />
private AlcorTCitysDAO          alcorTCitysDAO;<br />
@Autowired<br />
private AlcotTDistrictDAO       alcotTDistrictDAO;<br />
public CountryService(){<br />
}<br />
/**修改一个国家信息<br />
* @param alcorTCountries<br />
* @throws Exception<br />
*/<br />
public void updateCountry(AlcorTCountries alcorTCountries ) throws Exception{<br />
this.alcorTCountriesDAO.update(alcorTCountries);<br />
}<br />
&#8230;.<br />
//这里去掉了哪些DAO 变量的get 和set 方法。<br />
}</p>
<p>* 在applicatonContext.xml中 把原来 引用的&lt;porpery &gt;标签也去掉。<br />
&lt;bean id=&#8221;CountryService&#8221; class=&#8221;com.firemax.test.service.CountryService&#8221;&gt;<br />
&lt;property name=&#8221;alcorTCountriesDAO&#8221; ref=&#8221;AlcorTCountriesDAO&#8221; /&gt;<br />
&lt;property name=&#8221;alcorTProvincesDAO&#8221; ref=&#8221;AlcorTProvincesDAO&#8221; /&gt;<br />
&lt;property name=&#8221;alcorTCitysDAO&#8221; ref=&#8221;AlcorTCitysDAO&#8221; /&gt;<br />
&lt;property name=&#8221;alcotTDistrictDAO&#8221; ref=&#8221;AlcotTDistrictDAO&#8221; /&gt;<br />
&lt;/bean&gt;<br />
修改成<br />
&lt;bean id=&#8221;CountryService&#8221; class=&#8221;com.firemax.test.service.CountryService&#8221;&gt;<br />
&lt;/bean&gt;<br />
当然，我们也可以在构造函数上使用@Auwowired 注解 。如果构造函数有两个入参，分别是 bean1 和 bean2，@Autowired 将分别寻找和它们类型匹配的 Bean，将它们作为 CountryService (Bean1 bean1 ,Bean2 bean2) 的入参来创建 CountryService  Bean。</p>
<p>在运行一下你的业务程序。如果没有错误。恭喜你。这个步骤我们又完成了。</p>
]]></content:encoded>
			<wfw:commentRss>http://javadou.com/spring-jpa-hibernate-three-178/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Spring 2.5 JPA hibernate 使用方法的整理（二）</title>
		<link>http://javadou.com/spring-jpa-hibernate-two-177/</link>
		<comments>http://javadou.com/spring-jpa-hibernate-two-177/#comments</comments>
		<pubDate>Wed, 02 Sep 2009 07:22:00 +0000</pubDate>
		<dc:creator>阿超</dc:creator>
				<category><![CDATA[Hibernate]]></category>
		<category><![CDATA[Spring]]></category>
		<category><![CDATA[hibernate]]></category>
		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://javadou.com/spring-jpa-hibernate-two-177/</guid>
		<description><![CDATA[通过上面一步骤。我们简化了hibernate中扰人的 xxxxx.hbm.xml文件。那么是否可以再进行简化呢？
那么，我们在这一步骤的目的，就是把整个 hibernate.cfg.xml都给简化了。 

依然是利用注解注入的方式。通过jpa 我们可以把 ... ]]></description>
			<content:encoded><![CDATA[<p>&#160;&#160; <a href="http://javadou.com/spring-jpa-hibernate-one-176/" target="_blank">通过上面一步骤</a>。我们简化了hibernate中扰人的 xxxxx.hbm.xml文件。那么是否可以再进行简化呢？    <br />那么，我们在这一步骤的目的，就是把整个 hibernate.cfg.xml都给简化了。 </p>
<p>依然是利用注解注入的方式。通过jpa 我们可以把 hibernate.cfg.xml中那些 mapping classes再次简化与无形。 </p>
<p>&#160;&#160;&#160; 在applicationContext.xml中进行如下配置   <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;?xml version=&quot;0&quot; encoding=&quot;UTF-8&quot;?&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; xmlns:xsi=&quot;http://www.worg/2001/XMLSchema-instance&quot;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; xsi:schemaLocation=&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-xsd&quot;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; xmlns:tx=&quot;http://www.springframework.org/schema/tx&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;bean id=&quot;entityManagerFactory&quot;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; class=&quot;org.springframework.orm.jpa.LocalEntityManagerFactoryBean&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;persistenceUnitName&quot; value=&quot;testerPU&quot; /&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/bean&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;bean id=&quot;transactionManager&quot; class=&quot;org.springframework.orm.jpa.JpaTransactionManager&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;entityManagerFactory&quot; ref=&quot;entityManagerFactory&quot; /&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/bean&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;tx:annotation-driven transaction-manager=&quot;transactionManager&quot; /&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;bean id=&quot;transactionInterceptor&quot;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; class=&quot;org.springframework.transaction.interceptor.TransactionInterceptor&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;!&#8211; 事务拦截器bean需要依赖注入一个事务管理器 &#8211;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;transactionManager&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;ref local=&quot;transactionManager&quot; /&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/property&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;transactionAttributes&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;!&#8211; 下面定义事务（指service里面的方法）传播属性 &#8211;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;props&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;prop key=&quot;insert*&quot;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;prop key=&quot;update*&quot;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;prop key=&quot;save*&quot;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;prop key=&quot;add*&quot;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;prop key=&quot;update*&quot;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;prop key=&quot;remove*&quot;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;prop key=&quot;delete*&quot;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;prop key=&quot;get*&quot;&gt;PROPAGATION_REQUIRED,readOnly    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/prop&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;prop key=&quot;find*&quot;&gt;PROPAGATION_REQUIRED,readOnly    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/prop&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;prop key=&quot;load*&quot;&gt;PROPAGATION_REQUIRED,readOnly    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/prop&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;prop key=&quot;change*&quot;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;prop key=&quot;count*&quot;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;prop key=&quot;*&quot;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/props&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/property&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/bean&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;!&#8211; 定义自动代理BeanNameAutoProxyCreator &#8211;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;bean id=&quot;beanNameAutoProxyCreator&quot;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; class=&quot;org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;!&#8211; 指定对满足哪些bean name的bean自动生成业务代理 &#8211;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;beanNames&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;list&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;value&gt;*Service&lt;/value&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/list&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/property&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;!&#8211; 下面定义BeanNameAutoProxyCreator所需的事务拦截器&#160; &#8211;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;interceptorNames&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;list&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;!&#8211; 此处可增加其他新的Interceptor &#8211;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;value&gt;transactionInterceptor&lt;/value&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/list&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/property&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/bean&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;bean id=&quot;AlcorTCountriesDAO&quot; class=&quot;com.firemax.test.hibernate.AlcorTCountriesDAO&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;entityManagerFactory&quot; ref=&quot;entityManagerFactory&quot; /&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/bean&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;bean id=&quot;AlcorTProvincesDAO&quot; class=&quot;com.firemax.test.hibernate.AlcorTProvincesDAO&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;entityManagerFactory&quot; ref=&quot;entityManagerFactory&quot; /&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/bean&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;bean id=&quot;AlcotTDistrictDAO&quot; class=&quot;com.firemax.test.hibernate.AlcotTDistrictDAO&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;entityManagerFactory&quot; ref=&quot;entityManagerFactory&quot; /&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/bean&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;bean id=&quot;AlcorTCitysDAO&quot; class=&quot;com.firemax.test.hibernate.AlcorTCitysDAO&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;entityManagerFactory&quot; ref=&quot;entityManagerFactory&quot; /&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/bean&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;bean id=&quot;CountryService&quot; class=&quot;com.firemax.test.service.CountryService&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;alcorTCountriesDAO&quot; ref=&quot;AlcorTCountriesDAO&quot; /&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;alcorTProvincesDAO&quot; ref=&quot;AlcorTProvincesDAO&quot; /&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;alcorTCitysDAO&quot; ref=&quot;AlcorTCitysDAO&quot; /&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;alcotTDistrictDAO&quot; ref=&quot;AlcotTDistrictDAO&quot; /&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/bean&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/beans&gt; </p>
<p>&#160;&#160;&#160;&#160;&#160; 注意红色部分。这部分和（一）里面提到的那个applicationContext.xml中使用的bean是不同的。这里面已经用到了spring 的jpa部分。   <br />&#160;&#160;&#160;&#160;&#160; 其中 &lt;property name=&quot;persistenceUnitName&quot; value=&quot;testerPU&quot; /&gt;&#160; 是指向了一个 jpa的PU（Persistent Units） </p>
<p>&#160;&#160;&#160;&#160;&#160; 那么这个 是在哪里定义的呢？   <br />&#160;&#160;&#160;&#160;&#160; 这里的定义是在你的 classes（src）目录下META-INF下的persistence.xml文件中来定义    <br />&#160;&#160;&#160;&#160;&#160; persistence.xml文件内容如下： </p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;?xml version=&quot;0&quot; encoding=&quot;UTF-8&quot;?&gt;   <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;persistence xmlns=&quot;http://java.sun.com/xml/ns/persistence&quot;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; xmlns:xsi=&quot;http://www.worg/2001/XMLSchema-instance&quot;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; xsi:schemaLocation=&quot;http://java.sun.com/xml/ns/persistence    <br />http://java.sun.com/xml/ns/persistence/persistence_1_xsd&quot;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; version=&quot;0&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;persistence-unit name=&quot;testerPU&quot;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; transaction-type=&quot;RESOURCE_LOCAL&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;provider&gt;org.hibernate.ejb.HibernatePersistence&lt;/provider&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;class&gt;com.firemax.test.hibernate.AlcorTCountries&lt;/class&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;class&gt;com.firemax.test.hibernate.AlcorTProvinces&lt;/class&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;class&gt;com.firemax.test.hibernate.AlcotTDistrict&lt;/class&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;class&gt;com.firemax.test.hibernate.AlcorTCitys&lt;/class&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;properties&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;hibernate.connection.driver_class&quot;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; value=&quot;com.mysql.jdbc.Driver&quot; /&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;hibernate.connection.url&quot;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; value=&quot;jdbc:mysql://localhost:3306/alcorweb?useUnicode=true&amp;characterEncoding=utf-8&quot; /&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;hibernate.connection.username&quot;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; value=&quot;alcorweb&quot; /&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;hibernate.connection.password&quot;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; value=&quot;alcorweb&quot; /&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;hibernate.connection.provider_class&quot; value=&quot;org.hibernate.connection.C3P0ConnectionProvider&quot;/&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;hibernate.c3pmax_size&quot; value=&quot;100&quot;/&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;hibernate.c3pmin_size&quot;&#160; value=&quot;20&quot;/&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;hibernate.c3ptimeout&quot;&#160;&#160; value=&quot;120&quot;/&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;hibernate.c3pmax_statements&quot; value=&quot;0&quot;/&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;hibernate.c3pidle_test_period&quot;&#160; value=&quot;120&quot;/&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;hibernate.c3pacquire_increment&quot; value=&quot;5&#160; &quot;/&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;hibernate.cache.provider_class&quot; value=&quot;org.hibernate.cache.EhCacheProvider&quot;/&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;hibernate.cache.use_query_cache&quot; value=&quot;false&quot;/&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;hibernate.show_sql&quot; value=&quot;false&quot;/&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;hibernate.useUnicode&quot; value=&quot;true&quot;/&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;hibernate.characterEncoding&quot; value=&quot;utf8&quot;/&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/properties&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/persistence-unit&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/persistence&gt; </p>
<p>&#160;&#160;&#160;&#160;&#160; 仔细观察他的代码，我们发现其实和hibernate.cfg.xml和相似。都有指向pojo的定义 和 database连接的定义。先别着急。我们这次的优化，就先完成这个目标。主要是引入的spring的jpa框架。   <br />&#160;&#160;&#160;&#160;&#160; 后面将介绍更进一步的优化。来展示jpa 和 注释注入的能力。</p>
]]></content:encoded>
			<wfw:commentRss>http://javadou.com/spring-jpa-hibernate-two-177/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Spring 2.5 JPA hibernate 使用方法整理(一)</title>
		<link>http://javadou.com/spring-jpa-hibernate-one-176/</link>
		<comments>http://javadou.com/spring-jpa-hibernate-one-176/#comments</comments>
		<pubDate>Wed, 02 Sep 2009 06:21:00 +0000</pubDate>
		<dc:creator>阿超</dc:creator>
				<category><![CDATA[Hibernate]]></category>
		<category><![CDATA[Spring]]></category>
		<category><![CDATA[hibernate]]></category>
		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://javadou.com/spring-jpa-hibernate-one-176/</guid>
		<description><![CDATA[以下几篇文章简单的介绍一下jpa 和 spring5 hibernate2 整合配置的一个过程。纯粹个人经验只谈。如果有错误，请各位留言指出。 

本系列重点是涉及 配置过程 ，对注释的用法不多介绍。 

注释语法越来越多的被业界所... ]]></description>
			<content:encoded><![CDATA[<p>以下几篇文章简单的介绍一下jpa 和 spring5 hibernate2 整合配置的一个过程。纯粹个人经验只谈。如果有错误，请各位留言指出。 </p>
<p>本系列重点是涉及 配置过程 ，对注释的用法不多介绍。 </p>
<p>注释语法越来越多的被业界所使用,并且注释配置相对于 XML 配置具有很多的优势：它可以充分利用 Java 的反射机制获取类结构信息，这些信息可以有效减少配置的工作。注释和 Java 代码位于一个文件中，而 XML 配置采用独立的配置文件，大多数配置信息在程序开发完成后都不会调整，如果配置信息和 Java 代码放在一起，有助于增强程序的内聚性。而采用独立的 XML 配置文件，程序员在编写一个功能时，往往需要在程序文件和配置文件中不停切换，这种思维上的不连贯会降低开发效率。因此在很多情况下，注释配置比 XML 配置更受欢迎，注释配置有进一步流行的趋势。Spring 5 的一大增强就是引入了很多注释类，现在您已经可以使用注释配置完成大部分 XML 配置的功能。 </p>
<p>首先，我们已经通过 传统的spring +hibernate方式构架成功了一个应用的后台体系。   <br />这个体系里面 有这样几个重要的配置文件。 </p>
<p>&#160;&#160;&#160; hibernate.cfg.xml 。   <br />&#160;&#160;&#160;&#160;&#160; 里面通过 配置 mapping来指向每张数据表单生成配置文件.xxxx.hbm.xml文件    <br />&#160;&#160;&#160; applicaitonContex.xml。    <br />&#160;&#160;&#160;&#160;&#160; 里面通过定义一个一个bean 来配置 各个需要用到的 DAO 和 Service。    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;?xml version=&quot;0&quot; encoding=&quot;UTF-8&quot;?&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;!DOCTYPE beans PUBLIC &quot;-//SPRING//DTD BEAN//EN&quot; &quot;<a href="http://www.springframework.org/dtd/spring-beans.dtd&quot;">http://www.springframework.org/dtd/spring-beans.dtd&quot;</a>&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;beans &gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;bean id=&quot;sessionFactory&quot;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; class=&quot;org.springframework.orm.hibernateLocalSessionFactoryBean&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;configLocation&quot;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; value=&quot;classpath:hibernate.cfg.xml&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/property&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/bean&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;bean id=&quot;transactionManager&quot; class=&quot;org.springframework.orm.hibernateHibernateTransactionManager&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;sessionFactory&quot;&gt;     <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;ref local=&quot;sessionFactory&quot;/&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/property&gt;     <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/bean&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;bean id=&quot;transactionInterceptor&quot; class=&quot;org.springframework.transaction.interceptor.TransactionInterceptor&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;!&#8211;&#160; 事务拦截器bean需要依赖注入一个事务管理器 &#8211;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;transactionManager&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;ref local=&quot;transactionManager&quot;/&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/property&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;transactionAttributes&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;!&#8211;&#160; 下面定义事务传播属性&#8211;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;props&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;prop key=&quot;insert*&quot;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;prop key=&quot;update*&quot;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;prop key=&quot;save*&quot;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;prop key=&quot;add*&quot;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;prop key=&quot;update*&quot;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;prop key=&quot;remove*&quot;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;prop key=&quot;delete*&quot;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;prop key=&quot;get*&quot;&gt;PROPAGATION_REQUIRED,readOnly&lt;/prop&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;prop key=&quot;find*&quot;&gt;PROPAGATION_REQUIRED,readOnly&lt;/prop&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;prop key=&quot;load*&quot;&gt;PROPAGATION_REQUIRED,readOnly&lt;/prop&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;prop key=&quot;change*&quot;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;prop key=&quot;*&quot;&gt;PROPAGATION_REQUIRED,readOnly&lt;/prop&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/props&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/property&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/bean&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;!&#8211; 定义自动代理BeanNameAutoProxyCreator &#8211;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;bean id=&quot;beanNameAutoProxyCreator&quot;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; class=&quot;org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;!&#8211;&#160; 指定对满足哪些bean name的bean自动生成业务代理 &#8211;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;beanNames&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;list&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;value&gt;*Service&lt;/value&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/list&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/property&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;!&#8211;&#160; 下面定义BeanNameAutoProxyCreator所需的事务拦截器&#8211;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;interceptorNames&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;list&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;!&#8211; 此处可增加其他新的Interceptor &#8211;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;value&gt;transactionInterceptor&lt;/value&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/list&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/property&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/bean&gt;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;bean id=&quot;McCityInfoDAO&quot;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; class=&quot;com.firemax.manatee.hibernate.McCityInfoDAO&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;sessionFactory&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;ref bean=&quot;sessionFactory&quot; /&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/property&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/bean&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;bean id=&quot;McMaterialInfoDAO&quot;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; class=&quot;com.firemax.manatee.hibernate.McMaterialInfoDAO&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;sessionFactory&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;ref bean=&quot;sessionFactory&quot; /&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/property&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/bean&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/beans&gt;    <br />&#160;&#160;&#160;&#160;&#160; hibernate.cfg.xml要配置这么多 xxxxx.hbm.xml文件。每次数据结构发生变化的时候。要重新去改写pojo和dao以及这些xxxxx.hbm.xml    <br />&#160;&#160;&#160;&#160;&#160; 那么好。我们现在就用 注解的力量 去把这部分工作简化。 </p>
<p>&#160;&#160;&#160; * 首先我们需要 </p>
<p>&#160;&#160;&#160; hibernate2 以上版本的jar   <br />&#160;&#160;&#160; jdk 5 以上的环境    <br />&#160;&#160;&#160; spring2 </p>
<p>&#160;&#160;&#160; * 然后我们修改pojo的java类。加上注解。使起通过注解来取代原先要xxxx.hbm.xml里面配置的指向的数据库表单结构的信息。 </p>
<p>&#160;&#160;&#160; package com.alcor.web.hibernate;   <br />&#160;&#160;&#160; import java.util.HashSet;    <br />&#160;&#160;&#160; import java.util.Set;    <br />&#160;&#160;&#160; import javax.persistence.CascadeType;    <br />&#160;&#160;&#160; import javax.persistence.Column;    <br />&#160;&#160;&#160; import javax.persistence.Entity;    <br />&#160;&#160;&#160; import javax.persistence.FetchType;    <br />&#160;&#160;&#160; import javax.persistence.Id;    <br />&#160;&#160; import javax.persistence.JoinColumn;    <br />&#160;&#160; import javax.persistence.ManyToOne;    <br />&#160;&#160; import javax.persistence.OneToMany;    <br />&#160;&#160; import javax.persistence.Table;    <br />&#160;&#160; /**    <br />&#160;&#160;&#160; * AlcorTCitys entity. @author MyEclipse Persistence Tools    <br />&#160;&#160;&#160; */    <br />&#160;&#160; @Entity    <br />&#160;&#160; @Table(name = &quot;alcor_t_citys&quot;, catalog = &quot;alcorweb&quot;)    <br />&#160;&#160; public class AlcorTCitys implements java.io.Serializable {    <br />&#160;&#160;&#160;&#160;&#160;&#160; // Fields    <br />&#160;&#160;&#160;&#160;&#160;&#160; private String cityCode;    <br />&#160;&#160;&#160;&#160;&#160;&#160; private AlcorTProvinces alcorTProvinces;    <br />&#160;&#160;&#160;&#160;&#160;&#160; private String cityName;    <br />&#160;&#160;&#160;&#160;&#160;&#160; private Set&lt;AlcotTDistrict&gt; alcotTDistricts = new HashSet&lt;AlcotTDistrict&gt;(0);    <br />&#160;&#160;&#160;&#160;&#160;&#160; // Constructors    <br />&#160;&#160;&#160;&#160;&#160;&#160; /** default constructor */    <br />&#160;&#160;&#160;&#160;&#160;&#160; public AlcorTCitys() {    <br />&#160;&#160;&#160;&#160;&#160;&#160; }    <br />&#160;&#160;&#160;&#160;&#160;&#160; /** minimal constructor */    <br />&#160;&#160;&#160;&#160;&#160;&#160; public AlcorTCitys(String cityCode, AlcorTProvinces alcorTProvinces,    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; String cityName) {    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; this.cityCode = cityCode;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; this.alcorTProvinces = alcorTProvinces;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; this.cityName = cityName;    <br />&#160;&#160;&#160;&#160;&#160;&#160; }    <br />&#160;&#160;&#160;&#160;&#160;&#160; /** full constructor */    <br />&#160;&#160;&#160;&#160;&#160;&#160; public AlcorTCitys(String cityCode, AlcorTProvinces alcorTProvinces,    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; String cityName, Set&lt;AlcotTDistrict&gt; alcotTDistricts) {    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; this.cityCode = cityCode;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; this.alcorTProvinces = alcorTProvinces;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; this.cityName = cityName;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; this.alcotTDistricts = alcotTDistricts;    <br />&#160;&#160;&#160;&#160;&#160;&#160; }    <br />&#160;&#160;&#160;&#160;&#160;&#160; // Property accessors    <br />&#160;&#160;&#160;&#160;&#160;&#160; @Id    <br />&#160;&#160;&#160;&#160;&#160;&#160; @Column(name = &quot;city_code&quot;, unique = true, nullable = false, length = 32)    <br />&#160;&#160;&#160;&#160;&#160;&#160; public String getCityCode() {    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; return this.cityCode;    <br />&#160;&#160;&#160;&#160;&#160;&#160; }    <br />&#160;&#160;&#160;&#160;&#160;&#160; public void setCityCode(String cityCode) {    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; this.cityCode = cityCode;    <br />&#160;&#160;&#160;&#160;&#160;&#160; }    <br />&#160;&#160;&#160;&#160;&#160;&#160; @ManyToOne(fetch = FetchType.EAGER)    <br />&#160;&#160;&#160;&#160;&#160;&#160; @JoinColumn(name = &quot;province_code&quot;, nullable = false)    <br />&#160;&#160;&#160;&#160;&#160;&#160; public AlcorTProvinces getAlcorTProvinces() {    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; return this.alcorTProvinces;    <br />&#160;&#160;&#160;&#160;&#160;&#160; }    <br />&#160;&#160;&#160;&#160;&#160;&#160; public void setAlcorTProvinces(AlcorTProvinces alcorTProvinces) {    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; this.alcorTProvinces = alcorTProvinces;    <br />&#160;&#160;&#160;&#160;&#160;&#160; }    <br />&#160;&#160;&#160;&#160;&#160;&#160; @Column(name = &quot;city_name&quot;, nullable = false, length = 64)    <br />&#160;&#160;&#160;&#160;&#160;&#160; public String getCityName() {    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; return this.cityName;    <br />&#160;&#160;&#160;&#160;&#160;&#160; }    <br />&#160;&#160;&#160;&#160;&#160;&#160; public void setCityName(String cityName) {    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; this.cityName = cityName;    <br />&#160;&#160;&#160;&#160;&#160;&#160; }    <br />&#160;&#160;&#160;&#160;&#160;&#160; @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = &quot;alcorTCitys&quot;)    <br />&#160;&#160;&#160;&#160;&#160;&#160; public Set&lt;AlcotTDistrict&gt; getAlcotTDistricts() {    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; return this.alcotTDistricts;    <br />&#160;&#160;&#160;&#160;&#160;&#160; }    <br />&#160;&#160;&#160;&#160;&#160;&#160; public void setAlcotTDistricts(Set&lt;AlcotTDistrict&gt; alcotTDistricts) {    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; this.alcotTDistricts = alcotTDistricts;    <br />&#160;&#160;&#160;&#160;&#160;&#160; }    <br />&#160;&#160; } </p>
<p>&#160;&#160;&#160; * 修改hibernate.cfg.xml中的定义方式，把原来的maping source=“xxxxx.hbm.xml”修改成 </p>
<p>&lt;mapping class=&quot;com.alcor.web.hibernate.AlcorTCitys&quot; /&gt; </p>
<p>这样我们就可以把原来的 xxxxx.hbm.xml全部删除了。   <br />经过这个步骤。如果你原有的servcice层的功能能够正常使用。恭喜你。迈出了成功的第一步。</p>
]]></content:encoded>
			<wfw:commentRss>http://javadou.com/spring-jpa-hibernate-one-176/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Spring 2.5 JPA hibernate 使用方法整理(六)</title>
		<link>http://javadou.com/spring-jpa-hibernate-175/</link>
		<comments>http://javadou.com/spring-jpa-hibernate-175/#comments</comments>
		<pubDate>Wed, 02 Sep 2009 05:18:00 +0000</pubDate>
		<dc:creator>阿超</dc:creator>
				<category><![CDATA[Hibernate]]></category>
		<category><![CDATA[Spring]]></category>
		<category><![CDATA[hibernate]]></category>
		<category><![CDATA[jpa]]></category>
		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://javadou.com/spring-jpa-hibernate-175/</guid>
		<description><![CDATA[每个持久化POJO类都是一个实体Bean, 通过在类的定义中使用 Entity 注解来进行声明。

声明实体Bean

Entity
public class Flight implements Serializable {
  Long id;
  Id
  public Long getId() { return id; }
  public void setId(Long id) { this.id... ]]></description>
			<content:encoded><![CDATA[<p>一、 实体 Bean</p>
<p>每个持久化POJO类都是一个实体Bean, 通过在类的定义中使用 @Entity 注解来进行声明。</p>
<p>声明实体Bean</p>
<p>@Entity<br />
public class Flight implements Serializable {<br />
Long id;<br />
@Id<br />
public Long getId() { return id; }<br />
public void setId(Long id) { this.id = id; }<br />
}</p>
<p>@Entity 注解将一个类声明为实体 Bean, @Id 注解声明了该实体Bean的标识属性。</p>
<p>Hibernate 可以对类的属性或者方法进行注解。属性对应field类别，方法的 getXxx()对应property类别。</p>
<p>定义表</p>
<p>通过 @Table 为实体Bean指定对应数据库表，目录和schema的名字。</p>
<p>@Entity<br />
@Table(name=&#8221;tbl_sky&#8221;)<br />
public class Sky implements Serializable {</p>
<p>&#8230;</p>
<p>@Table 注解包含一个schema和一个catelog 属性，使用@UniqueConstraints 可以定义表的唯一约束。</p>
<p>@Table(name=&#8221;tbl_sky&#8221;,<br />
uniqueConstraints = <a href="mailto:%7B@UniqueConstraint%28columnNames=%7B%22month">{@UniqueConstraint(columnNames={&#8220;month</a>&#8220;, &#8220;day&#8221;})}<br />
)</p>
<p>上述代码在  &#8220;month&#8221; 和 &#8220;day&#8221; 两个 field 上加上 unique constrainst.</p>
<p>@Version 注解用于支持乐观锁版本控制。</p>
<p>@Entity<br />
public class Flight implements Serializable {<br />
&#8230;<br />
@Version<br />
@Column(name=&#8221;OPTLOCK&#8221;)<br />
public Integer getVersion() { &#8230; }<br />
}</p>
<p>version属性映射到 &#8220;OPTLOCK&#8221; 列，entity manager 使用这个字段来检测冲突。 一般可以用 数字 或者 timestamp 类型来支持 version.</p>
<p>实体Bean中所有非static 非 transient 属性都可以被持久化，除非用@Transient注解。</p>
<p>默认情况下，所有属性都用 @Basic 注解。</p>
<p>public transient int counter; //transient property</p>
<p>private String firstname; //persistent property<br />
@Transient<br />
String getLengthInMeter() { &#8230; } //transient property<br />
String getName() {&#8230; } // persistent property<br />
@Basic<br />
int getLength() { &#8230; } // persistent property<br />
@Basic(fetch = FetchType.LAZY)<br />
String getDetailedComment() { &#8230; } // persistent property<br />
@Temporal(TemporalType.TIME)<br />
java.util.Date getDepartureTime() { &#8230; } // persistent property<br />
@Enumerated(EnumType.STRING)<br />
Starred getNote() { &#8230; } //enum persisted as String in database</p>
<p>上述代码中 counter, lengthInMeter 属性将忽略不被持久化，而 firstname, name, length 被定义为可持久化和可获取的。</p>
<p>@TemporalType.(DATE,TIME,TIMESTAMP) 分别Map java.sql.(Date, Time, Timestamp).</p>
<p>@Lob 注解属性将被持久化为 Blog 或 Clob 类型。具体的java.sql.Clob, Character[], char[] 和 java.lang.String 将被持久化为 Clob 类型. java.sql.Blob, Byte[], byte[] 和 serializable type 将被持久化为 Blob 类型。</p>
<p>@Lob<br />
public String getFullText() {<br />
return fullText;  // clob type<br />
}</p>
<p>@Lob<br />
public byte[] getFullCode() {<br />
return fullCode;  // blog type<br />
}</p>
<p>@Column 注解将属性映射到列。</p>
<p>@Entity<br />
public class Flight implements Serializable {<br />
&#8230;<br />
@Column(updatable = false, name = &#8220;flight_name&#8221;, nullable = false, length=50)<br />
public String getName() { &#8230; }</p>
<p>定义 name 属性映射到 flight_name column, not null, can&#8217;t update, length equal 50</p>
<p>@Column(<br />
name=&#8221;columnName&#8221;; (1) 列名<br />
boolean unique() default false; (2)    是否在该列上设置唯一约束<br />
boolean nullable() default true; (3)   列可空？<br />
boolean insertable() default true; (4) 该列是否作为生成 insert语句的一个列<br />
boolean updatable() default true; (5)  该列是否作为生成 update语句的一个列<br />
String columnDefinition() default &#8220;&#8221;; (6)  默认值<br />
String table() default &#8220;&#8221;; (7)             定义对应的表（deault 是主表）<br />
int length() default 255; (8)              列长度<br />
int precision() default 0; // decimal precision (9)  decimal精度<br />
int scale() default 0; // decimal scale        (10)  decimal长度</p>
<p>嵌入式对象（又称组件）也就是别的对象定义的属性</p>
<p>组件类必须在类一级定义 @Embeddable 注解。在特定的实体关联属性上使用 @Embeddable 和 @AttributeOverride 注解可以覆盖该属性对应的嵌入式对象的列映射。</p>
<p>@Entity<br />
public class Person implements Serializable {<br />
// Persistent component using defaults<br />
Address homeAddress;<br />
@Embedded<br />
@AttributeOverrides( {<br />
@AttributeOverride(name=&#8221;iso2&#8243;, column = @Column(name=&#8221;bornIso2&#8243;) ),<br />
@AttributeOverride(name=&#8221;name&#8221;, column = @Column(name=&#8221;bornCountryName&#8221;) )<br />
} )<br />
Country bornIn;<br />
&#8230;<br />
}</p>
<p>@Embeddable<br />
public class Address implements Serializable {<br />
String city;<br />
Country nationality; //no overriding here<br />
}</p>
<p>@Embeddable<br />
public class Country implements Serializable {<br />
private String iso2;<br />
@Column(name=&#8221;countryName&#8221;) private String name;<br />
public String getIso2() { return iso2; }<br />
public void setIso2(String iso2) { this.iso2 = iso2; }<br />
public String getName() { return name; }<br />
public void setName(String name) { this.name = name; }<br />
&#8230;<br />
}</p>
<p>Person 类定义了 Address 和  Country 对象，具体两个类实现见上。</p>
<p>无注解属性默认值：</p>
<p>• 属性为简单类型，则映射为 @Basic</p>
<p>• 属性对应的类型定义了 @Embeddable 注解，则映射为 @Embedded</p>
<p>• 属性对应的类型实现了Serializable,则属性被映射为@Basic并在一个列中保存该对象的serialized版本。</p>
<p>• 属性的类型为 java.sql.Clob or java.sql.Blob, 则映射到 @Lob 对应的类型。</p>
<p>映射主键属性</p>
<p>@Id 注解可将实体Bean中某个属性定义为主键，使用@GenerateValue注解可以定义该标识符的生成策略。</p>
<p>• AUTO -  可以是 identity column, sequence 或者 table 类型，取决于不同底层的数据库<br />
• TABLE &#8211; 使用table保存id值<br />
• IDENTITY &#8211; identity column<br />
• SEQUENCE &#8211; seque</p>
<p>nce<br />
@Id @GeneratedValue(strategy=GenerationType.SEQUENCE, generator=&#8221;SEQ_STORE&#8221;)<br />
public Integer getId() { &#8230; }</p>
<p>@Id @GeneratedValue(strategy=GenerationType.IDENTITY)<br />
public Long getId() { &#8230; }</p>
<p>AUTO 生成器，适用与可移值的应用，多个@Id可以共享同一个 identifier生成器，只要把generator属性设成相同的值就可以。通过@SequenceGenerator 和 @TableGenerator 可以配置不同的 identifier 生成器。</p>
<p>&lt;table-generator name=&#8221;EMP_GEN&#8221;<br />
table=&#8221;GENERATOR_TABLE&#8221;<br />
pk-column-name=&#8221;key&#8221;<br />
value-column-name=&#8221;hi&#8221;<br />
pk-column-value=&#8221;EMP&#8221;<br />
allocation-size=&#8221;20&#8243;/&gt;<br />
//and the annotation equivalent<br />
@javax.persistence.TableGenerator(<br />
name=&#8221;EMP_GEN&#8221;,<br />
table=&#8221;GENERATOR_TABLE&#8221;,<br />
pkColumnName = &#8220;key&#8221;,<br />
valueColumnName = &#8220;hi&#8221;<br />
pkColumnValue=&#8221;EMP&#8221;,<br />
allocationSize=20<br />
)<br />
&lt;sequence-generator name=&#8221;SEQ_GEN&#8221;<br />
sequence-name=&#8221;my_sequence&#8221;<br />
allocation-size=&#8221;20&#8243;/&gt;<br />
//and the annotation equivalent<br />
@javax.persistence.SequenceGenerator(<br />
name=&#8221;SEQ_GEN&#8221;,<br />
sequenceName=&#8221;my_sequence&#8221;,<br />
allocationSize=20<br />
)</p>
<p>The next example shows the definition of a sequence generator in a class scope:</p>
<p>@Entity<br />
@javax.persistence.SequenceGenerator(<br />
name=&#8221;SEQ_STORE&#8221;,<br />
sequenceName=&#8221;my_sequence&#8221;<br />
)<br />
public class Store implements Serializable {<br />
private Long id;<br />
@Id @GeneratedValue(strategy=GenerationType.SEQUENCE, generator=&#8221;SEQ_STORE&#8221;)<br />
public Long getId() { return id; }<br />
}</p>
<p>Store类使用名为my_sequence的sequence，并且SEQ_STORE生成器对于其他类是不可见的。</p>
<p>通过下面语法，你可以定义组合键。</p>
<p>• 将组件类注解为 @Embeddable， 并将组件的属性注解为 @Id<br />
• 将组件的属性注解为 @EmbeddedId<br />
• 将类注解为 @IdClass，并将该实体中所有主键的属性都注解为 @Id</p>
<p>@Entity<br />
@IdClass(FootballerPk.class)<br />
public class Footballer {<br />
//part of the id key<br />
@Id public String getFirstname() {<br />
return firstname;<br />
}<br />
public void setFirstname(String firstname) {<br />
this.firstname = firstname;<br />
}<br />
//part of the id key<br />
@Id public String getLastname() {<br />
return lastname;<br />
}<br />
public void setLastname(String lastname) {<br />
this.lastname = lastname;<br />
}<br />
public String getClub() {<br />
return club;<br />
}<br />
public void setClub(String club) {<br />
this.club = club;<br />
}<br />
//appropriate equals() and hashCode() implementation<br />
}</p>
<p>@Embeddable<br />
public class FootballerPk implements Serializable {<br />
//same name and type as in Footballer<br />
public String getFirstname() {<br />
return firstname;<br />
}<br />
public void setFirstname(String firstname) {<br />
this.firstname = firstname;<br />
}<br />
//same name and type as in Footballer<br />
public String getLastname() {<br />
return lastname;<br />
}<br />
public void setLastname(String lastname) {<br />
this.lastname = lastname;<br />
}<br />
//appropriate equals() and hashCode() implementation<br />
}</p>
<p>@Entity<br />
@AssociationOverride( name=&#8221;id.channel&#8221;, joinColumns = @JoinColumn(name=&#8221;chan_id&#8221;) )<br />
public class TvMagazin {<br />
@EmbeddedId public TvMagazinPk id;<br />
@Temporal(TemporalType.TIME) Date time;<br />
}</p>
<p>@Embeddable<br />
public class TvMagazinPk implements Serializable {<br />
@ManyToOne<br />
public Channel channel;<br />
public String name;<br />
@ManyToOne<br />
public Presenter presenter;<br />
}</p>
<p>映射继承关系</p>
<p>EJB支持3种类型的继承。</p>
<p>• Table per Class Strategy: the &lt;union-class&gt; element in Hibernate 每个类一张表<br />
• Single Table per Class Hierarchy Strategy: the &lt;subclass&gt; element in Hibernate 每个类层次结构一张表<br />
• Joined Subclass Strategy: the &lt;joined-subclass&gt; element in Hibernate 连接的子类策略</p>
<p>@Inheritance 注解来定义所选的之类策略。</p>
<p>每个类一张表</p>
<p>@Entity<br />
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)<br />
public class Flight implements Serializable {</p>
<p>有缺点，如多态查询或关联。Hibernate 使用 SQL Union 查询来实现这种策略。 这种策略支持双向的一对多关联，但不支持 IDENTIFY 生成器策略，因为ID必须在多个表间共享。一旦使用就不能使用AUTO和IDENTIFY生成器。</p>
<p>每个类层次结构一张表</p>
<p>@Entity<br />
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)<br />
@DiscriminatorColumn(<br />
name=&#8221;planetype&#8221;,<br />
discriminatorType=DiscriminatorType.STRING<br />
)<br />
@DiscriminatorValue(&#8220;Plane&#8221;)<br />
public class Plane { &#8230; }</p>
<p>@Entity<br />
@DiscriminatorValue(&#8220;A320&#8243;)<br />
public class A320 extends Plane { &#8230; }</p>
<p>整个层次结构中的所有父类和子类属性都映射到同一个表中，他们的实例通过一个辨别符列（discriminator）来区分。</p>
<p>Plane 是父类。@DiscriminatorColumn 注解定义了辨别符列。对于继承层次结构中的每个类, @DiscriminatorValue 注解指定了用来辨别该类的值。 辨别符列名字默认为 DTYPE，其默认值为实体名。其类型为DiscriminatorType.STRING。</p>
<p>连接的子类</p>
<p>@Entity<br />
@Inheritance(strategy=InheritanceType.JOINED)<br />
public class Boat implements Serializable { &#8230; }</p>
<p>@Entity<br />
public class Ferry extends Boat { &#8230; }</p>
<p>@Entity<br />
@PrimaryKeyJoinColumn(name=&#8221;BOAT_ID&#8221;)<br />
public class AmericaCupClass extends Boat { &#8230; }</p>
<p>以上所有实体使用 JOINED 策略 Ferry和Boat class使用同名的主键关联(eg: Boat.id = Ferry.id)， AmericaCupClass 和 Boat 关联的条件为 Boat.id = AmericaCupClass.BOAT_ID.</p>
<p>从父类继承的属性</p>
<p>@MappedSuperclass<br />
public class BaseEntity {<br />
@Basic<br />
@Temporal(TemporalType.TIMESTAMP)<br />
public Date getLastUpdate() { &#8230; }<br />
public String getLastUpdater() { &#8230; }<br />
&#8230;<br />
}</p>
<p>@Entity class Order extends BaseEntity {<br />
@Id public Integer getId() { &#8230; }<br />
&#8230;<br />
}</p>
<p>继承父类的一些属性，但不用父类作为映射实体，这时候需要 @MappedSuperclass 注解。 上述实体映射到数据库中的时候对应 Order 实体Bean, 其具有 id, lastUpdate, lastUpdater 三个属性。如果没有@MappedSuperclass 注解,则父类中属性忽略，这是 Order 实体 Bean 只有 id 一个属性。</p>
<p>映射实体Bean的关联关系</p>
<p>一对一</p>
<p>使用 @OneToOne 注解可以建立实体Bean之间的一对一关系。一对一关系有3种情况。</p>
<p>• 关联的实体都共享同样的主键。</p>
<p>@Entity<br />
public class Body {<br />
@Id<br />
public Long getId() { return id; }<br />
@OneToOne(cascade = CascadeType.ALL)<br />
@PrimaryKeyJoinColumn<br />
public Heart getHeart() {<br />
return heart;<br />
}<br />
&#8230;<br />
}</p>
<p>@Entity<br />
public class Heart {<br />
@Id<br />
public Long getId() { &#8230;}<br />
}</p>
<p>通过@PrimaryKeyJoinColumn 注解定义了一对一的关联关系。</p>
<p>• 其中一个实体通过外键关联到另一个实体的主键。注：一对一，则外键必须为唯一约束。</p>
<p>@Entity<br />
public class Customer implements Serializable {<br />
@OneToOne(cascade = CascadeType.ALL)<br />
@JoinColumn(name=&#8221;passport_fk&#8221;)<br />
public Passport getPassport() {<br />
&#8230;<br />
}</p>
<p>@Entity<br />
public class Passport implements Serializable {<br />
@OneToOne(mappedBy = &#8220;passport&#8221;)<br />
public Customer getOwner() {<br />
&#8230;<br />
}</p>
<p>通过@JoinColumn注解定义一对一的关联关系。如果没有@JoinColumn注解，则系统自动处理，在主表中将创建连接列，列名为：主题的关联属性名 + 下划线 + 被关联端的主键列名。上例为 passport_id, 因为Customer 中关联属性为 passport, Passport 的主键为 id.</p>
<p>• 通过关联表来保存两个实体之间的关联关系。注：一对一，则关联表每个外键都必须是唯一约束。</p>
<p>@Entity<br />
public class Customer implements Serializable {<br />
@OneToOne(cascade = CascadeType.ALL)<br />
@JoinTable(name = &#8220;CustomerPassports&#8221;,<br />
joinColumns = @JoinColumn(name=&#8221;customer_fk&#8221;),<br />
inverseJoinColumns = @JoinColumn(name=&#8221;passport_fk&#8221;)<br />
)<br />
public Passport getPassport() {<br />
&#8230;<br />
}</p>
<p>@Entity public class Passport implements Serializable {<br />
@OneToOne(mappedBy = &#8220;passport&#8221;)<br />
public Customer getOwner() {<br />
&#8230;<br />
}</p>
<p>Customer 通过 CustomerPassports 关联表和 Passport 关联。该关联表通过 passport_fk 外键指向 Passport 表，该信心定义为 inverseJoinColumns 的属性值。 通过 customer_fk 外键指向 Customer 表，该信息定义为 joinColumns 属性值。</p>
<p>多对一</p>
<p>使用 @ManyToOne 注解定义多对一关系。</p>
<p>@Entity()<br />
public class Flight implements Serializable {<br />
@ManyToOne( cascade = {CascadeType.PERSIST, CascadeType.MERGE} )<br />
@JoinColumn(name=&#8221;COMP_ID&#8221;)<br />
public Company getCompany() {<br />
return company;<br />
}<br />
&#8230;<br />
}</p>
<p>其中@JoinColumn 注解是可选的，关键字段默认值和一对一关联的情况相似。列名为：主题的关联属性名 + 下划线 + 被关联端的主键列名。本例中为company_id,因为关联的属性是company, Company的主键为 id.</p>
<p>@ManyToOne 注解有个targetEntity属性，该参数定义了目标实体名。通常不需要定义，大部分情况为默认值。但下面这种情况则需要 targetEntity 定义（使用接口作为返回值，而不是常用的实体）。</p>
<p>@Entity()<br />
public class Flight implements Serializable {<br />
@ManyToOne(cascade=   {CascadeType.PERSIST,CascadeType.MERGE},targetEntity= CompanyImpl.class)<br />
@JoinColumn(name=&#8221;COMP_ID&#8221;)<br />
public Company getCompany() {<br />
return company;<br />
}<br />
&#8230;<br />
}</p>
<p>public interface Company {<br />
&#8230;</p>
<p>多对一也可以通过关联表的方式来映射，通过 @JoinTable 注解可定义关联表。该关联表包含指回实体的外键（通过@JoinTable.joinColumns）以及指向目标实体表的外键（通过@JoinTable.inverseJoinColumns）.</p>
<p>@Entity()<br />
public class Flight implements Serializable {</p>
<p>@ManyToOne( cascade = {CascadeType.PERSIST, CascadeType.MERGE} )<br />
@JoinTable(name=&#8221;Flight_Company&#8221;,<br />
joinColumns = @JoinColumn(name=&#8221;FLIGHT_ID&#8221;),<br />
inverseJoinColumns = @JoinColumn(name=&#8221;COMP_ID&#8221;)<br />
)<br />
public Company getCompany() {<br />
return company;<br />
}<br />
&#8230;<br />
}</p>
<p>集合类型</p>
<p>一对多</p>
<p>@OneToMany 注解可定义一对多关联。一对多关联可以是双向的。</p>
<p>双向</p>
<p>规范中多对一端几乎总是双向关联中的主体（owner）端，而一对多的关联注解为 @OneToMany(mappedBy=)</p>
<p>@Entity<br />
public class Troop {<br />
@OneToMany(mappedBy=&#8221;troop&#8221;)<br />
public Set&lt;Soldier&gt; getSoldiers() {<br />
&#8230;<br />
}</p>
<p>@Entity<br />
public class Soldier {<br />
@ManyToOne<br />
@JoinColumn(name=&#8221;troop_fk&#8221;)<br />
public Troop getTroop() {<br />
&#8230;<br />
}</p>
<p>Troop 通过troop属性和Soldier建立了一对多的双向关联。在 mappedBy 端不必也不能定义任何物理映射。</p>
<p>单向</p>
<p>@Entity<br />
public class Customer implements Serializable {<br />
@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)<br />
@JoinColumn(name=&#8221;CUST_ID&#8221;)<br />
public Set&lt;Ticket&gt; getTickets() {<br />
&#8230;<br />
}</p>
<p>@Entity<br />
public class Ticket implements Serializable {<br />
&#8230; //no bidir<br />
}</p>
<p>一般通过连接表来实现这种关联，可以通过@JoinColumn注解来描述这种单向关联关系。上例 Customer 通过 CUST_ID 列和 Ticket 建立了单向关联关系。</p>
<p>通过关联表来处理单向关联</p>
<p>@Entity<br />
public class Trainer {<br />
@OneToMany<br />
@JoinTable(<br />
name=&#8221;TrainedMonkeys&#8221;,<br />
joinColumns = @JoinColumn( name=&#8221;trainer_id&#8221;),<br />
inverseJoinColumns = @JoinColumn( name=&#8221;monkey_id&#8221;)<br />
)<br />
public Set&lt;Monkey&gt; getTrainedMonkeys() {<br />
&#8230;<br />
}</p>
<p>@Entity<br />
public class Monkey {<br />
&#8230; //no bidir<br />
}</p>
<p>通过关联表来处理单向一对多关系是首选，这种关联通过 @JoinTable 注解来进行描述。上例子中 Trainer 通过TrainedMonkeys表和Monkey建立了单向关联关系。其中外键trainer_id关联到Trainer(joinColumns)而外键monkey_id关联到Monkey(inverseJoinColumns).</p>
<p>默认处理机制</p>
<p>通过连接表来建立单向一对多关联不需要描述任何物理映射，表名由一下3个部分组成，主表(owner table)表名 + 下划线 + 从表(the other side table)表名。指向主表的外键名:主表表名+下划线+主表主键列名指向从表的外键定义为唯一约束，用来表示一对多的关联关系。</p>
<p>@Entity<br />
public class Trainer {<br />
@OneToMany<br />
public Set&lt;Tiger&gt; getTrainedTigers() {<br />
&#8230;<br />
}</p>
<p>@Entity<br />
public class Tiger {<br />
&#8230; //no bidir<br />
}</p>
<p>上述例子中 Trainer 和 Tiger 通过 Trainer_Tiger 连接表建立单向关联关系。其中外键 trainer_id 关联到 Trainer表，而外键 trainedTigers_id 关联到 Tiger 表。</p>
<p>多对多</p>
<p>通过 @ManyToMany 注解定义多对多关系，同时通过 @JoinTable 注解描述关联表和关联条件。其中一端定义为 owner, 另一段定义为 inverse(对关联表进行更新操作，这段被忽略)。</p>
<p>@Entity<br />
public class Employer implements Serializable {<br />
@ManyToMany(<br />
targetEntity=org.hibernate.test.metadata.manytomany.Employee.class,<br />
cascade={CascadeType.PERSIST, CascadeType.MERGE}<br />
)<br />
@JoinTable(<br />
name=&#8221;EMPLOYER_EMPLOYEE&#8221;,<br />
<a href="mailto:joinColumns=@JoinColumn%28name=%22EMPER_ID">joinColumns=@JoinColumn(name=&#8221;EMPER_ID</a>&#8220;),<br />
<a href="mailto:inverseJoinColumns=@JoinColumn%28name=%22EMPEE_ID">inverseJoinColumns=@JoinColumn(name=&#8221;EMPEE_ID</a>&#8220;)<br />
)<br />
public Collection getEmployees() {<br />
return employees;<br />
}<br />
&#8230;<br />
}</p>
<p>@Entity<br />
public class Employee implements Serializable {<br />
@ManyToMany(<br />
cascade = {CascadeType.PERSIST, CascadeType.MERGE},<br />
mappedBy = &#8220;employees&#8221;,<br />
targetEntity = Employer.class<br />
)<br />
public Collection getEmployers() {<br />
return employers;<br />
}<br />
}</p>
<p>默认值：</p>
<p>关联表名：主表表名 + 下划线 + 从表表名；关联表到主表的外键：主表表名 + 下划线 + 主表中主键列名；关联表到从表的外键名：主表中用于关联的属性名 + 下划线 + 从表的主键列名。</p>
<p>用 cascading 实现传播持久化（Transitive persistence）</p>
<p>cascade 属性接受值为 CascadeType 数组，其类型如下：</p>
<p>• CascadeType.PERSIST: cascades the persist (create) operation to associated entities persist() is called or if the entity is managed 如果一个实体是受管状态，或者当 persist() 函数被调用时，触发级联创建(create)操作。</p>
<p>• CascadeType.MERGE: cascades the merge operation to associated entities if merge() is called or if the entity is managed 如果一个实体是受管状态，或者当 merge() 函数被调用时，触发级联合并(merge)操作。</p>
<p>• CascadeType.REMOVE: cascades the remove operation to associated entities if delete() is called 当 delete() 函数被调用时，触发级联删除(remove)操作。</p>
<p>• CascadeType.REFRESH: cascades the refresh operation to associated entities if refresh() is called  当 refresh() 函数被调用时，出发级联更新(refresh)操作。</p>
<p>• CascadeType.ALL: all of the above  以上全部</p>
<p>映射二级列表</p>
<p>使用类一级的 @SecondaryTable 和 @SecondaryTables 注解可以实现单个实体到多个表的映射。使用 @Column 或者 @JoinColumn 注解中的 table 参数可以指定某个列所属的特定表。</p>
<p>@Entity<br />
@Table(name=&#8221;MainCat&#8221;)<br />
@SecondaryTables({<br />
@SecondaryTable(name=&#8221;Cat1&#8243;, pkJoinColumns={<br />
@PrimaryKeyJoinColumn(name=&#8221;cat_id&#8221;, referencedColumnName=&#8221;id&#8221;)}),<br />
@SecondaryTable(name=&#8221;Cat2&#8243;, uniqueConstraints={<br />
@UniqueConstraint(columnNames={&#8220;storyPart2&#8243;})})<br />
})<br />
public class Cat implements Serializable {<br />
private Integer id;<br />
private String name;</p>
<p>private String storyPart1;<br />
private String storyPart2;<br />
@Id @GeneratedValue<br />
public Integer getId() {<br />
return id;<br />
}<br />
public String getName() {<br />
return name;<br />
}<br />
@Column(table=&#8221;Cat1&#8243;)<br />
public String getStoryPart1() {<br />
return storyPart1;<br />
}<br />
@Column(table=&#8221;Cat2&#8243;)<br />
public String getStoryPart2() {<br />
return storyPart2;<br />
}</p>
<p>上述例子中， name 保存在 MainCat 表中，storyPart1保存在 Cat1 表中，storyPart2 保存在 Cat2 表中。 Cat1 表通过外键 cat_id 和 MainCat 表关联， Cat2 表通过 id 列和 MainCat 表关联。对storyPart2 列还定义了唯一约束。</p>
<p>映射查询</p>
<p>使用注解可以映射 EJBQL/HQL 查询，@NamedQuery 和 @NamedQueries 是可以使用在类级别或者JPA的XML文件中的注解。</p>
<p>&lt;entity-mappings&gt;<br />
&lt;named-query name=&#8221;plane.getAll&#8221;&gt;<br />
&lt;query&gt;select p from Plane p&lt;/query&gt;<br />
&lt;/named-query&gt;<br />
&#8230;<br />
&lt;/entity-mappings&gt;<br />
&#8230;<br />
@Entity<br />
@NamedQuery(name=&#8221;night.moreRecentThan&#8221;, query=&#8221;select n from Night n where n.date &gt;= :date&#8221;)<br />
public class Night {<br />
&#8230;<br />
}<br />
public class MyDao {<br />
doStuff() {<br />
Query q = s.getNamedQuery(&#8220;night.moreRecentThan&#8221;);<br />
q.setDate( &#8220;date&#8221;, aMonthAgo );<br />
List results = q.list();<br />
&#8230;<br />
}<br />
&#8230;<br />
}</p>
<p>可以通过定义 QueryHint 数组的 hints 属性为查询提供一些 hint 信息。下图是一些 Hibernate hints:</p>
<p>映射本地化查询</p>
<p>通过@SqlResultSetMapping 注解来描述 SQL 的 resultset 结构。如果定义多个结果集映射，则用 @SqlResultSetMappings。</p>
<p>@NamedNativeQuery(name=&#8221;night&amp;area&#8221;, query=&#8221;select night.id nid, night.night_duration, &#8221;<br />
+ &#8221; night.night_date, area.id aid, night.area_id, area.name &#8221;<br />
+ &#8220;from Night night, Area area where night.area_id = area.id&#8221;, resultSetMapping=&#8221;joinMapping&#8221;)</p>
<p>@SqlResultSetMapping( name=&#8221;joinMapping&#8221;, entities={<br />
@EntityResult(entityClass=org.hibernate.test.annotations.query.Night.class, fields = {<br />
@FieldResult(name=&#8221;id&#8221;, column=&#8221;nid&#8221;),<br />
@FieldResult(name=&#8221;duration&#8221;, column=&#8221;night_duration&#8221;),<br />
@FieldResult(name=&#8221;date&#8221;, column=&#8221;night_date&#8221;),<br />
@FieldResult(name=&#8221;area&#8221;, column=&#8221;area_id&#8221;),<br />
discriminatorColumn=&#8221;disc&#8221;<br />
}),<br />
@EntityResult(entityClass=org.hibernate.test.annotations.query.Area.class, fields = {<br />
@FieldResult(name=&#8221;id&#8221;, column=&#8221;aid&#8221;),<br />
@FieldResult(name=&#8221;name&#8221;, column=&#8221;name&#8221;)<br />
})<br />
}<br />
)</p>
<p>上面的例子，名为“night&amp;area”的查询和 &#8220;joinMapping&#8221;结果集映射对应，该映射返回两个实体，分别为 Night 和 Area, 其中每个属性都和一个列关联，列名通过查询获取。</p>
<p>@Entity<br />
@SqlResultSetMapping(name=&#8221;implicit&#8221;,<br />
<a href="mailto:entities=@EntityResult">entities=@EntityResult</a>(<br />
<a href="mailto:entityClass=org.hibernate.test.annotations.@NamedNativeQuery">entityClass=org.hibernate.test.annotations.@NamedNativeQuery</a>(<br />
name=&#8221;implicitSample&#8221;, query=&#8221;select * from SpaceShip&#8221;,<br />
resultSetMapping=&#8221;implicit&#8221;)<br />
public class SpaceShip {<br />
private String name;<br />
private String model;<br />
private double speed;<br />
@Id<br />
public String getName() {<br />
return name;<br />
}<br />
public void setName(String name) {<br />
this.name = name;<br />
}<br />
@Column(name=&#8221;model_txt&#8221;)<br />
public String getModel() {<br />
return model;<br />
}<br />
public void setModel(String model) {<br />
this.model = model;<br />
}<br />
public double getSpeed() {<br />
return speed;<br />
}<br />
public void setSpeed(double speed) {<br />
this.speed = speed;<br />
}<br />
}</p>
<p>上例中 model1 属性绑定到 model_txt 列，如果和相关实体关联设计到组合主键，那么应该使用 @FieldResult 注解来定义每个外键列。@FieldResult的名字组成：定义这种关系的属性名字 + &#8220;.&#8221; + 主键名或主键列或主键属性。</p>
<p>@Entity<br />
@SqlResultSetMapping(name=&#8221;compositekey&#8221;,<br />
<a href="mailto:entities=@EntityResult%28entityClass=org.hibernate.test.annotations.query.SpaceShip.class">entities=@EntityResult(entityClass=org.hibernate.test.annotations.query.SpaceShip.class</a>,<br />
fields = {<br />
@FieldResult(name=&#8221;name&#8221;, column = &#8220;name&#8221;),<br />
@FieldResult(name=&#8221;model&#8221;, column = &#8220;model&#8221;),<br />
@FieldResult(name=&#8221;speed&#8221;, column = &#8220;speed&#8221;),<br />
@FieldResult(name=&#8221;captain.firstname&#8221;, column = &#8220;firstn&#8221;),<br />
@FieldResult(name=&#8221;captain.lastname&#8221;, column = &#8220;lastn&#8221;),<br />
@FieldResult(name=&#8221;dimensions.length&#8221;, column = &#8220;length&#8221;),<br />
@FieldResult(name=&#8221;dimensions.width&#8221;, column = &#8220;width&#8221;)<br />
}),<br />
columns = { @ColumnResult(name = &#8220;surface&#8221;),<br />
@ColumnResult(name = &#8220;volume&#8221;) } )<br />
@NamedNativeQuery(name=&#8221;compositekey&#8221;,<br />
query=&#8221;select name, model, speed, lname as lastn, fname as firstn, length, width, length * width as resultSetMapping=&#8221;compositekey&#8221;)<br />
})</p>
<p>如果查询返回的是单个实体，或者打算用系统默认的映射，这种情况下可以不使用 resultSetMapping，而使用resultClass属性，例如：</p>
<p>@NamedNativeQuery(name=&#8221;implicitSample&#8221;, query=&#8221;select * from SpaceShip&#8221;,<br />
resultClass=SpaceShip.class)<br />
public class SpaceShip {</p>
<p>Hibernate 独有的注解扩展</p>
<p>Hibernate 提供了与其自身特性想吻合的注解，org.hibernate.annotations package包含了这些注解。</p>
<p>实体</p>
<p>org.hibernate.annotations.Entity 定义了  Hibernate 实体需要的信息。</p>
<p>• mutable: whether this entity is mutable or not  此实体是否可变</p>
<p>• dynamicInsert: allow dynamic SQL for inserts   用动态SQL新增</p>
<p>• dynamicUpdate: allow dynamic SQL for updates   用动态SQL更新</p>
<p>• selectBeforeUpdate: Specifies that Hibernate should never perform an SQL UPDATE unless it is certain that an object is actually modified.指明Hibernate从不运行SQL Update，除非能确定对象已经被修改</p>
<p>• polymorphism: whether the entity polymorphism is of PolymorphismType.IMPLICIT (default) or PolymorphismType.EXPLICIT 指出实体多态是 PolymorphismType.IMPLICIT(默认)还是PolymorphismType.EXPLICIT</p>
<p>• optimisticLock: optimistic locking strategy (OptimisticLockType.VERSION, OptimisticLockType.NONE, OptimisticLockType.DIRTY or OptimisticLockType.ALL) 乐观锁策略</p>
<p>标识符</p>
<p>@org.hibernate.annotations.GenericGenerator和@org.hibernate.annotations.GenericGenerators允许你定义hibernate特有的标识符。</p>
<p>@Id @GeneratedValue(generator=&#8221;system-uuid&#8221;)<br />
@GenericGenerator(name=&#8221;system-uuid&#8221;, strategy = &#8220;uuid&#8221;)<br />
public String getId() {<br />
@Id @GeneratedValue(generator=&#8221;hibseq&#8221;)<br />
@GenericGenerator(name=&#8221;hibseq&#8221;, strategy = &#8220;seqhilo&#8221;,<br />
parameters = {<br />
@Parameter(name=&#8221;max_lo&#8221;, value = &#8220;5&#8243;),<br />
@Parameter(name=&#8221;sequence&#8221;, value=&#8221;heybabyhey&#8221;)<br />
}<br />
)<br />
public Integer getId() {</p>
<p>新例子</p>
<p>@GenericGenerators(<br />
{<br />
@GenericGenerator(<br />
name=&#8221;hibseq&#8221;,<br />
strategy = &#8220;seqhilo&#8221;,<br />
parameters = {<br />
@Parameter(name=&#8221;max_lo&#8221;, value = &#8220;5&#8243;),<br />
@Parameter(name=&#8221;sequence&#8221;, value=&#8221;heybabyhey&#8221;)<br />
}<br />
),<br />
@GenericGenerator(&#8230;)<br />
}<br />
)</p>
<p>自然ID</p>
<p>用 @NaturalId 注解标识</p>
<p>公式</p>
<p>让数据库而不是JVM进行计算。</p>
<p>@Formula(&#8220;obj_length * obj_height * obj_width&#8221;)<br />
public long getObjectVolume()</p>
<p>索引</p>
<p>通过在列属性(property)上使用@Index注解，可以指定特定列的索引，columnNames属性(attribute)将随之被忽略。</p>
<p>@Column(secondaryTable=&#8221;Cat1&#8243;)<br />
@Index(name=&#8221;story1index&#8221;)<br />
public String getStoryPart1() {<br />
return storyPart1;<br />
}</p>
<p>辨别符</p>
<p>@Entity<br />
@DiscriminatorFormula(&#8220;case when forest_type is null then 0 else forest_type end&#8221;)<br />
public class Forest { &#8230; }</p>
]]></content:encoded>
			<wfw:commentRss>http://javadou.com/spring-jpa-hibernate-175/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Hibernate getCurrentSession与openSession区别</title>
		<link>http://javadou.com/hibernate-currentsession-opensession-174/</link>
		<comments>http://javadou.com/hibernate-currentsession-opensession-174/#comments</comments>
		<pubDate>Wed, 02 Sep 2009 04:16:00 +0000</pubDate>
		<dc:creator>阿超</dc:creator>
				<category><![CDATA[Hibernate]]></category>
		<category><![CDATA[Spring]]></category>
		<category><![CDATA[hibernate]]></category>
		<category><![CDATA[session]]></category>
		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://javadou.com/hibernate-currentsession-opensession-174/</guid>
		<description><![CDATA[getCurrentSession () 使用当前的session
openSession()          重新建立一个新的session 
在一个应用程序中，如果DAO 层使用Spring 的hibernate 模板，通过Spring 来控制session 的生命周期，则首选getCurrentSession ()。
    1. 如果使用的是... ]]></description>
			<content:encoded><![CDATA[<p>getCurrentSession () 使用当前的session<br />
openSession()          重新建立一个新的session<br />
在一个应用程序中，如果DAO 层使用Spring 的hibernate 模板，通过Spring 来控制session 的生命周期，则首选getCurrentSession ()。<br />
1. 如果使用的是getCurrentSession来创建session的话，在commit后，session就自动被关闭了，<br />
也就是不用再session.close()了。但是如果使用的是openSession方法创建的session的话，<br />
那么必须显示的关闭session，也就是调用session.close()方法。这样commit后，session并没有关闭<br />
2. getCurrentSession的使用可以参见hibernate\hibernate-3.2\doc\tutorial\src项目<br />
3.  使用SessionFactory.getCurrentSession()需要在hibernate.cfg.xml中如下配置：<br />
* 如果采用jdbc独立引用程序配置如下：<br />
&lt;property name=&#8221;hibernate.current_session_context_class&#8221;&gt;thread&lt;/property&gt;<br />
* 如果采用了JTA事务配置如下<br />
&lt;property name=&#8221;hibernate.current_session_context_class&#8221;&gt;jta&lt;/property&gt;</p>
<p>Hibernate代码:<br />
Session session = HibernateUnit.getSessionFactory().getCurrentSession();<br />
session.beginTransaction();<br />
&#8230;.<br />
session.getTransaction().commit();<br />
getcurrentSession()方法总是会返回“当前的”工作单元。<br />
Session 在第一次被使用的时候，即第一次调用getCurrentSession()的时候，其生命周期就开始。然后她被Hibernate绑定到当前线程。当事物结束的时候，不管是提交还是回滚，Hibernate会自动把Session从当前线程剥离，并且关闭。若在次调用 getCurrentSession()，会得到一个新的Session,并且开始一个新的工作单元。这是Hibernate最广泛的thread- bound model，支持代码灵活分层(事物划分和数据访问代码的分离)。</p>
<p>从实现的功能上看Spring与Hibernate的整合</p>
<p>2008年02月27日 星期三 03:26</p>
<p>1.管理SessionFactory</p>
<p>使用Spring整合Hibernate时我们不需要hibernate.cfg.xml文件。首先，在applicationContext.xml中配置数据源（dataSource）bean和session工厂（sessionFactory）bean。其中，在配置session工厂bean 时，应该注入三个方面的信息：</p>
<p>●数据源bean</p>
<p>●所有持久化类的配置文件</p>
<p>●Hibernate的SessionFactory的属性</p>
<p>Hibernate的SessionFactory的属性信息又包括两个内容，一，Hibernate的连接方法；二，不同数据库连接，启动时的选择。</p>
<p>2.为HibernateTemplate注入SessionFactory对象，通过HibernateTemplate来持久化对象</p>
<p>Spring提供了HibernateTemplate，用于持久层访问，该模板无需打开Session及关闭Session。它只要获得 SessionFactory的引用，将可以只能地打开Session，并在持久化访问结束后关闭Session，程序开发只需完成持久层逻辑，通用的操作（如对数据库中数据的增，删，改，查）则有HibernateTemplate完成。</p>
<p>HibernateTemplate有三个构造函数，不论是用哪一种构造，要使HibernateTemplate能完成持久化操作，都必须向其传入一个SessionFactory的引用。</p>
<p>HibernateTemplate的用法有两种，一种是常规的用法，另一种是复杂的用。</p>
<p>一，常规的用法</p>
<p>HibernateTemplate通过它自己的delete(Object entity) ，find(String queryString)，save(Object entity)等等常用的方法即可完成大多数DAO对象的增，删，改，查等操作。</p>
<p>二，复杂的用法</p>
<p>HibernateTemplate的复杂的用法是通过如下的两个方法来完成的：</p>
<p>●Object execute(HibernateCallback action)</p>
<p>●List execute(HibernateCallback action)</p>
<p>这两个方法都需要一个HibernateCallback实例，程序开发者通过HibernateCallback，可以完全使用Hibernate灵活的方式来访问数据库，解决了Spring封装Hibernate后灵活不足的缺陷。HibernateCallback是一个接口，该接口只有一个方法 doInHibernate(org.hibernate.Session session)，该方法只有一个参数Session。</p>
<p>通常，程序中采用实现HibernateCallback的匿名内部类来获取HibernateCallback的实例，方法doInHibernate就是Spring执行的持久化操作。具体的代码实例如下：</p>
<p>public class PersonDaoImpl {</p>
<p>private SessionFactory sessionFactory;</p>
<p>public void setSessionFactory(SessionFactory sessionFactory) {</p>
<p>this.sessionFactory = sessionFactory;</p>
<p>}</p>
<p>public List findPersonByName(final String name) {</p>
<p>HibernateTemplate hibernateTemplate =</p>
<p>new HibernateTemplate(this.sessionFactory);</p>
<p>return (List)hibernateTemplate.execute(</p>
<p>public Object doInHibernate(Session session) throws Hibernate Exception {</p>
<p>List result =session.createCriteria(Person.clsss)</p>
<p>.add(Restrictions.like(&#8220;name&#8221;,name+&#8221;%&#8221;)).list();</p>
<p>return result;</p>
<p>}</p>
<p>);</p>
<p>}</p>
<p>}</p>
<p>注：在方法doInHibernate内可以访问Session，该Session对象是绑定到该线程的Session实例，该方法内的持久层操作与不使用Spring时的持久层操作完全相同，这保证了对于复杂的持久层访问时，依然可以使用Hibernate的访问方式。</p>
<p>3.DAO的实现</p>
<p>DAO的实现有两种方式：一，继承HibernateDaoSupport实现DAO；二，基于Hibernate3.0实现DAO。</p>
<p>一，继承HibernateDaoSupport实现DAO</p>
<p>Spring为Hibernate的DAO提供了工具类HibernateDaoSupport。该类主要提供了如下两个方法来方便DAO的实现：</p>
<p>●public final HibernateTemplate getHibernateTemplate()</p>
<p>●public final void setSessionFactory(SessionFactory sessionFactory)</p>
<p>其中，setSessionFactory方法用来接收Spring的ApplicationContext依赖注入的SessionFactory实例；getHibernateTemplate方法则用来根据刚才的SessionFactory产生Session，最后由 HibernateTemplate来完成数据库访问。</p>
<p>二，基于Hibernate3.0实现DAO</p>
<p>在Hibernate处于事务的管理下时（通常Spring为Hibernate提供事务管理），通过SessionFactory的 getCurrentSession()方法可以返回当前的Session，如果当前的JTA事务关联的Session不存在，则系统打开一次新的 Session，并关联到当前的JTA事务；如果当前JTA事务关联的Session已经存在，则直接返回该Session。获得了当前的Session 后就可以进行持久化操作了。</p>
<p>可见，不论使用上面的哪一种方式实现DAO都需要用Spring来注入SessionFactory实例。</p>
<p>4.事务的管理</p>
<p>Hibernate建议所有的对数据库的访问都应放在事务内进行，即使进行的只是读操作。Spring同时支持编程式事务和声明式事务。通常推荐使用声明式事务。</p>
<p>编程式事务管理：</p>
<p>编程式事务提供了TransactionTemplate模板类，用的时候必须向其体提供一个PlatformTransactionManager实例。只要TransactionTemplate获取了PlatformTransactionManager的引用，TransactionTemplate就可以完成事务操作了。TransactionTemplate提供了一个execute方法，它接收一个 TransactionCallback实例。TransactionCallback包含如下方法：</p>
<p>●Object doInTransaction(TransactionStatus status)</p>
<p>这是需要有返回值的情况。如果不需要有返回值的话，我们可以用TransactionCallbackWithOutResult类来代替TransactionCallback类，它也有一个方法：</p>
<p>●void doInTransaction(TransactionStatus status)</p>
<p>在这个两个方法中，在出现异常时，TransactionStatus的实例status可以调用setRollbackOnly()方法进行回滚。</p>
<p>一般情况下，向execute方法传入TransactionCallback或TransactionCallbackWithOutResult实例时，采用的是匿名内部类的形式。</p>
<p>声明式事务管理：</p>
<p>声明式事务管理的配置方式通常有三种：</p>
<p>●使用TransactionProxyFactoryBean为目标bean生成事务代理的配置。</p>
<p>●使用BeanNameAutoProxyCreator，根据bean name自动生成事务代理的方式，这是直接利用Spring的AOP框架配置事务代理的方式，需要对Spring的AOP框架有所了解。</p>
<p>●使用DefaultAdvisorAutoProxyCreator，这也是直接利用Spring的AOP框架配置事务代理的方式，只是这种配置方式的可读性不如使用BeanNameAutoProxyCreator的配置方式。<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</p>
<p>&lt;?xml version=&#8221;1.0&#8243; encoding=&#8221;UTF-8&#8243;?&gt;</p>
<p>&lt;beans xmlns=&#8221;<a href="http://www.springframework.org/schema/beans">http://www.springframework.org/schema/beans</a>&#8221;<br />
xmlns:xsi=&#8221;<a href="http://www.w3.org/2001/xmlschema-instance">http://www.w3.org/2001/XMLSchema-instance</a>&#8221;<br />
xsi:schemaLocation=&#8221;<a href="http://www.springframework.org/schema/beans">http://www.springframework.org/schema/beans</a> <a href="http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">http://www.springframework.org/schema/beans/spring-beans-2.0.xsd</a><br />
<a href="http://www.springframework.org/schema/aop">http://www.springframework.org/schema/aop</a> <a href="http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">http://www.springframework.org/schema/aop/spring-aop-2.0.xsd</a><br />
<a href="http://www.springframework.org/schema/tx">http://www.springframework.org/schema/tx</a> <a href="http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">http://www.springframework.org/schema/tx/spring-tx-2.0.xsd</a>&#8220;&gt;<br />
&lt;!&#8211; 数据源 &#8211;&gt;<br />
&lt;bean id=&#8221;dataSource&#8221; class=&#8221;org.apache.commons.dbcp.BasicDataSource&#8221; destroy-method=&#8221;close&#8221;&gt;<br />
&lt;property name=&#8221;driverClassName&#8221;&gt;<br />
&lt;value&gt;COM.ibm.db2.jdbc.net.DB2Driver&lt;/value&gt;<br />
&lt;/property&gt;<br />
&lt;property name=&#8221;url&#8221;&gt;<br />
&lt;value&gt;jdbc:db2://localhost:6789/GUOZIWEI&lt;/value&gt;<br />
&lt;/property&gt;<br />
&lt;property name=&#8221;username&#8221;&gt;<br />
&lt;value&gt;db2admin&lt;/value&gt;<br />
&lt;/property&gt;<br />
&lt;property name=&#8221;password&#8221;&gt;<br />
&lt;value&gt;db2admin&lt;/value&gt;<br />
&lt;/property&gt;<br />
&lt;/bean&gt;<br />
&lt;!&#8211;数据库会话工厂 &#8211;&gt;<br />
&lt;bean id=&#8221;sessionFactory&#8221; class=&#8221;org.springframework.orm.hibernate3.LocalSessionFactoryBean&#8221;&gt;<br />
&lt;property name=&#8221;dataSource&#8221;&gt;<br />
&lt;ref local=&#8221;dataSource&#8221; /&gt;<br />
&lt;/property&gt;<br />
&lt;property name=&#8221;mappingResources&#8221;&gt;<br />
&lt;list&gt;<br />
&lt;value&gt;com/becom/ins/dto/User.hbm.xml&lt;/value&gt;<br />
&lt;value&gt;com/becom/ins/dto/InsFunds.hbm.xml&lt;/value&gt;<br />
&lt;value&gt;com/becom/ins/dto/Company.hbm.xml&lt;/value&gt;<br />
&lt;value&gt;com/becom/ins/dto/Group.hbm.xml&lt;/value&gt;<br />
&lt;value&gt;com/becom/ins/dto/OtherFunds.hbm.xml&lt;/value&gt;<br />
&lt;/list&gt;<br />
&lt;/property&gt;<br />
&lt;property name=&#8221;hibernateProperties&#8221;&gt;<br />
&lt;props&gt;<br />
&lt;prop key=&#8221;hibernate.dialect&#8221;&gt;org.hibernate.dialect.Oracle9Dialect&lt;/prop&gt;<br />
&lt;prop key=&#8221;hibernate.show_sql&#8221;&gt;true&lt;/prop&gt;<br />
&lt;prop key=&#8221;hibernate.cglib.use_reflection_optimizer&#8221;&gt;true&lt;/prop&gt;<br />
&lt;/props&gt;<br />
&lt;/property&gt;<br />
&lt;/bean&gt;</p>
<p>&lt;!&#8211; 事务管理器 &#8211;&gt;<br />
&lt;bean id=&#8221;transactionManager&#8221; class=&#8221;org.springframework.orm.hibernate3.HibernateTransactionManager&#8221;&gt;<br />
&lt;property name=&#8221;sessionFactory&#8221;&gt;&lt;ref local=&#8221;sessionFactory&#8221;/&gt;&lt;/property&gt;<br />
&lt;/bean&gt;<br />
&lt;!&#8211; Spring 事务管理器代理 &#8211;&gt;<br />
&lt;bean id=&#8221;transactionProxyFactory&#8221; abstract=&#8221;true&#8221; lazy-init=&#8221;true&#8221; class=&#8221;org.springframework.transaction.interceptor.TransactionProxyFactoryBean&#8221;&gt;<br />
&lt;property name=&#8221;transactionManager&#8221;&gt;<br />
&lt;ref local=&#8221;transactionManager&#8221;/&gt;<br />
&lt;/property&gt;<br />
&lt;property name=&#8221;transactionAttributes&#8221;&gt;<br />
&lt;props&gt;<br />
&lt;prop key=&#8221;save*&#8221;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />
&lt;prop key=&#8221;insert*&#8221;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />
&lt;prop key=&#8221;del*&#8221;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />
&lt;prop key=&#8221;add*&#8221;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />
&lt;prop key=&#8221;update*&#8221;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />
&lt;prop key=&#8221;find*&#8221;&gt;PROPAGATION_REQUIRED,readOnly&lt;/prop&gt;<br />
&lt;prop key=&#8221;search*&#8221;&gt;PROPAGATION_REQUIRED,readOnly&lt;/prop&gt;<br />
&lt;prop key=&#8221;remove*&#8221;&gt;PROPAGATION_REQUIRED,readOnly&lt;/prop&gt;<br />
&lt;prop key=&#8221;query*&#8221;&gt;PROPAGATION_REQUIRED,readOnly&lt;/prop&gt;<br />
&lt;prop key=&#8221;list*&#8221;&gt;PROPAGATION_REQUIRED,readOnly&lt;/prop&gt;<br />
&lt;prop key=&#8221;count*&#8221;&gt;PROPAGATION_REQUIRED,readOnly&lt;/prop&gt;<br />
&lt;prop key=&#8221;get*&#8221;&gt;PROPAGATION_REQUIRED,readOnly&lt;/prop&gt;<br />
&lt;/props&gt;<br />
&lt;/property&gt;<br />
&lt;/bean&gt;</p>
<p>&lt;!&#8211; Hibernate模板 &#8211;&gt;<br />
&lt;bean id=&#8221;hibernateTemplate&#8221; class=&#8221;org.springframework.orm.hibernate3.HibernateTemplate&#8221;&gt;<br />
&lt;property name=&#8221;sessionFactory&#8221;&gt;<br />
&lt;ref local=&#8221;sessionFactory&#8221; /&gt;<br />
&lt;/property&gt;<br />
&lt;/bean&gt;<br />
&lt;!&#8211; 用户服务对象 &#8211;&gt;<br />
&lt;bean id=&#8221;userService&#8221; parent=&#8221;transactionProxyFactory&#8221;&gt;<br />
&lt;property name=&#8221;target&#8221;&gt;<br />
&lt;bean class=&#8221;com.becom.ins.user.service.UserService&#8221;&gt;<br />
&lt;property name=&#8221;userDAO&#8221;&gt;<br />
&lt;ref local=&#8221;userDAO&#8221;/&gt;<br />
&lt;/property&gt;<br />
&lt;/bean&gt;<br />
&lt;/property&gt;<br />
&lt;/bean&gt;<br />
&lt;!&#8211; 用户数据访问对象 &#8211;&gt;<br />
&lt;bean id=&#8221;userDAO&#8221; class=&#8221;com.becom.ins.user.dao.UserDAO&#8221;&gt;<br />
&lt;property name=&#8221;hibernateTemplate&#8221; ref=&#8221;hibernateTemplate&#8221;/&gt;<br />
&lt;/bean&gt;<br />
&lt;!&#8211; 破产服务对象 &#8211;&gt;<br />
&lt;bean id=&#8221;insService&#8221; parent=&#8221;transactionProxyFactory&#8221;&gt;<br />
&lt;property name=&#8221;target&#8221;&gt;<br />
&lt;bean class=&#8221;com.becom.ins.insolvency.service.InsFundsService&#8221;&gt;<br />
&lt;property name=&#8221;insDAO&#8221;&gt;<br />
&lt;ref local=&#8221;insDAO&#8221;/&gt;<br />
&lt;/property&gt;<br />
&lt;/bean&gt;<br />
&lt;/property&gt;<br />
&lt;/bean&gt;<br />
&lt;!&#8211; 用户数据访问对象 &#8211;&gt;<br />
&lt;bean id=&#8221;insDAO&#8221; class=&#8221;com.becom.ins.insolvency.dao.InsFundsDAO&#8221;&gt;<br />
&lt;property name=&#8221;hibernateTemplate&#8221; ref=&#8221;hibernateTemplate&#8221;/&gt;<br />
&lt;/bean&gt;<br />
&lt;!&#8211; 集团服务对象 &#8211;&gt;<br />
&lt;bean id=&#8221;groupService&#8221; parent=&#8221;transactionProxyFactory&#8221;&gt;<br />
&lt;property name=&#8221;target&#8221;&gt;<br />
&lt;bean class=&#8221;com.becom.ins.group.service.GroupServiceImpl&#8221;&gt;<br />
&lt;property name=&#8221;groupDAO&#8221;&gt;<br />
&lt;ref local=&#8221;groupDAO&#8221;/&gt;<br />
&lt;/property&gt;<br />
&lt;/bean&gt;<br />
&lt;/property&gt;<br />
&lt;/bean&gt;<br />
&lt;!&#8211; 用户数据访问对象 &#8211;&gt;<br />
&lt;bean id=&#8221;groupDAO&#8221; class=&#8221;com.becom.ins.group.dao.GroupDAOImpl&#8221;&gt;<br />
&lt;property name=&#8221;hibernateTemplate&#8221; ref=&#8221;hibernateTemplate&#8221;/&gt;<br />
&lt;/bean&gt;</p>
<p>&lt;!&#8211; 公司服务对象 &#8211;&gt;<br />
&lt;bean id=&#8221;companyService&#8221; parent=&#8221;transactionProxyFactory&#8221;&gt;<br />
&lt;property name=&#8221;target&#8221;&gt;<br />
&lt;bean class=&#8221;com.becom.ins.company.service.CompanyServiceImpl&#8221;&gt;<br />
&lt;property name=&#8221;companyDAO&#8221;&gt;<br />
&lt;ref local=&#8221;companyDAO&#8221;/&gt;<br />
&lt;/property&gt;<br />
&lt;/bean&gt;<br />
&lt;/property&gt;<br />
&lt;/bean&gt;<br />
&lt;!&#8211; 公司数据访问对象 &#8211;&gt;<br />
&lt;bean id=&#8221;companyDAO&#8221; class=&#8221;com.becom.ins.company.dao.CompanyDAOImpl&#8221;&gt;<br />
&lt;property name=&#8221;hibernateTemplate&#8221; ref=&#8221;hibernateTemplate&#8221;/&gt;<br />
&lt;/bean&gt;<br />
&lt;/beans&gt;</p>
]]></content:encoded>
			<wfw:commentRss>http://javadou.com/hibernate-currentsession-opensession-174/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>JPA&#8212;Hibernate Annotation入门教程</title>
		<link>http://javadou.com/jpa-hibernate-annotation-base-167/</link>
		<comments>http://javadou.com/jpa-hibernate-annotation-base-167/#comments</comments>
		<pubDate>Tue, 01 Sep 2009 18:38:00 +0000</pubDate>
		<dc:creator>阿超</dc:creator>
				<category><![CDATA[Hibernate]]></category>
		<category><![CDATA[annotation]]></category>
		<category><![CDATA[hibernate]]></category>

		<guid isPermaLink="false">http://javadou.com/jpa-hibernate-annotation-base-167/</guid>
		<description><![CDATA[目前，JPA（Java Persistence API）的使用范围越来越广，作为Java EE 5.0平台标准的ORM规范，得到了诸如：Hibernate、TopLink、OpenJpa等ORM框架的支持，同时还是EJB 3.0的重要组成部分。JPA的宗旨是为POJO提供持久化标准规范。它能... ]]></description>
			<content:encoded><![CDATA[<p>&#160;&#160;&#160;&#160; 目前，JPA（Java Persistence API）的使用范围越来越广，作为Java EE 5.0平台标准的ORM规范，得到了诸如：Hibernate、TopLink、OpenJpa等ORM框架的支持，同时还是EJB 3.0的重要组成部分。JPA的宗旨是为POJO提供持久化标准规范。它能够脱离容器独立运行，方便开发和测试。本文将通过一个小实例来说明如何在Hibernate中使用JPA，来达到简化编程的目的。    <br />开发环境&#160; Eclipse 3.3.1&#160; MyEclipse 6.0.1GA&#160; Tomcat 6.10 SQL Server 2000&#160; <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; hibernate-3.2.5.GA&#160; hibernate-annotations-3.3.0.GA     <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; ejb3-persistence&#160; hibernate-commons-annotations-3.0.0.GA     <br />&#160;&#160;&#160; 本文是为后续的多种Ajax技术框架应用系列作一个前期准备，让大家先了解一下相比与以前的Hibernate ORM映射的不同之处，以及采用JPA所带来的好处。     <br />&#160;&#160;&#160; 为了保证程序能顺序运行，避免不同的Eclipse版本之间产生错误，大象强烈建议，下载源码后，按源码中的工程名，自己单独新建同一个工程，再将src和WEB-INF/lib目录下的所有文件COPY至对应的目录下。     <br /><strong>1、创建</strong><strong>Web Project      <br /></strong>&#160;&#160;&#160;&#160;&#160;&#160; 点击&quot;File&quot;-&gt;&quot;New&quot;，选择&quot;Web Project&quot;，在&quot;Project Name&quot;中输入ajax，点击&quot;Finish&quot;。下载本文后面需要用到的JAR包，加入到WEB-INF/lib目录下，在ajax工程中，文本采用的是UTF-8编码。     <br /><strong>2、创建</strong><strong>HibernateSessionFactory      <br /></strong>&#160;&#160;&#160;&#160;&#160;&#160; 传统的方法就是在工程名上点右键，选择”MyEclipse”-&gt;”Add Hibernate Capabilities”，然后就是按照提示一步一步做，不过在MyEclipse 6.0.1中添加Hibernate还是只能支持3.1，除非你选择” Add Spring Capabilities”，里面才有Hibernate 3.2的类库，要想完全兼容JPA，必须采用3.2以上版本。     <br />&#160;&#160;&#160;&#160;&#160;&#160; 这里大家直接使用源码中的HibernateSessionFactory，注意请先建包：com.ajax.core,HibernateSessionFactory中有一个地方需要改动，原来的写法是：</p>
<pre class="java">private static Configuration configuration = new Configuration();</pre>
<p>修改后为：</p>
<pre class="java">private static AnnotationConfiguration configuration = new AnnotationConfiguration();</pre>
<p>因为我们采用的是JPA注释方式来映射实体，另外AnnotationConfiguration这个类在hibernate-annotations.jar这个包中。<br />
  <br /><strong>3、创建</strong><strong>BaseDao<br />
    <br /></strong>&#160;&#160;&#160;&#160;&#160;&#160; 在com.ajax.core包下面新建BaseDao抽象类，里面定义的是持久化操作方法，有一点特别要注意，一定要在增加、删除、修改这几个方法中加入事务控制，不管是在BaseDao基类方法中加，还是在业务方法中加，一定要加事务控制，大象觉得在基类中加会比较好一点，这样做代码显得更少更简洁。如果不加事务控制，那么增、删、改这些操作都不会产生效果，因为默认情况下，它不会进行自动提交。在做这个例子的时候，这个问题曾经困扰了我好长时间。因此，请大家记住不要再犯和大象一样的错误！贴出部分代码，详情请看源码，里面有很全面的注释。</p>
<pre class="java">/**
 * 抽象Dao类，用于持久化操作
 * @author <a href="http://javadou.com">Java豆</a>
 * @version 1.0
 */
public abstract class BaseDao<t> {

    private static Log log = LogFactory.getLog(BaseDao.class);

    /**
     * 获取Hibernate的Session对象
     */
    public Session getSession(){
        return HibernateSessionFactory.getSession();
    }

    /**
     * 根据主键得到对象
     */
    public T getObject(Class clazz, Serializable id){
        return (T)getSession().get(clazz, id);
    }

    /**
     * 保存对象
     */
    public void saveObject(T t) {
        Session session = getSession();
        Transaction tx = beginTransaction(session);
        try{
            session.saveOrUpdate(t);
            tx.commit();
        }catch(Exception e){
            tx.rollback();
            log.error(&quot;保存对象失败&quot;);
        }
    }

    /**
     * 创建事务
     */
    private Transaction beginTransaction(Session session){
        return session.beginTransaction();
    }
}</pre>
<p><strong>4、创建</strong><strong>Employee<br />
    <br /></strong>&#160;&#160;&#160;&#160;&#160;&#160; 在com.ajax.employee.mode包下新建Employee类，这个就是POJO类，下面来详细说明里面的含义。</p>
<pre class="java">@Entity
@Table(name = &quot;EMPLOYEE&quot;)
public class Employee implements java.io.Serializable{

    private Integer employee_id; //人员ID（主键）
    private String employee_name; //人员姓名
    private String sex; //性别
    private String birthday; //出生日期
    private String address; //地址

    @Id
    @Column(name = &quot;EMPLOYEE_ID&quot;)
    @TableGenerator(
         name=&quot;tab-store&quot;,
         table=&quot;GENERATOR_TABLE&quot;,
         pkColumnName = &quot;G_KEY&quot;,
         pkColumnValue=&quot;EMPLOYEE_PK&quot;,
         valueColumnName = &quot;G_VALUE&quot;,
         allocationSize=1
    )
    @GeneratedValue(strategy = GenerationType.TABLE,generator=&quot;tab-store&quot;)
    public Integer getEmployee_id() {
        return employee_id;
    }
    public void setEmployee_id(Integer employee_id) {
        this.employee_id = employee_id;
    }
}</pre>
<p>其它几个属性的getter和setter省略，这里我们要用到ejb3-persistence.jar，JPA的注解类就在这个包中，下面详细说明上面使用到的注解。<br />
  <br />@Entity：通过@Entity注解将一个类声明为一个实体bean </p>
<p>@Table：通过 @Table注解可以为实体bean映射指定表，name属性表示实体所对应表的名称，如果没有定义 @Table，那么系统自动使用默认值：实体的类名（不带包名） </p>
<p>@Id：用于标记属性的主键 </p>
<p>@Column：表示持久化属性所映射表中的字段，如果属性名与表中的字段名相同，则可以省略@Column注解，另外有两种方式标记，一是放在属性前，另一种是放在getter方法前，例如：</p>
<pre class="java">
@Column(name = &quot;EMPLOYEE_NAME&quot;)
    private String employee_name;</pre>
<p>或者 </p>
<pre class="java">
@Column(name = &quot;EMPLOYEE_NAME&quot;)
  public String getEmployee_name() {
      return employee_name;
  }</pre>
<p>这两种方式都是正解的，根据个人喜好来选择。大象偏向于第二种，并且喜欢将属性名与字段名设成一样的，这样可以省掉@Column注解，使代码更简洁。<br />
  <br />@TableGenerator：表生成器，将当前主键的值单独保存到一个数据库表中，主键的值每次都是从指定的表中查询来获得，这种生成主键的方式是很常用的。这种方法生成主键的策略可以适用于任何数据库，不必担心不同数据库不兼容造成的问题。大象推荐这种方式管理主键，很方便，集中式管理表的主键，而且更换数据库不会造成很大的问题。各属性含义如下： </p>
<p>name：表示该表主键生成策略的名称，这个名字可以自定义，它被引用在@GeneratedValue中设置的&quot;generator&quot;值中 </p>
<p>table：表示表生成策略所持久化的表名，说简单点就是一个管理其它表主键的表，本例中，这个表名为GENERATOR_TABLE </p>
<p>pkColumnName：表生成器中的列名，用来存放其它表的主键键名，这个列名是与表中的字段对应的 </p>
<p>pkColumnValue：实体表所对应到生成器表中的主键名，这个键名是可以自定义滴 </p>
<p>valueColumnName：表生成器中的列名，实体表主键的下一个值，假设EMPLOYEE表中的EMPLOYEE_ID最大为2，那么此时，生成器表中与实体表主键对应的键名值则为3 </p>
<p>allocationSize：表示每次主键值增加的大小，例如设置成1，则表示每次创建新记录后自动加1，默认为50</p>
<p><img height="111" alt="" src="http://www.blogjava.net/images/blogjava_net/bolo/ajax/ajax2.JPG" width="390" /> </p>
<p>@GeneratedValue：定义主键生成策略，这里因为使用的是TableGenerator，所以，主键的生成策略为GenerationType.TABLE，生成主键策略的名称则为前面定义的”tab-store”。 </p>
<p>这里大象想说下，网上有很多文章写的是strategy = GenerationType.AUTO或是strategy = GenerationType.SEQUENCE，采用SEQUENCE序列是因为Oracle数据中不支持identity自动增长，要想使用它，还得在数据库中创建一个序列，如果要更换数据库，那将是一个非常麻烦的事情。SEQUENCE生成方式我们暂且不谈，这里说下采用AUTO和IDENTITY的生成方式，本例采用的是SQL Server 2000作为数据库，所以如果想使用AUTO或是IDENTITY生成策略，则一定要对主键加上identity标识，如identity(1,1)。不过对于AUTO来说，是根据不同的数据库选择最合适的自增主键生成策略。如果使用MySQL，则主键要定义AUTO_INCREMENT，如果是Oracle，则要创建Sequence来实现自增。不管采用何种生成策略，增、删、改这些方法中一定要加入事务，否则数据是不会添加到数据库中滴~~~这是大象反复测试过的结果！ </p>
<p><strong>5、创建数据库及表<br />
    <br /></strong>&#160;&#160;&#160;&#160;&#160;&#160; 接下来，我们需要为本例创建一个数据库及必要的表。数据库名为ajax，表只有两个EMPLOYEE和GENERATOR_TABLE，下面是SQL脚本：</p>
<pre class="sql">CREATE TABLE EMPLOYEE(
    EMPLOYEE_ID int not null,
    EMPLOYEE_NAME varchar (20) null,
    SEX char (2) null,
    BIRTHDAY varchar(10) null,
    ADDRESS varchar(50) null,
    CONSTRAINT PK_EMPLOYEE PRIMARY KEY (EMPLOYEE_ID)
) 

CREATE TABLE GENERATOR_TABLE(
    ID int not null,
    G_KEY varchar(20) null,
    G_VALUE int null,
    CONSTRAINT PK_GENERATOR_TABLE PRIMARY KEY (ID)
)

INSERT INTO GENERATOR_TABLE VALUES(1,EMPLOYEE_PK,1)</pre>
<p>如果你觉得麻烦，不想建库及表，可以将后面的数据库下载下来，然后还原数据库就可以了。<br />
  <br /><strong>6、修改hibernate.cfg.xml<br />
    <br /></strong>&#160;&#160;&#160;&#160;&#160;&#160; 本例中，采用的是JTDS连接驱动，我们要对配置文件作一些设置，另外还要加入POJO类。</p>
<pre class="xml">
<property name="dialect">org.hibernate.dialect.SQLServerDialect</property>
<property name="connection.driver_class">net.sourceforge.jtds.jdbc.Driver</property>
<property name="connection.url">jdbc:jtds:sqlserver://localhost:1433/ajax</property>
<property name="connection.username">sa</property>
<property name="connection.password">自己密码(无密码就空着)</property>
    <!-- 实体类 -->
<mapping class="com.ajax.employee.model.Employee" /></pre>
<p>以前没有使用JPA注解的时候，我们这里加入的都是hbm.xml文件，现在我们则加入的是类。<br />
  <br /><strong>7、创建EmployeeManager<br />
    <br /></strong>&#160;&#160;&#160;&#160;&#160;&#160; 在com.ajax.employee.service下新建EmployeeManager类，这里面就是写业务方法，另外在这个类中添加一个main方法用于测试，将log4j的日志级别调整为DEBUG，这样我们就可以看到很详细的程序运行信息，源码中的注释很详细，这里就不贴出来了。 </p>
<p>本例没有提供MySQL和Oracle数据库的脚本，不过这些应该很简单，按照最基本的方式建一个数据库和两张表就行了，这里附上两种数据库的hibernate配置。 </p>
<p>&#160;&#160;&#160; MySQL：</p>
<pre class="xml">
<property name="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</property>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost:3306/ajax</property>
<property name="connection.username">root</property>
<property name="connection.password">自己的密码(无密码就空着)</property></pre>
<p>Oracle：</p>
<pre class="xml">
<property name="hibernate.dialect">org.hibernate.dialect.OracleDialect</property>
<property name="connection.driver_class">oracle.jdbc.driver.OracleDriver</property>
<property name="connection.url">jdbc:oracle:thin:@127.0.0.1:1521:自己的SID</property>
<property name="connection.username">system</property>
<property name="connection.password">自己的密码(无密码就空着)</property></pre>
]]></content:encoded>
			<wfw:commentRss>http://javadou.com/jpa-hibernate-annotation-base-167/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Hibernate入门 &#8211; Set 映射</title>
		<link>http://javadou.com/hibernate-step-set-81/</link>
		<comments>http://javadou.com/hibernate-step-set-81/#comments</comments>
		<pubDate>Mon, 24 Aug 2009 06:37:16 +0000</pubDate>
		<dc:creator>阿超</dc:creator>
				<category><![CDATA[Hibernate]]></category>
		<category><![CDATA[hibernate]]></category>
		<category><![CDATA[set]]></category>

		<guid isPermaLink="false">http://javadou.com/hibernate-step-set-81/</guid>
		<description><![CDATA[这个主题介绍如果在对象中包括集合对象，像是使用HashSet来包括其它对象时，该如何进行对象与数据表的映像，像Set这样的集合，可以包括所有的Java对象，这边先介绍当Set中包括的对象没有实体（Entiy）时的映像方... ]]></description>
			<content:encoded><![CDATA[<p>&#160;&#160;&#160; 这个主题介绍如果在对象中包括集合对象，像是使用HashSet来包括其它对象时，该如何进行对象与数据表的映像，像Set这样的集合，可以包括所有的Java对象，这边先介绍当Set中包括的对象没有实体（Entiy）时的映像方式。    <br />（简单的说，也就是所包括的对象没有对象识别（identity）值，没有数据库层次上的识别值之表格与之对应的对象，只是纯綷的值型态（value type）对象，关于Entity与value type的说明，可以看看参考手册5.2.1或是Hibernate in Action的第六章。）     <br />假设我们有一个User类别，当中除了名称属性之外，另一个就是使用者的电子邮件地址，同一个使用者可能有多个不同的邮件地址，所以我们在 User类别中使用Set对象来加以记录，在这边我们使用String来记录每一笔邮件地址，为了不允许重复的邮件地址记录，所以我们使用Set对象，我们的User类别如下：</p>
<pre class="java">User.java
package onlyfun.caterpillar;
import java.util.HashSet;
import java.util.Set;
public class User {
    private long id;
    private String name;
    private Set addrs = new HashSet();
      public Set getAddrs() {
      return addrs;
   }
   public void setAddrs(Set addrs) {
      this.addrs = addrs;
   }
   public long getId() {
      return id;
   }
   public void setId(long id) {
      this.id = id;
   }
   public String getName() {
      return name;
   }
   public void setName(String name) {
      this.name = name;
   }
       public void addAddress(String addr) {
        addrs.add(addr);
    }
}</pre>
<p>addAddress()方法是为了加入一笔一笔的邮件地址而另外增加的，我们也可以在外部设定好Set对象，再使用setAddrs()方法设定给User对象，在映像文件上，为了进行Set的映像，我们使用&lt;set&gt;标签来进行设定，如下所示： </p>
<p><strong>User.hbm.xml</strong></p>
<pre class="xml">

&lt;?xml version=&quot;1.0&quot;?&gt;

&lt;!DOCTYPE hibernate-mapping

PUBLIC &quot;-//Hibernate/Hibernate Mapping DTD//EN&quot;

&quot;http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd&quot;&gt;

&lt;hibernate-mapping&gt;

&lt;class name=&quot;onlyfun.caterpillar.User&quot; table=&quot;USER&quot;&gt;

&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;id name=&quot;id&quot; type=&quot;long&quot; unsaved-value=&quot;null&quot;&gt;

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;column name=&quot;USER_ID&quot;/&gt;

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;generator class=&quot;increment&quot;/&gt;

&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/id&gt;

&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;name&quot; type=&quot;string&quot; not-null=&quot;true&quot;&gt;

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;column name=&quot;NAME&quot; length=&quot;16&quot; not-null=&quot;true&quot;/&gt;

&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/property&gt;

&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;set name=&quot;addrs&quot; table=&quot;ADDRS&quot;&gt;

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;key column=&quot;USER_ID&quot;/&gt;

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;element type=&quot;string&quot; column=&quot;ADDRESS&quot; not-null=&quot;true&quot;/&gt;

&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/set&gt;

&#160;&#160;&#160; &lt;/class&gt;

&lt;/hibernate-mapping&gt;
</pre>
<p>从映射文件中我们可以看到，我们使用另一个表格ADDRS来记录Set中真正记录的对象，为了表明ADDRS中的每一 笔数据是属于哪一个USER 的，我们透过ADDRS的外键USER_ID参考至USER的USER_ID，ADDRS的USER_ID与USER_ID的内容将会是相同的，而 &lt;element&gt;中设定Set所包括的对象之型态，以及它将记录在哪一个字段中。<br />
  <br />假设我们使用下面的程序来储存User的数据：</p>
<pre class="java">        User user1 = new User();
        user1.setName(&quot;caterpillar&quot;);
        user1.addAddress(&quot;caterpillar@caterpillar.onlyfun.net&quot;);
        user1.addAddress(&quot;justin@caterpillar.onlyfun.net&quot;);
        user1.addAddress(&quot;justin@fake.com&quot;);

        User user2 = new User();
        user2.setName(&quot;momor&quot;);
        user2.addAddress(&quot;momor@caterpillar.onlyfun.net&quot;);
        user2.addAddress(&quot;momor@fake.com&quot;);

        Session session = sessionFactory.openSession();
        Transaction tx= session.beginTransaction();
        session.save(user1);
        session.save(user2);
        tx.commit();
        session.close();</pre>
<p>实际上在数据库中的USER与ADDRS表格的内容将如下： </p>
<p>mysql&gt; select * from user;</p>
<p>+&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;&#8212;-+</p>
<p>| USER_ID | NAME&#160;&#160;&#160;&#160;&#160;&#160;&#160; |</p>
<p>+&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;&#8212;-+</p>
<p>|&#160;&#160;&#160;&#160;&#160;&#160; 1 | caterpillar |</p>
<p>|&#160;&#160;&#160;&#160;&#160;&#160; 2 | momor&#160;&#160;&#160;&#160;&#160;&#160; |</p>
<p>+&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;&#8212;-+</p>
<p>2 rows in set (0.00 sec)</p>
<p>mysql&gt; select * from addrs;</p>
<p>+&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-+</p>
<p>| USER_ID | ADDRESS&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; |</p>
<p>+&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-+</p>
<p>|&#160;&#160;&#160;&#160;&#160;&#160; 1 | caterpillar@caterpillar.onlyfun.net |</p>
<p>|&#160;&#160;&#160;&#160;&#160;&#160; 1 | justin@caterpillar.onlyfun.net&#160;&#160;&#160;&#160;&#160; |</p>
<p>|&#160;&#160;&#160;&#160;&#160;&#160; 1 | justin@fake.com&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; |</p>
<p>|&#160;&#160;&#160;&#160;&#160;&#160; 2 | momor@caterpillar.onlyfun.net&#160;&#160;&#160;&#160;&#160;&#160; |</p>
<p>|&#160;&#160;&#160;&#160;&#160;&#160; 2 | momor@fake.com&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; |</p>
<p>+&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-+</p>
<p>5 rows in set (0.00 sec)</p>
<p>&#160;</p>
<p>下面的程序则简单的示范如何取出数据</p>
<pre class="java">Session session = sessionFactory.openSession();

        List users = session.find(&quot;from User&quot;);

        session.close();
        sessionFactory.close();

        for (ListIterator iterator = users.listIterator(); iterator.hasNext(); ) {
            User user = (User) iterator.next();
            System.out.println(user.getName());
            Object[] addrs = user.getAddrs().toArray();
            for(int i = 0; i &lt; addrs.length; i++) {
                System.out.println(&quot;\taddress &quot; + (i+1) + &quot;: &quot; + addrs[i]);
            }
        }</pre>
]]></content:encoded>
			<wfw:commentRss>http://javadou.com/hibernate-step-set-81/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
