教程:Hibernate,JPA –第1部分

這是關于使用Hibernate和JPA的教程的第一部分。 這部分是對JPA和Hibernate的介紹。 第二部分將研究使用Spring ORM組合Spring MVC應用程序以減少創建CRUD應用程序所需的代碼量。

為此,您需要熟悉Maven,JUnit,SQL和關系數據庫。

依存關系

首先,我們需要幾個基本的依賴關系。 本質上分為三層:

  1. 最低層是Hibernate用于連接數據庫的JDBC驅動程序。 我將使用一個簡單的嵌入式數據庫Derby。 沒有要安裝或配置的服務器,因此,即使是MySQL或PostgreSQL,其設置也更容易。 它不適合生產。
  2. 中間層是Hibernate庫。 我將使用3.5.6版。 這適用于Java 1.5,而不適用于4.x。
  3. JPA庫。

另外,我們希望使用JUnit創建測試和Tomcat,因此我們可以將其JNDI命名用于測試。 出于我們將要提到的原因,JNDI是將服務器詳細信息包含在屬性文件中的首選系統。

<dependencies><dependency><groupId>org.apache.derby</groupId><artifactId>derby</artifactId><version>10.4.1.3</version></dependency><dependency><groupId>org.hibernate</groupId><artifactId>hibernate-entitymanager</artifactId><version>3.6.9.Final</version></dependency><dependency><groupId>org.hibernate.javax.persistence</groupId><artifactId>hibernate-jpa-2.0-api</artifactId><version>1.0.0.Final</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.10</version><scope>test</scope></dependency><dependency><groupId>org.apache.tomcat</groupId><artifactId>catalina</artifactId><version>6.0.18</version><scope>test</scope></dependency></dependencies>

組態

JPA的關鍵配置文件是persistence.xml。 這位于META-INF目錄中。 它詳細說明了要使用的持久性驅動程序以及要連接的JNDI數據源。 還可以指定其他屬性,在這種情況下,我們將包括一些Hibernate屬性。

我在其他屬性上添加了一些注釋,以便您了解它們的用途。 您可以直接配置數據源,但是使用JNDI意味著我們可以以最小的代碼更改輕松地將代碼作為獨立的代碼運行在容器中或運行單元測試。

<?xml version='1.0' encoding='UTF-8'?>
<persistence 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'version='1.0'><persistence-unit name='tutorialPU' transaction-type='RESOURCE_LOCAL'><provider>org.hibernate.ejb.HibernatePersistence</provider><!-- the JNDI data source --><non-jta-data-source>java:comp/env/jdbc/tutorialDS</non-jta-data-source><properties><!-- if this is true, hibernate will print (to stdout) the SQL it executes, so you can check it to ensure it's not doing anything crazy --><property name='hibernate.show_sql' value='true' /><property name='hibernate.format_sql' value='true' /><!-- since most database servers have slightly different versions of the SQL, Hibernate needs you to choose a dialect so it knows the subtleties of talking to that server --><property name='hibernate.dialect' value='org.hibernate.dialect.DerbyDialect' /><!-- this tell Hibernate to update the DDL when it starts, very useful for development, dangerous in production --><property name='hibernate.hbm2ddl.auto' value='update' /></properties></persistence-unit>
</persistence>

實體

JPA談論實體而不是數據庫記錄。 實體是類的實例,映射到表中的單個記錄(類映射到表)。 實體字段(應使用JavaBean命名約定)被映射到列。

注釋可用于向類添加額外的信息。 它們將類標記為實體,并允許您指定有關表和列的元信息,例如名稱,大小和約束。

在我們的例子中,我們將從最簡單的實體開始。

package tutorial;import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;@Entity
@Table(name = 'usr') // @Table is optional, but 'user' is a keyword in many SQL variants 
public class User {@Id // @Id indicates that this it a unique primary key@GeneratedValue // @GeneratedValue indicates that value is automatically generated by the serverprivate Long id;@Column(length = 32, unique = true)// the optional @Column allows us makes sure that the name is limited to a suitable size and is uniqueprivate String name;// note that no setter for ID is provided, Hibernate will generate the ID for uspublic long getId() {return id;}public void setName(String name) {this.name = name;}public String getName() {return name;}
}

