教程: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.mzph.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.执行命令…