初识JPA

何为JPA
JPA即Java Persistence API,这门技术是06年05月份由SUN官方提出的Java持久化规范
1、它为Java开发人员提供了一种对象/关系映射工具来管理Java应用中的关系数据
      它的出现主要是为了简化现有的持久化开发工作和整合ORM技术
      结束现在Hibernate、TopLink、JDO等ORM框架各自为营的局面
2、JPA只是一套规范,不是产品,JPA规范是由Hibernate的作者主导制定的
      JPA是在充分吸收现有ORM框架的基础上发展而来的,具有易于使用、伸缩性强等优点
      采用JPA开发的应用可以运行在实现JPA规范的持久化产品中,如Hibernate、TopLink等
3、JPA不是一种新的ORM框架,它的出现只是用于规范ORM技术不能取代现有ORM框架
      相反,采用JPA开发时仍要用到ORM框架,但此时开发的应用不再依赖于某个持久化提供商
      应用可以在不修改代码的情况下在任何JPA环境下运行,真正做到低耦合,可扩展的程序设计


JPA的思想
JPA的总体思想和现有Hibernate、TopLink、JDO等ORM框架大体一致。总的来说包括以下3方面的技术:
1、ORM映射元数据
      JPA支持XMLJDK5注解两种元数据的形式
      所谓元数据,是描述对象和表之间的映射关系
      框架根据元数据将实体对象持久化到数据库表中
2、Java持久化API
      用来操作实体对象,执行CRUD操作
      框架在后台替我们完成所有的事情
      开发者可以从繁琐的JDBC和SQL代码中解脱出来
3、查询语言
      通过面向对象而非面向数据库的查询语言查询数据
      避免程序的SQL语句紧密耦合
      这是持久化操作中很重要的一方面


JPA所依赖的Hibernate的JAR文件
1、Hibernate核心包(8个文件)
      hibernate-distribution-3.3.1.GA//..//Hibernate3.jar
      hibernate-distribution-3.3.1.GA//..//lib//required//*.jar
      hibernate-distribution-3.3.1.GA//..//lib//bytecode//cglib///hibernate-cglib-repack-2.1_3.jar
2、Hibernate注解包(3个文件)
      hibernate-annotations-3.4.0.GA//..//hibernate-annotations.jar
      hibernate-annotations-3.4.0.GA//..//lib//ejb3-persistence.jar
      hibernate-annotations-3.4.0.GA//..//lib//hibernate-commons-annotations.jar
3、Hibernate针对JPA的实现包(3个文件)
      hibernate-entitymanager-3.4.0.GA//..//hibernate-entitymanager.jar
      hibernate-entitymanager-3.4.0.GA//..//lib//test//log4j.jar
      hibernate-entitymanager-3.4.0.GA//..//lib//test//slf4j-log4j12.jar
4、合计14个JAR文件
注意:這些JAR文件不要放在含有中文或空格的路径下

下面是示例代码,这是一个Java Project

首先是位于类路径的META-INF下的persistence.xml文件

<?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"> <!-- JPA规范要求在类路径的META-INF下放置persistence.xml文件,该文件的名称是固定的 --> <!-- persistence-unit是指持久化单元,简单的说就代表一堆实体bean的集合 --> <!-- 事务分为本地事务和全局事务,JDBC属于本地事务,JTA属于全局事务 --> <persistence-unit name="jadyerJPADemo" transaction-type="RESOURCE_LOCAL"> <properties> <property name="hibernate.dialect" value="org.hibernate.dialect.OracleDialect" /> <property name="hibernate.show_sql" value="true"/> <property name="hibernate.format_sql" value="true"/> <!-- 这里hibernate的前缀必须带上 --> <!-- 这里hbm2ddl.auto值设为update,那么在获取到EntityManagerFactory对象时,若元数据未更改并且表已存在,则不更新表 --> <!-- 若表不存在则创建表,表名则是根据实体名称来建立的。当映射元数据中添加新字段时,就会把新添加的映射字段添加到数据表中 --> <property name="hibernate.hbm2ddl.auto" value="update" /> <property name="hibernate.connection.driver_class" value="oracle.jdbc.OracleDriver" /> <property name="hibernate.connection.username" value="scott" /> <property name="hibernate.connection.password" value="jadyer" /> <property name="hibernate.connection.url" value="jdbc:oracle:thin:@127.0.0.1:1521:jadyer" /> </properties> </persistence-unit> </persistence> <!-- 在企业开发中通常有两种做法 --> <!-- 1.先建表,然后根据表来编写配置文件和实体bean。使用这种方案的开发人员受到了传统数据库建模的影响 --> <!-- 2.先编写配置文件和实体bean,然后生成表。使用这种方案的开发人员采用的是领域建模思想,相对前一种思想更加OOP --> <!-- 第一种思想已经使用了10多年了,而第二种思想是近几年才兴起的。并且采用第二种思想的话,也就对开发人员的要求高一些 -->