JPA可以在啟動時使用元信息來創建DDL。 這對開發很有幫助,因為它使您可以快速啟動并運行,而無需研究創建表所需的SQL。 要添加一列嗎? 只需添加列,編譯并運行即可。 不幸的是,您獲得的便利還增加了風險(例如,當一個表具有數百萬條記錄并且您添加了新列時,數據庫服務器會做什么)和失去控制。

這是一個折衷,一旦由Hibernate創建了實體,就可以導出DDL并更改Hibernate的配置以停止其更新DDL。

測試用例

只有兩部分,首先,我們將創建一個抽象測試用例作為所有測試的根。 這將在JNDI中注冊數據源,并且我們將使用其他測試來擴展它,以便他們訪問數據庫。

package tutorial;import org.apache.derby.jdbc.EmbeddedDataSource;
import org.apache.naming.java.javaURLContextFactory;
import org.junit.AfterClass;
import org.junit.BeforeClass;import javax.naming.Context;
import javax.naming.InitialContext;public abstract class AbstractTest {@BeforeClasspublic static void setUpClass() throws Exception {System.setProperty(Context.INITIAL_CONTEXT_FACTORY, javaURLContextFactory.class.getName());System.setProperty(Context.URL_PKG_PREFIXES, 'org.apache.naming');InitialContext ic = new InitialContext();ic.createSubcontext('java:');ic.createSubcontext('java:comp');ic.createSubcontext('java:comp/env');ic.createSubcontext('java:comp/env/jdbc');EmbeddedDataSource ds = new EmbeddedDataSource();ds.setDatabaseName('tutorialDB');// tell Derby to create the database if it does not already existds.setCreateDatabase('create');ic.bind('java:comp/env/jdbc/tutorialDS', ds);}@AfterClasspublic static void tearDownClass() throws Exception {InitialContext ic = new InitialContext();ic.unbind('java:comp/env/jdbc/tutorialDS');}
}

最后一塊是測試用例。 實體管理器提供對數據的訪問。 持久操作(在這種情況下將導致單次插入)必須在事務中執行。 實際上,在提交之前,Hibernate不會做任何工作。 您可以通過在提交之前立即添加Thread.sleep來查看此信息。

@Testpublic void testNewUser() {EntityManager entityManager = Persistence.createEntityManagerFactory('tutorialPU').createEntityManager();entityManager.getTransaction().begin();User user = new User();user.setName(Long.toString(new Date().getTime()));entityManager.persist(user);entityManager.getTransaction().commit();// see that the ID of the user was set by HibernateSystem.out.println('user=' + user + ', user.id=' + user.getId());User foundUser = entityManager.find(User.class, user.getId());// note that foundUser is the same instance as user and is a concrete class (not a proxy)System.out.println('foundUser=' + foundUser);assertEquals(user.getName(), foundUser.getName());entityManager.close();}

異常處理

需要開始和提交很冗長。 此外,最后一個示例是不完整的,因為如果發生異常,它將錯過任何回滾。

異常處理是樣板代碼。 就像它的JDBC一樣,它也不漂亮。 這是一個例子:

@Test(expected = Exception.class)public void testNewUserWithTxn() throws Exception {EntityManager entityManager = Persistence.createEntityManagerFactory('tutorialPU').createEntityManager();entityManager.getTransaction().begin();try {User user = new User();user.setName(Long.toString(new Date().getTime()));entityManager.persist(user);if (true) {throw new Exception();}entityManager.getTransaction().commit();} catch (Exception e) {entityManager.getTransaction().rollback();throw e;}entityManager.close();}

由于存在更好的方法,因此我暫時將其排除在外。 稍后,我們將研究JSR-330的@Inject和Spring Data的@Transactional如何減少樣板。

實體關系

由于我們正在使用關系數據庫,因此幾乎可以肯定,我們希望在實體之間創建一個關系。 我們將創建一個角色實體,并在用戶和角色之間建立多對多關系。 要創建角色實體,只需復制用戶實體,將其命名為Role并刪除@Table行。 我們不需要創建UserRole實體。 但是我們將要向用戶添加和刪除角色。

將以下字段和方法添加到用戶表:

@ManyToManyprivate Set<Role> roles = new HashSet<Role>();public boolean addRole(Role role) {return roles.add(role);}public Set<Role> getRoles() {return roles;}

@ManyToMany注釋告訴JPA這是一個多對多關系。 我們可以用一個新的測試用例進行測試。 該測試在一個事務中創建用戶和角色,然后在第二個事務中使用合并更新用戶。 合并用于更新數據庫中的實體。

@Testpublic void testNewUserAndAddRole() {EntityManager entityManager = Persistence.createEntityManagerFactory('tutorialPU').createEntityManager();entityManager.getTransaction().begin();User user = new User();user.setName(Long.toString(new Date().getTime()));Role role = new Role();role.setName(Long.toString(new Date().getTime()));entityManager.persist(user);entityManager.persist(role);entityManager.getTransaction().commit();assertEquals(0, user.getRoles().size());entityManager.getTransaction().begin();user.addRole(role);entityManager.merge(user);entityManager.getTransaction().commit();assertEquals(1, user.getRoles().size());entityManager.close();}

查詢

JPA允許您使用與SQL非常相似的查詢語言JPQL。 查詢可以直接編寫,但是命名查詢更易于控制,維護,并具有更好的性能,因為Hibernate可以準備該語句。 使用@NamedQuery批注指定它們。 將此行添加到@Table批注之后的User類中:

@NamedQuery(name='User.findByName', query = 'select u from User u where u.name = :name')

您可以如下進行測試:

@Testpublic void testFindUser() throws Exception {EntityManager entityManager = Persistence.createEntityManagerFactory('tutorialPU').createEntityManager();entityManager.getTransaction().begin();User user = new User();String name = Long.toString(new Date().getTime());user.setName(name);Role role = new Role();role.setName(name);user.addRole(role);entityManager.persist(role);entityManager.persist(user);entityManager.getTransaction().commit();entityManager.close();entityManager = Persistence.createEntityManagerFactory('tutorialPU').createEntityManager();User foundUser = entityManager.createNamedQuery('User.findByName', User.class).setParameter('name', name).getSingleResult();System.out.println(foundUser);assertEquals(name, foundUser.getName());assertEquals(1, foundUser.getRoles().size());System.out.println(foundUser.getRoles().getClass());entityManager.close();}

在此示例中,我關閉并重新打開了實體管理器。 這迫使Hibernate從數據庫中請求用戶。 注意到關于輸出的任何有趣的東西嗎? 獲取角色的SQL出現在找到的用戶的toString之后。 Hibernate為角色創建了一個代理對象(在本例中為org.hibernate.collection.PersistentSet),并且僅在您首次訪問該對象時填充它。 這可能會導致違反直覺的行為,并有其自身的陷阱。

請嘗試上述測試的此變體,在我們首先查詢角色之前,我們關閉實體管理器:

@Test(expected = LazyInitializationException.class)public void testFindUser1() throws Exception {EntityManager entityManager = Persistence.createEntityManagerFactory('tutorialPU').createEntityManager();entityManager.getTransaction().begin();User user = new User();String name = Long.toString(new Date().getTime());user.setName(name);Role role = new Role();role.setName(name);user.addRole(role);entityManager.persist(role);entityManager.persist(user);entityManager.getTransaction().commit();entityManager.close();entityManager = Persistence.createEntityManagerFactory('tutorialPU').createEntityManager();User foundUser = entityManager.createNamedQuery('User.findByName', User.class).setParameter('name', name).getSingleResult();entityManager.close();assertEquals(1, foundUser.getRoles().size());}

LazyInitializationException將在getRoles()調用上引發。 這不是錯誤。 實體管理器關閉后,任何實體都將無法使用。

結束

這是Hibernate JPA入門和運行的基礎。 在本教程的下一部分中,我將討論驗證,并更深入地研究其他一些細節。

參考: 教程:Hibernate,JPA –來自JCG合作伙伴 Alex Collins的第1部分 ,位于Alex Collins的博客博客中。


翻譯自: https://www.javacodegeeks.com/2012/05/tutorial-hibernate-jpa-part-1.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/372807.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/372807.shtml
英文地址,請注明出處:http://en.pswp.cn/news/372807.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

TCP、UDP套接字的數據傳輸

tcp發送數據&#xff1a; 1 #include <sys/types.h> 2 #include <socket.h> 3 ssize_t send(int sockfd,const void *msg,size_t len,int flags); 函數send只能對面向連接的套接字使用。參數sockfd為已經建立好連接的套接字描述符。參數msg指向待發送數據的緩沖區&…

Windows下用PIP安裝scipy出現no lapack/blas resources found

Windows下升級了pandas&#xff0c;但是發現scipy包隨后引用出錯&#xff0c;后來確認需重新安裝scipy&#xff0c; 在用PIP安裝scipy出現no lapack/blas resources found的錯誤&#xff0c;具體原因可參考 這里。 后來找到一種簡便的解決方案&#xff0c;只要在網站 Unofficia…

Aleri –復雜事件處理

Sybase的Aleri流媒體平臺是CEP市場中最受歡迎的產品之一。 它在Sybase的交易平臺RAP版本中使用&#xff0c;該版本在資本市場中廣泛用于管理投資組合中的頭寸。 今天&#xff0c;在這個由多個部分組成的系列文章的第一個部分中&#xff0c;我希望提供Aleri平臺的概述&#xff0…

python版本回退_Python爬蟲之BeautifulSoup解析之路

上一篇分享了正則表達式的使用&#xff0c;相信大家對正則也已經有了一定的了解。它可以針對任意字符串做任何的匹配并提取所需信息。但是我們爬蟲基本上解析的都是html或者xml結構的內容&#xff0c;而非任意字符串。正則表達式雖然很強大靈活&#xff0c;但是對于html這樣結構…

0615 團隊第二階段貢獻

0615 團隊第二階段貢獻 列志華http://www.cnblogs.com/liezhihua/ 26% 組長 黃柏堂 http://www.cnblogs.com/huang123/ 22% 團隊 韓麒麟 http://www.cnblogs.com/hanqilin/ 26% 團隊 王俊杰 http://www.cnblogs.com/wangjunjie123/ 28%團隊posted on 2016…

WebStorm 運行Rect Native 項目

今天教大家如何直接使用WebStorm這個IDE直接完成編碼運行項目工作.這樣就可以不用打開Xcode了. 1.首先點擊WebStorm右上方的下拉箭頭彈出的Edit Configurations.... 2.然后會進入一個配置頁面.點擊左上方的.在彈出的列表中選中npm.如圖. 3.在右邊的配置框中,先選擇Command為hel…

python編程比賽_用Python編程分析4W場球賽后,2018世界杯冠軍竟是…

比賽已經開始&#xff0c;我們不妨用 Python 來對參賽隊伍的實力情況進行分析&#xff0c;并大膽的預測下本屆世界杯的奪冠熱門球隊吧&#xff01;通過數據分析&#xff0c;可以發現很多有趣的結果&#xff0c;比如&#xff1a;找出哪些隊伍是首次進入世界杯的黑馬隊伍找出2018…

GlassFish 3.1.2充滿了MOXy(EclipseLink JAXB)

我非常高興地宣布&#xff0c; EclipseLink JAXB&#xff08;MOXy&#xff09;現在是GlassFish 3.1.2中的JAXB&#xff08; JSR-222 &#xff09;提供程序。 我要感謝EclipseLink和GlassFish提交者為實現這一目標付出的??辛勤工作。 在本文中&#xff0c;我將介紹如何利用MOX…

夢斷代碼閱讀筆記03

讀完《夢斷代碼(Dream In Code)》樣書&#xff0c;我感覺心情有點沉重&#xff0c;Chandler項目的結局&#xff0c;它失敗了&#xff0c;它成了眾多失敗軟件項目中的一個。這個結局讓那個我感受到軟件實在是太難了&#xff0c;我覺得當初選這個專業可能到最后只是一個碼農。但是…

Java訪問權限的范圍

二、下面用表格來展示四種修飾符的訪問權限范圍&#xff1a; 同一個類 同一個包 不同包的子類 不同包的非子類 public √ √ √ √ protected √ √ √ 默認(default) √ √ private √ 轉載于:https://www.cnblogs.com/jianxin-lilang/p/6…

JavaFX 2 GameTutorial第2部分

介紹 ?他的是一系列與一個JavaFX 2游戲教程博客條目的第二批。 如果您尚未閱讀第1部分&#xff0c;請參閱JavaFX 2游戲教程的簡介部分。 在第1部分中&#xff0c;我提到了游戲的某些方面以及原型飛船的簡單演示&#xff08;原型由簡單的形狀組成&#xff09;&#xff0c;該飛船…

sqlyog連接mysql教程_如何用SQLyog實現遠程連接MySQL

SQLyog客戶端&#xff0c;用root用戶遠程鏈接MySQL時&#xff0c;提示ldquo;訪問被拒絕rdquo;&#xff0c;在網上搜索了一下原因。原來是MySQL沒有授權其遠程鏈1&#xff0c;SQLyog客戶端&#xff0c;&#xff0c;用root用戶遠程鏈接MySQL時&#xff0c;提示“訪問被拒絕”&…

動態SQL+變量綁定:解決ORA-01704: 字符串文字太長的問題

最近在做一個ESB項目&#xff0c;有一個trigger里面執行動態SQL的時候報錯&#xff1a; ORA-01704: 字符串文字太長 經檢查發現SQL里面有個字段是clob類型&#xff0c;內容長度4009&#xff0c;在oracle里面&#xff0c; 一對引號內的字符長度如果超過4000&#xff0c;就會報OR…

JavaME:Google靜態地圖API

無論您是需要基于位置的應用程序的地圖還是只是出于娛樂目的&#xff0c;都可以使用有史以來最簡單的方法&#xff1a;Google Static Maps API。 在這篇文章中&#xff0c;我們將看到如何從緯度和經度獲得地圖作為圖像。 可以使用Location API獲得緯度和經度&#xff0c;我們將…

在ASP.NET中實現OAuth2.0(一)之了解OAuth

1、什么是OAuth2.0 是一個開放授權標準&#xff0c;允許用戶讓第三方應用訪問該用戶在某一個網站或平臺上的私密資源&#xff08;如照片、視頻、聯系人等&#xff09;&#xff0c;而無須將用戶名和密碼提供給第三方應用 2、OAuth2.0授權模式 授權碼模式&#xff08;authorizati…

mysql日期條件如何應用_MySQL如何使用時間作為判斷條件

背景&#xff1a;在開發過程中&#xff0c;我們經常需要根據時間作為判斷條件來查詢數據&#xff0c;例如&#xff1a;當月&#xff0c;當日&#xff0c;當前小時&#xff0c;幾天內......1. 當月我們只需要使用一個mysql的month(date)函數即可實現。(注意判斷年份)month(date)…

深入探討JS中的數組排序函數sort()和reverse()

最近在研究Javascript發現了其中一些比較靈異的事情。有點讓人感到無語比如&#xff1a; alert(typeof( NaN NaN));//結果為假。 alert(typeof( NaN ! NaN));//結果為真。 嘿嘿&#xff0c;當然這個不是這篇文章要討論的!!開始我們的正文 首先&#xff0c;我們來看一下JS中sor…

帶有謂詞的Java中的功能樣式-第1部分

您一直在聽到將要席卷全球的函數式編程&#xff0c;而您仍然堅持使用普通Java&#xff1f; 不用擔心&#xff0c;因為您已經可以在日常Java中添加一些功能樣式。 此外&#xff0c;它很有趣&#xff0c;可以節省許多代碼行并減少錯誤。 什么是謂詞&#xff1f; 實際上&#xff…

寶塔添加多占點_寶塔面板啟用WordPress多站點子域名、子目錄

其實在很早以前&#xff0c;陌小雨就聽說了 wordpress 的多站點功能&#xff0c;不過因為不清楚&#xff0c;所以懶得折騰&#xff0c;這不這幾天閑著蛋疼&#xff0c;好好研究了下這玩意&#xff0c;用起來的感覺還是相當不錯的&#xff0c;總結起來就是如果你準備開始用 word…

centos 6.5下安裝文件上傳下載服務

centos 6.5下安裝文件上傳下載服務 由于每次在CentOS中要下載一些配置文件到物理機&#xff0c;和上傳一些文件到服務器&#xff0c;導致來回的開啟ftp軟件有點麻煩&#xff0c;這里我們可以使用文件上傳下載服務&#xff0c;來解決上傳和下載的問題。 1.登錄服務器 2.執行命令…