基于Hibernate的JPA2.0快速构建
2019獨角獸企業重金招聘Python工程師標準>>>
前言
盡管現在開源的框架已經非常優秀,但是缺乏統一的標準有違軟件開源的初衷,因此Sun公司的JCP組織發布了Java EE的JPA標準,并統一ORM規則、JPQL查詢語言、子查詢、高級查詢和批量處理等操作。推出JPA規范有兩點原因:一是,希望簡化現有的SE和EE工作,特別是EJB3.0的推出,使得企業級項目的開發推向更高的層次(EJB3.0已經非常優秀,但是由于時間的問題,并且Spring已經占領了市場);二是,希望業界有一個統一的標準,就像當年JDBC推出一樣,只實現接口,其余API的實現交給項目廠商或者組織去完成。
Hibernate JPA
實際項目開發應該盡量使用JPA的API編程,為什么要這樣做?JPA是一個規范,不是產品,最終實現交給Hibernate這些ORM框架去實現,即使以后我們要改變ORM的底層,也只需要簡單更改一下配置即可,JPA還是屬于javax.persistence.*的包里面,稍微有些不同的是主鍵的生成策略不同的ORM規范有所差異,但基本原理還是一樣。
下面將分hibernate實現和整合Spring實現兩種案例說明JPA整合的好處。
Maven包管理
由于Spring、Hibernate和log4j的maven配置比較繁瑣,這里只提供版本管理:
<properties><!--Spring版本號--><spring.version>4.0.5.RELEASE</spring.version><!--hibernate--><hibernate.version>4.3.0.Final</hibernate.version><!--log4j日志文件管理包版本--><slf4j.version>1.6.6</slf4j.version><log4j.version>1.2.12</log4j.version><!--項目編碼級別--><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><!--spring jpa--><spring-data-jpa.version>1.4.1.RELEASE</spring-data-jpa.version><hibernate-jpa-api.version>1.0.1.Final</hibernate-jpa-api.version> </properties>POJO實體
由于使用注解方式創建,因此本文將不創建orm.xml文件,并且JPA的注解也非常容易看懂,因此注解內容不做詳述,下面創建一個用戶實體對象,對應數據庫中的表為t_user;
import javax.persistence.*; import java.io.Serializable;/*** @author Barudisshu*/ @Entity(name = "USER") @Table(name = "t_user",uniqueConstraints = {@UniqueConstraint(columnNames = {"username"})}) public class UserInfo implements Serializable{@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;// 希望用戶名是唯一的@Basic@Column(name = "username")private String username;@Basic@Column(name = "password")private String password;// 如果Id生成策略被指定,不應該有帶參數的構造函數// 省略getter和setter方法 }因為@Id中的Id字段是唯一的,如果生成策略已經指定,使用persist(Object obj)方法時將拋出異常,因此,要么改為merge方法,要么去掉@GeneratedVale注解,因為persist會尋找游離態的實體是根據Id進行標識,如果沒有則自行創建。
persistence.xml
默認persistence.xml文件處于根目錄的META-INF文件下,并且名稱固定,如果使用想使用Maven指定,需要配置ant插件:
<plugins><!--如果想指定persistence.xml位置,則添加如下插件--><plugin><artifactId>maven-antrun-plugin</artifactId><version>1.3</version><executions><execution><id>copy-test-persistence</id><phase>process-test-resources</phase><configuration><tasks><!--backup the "proper" persistence.xml--><copy file="${project.build.outputDirectory}/META-INF/persistence.xml" tofile="${project.build.outputDirectory}/META-INF/persistence.xml.proper"/><!--replace the "proper" persistence.xml with the "test" version--><copy file="${project.build.testOutputDirectory}/META-INF/persistence.xml" tofile="${project.build.outputDirectory}/META-INF/persistence.xml"/></tasks></configuration><goals><goal>run</goal></goals></execution><execution><id>restore-persistence</id><phase>prepare-package</phase><configuration><tasks><!--restore the "proper" persistence.xml--><copy file="${project.build.outputDirectory}/META-INF/persistence.xml.proper" tofile="${project.build.outputDirectory}/META-INF/persistence.xml"/></tasks></configuration><goals><goal>run</goal></goals></execution></executions></plugin> </plugins>OK,前面已經說過,只使用注解方式,不使用xml方式,所以persistence.xml使用類加載的方式。
<?xml version='1.0' encoding='utf-8'?> <persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"version="2.1"><!--持久化單元,使用JTA必須架構在JBOSS服務器上--><persistence-unit name="person_pu" transaction-type="RESOURCE_LOCAL"><!--hibernate jpa提供者為HibernatePersistenceProvider--><provider>org.hibernate.jpa.HibernatePersistenceProvider</provider><!--持久化對象--><class>ls.jpa.entity.UserInfo</class><properties><!--基本屬性--><property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/><property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/db_test"/><property name="javax.persistence.jdbc.user" value="root"/><property name="javax.persistence.jdbc.password" value="***"/><!--hibernate配置--><property name="hibernate.hbm2ddl.auto" value="update"/><property name="hibernate.show_sql" value="true"/><property name="hibernate.format_sql" value="true"/></properties></persistence-unit> </persistence>注意:JPA2.0和JPA1.0有較大差別,JPA2.0是提供了類型安全的查詢機制、豐富的表達式等功能,并且已經從EJB中獨立開來。
單元測試
單元測試類不用顯式加載persistence.xml文件,到底persistence.xml文件是如何加載的為什么名稱是固定的?筆者找了很久,原來是是在org.hibernate.jpa.boot.internal.PersistenceXmlParser類下定義的,如果單純從Persistence類下是找不到的,因為hibernate.jpa.boot包下會加載所有配置文件并轉換為properties屬性存儲在Map中,然后通過工具類或者通過ClassLoader進行屬性訪問。下面為單元測試代碼:
import ***;/*** @author Barudisshu*/ public class LogonTest {private static final Logger logger = Logger.getLogger(LogonTest.class);private static final String PERSISTENCE_UNIT_NAME = "person_pu";@Testpublic void simpleTests(){// Obtaining an entity managerEntityManagerFactory factory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);EntityManager entityManager = factory.createEntityManager();// Read the existing entries and write to consoleTypedQuery<UserInfo> query = entityManager.createQuery("select u from USER u", UserInfo.class);List<UserInfo> userList = query.getResultList();// List user namefor (UserInfo userInfo : userList) {logger.info(userInfo.getUsername());}logger.info("Size: " + userList.size());// Simple transactionentityManager.getTransaction().begin();UserInfo userInfo = new UserInfo();userInfo.setUsername("Barudisshu");userInfo.setPassword("88888888");entityManager.persist(userInfo);entityManager.getTransaction().commit();// Close the EM and EMF when doneentityManager.close();factory.close();}}
Spring集成
單純使用JPA很難滿足業務上的需求,因此可以通過Spring進行集成,進而架構成為邏輯清晰的業務層次。首先添加相應的Maven管理包,如下:
<dependency><groupId>org.springframework</groupId><artifactId>spring-orm</artifactId><version>${spring.version}</version> </dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>${spring.version}</version> </dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>${spring.version}</version> </dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-beans</artifactId><version>${spring.version}</version> </dependency><dependency><groupId>org.springframework.data</groupId><artifactId>spring-data-jpa</artifactId><version>${spring-data-jpa.version}</version> </dependency>為了達到分層的架構,一下分別添加Dao層和Service層,代碼清單如下:
Dao層,自動裝配持久化上下文:
import ***;/*** @author Barudisshu*/ @Repository public class UserDao {@PersistenceContextprivate EntityManager em;@Transactionalpublic UserInfo save(UserInfo userInfo){em.persist(userInfo);return userInfo;} } Service層,創建服務: import ***;/*** @author Barudisshu*/ @Service public class UserService {@Autowiredprivate UserDao userDao;@Transactionalpublic UserInfo create(String name,String password){UserInfo userInfo = new UserInfo();userInfo.setUsername(name);userInfo.setPassword(password);return userDao.save(userInfo);} }上述代碼沒有使用JpaTemplate模版,自spring3.1之后就沒有了,可能是JPA規范做得足夠好的原因,就像自spring3.2.x之后不再支持HibernateTemplate一樣。
Spring整合Hibernate時,Spring可以通過容器來管理Hibernate的SessionFactory;類似地,Spring整合JPA時,Spring可以通過容器管理JPA的EntityManagerFactory。Spring為JPA EntityManagerFactory管理提供了兩種方式:
LocalEntityMangerFactoryBean功能比較有限,只能通過persistence.xml內容的屬性構建,因此不能使用Spring容器中已有的DataSource,也不能切換全局事務。而LocalContainerEntityManagerFactoryBean則剛好彌補了這方面的不足,并且可以使用Spring容器中已有的數據源,這樣persistence.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"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd"><context:component-scan base-package="ls.jpa"/><bean id="emf" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean"><!--注入JPA持久化單元--><property name="persistenceUnitName" value="person_pu"/></bean><bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager"><property name="entityManagerFactory" ref="emf"/></bean><!--開啟AOP監聽--><aop:aspectj-autoproxy expose-proxy="true"/><!--使用聲明式事務--><tx:annotation-driven transaction-manager="txManager"/></beans> OK,所有配置已經完成,下面進行簡單的單元測試: import ***;/*** @author Barudisshu*/ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = {"classpath:spring-config.xml"}) @Transactional @TransactionConfiguration(transactionManager = "txManager",defaultRollback = true) public class SimpleTest {private static final Logger logger = Logger.getLogger(SimpleTest.class);@Autowiredprivate UserService userService;@Testpublic void userTests(){UserInfo userInfo = userService.create("Barudisshu","liter");logger.info(JSON.toJSONString(userInfo));} }單元測試綠條通過后,打開數據庫可以看到,已經自動為你創建t_user用戶表:
Well done!
轉載于:https://my.oschina.net/Barudisshu/blog/314843
總結
以上是生活随笔為你收集整理的基于Hibernate的JPA2.0快速构建的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: zabbix之使用proxy实现分布式监
- 下一篇: 【BZOJ】3390: [Usaco20