然后是用到的一个枚举类Gender.java

package com.jadyer.model; /** * 用于保存性别的枚举类型 */ public enum Gender {MAN, WOMEN}

采用Annotation映射元数据的实体类Person.java

package com.jadyer.model; import java.util.Date; import javax.persistence.Basic; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.EnumType; import javax.persistence.Enumerated; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.Lob; import javax.persistence.Table; import javax.persistence.Temporal; import javax.persistence.TemporalType; import javax.persistence.Transient; /** * 注解可以标注在属性或者getter上面,但是,要么全标注在属性上,要么全标注在getter上 * 如果,把@Id标注在了属性上面的话,那就没有必要再把注解标注在其它属性的getter上面了 * 因为当发现@Id标注在属性上,它就会认为所有注解都标准在属性上,于是会忽略对getter的检查 */ @Entity //将普通JavaBean变为实体Bean,注意这里导入的是SUN的注解 @Table(name="personxx") //自定义生成的表名为personxx。。默认创建的表名与该实体类名相同 public class Person { //JPA规范中可能并不提供uuid生成策略,但我们可以利用JDK5提供的UUID类,即UUID.randomUUID().toString() //@Id @GeneratedValue(strategy=GenerationType.AUTO) //设置主键生成策略,默认值就是AUTO @Id @GeneratedValue private Integer id; @Column(name="personName", length=10, nullable=false) //指定表字段为personName,长度10,且不可为空 private String name; @Temporal(TemporalType.DATE) //指定生成的字段类型为DATE private Date birthday; //若定义为EnumType.ORDINAL则表示,保存时保存的是枚举的索引,索引值是从0开始的 @Enumerated(EnumType.STRING) //指定该字段为枚举类型,并且保存时保存的是枚举的字符串 @Column(length=5, nullable=false) private Gender gender = Gender.MAN; //使用了枚举类型。由于面向对象编程,故设定表字段默认值时,便可在此处设定 @Lob //指定该字段为大文本类型 private String info; @Lob //这是专门用来处理大文本和二进制数据的映射注解 @Basic(fetch=FetchType.LAZY) //指定该字段延迟加载。即只有在访问该属性时,才会把它的数据装载进内存中 private Byte[] context; @Transient //指定该属性不作为持久化字段,也就是说不与数据库表中的字段做任何关系映射 private String imagepath; /* 关于上面的七个属性的setter和getter略 */ /* * 因为对象创建时,是由Hibernate内部通过反射技术帮我们创建的,反射时就用到了默认的构造函数 * 所以我们在重写构造方法时,必须再显式的提供public的无参的构造器 */ public Person(){} //为了添加数据的方便,这里提供一个构造函数 public Person(String name) { this.name = name; } }

最后是用到的JUnit4单元测试类JPADemoTest.java

