跟我学OpenJPA
http://www.iteye.com/topic/1122411
本章是基礎開發環境配置,不需要請繞行跟我學OpenJPA之二(Hello OpenJPA)
?
?
受jinnianshilongnian的委托要我寫個《跟我學JPA》的系列,但是JPA方面確實研究不深,平時工作太多,也無心去研究那些深奧的源碼和理論,大多做的都是一些實際的工作。所以力所能及,簡單寫個《跟我學OpenJPA》,希望更多的人和我一起使用OpenJPA。
?
以前一直沒有寫過系列的文章,本來沒有什么思路,但是開頭的時候突然想到了一句話“工欲善其事,必先利其器”,那么今天我們就從這里開始,“器”!
?
此器稱之為Eclipse,此器兇名之大以至于Sun如其名一般,被O一口吃掉。因此江湖中各種版本無數,以My系老大為主,MyEclipse是目前培訓中心必備之利器也,可惜My老大水土不服,鬧了會肚子之后居然把我等墻之。想當初為了其碩大無比的身材,中海、電信、鐵通輪番上陣可惜依然無法越過那高高的圍墻,第一次碰到了被別人墻的滋味。最后不得已轉向原汁原味的Eclipse后發現“原裝的才是最好的”!
==================GTK 下Eclipse緊湊布局的分割線==============
每次我貼Eclipse的截圖有人問這個問題,那么有此問題的請參見我之前的文章Ubuntu下Eclipse緊湊布局修改方法
?
=====================開工的分割線==================
外事問谷哥,輸入Eclipse后直奔Download而去,問度娘者請注意屏蔽各類廣告。記得是下載Eclipse IDE for Java EE Developers。下載后給JDK安好家,安排好eclipse.ini的內容,就可以直奔主題了。下面是我的布局,因為用到了GIT、GWT調試,界面略顯復雜。
下面給Eclipse配上各大殺器:
?
一、Maven(M2E)
我個人的經驗,安裝這個兩個都差不多。反正我只準備用maven做庫的管理,編譯還是讓Eclipse去搞定吧。
?
?
二、Properties Editor(小日本也能出好東西)
這個是一直用的東西,比其他此類插件包括自帶的都要好用。
?
?
三、EditorList
這個插件也是我必備之一,可惜作者沒有升級,我是用他的源碼用新的Eclipse編譯了一個jar出來EditorList_1.0.7.jar ,直接放入plugins目錄即可,記得--clean
?
?
http://www.iteye.com/topic/1122417
Hello World、Hello Delphi、Hello ASP、Hello Java、Hello SSH,這些都是我經歷過的Hello,今天大家陪我再一次經歷Hello OpenJPA。。。。
?
一、新建一個普通的Java項目(不是WTP項目)
?
二、轉換為Maven項目
?
增加一些庫依賴,pom.xml代碼如下:
Xml代碼 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>StrongOpenJPA</groupId><artifactId>StrongOpenJPA</artifactId><version>0.0.1-SNAPSHOT</version><dependencies><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.6.4</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>1.6.4</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>3.1.1.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>3.1.1.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>3.1.1.RELEASE</version></dependency><dependency><groupId>org.apache.openjpa</groupId><artifactId>openjpa</artifactId><version>2.1.1</version><scope>compile</scope></dependency></dependencies> </project>因為pom.xml中沒有配置src的未知,所以默認轉換為maven項目之后,build path中的source中會變為空,這個時候要吧src重新增加進去,最簡單的方法就是直接加!
?
三、增加slf4j記錄日志
在src中新建一個log4j.properties文件,修改內容如下:
Cpp代碼# This is the configuring for logging displayed in the Application Server log4j.rootCategory=INFO, stdout#stdout configure log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=[%-d{HH:mm:ss}-%p]%m%n?
四、轉換為JPA項目
首先在Data Source Explorer中增加對應的數據庫,Drivers沒有請自己設置
?
然后右鍵項目,將其轉換為JPA的項目
因為Eclipse沒有直接支持OpenJPA,所以這里直接選擇Generic2.0
?
完成后,Eclipse會自動在src中新建META-INF目錄,在META-INF中新建persistence.xml文件,自動生成的大多不能用,結合OpenJPA的配置方法修改內容如下:
Xml代碼 <?xml version="1.0" encoding="UTF-8"?> <persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"><persistence-unit name="StrongOpenJPAPU" transaction-type="RESOURCE_LOCAL"><provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider><properties><property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" /><property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/strongjpa" /><property name="javax.persistence.jdbc.user" value="root" /><property name="javax.persistence.jdbc.password" value="root" /><!-- 日志的級別 --><property name="openjpa.Log" value="DefaultLevel=WARN, Runtime=WARN, Tool=INFO, SQL=TRACE" /><property name="openjpa.RemoteCommitProvider" value="sjvm" /><!-- 啟用緩存,并且設置緩存的容量為5000,并且禁用軟引用容量 --><property name="openjpa.DataCache" value="true(CacheSize=5000, SoftReferenceSize=100)" /><!-- 啟用查詢結果緩存,緩存的容量為1000,并且軟引用的容量為100 --><property name="openjpa.QueryCache" value="true(CacheSize=5000, SoftReferenceSize=100)" /><!-- 緩存的數據存儲類型 --><property name="openjpa.QueryCompilationCache" value="true" /><!-- 數據庫連接工廠時的屬性 QueryTimeout:JDBC驅動執行查詢超時的時間,以秒為單位。 PrettyPrint:是否格式化輸出SQL語句。 PrettyPrintLineLength:SQL每行輸出的最大長度。 --><property name="openjpa.ConnectionFactoryProperties" value="PrettyPrint=true, PrettyPrintLineLength=100" /><!-- 查詢結果一次轉化為對象的最多個數,相當于JDBC的結果集對象Statement.set FetchSize。默認為-1,表示所有的查詢對象立即初始化;0表示使用JDBC驅動默認的數值 --><property name="openjpa.FetchBatchSize" value="-1" /></properties></persistence-unit> </persistence>這些配置的參數在OpenJPA的文檔中都有,因為沒有找到中文的文檔,大家有需要的話直接去看官方文檔吧。其中有一個地方需要解釋的,javax.persistence.jdbc.driver等等這些參數是JPA標準,OpenJPA中也有類似的參數,一般情況下建議大家還是直接使用標準參數來配置
?
五、生成Entities From Tables
轉換為JPA項目之后,Eclipse就能夠使用JPA Tools進行JPA的管理,尤其是Entities From Tables非常好用(雖然我重來不用 ^_^)。
右鍵項目,選擇JPA Tools進行操作,我們先把數據庫中的t_xx表轉換出來
?
剩下的操作,大家就按照步驟來吧,因為演示的t_xx沒有任何外鍵,所以按照最簡單的方式轉出來就可以。有可能自動生成后這個class會報錯,這個時因為Eclipse誒有把TXx定義到persistence.xml中,如果報錯大家就手工添加進去,下載的源碼包內我已經手工修改過。
但是自動化生成的東西并不非常合適,至少在以后的通過Entities生成Tables的時候就存在很多的問題,因此我一般都用自己的做的一個轉換工具進行代碼自動生成。
com.strong.module.txx.jpa.TXx
Java代碼 package com.strong.module.txx.jpa;import java.util.Date;import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.SequenceGenerator; import javax.persistence.Table; import javax.persistence.Temporal; import javax.persistence.TemporalType;/*** TXx entity* * @author Simen 自動生成時間: 2011-10-02 08:31:29*/@Entity @Table(name = "t_xx") public class TXx implements java.io.Serializable {/*** */private static final long serialVersionUID = 1L;public static final String S_XXID = "xx_id"; // PRIMARYpublic static final String S_XXBZ = "xx_bz"; // 選項備注public static final String S_XXDM = "xx_dm"; // 選項代碼public static final String S_XXLX = "xx_lx"; // 選項類型public static final String S_XXMC = "xx_mc"; // 選項名稱public static final String S_XXXH = "xx_xh"; // 選項序號 在同一分類中的順序號public static final String S_XXBY1 = "xx_by1"; // 備用1public static final String S_XXBY2 = "xx_by2"; // 備用2public static final String S_XXBY3 = "xx_by3"; // 備用3public static final String S_XXBY4 = "xx_by4"; // 備用4public static final String S_XXBY5 = "xx_by5"; // 備用5public static final String S_XXBY6 = "xx_by6"; // 備用6public static final String S_XXBY7 = "xx_by7"; // 備用7public static final String S_XXBY8 = "xx_by8"; // 備用8// Fieldsprivate Integer xxId; // PRIMARYprivate String xxBz; // 選項備注private String xxDm; // 選項代碼private String xxLx; // 選項類型private String xxMc; // 選項名稱private Integer xxXh; // 選項序號 在同一分類中的順序號private String xxBy1; // 備用1private String xxBy2; // 備用2private String xxBy3; // 備用3private Integer xxBy4; // 備用4private Integer xxBy5; // 備用5private Date xxBy6; // 備用6private Date xxBy7; // 備用7private Float xxBy8; // 備用8public TXx() {}// Constructors@Id@GeneratedValue(strategy = GenerationType.IDENTITY, generator = "AuthorSeqXX")@SequenceGenerator(name = "AuthorSeqXX", allocationSize = 1)@Column(name = "xx_id", unique = true, nullable = false, insertable = true, updatable = true)public Integer getXxId() {return xxId;}public void setXxId(Integer xxId) {this.xxId = xxId;}@Column(name = "xx_bz", length = 255)public String getXxBz() {return xxBz;}public void setXxBz(String xxBz) {this.xxBz = xxBz;}@Column(name = "xx_dm", length = 255)public String getXxDm() {return xxDm;}public void setXxDm(String xxDm) {this.xxDm = xxDm;}@Column(name = "xx_lx", length = 255)public String getXxLx() {return xxLx;}public void setXxLx(String xxLx) {this.xxLx = xxLx;}@Column(name = "xx_mc", length = 255)public String getXxMc() {return xxMc;}public void setXxMc(String xxMc) {this.xxMc = xxMc;}@Column(name = "xx_xh", length = 10)public Integer getXxXh() {return xxXh;}public void setXxXh(Integer xxXh) {this.xxXh = xxXh;}@Column(name = "xx_by1", length = 255)public String getXxBy1() {return xxBy1;}public void setXxBy1(String xxBy1) {this.xxBy1 = xxBy1;}@Column(name = "xx_by2", length = 255)public String getXxBy2() {return xxBy2;}public void setXxBy2(String xxBy2) {this.xxBy2 = xxBy2;}@Column(name = "xx_by3", length = 255)public String getXxBy3() {return xxBy3;}public void setXxBy3(String xxBy3) {this.xxBy3 = xxBy3;}@Column(name = "xx_by4", length = 10)public Integer getXxBy4() {return xxBy4;}public void setXxBy4(Integer xxBy4) {this.xxBy4 = xxBy4;}@Column(name = "xx_by5", length = 10)public Integer getXxBy5() {return xxBy5;}public void setXxBy5(Integer xxBy5) {this.xxBy5 = xxBy5;}@Temporal(TemporalType.TIMESTAMP)@Column(name = "xx_by6", length = 19)public Date getXxBy6() {return xxBy6;}public void setXxBy6(Date xxBy6) {this.xxBy6 = xxBy6;}@Temporal(TemporalType.TIMESTAMP)@Column(name = "xx_by7", length = 19)public Date getXxBy7() {return xxBy7;}public void setXxBy7(Date xxBy7) {this.xxBy7 = xxBy7;}@Column(name = "xx_by8", length = 12)public Float getXxBy8() {return xxBy8;}public void setXxBy8(Float xxBy8) {this.xxBy8 = xxBy8;}}?
com.strong.module.txx.jpa.TXx_ 這個類比較奇特,是JPA規范中定義個一個特殊類,主要的作用是構造查詢,這個以后再說
Java代碼 package com.strong.module.txx.jpa;import java.util.Date;import javax.persistence.metamodel.SingularAttribute; import javax.persistence.metamodel.StaticMetamodel;/*** TXx_ entity* * @author Simen 自動生成時間: 2011-10-02 08:31:29*/@StaticMetamodel(TXx.class) public abstract class TXx_ {public static volatile SingularAttribute<TXx, Integer> xxId;public static volatile SingularAttribute<TXx, String> xxBz;public static volatile SingularAttribute<TXx, String> xxDm;public static volatile SingularAttribute<TXx, String> xxLx;public static volatile SingularAttribute<TXx, String> xxMc;public static volatile SingularAttribute<TXx, Integer> xxXh;public static volatile SingularAttribute<TXx, String> xxBy1;public static volatile SingularAttribute<TXx, String> xxBy2;public static volatile SingularAttribute<TXx, String> xxBy3;public static volatile SingularAttribute<TXx, Integer> xxBy4;public static volatile SingularAttribute<TXx, Integer> xxBy5;public static volatile SingularAttribute<TXx, Date> xxBy6;public static volatile SingularAttribute<TXx, Date> xxBy7;public static volatile SingularAttribute<TXx, Float> xxBy8;}?
六、配置Spring
在src下新建applicationContext.xml文件如下:
Xml代碼 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"><!-- 注解掃描 --><context:component-scan base-package="com.strong" /><!--整合Spring和JPA --><bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"><property name="persistenceUnitName" value="StrongOpenJPAPU" /><property name="loadTimeWeaver"><bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" /></property></bean><!--注入事務管理類 --><bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"><property name="entityManagerFactory" ref="entityManagerFactory" /></bean><!--允許使用注解方式配置事務 --><tx:annotation-driven transaction-manager="transactionManager" /> </beans>?
七、建立Junit測試單元
新建一個類:test.com.strong.StringOpenJPATest
Java代碼 package test.com.strong;import javax.persistence.EntityManager; import javax.persistence.PersistenceContext;import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = { "classpath:applicationContext.xml" }) public class StringOpenJPATest {// 使用注解的方式注入,3.1以前版本使用JpaDaoSupport和JpaTemplate實現@PersistenceContextprivate EntityManager entityManager;@Testpublic void doTest() {System.out.println("=====Hello OpenJPA " + entityManager + "=======");}}這里和Spring3.1以前的版本有一些不同,具體內容請參見Spring3.1+ JpaDaoSupport被deprecated后的研究
?
執行測試獲得結果如下:
Cpp代碼 ...... =====Hello OpenJPA Shared EntityManager proxy for target factory [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@6087e704]======= .......到這里,我們成功的運行起來Spring+OpenJPA,并獲取了對應的EntityManager,下一步將在這個的基礎之上其他的操作,因為我是按照最初始的步驟進行的,所以現在的配置文件正式運行可能定存在問題,下節將進行詳細的介紹
?
?
http://simen-net.iteye.com/blog/1477748
------OpenJPA的增強器(Enhancer)能夠在運行時對系統性能進行優化,并且提高惰性加載的靈活性,是OpenJPA與Hibernate最大不同之處。增強器能夠自動為持久化的類添加一些代碼,這些代碼能夠幫助二進制的類實現持久化類所必需的一些特性。OpenJPA的增強器可以通過兩種方式對持久化類進行優化,一是編譯時強化;二是使用Java 5 提供的新特性Instrumentation,在運行時創建代理來強化。
?
這個是OpenJPA的一大特點,很多人在剛開始接觸的時候很容易因為這個出錯,因為OpenJPA默認是開啟了編譯時強化,我最開始使用OpenJPA的時候就經歷了下面的過程。
?
我們現在修改上次Test代碼:
Java代碼 @Testpublic void doTest() {System.out.println("=====Hello OpenJPA " + entityManager + "=======");TXx txx = new TXx();txx.setXxMc("第一選項");entityManager.persist(txx);}運行后報錯如下:
Html代碼 ............. <openjpa-2.1.1-r422266:1148538 nonfatal user error> org.apache.openjpa.persistence.ArgumentException: This configuration disallows runtime optimization, but the following listed types were not enhanced at build time or at class load time with a javaagent: " com.strong.module.txx.jpa.TXx". .............解決的方法有三種:
?
第一,在我之前的文章寫過,就是使用Spring的Instrumentation(傳送門Spring3(MVC)+OpenJPA2構建及發布 ),這個方法的缺點就是發布的時候在Tomcat的啟動配置中也需要增加-javaagent:/simen/workspace/tomcat/lib/spring-agent.jar,且效率不高。下面列出我之前文章的內容給大家參考一下,不建議大家在實際中使用:
?
----當初為這個把我郁悶的,去 OpenJPA和Spring網站翻了半天才知道tomcat啟動的時候要注冊一個agent,名字叫spring-agent.jar,興奮……翻遍 spring的包沒找到這個東東? 狂暈……,求教Google半天從一個犄角旮旯發現2.5這個包換名字,現在是org.springframework.instrument- 3.0.1.RELEASE-A.jar,找到2.5的spring-agent.jar才發現本來包里面的路徑名就應該是instrument。把這個包改成spring-agent.jar(本身那個太長了),放到tomcat/lib目錄里面,然后給tomcat加上啟動參數? -javaagent:/simen/workspace/tomcat/lib/spring-agent.jar,在Eclipse里面是右鍵點這個項目,Debug as -> Debug Configrations.... 。
?
第二,在persistence.xml中增加如下:
Xml代碼 <!-- 不使用加載時強化和編譯時強化,使用運行時Unenhanced --> <property name="openjpa.ClassLoadEnhancement" value="false" /> <property name="openjpa.DynamicEnhancementAgent" value="false" /> <property name="openjpa.RuntimeUnenhancedClasses" value="supported" />這個方法最簡單,可惜不能發揮OpenJPA的最大效能,所以也不推薦
?
第三,終極解決方案(參考http://www.ibm.com/developerworks/cn/java/j-lo-openjpa2/ )對每個持久化類執行
Cpp代碼 java org.apache.openjpa.enhance.PCEnhancer TXx.java介個.......太麻煩了..............我還是不用了吧,不過等等,OpenJPA官方提供了幾種解決方法,參見http://openjpa.apache.org/entity-enhancement.html ,如果使用的是Eclipse,那么還有無縫解決方案,參見http://openjpa.apache.org/enhancement-with-eclipse.html ,這里我使用的是Eclipse增加Ant編譯的方法,過程如下(簡單翻譯官方文檔,E文較差大家將就):
?
1、下載enhance.xml.tar.gz 解壓到項目的根目錄;新建openjpa_libs目錄,下載與項目maven中openjpa版本相同openjpa-all 的jar包到這個目錄(千萬不要直接用openjpa-****.jar,必須是openjpa-all-*****.jar ),刷新項目保證能看增加的內容
?
2、右鍵項目,選擇屬性,進入Builders
?
3、在Main選項卡,新建一個Ant Builder,Buildfile的點“Browse Workspace”,選擇上面的那個xml文件
?
Base Directory的點“Variables ”,選擇build_project
?
最后填寫Arguments的內容如圖:
?
4、在Targets選項卡中為Manual Build 和 Auto Build點“Set Targets..”添加enhance
?
5、保存后控制臺提示Ant Build的信息如下(不能顯示的話刷新項目):
Cpp代碼 Buildfile: /simen/ramwork/StrongOpenJPA/enhance.xmlopenjpa.libs.check:build.dir.check:enhance:[echo] /simen/ramwork/StrongOpenJPA/target/classes:/simen/ramwork/StrongOpenJPA/openjpa_libs/openjpa-all-2.2.0.jar[openjpac] 299 StrongOpenJPAPU INFO [Worker-44] openjpa.Tool - Enhancer running on type "com.strong.module.txx.jpa.TXx". BUILD SUCCESSFUL Total time: 1 second這里提示TXx類在編譯的時候被增強,再次運行Test,運行通過
?
本節成功的把TXx增強了起來,如果大家覺得麻煩也可以直接槍斃了這個增強,或者在開發過程中不增強只是在發布的時候增強一下,恩這個主意不錯!
可能大家會發現一個問題,剛才的Test執行了,但是數據庫的內容沒有變化,為什么?當然是事務的問題,這個問題下節我們繼續。
?
本節資源:
OpenJPA官方提供的Eclipse增強xml:enhance.xml.tar.gz
本節的源碼(內含openjpa-2.2.0.jar,上節源碼在maven中沒有MySQL的JDBC,本節已默認增加):StrongOpenJPA.tar.gz
?
?
總結
以上是生活随笔為你收集整理的跟我学OpenJPA的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux su和sudo命令的区别
- 下一篇: 基于weblogic 的EJB 学习笔记