package com.jadyer.junit; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import javax.persistence.Query; import org.junit.Test; import com.jadyer.model.Person; public class JPADemoTest { @Test public void save(){ //这里EntityManagerFactory可以看作是类似于Hibernate中的SessionFactory对象 //由于hibernate.hbm2ddl.auto设为update,所以这里得到factory时,表会自动创建,这点与Hibernate是相同的 //所以通过这一特性,在开发时也可以用来验证我们编写的实体映射元数据是否是正确的,即这里的Person.java类 EntityManagerFactory factory = Persistence.createEntityManagerFactory("jadyerJPADemo"); //EntityManager相当于Hibernate中的获取session对象,它内部只是对session对象做了一个封装 EntityManager em = factory.createEntityManager(); em.getTransaction().begin(); //开启事务 //在Hibernate中的session有一个save()方法,但Hibernate的作者更推荐使用persist()方法 //并不是因为这两个方法在功能或代码上有什么不同,它们的功能都是相同的,事实上主要是名字的问题 //因为我们把ORM技术叫做持久化产品,那么当对某个对象进行持久化时,应该叫做持久化,不应该叫做保存 em.persist(new Person("杨过")); em.getTransaction().commit();//提交事务。注意两次得到的事务对象都是同一个事务对象 em.close(); factory.close(); } /** * 读取数据,不需要开启事务。只有存在更改数据的动作时,才开启事务 */ @Test public void getPerson(){ EntityManagerFactory factory = Persistence.createEntityManagerFactory("jadyerJPADemo"); EntityManager em = factory.createEntityManager(); //持久化管理器的find()方法采用了泛型。我们传进去什么类型,它就会返回什么类型。所以这里不需要类型转换 //这里find()类似于Hibernate中的get()方法。同样若数据不存在,则返回null Person person = em.find(Person.class, 1); //我们在获取某条记录之后,在我们操作记录的过程中,假设有人在数据库中删掉了或更新了该记录 //这时若使用find()去重新获取记录的话,那么它会从EntityManager的一级缓存中查找记录 //这时若想得到数据库中的最新数据的话,可以使用em.refresh()可以重新获取记录 //它相当于重新获取了一个EntityManager对象,然后用新的实体管理器再去获取记录 //em.refresh(arg0); System.out.println(person.getName()); em.close(); factory.close(); } @Test public void getPerson22(){ EntityManagerFactory factory = Persistence.createEntityManagerFactory("jadyerJPADemo"); EntityManager em = factory.createEntityManager(); //这里getReference()类似于Hibernate中的load()方法。同样若数据不存在,则抛出异常 Person person = em.getReference(Person.class, 2); System.out.println(person.getName()); em.close(); factory.close(); } /** * JPA中的四种实体状态 * 1.新建状态-->new Person("杨过") * 2.托管状态-->find() * 3.游离状态-->clear() * 4.删除状态 */ @Test public void update(){ EntityManagerFactory factory = Persistence.createEntityManagerFactory("jadyerJPADemo"); EntityManager em = factory.createEntityManager(); em.getTransaction().begin(); Person person = em.find(Person.class, 2); person.setName("沈浪"); //当对象处于托管状态,并且实体管理器已经与事务关联,这时对属性的修改就能够同步到数据库 em.getTransaction().commit(); em.close(); factory.close(); } @Test public void update22(){ EntityManagerFactory factory = Persistence.createEntityManagerFactory("jadyerJPADemo"); EntityManager em = factory.createEntityManager(); em.getTransaction().begin(); Person person = em.find(Person.class, 2); em.clear(); //将目前处于实体管理器中的所有的实体变成游离状态 person.setName("王怜花"); //对游离状态的对象进行更新时,不会同步到数据库中 em.merge(person); //把游离状态时的更新,同步回数据库中。注意前提条件是游离状态 em.getTransaction().commit(); em.close(); factory.close(); } @Test public void delete(){ EntityManagerFactory factory = Persistence.createEntityManagerFactory("jadyerJPADemo"); EntityManager em = factory.createEntityManager(); em.getTransaction().begin(); Person person = em.find(Person.class, 2); em.remove(person); //删除托管状态的实体。经测试:它是不能删除游离状态中的实体的 em.getTransaction().commit(); em.close(); factory.close(); } /** * 在JPA规范中,它的JPQL语言里面,进行查询操作时需要以select开头 * 但所使用的JPA实现产品如果是Hibernate,那么查询语句不以select也是可以的。但不能确保在其它产品中也是可以的 */ @Test public void JPQLquery(){ EntityManagerFactory factory = Persistence.createEntityManagerFactory("jadyerJPADemo"); EntityManager em = factory.createEntityManager(); Query query = em.createQuery("select p from Person p where p.id=?88"); //使用的是javax.persistence.Query接口 query.setParameter(88, 1); //在JPA中,可以在参数问号的后面加上数字,用来指定它的索引值 //JPA中的query.getResultList()就类似于Hibernate中的query.list()方法 //JPA中的query.getSingleResult()类似于Hibernate中的query.uniqueResult()方法 Person person = (Person)query.getSingleResult(); System.out.println(person.getName()); em.close(); factory.close(); } @Test public void JPQLupdate(){ EntityManagerFactory factory = Persistence.createEntityManagerFactory("jadyerJPADemo"); EntityManager em = factory.createEntityManager(); em.getTransaction().begin(); Query query = em.createQuery("update Person p set p.name=:name where p.id=:id"); query.setParameter("name", "李寻欢"); query.setParameter("id", 1); query.executeUpdate(); em.getTransaction().commit(); em.close(); factory.close(); } @Test public void JPQLdelete(){ EntityManagerFactory factory = Persistence.createEntityManagerFactory("jadyerJPADemo"); EntityManager em = factory.createEntityManager(); em.getTransaction().begin(); Query query = em.createQuery("delete from Person p where p.id=?88"); query.setParameter(88, 1); query.executeUpdate(); em.getTransaction().commit(); em.close(); factory.close(); } }

你可能感兴趣的:(数据库,Hibernate,jpa,query,getter,数据库建模)