JPA 相关API (一)

【Query 接口下的常用API】

【API 测试类:Test_QueryAPI.java】

  1 package org.zgf.jpa.entity;  
  2   
  3 import java.math.BigInteger;  
  4 import java.util.Calendar;  
  5 import java.util.Date;  
  6 import java.util.List;  
  7   
  8 import javax.persistence.Query;  
  9 import javax.persistence.TemporalType;  
 10   
 11 import org.junit.Test;  
 12 import org.zgf.jpa.enumer.Gender;  
 13 /** 
 14  * JPA 中sql 语句设置参数有两种形式,一种是命名参数,另一种是位置参数: 
 15  * 位置参数:执行效率高, 可读性差,可用于原生sql 和 JPQL 语句中, 格式《?+数字》,数字可任意指定  
 16  * 命名参数:执行效率低 ,可读性强,可用于原生sql 和 JPQL 语句中, 格式《:+ 名称》,名称自定义 
 17  *  
 18  * @Description: 测试Query接口的相关API 
 19  * @author zonggf 
 20  * @date 2015年11月4日-下午4:07:12 
 21  */  
 22 public class Test_QueryAPI extends BasicJPATest{  
 23       
 24     //2. Test API 1: 测试返回列表API  
 25     @Test  
 26     public void test_getResultList(){  
 27         String jpql = "from PersonEntity";  
 28         Query query = this.entityManager.createQuery(jpql);  
 29         List<PersonEntity> personEntityList = query.getResultList();  
 30         for (PersonEntity personEntity : personEntityList) {  
 31             System.out.println(personEntity);  
 32         }  
 33     }  
 34       
 35     //2. Test API 2: 使用query.getSingleResult()方式时,必须保证查询的结果有且只有一个返回对象  
 36     @Test  
 37     public void test_getSingleResult(){  
 38         String jpql = "from PersonEntity personEntity where personEntity.id = 1";  
 39         Query query =  this.entityManager.createQuery(jpql);  
 40         PersonEntity personEntity = (PersonEntity) query.getSingleResult();  
 41         System.out.println(personEntity);  
 42     }  
 43       
 44     //2. Test API 2: 如果没有返回对象,则会抛出异常 NoResultException.class  
 45     @Test(expected=javax.persistence.NoResultException.class)  
 46     public void test_getSingleResult_Exception(){  
 47         String jpql = "from PersonEntity personEntity where personEntity.id = 100";  
 48         Query query =  this.entityManager.createQuery(jpql);  
 49         PersonEntity personEntity = (PersonEntity) query.getSingleResult();  
 50         System.out.println(personEntity);  
 51     }  
 52       
 53     //2. Test API 2: 如果有多个返回对象,则会抛出异常 NonUniqueResultException.class  
 54     @Test(expected=javax.persistence.NonUniqueResultException.class)  
 55     public void test_getSingleResult_Exception_(){  
 56         String jpql = "from PersonEntity";  
 57         Query query =  this.entityManager.createQuery(jpql);  
 58         PersonEntity personEntity = (PersonEntity) query.getSingleResult();  
 59         System.out.println(personEntity);  
 60     }  
 61       
 62       
 63     //3. Test API 3: 测试位置参数使用方法  
 64     @Test  
 65     public void test_setPositionParameter(){  
 66         String jpql = "from PersonEntity personEntity where personEntity.id = ?1";  
 67         Query query = this.entityManager.createQuery(jpql);  
 68         query.setParameter(1, 1);  
 69         PersonEntity personEntity = (PersonEntity) query.getSingleResult();  
 70         System.out.println(personEntity);  
 71           
 72     }  
 73       
 74     //3. Test API 3: 测试位置参数使用方法,参数类型为java.util.Date  
 75     @Test  
 76     public void test_setPositionParameter_date(){  
 77         String sql = "select count(*) from tb_person p where p.birthdayDate = ?2";  
 78         Query query = this.entityManager.createNativeQuery(sql);  
 79         query.setParameter(2,new Date(), TemporalType.DATE);  
 80         //注意此处返回的是BigInteger 类型, 不是Int类型  
 81         BigInteger count = (BigInteger) query.getSingleResult();  
 82         System.out.println("共有记录:" + count);  
 83     }  
 84       
 85     //3. Test API 3: 测试位置参数使用方法, 参数类型为 java.util.Calendar;  
 86     @Test  
 87     public void test_setPositionParameter_calender(){  
 88         String sql = "select count(*) from tb_person p where p.birthdayDate = ?2";  
 89         Query query = this.entityManager.createNativeQuery(sql);  
 90         query.setParameter(2,Calendar.getInstance(), TemporalType.DATE);  
 91         //注意此处返回的是BigInteger 类型, 不是Int类型  
 92         BigInteger count = (BigInteger) query.getSingleResult();  
 93         System.out.println("共有记录:" + count);  
 94     }  
 95       
 96     //Test API 4: 测试命名参数:参数类型为普通参数  
 97     @Test  
 98     public void test_setNameParameter(){  
 99         String jpql = "from PersonEntity personEntity where personEntity.id = :id";  
100         Query query = this.entityManager.createQuery(jpql);  
101         query.setParameter("id", 1);  
102         PersonEntity personEntity = (PersonEntity) query.getSingleResult();  
103         System.out.println(personEntity);  
104     }  
105       
106     //Test API 4: 测试命名参数:参数类型为java.util.Date  
107     @Test  
108     public void test_setNameParameter_date(){  
109         String sql = "select count(*) from tb_person p where p.birthdayDate = :birthDate";  
110         Query query = this.entityManager.createNativeQuery(sql);  
111         query.setParameter("birthDate",new Date(), TemporalType.DATE);  
112         //注意此处返回的是BigInteger 类型, 不是Int类型  
113         BigInteger count = (BigInteger) query.getSingleResult();  
114         System.out.println("共有记录:" + count);  
115     }  
116       
117     //Test API 4: 测试命名参数:参数类型为java.util.Calendar  
118     @Test  
119     public void test_setNameParameter_calender(){  
120         String sql = "select count(*) from tb_person p where p.birthdayDate = :birthDate";  
121         Query query = this.entityManager.createNativeQuery(sql);  
122         query.setParameter("birthDate",Calendar.getInstance(), TemporalType.DATE);  
123         //注意此处返回的是BigInteger 类型, 不是Int类型  
124         BigInteger count = (BigInteger) query.getSingleResult();  
125         System.out.println("共有记录:" + count);  
126     }  
127       
128     //Test API 5: excuteUpdate 用于执行更新更新,删除语句或者DDL语句  
129     @Test  
130     public void test_excuteUpdate_clear(){  
131         String jpql = "delete PersonEntity";  
132         Query query = this.entityManager.createQuery(jpql);  
133         int deleteCnt = query.executeUpdate();  
134         System.out.println("共删除记录条数:" + deleteCnt);  
135     }  
136       
137     //Test API 5: excuteUpdate 执行DDL 语句删除表  
138     @Test  
139     public void test_excuteUpdate_drop(){  
140         String sql = "drop table tb_person";  
141         Query query = this.entityManager.createNativeQuery(sql);  
142         int cnt = query.executeUpdate();  
143         System.out.println("cnt:" + cnt);  
144     }  
145       
146     //Test API 6: 测试分页数据  
147     @Test  
148     public void test_page(){  
149         String jpql = "from PersonEntity";  
150         Query query = this.entityManager.createQuery(jpql);  
151         query.setFirstResult(10); //序号从0 开始  
152         query.setMaxResults(20);  
153         List<PersonEntity> personList = query.getResultList();  
154         System.out.println("count:" + personList.size());  
155         for (PersonEntity personEntity : personList) {  
156             System.out.println(personEntity);  
157         }  
158     }  
159       
160     //初始化100 条数据  
161     @Test  
162     public void test_savePerson(){  
163         Date date = new Date();  
164         for(int i=0; i<100;  i++){  
165             PersonEntity person = new PersonEntity();  
166             person.setName("zhangsan" + i);  
167             person.setAge(20);  
168             person.setBirthday(date);  
169             person.setBirthdayDate(date);  
170             person.setBirthdayTime(date);  
171             person.setEnglishScore(20.20);  
172             person.setMathScore(89.8f);  
173             person.setGender(Gender.BOY);  
174             person.setInfo("I am a good boy".getBytes());  
175             this.entityManager.persist(person);  
176         }  
177     }  
178       
179 }  

【注意】

1.  JPA 中sql 语句设置参数有两种形式,一种是命名参数,另一种是位置参数:

     位置参数:执行效率高, 可读性差,可用于原生sql 和 JPQL 语句中, 格式《?+数字》,数字可任意指定 也可以不指定,直接用问号
     命名参数:执行效率低 ,可读性强,可用于原生sql 和 JPQL 语句中, 格式《:+ 名称》,名称自定义

2. query.getSigleResult(); 方法必须确保查询结果有且只有一个放回对象。

3. query.excuteUpdate();方法可用于执行更新,删除语句

 

其它涉及类PersonEntity, BasicJPATest 参看 下面

简单实体映射和EntityManagerAPI

【常用注解】

使用JPA 指定映射关系时,有两种方式,一种是使用xml 方式,另一种是注解方式,笔者推荐使用注解方式。在JPA 映射简单实体时,常用的注解如下:

@Entity:修饰实体类对象,表示该实体类对象进行数据库映射

@Table(name="***"):指定实体类对象映射的表名称

@Id: 指定主键

@GeneratedValue(strategy=GenerationType.AUTO):指定主键生成方式,默认为Auto。

    IDENTITY:采用数据库 ID自增长的方式来自增主键字段,Oracle 不支持这种方式;
    AUTO: JPA自动选择合适的策略,是默认选项;
    SEQUENCE:通过序列产生主键,通过 @SequenceGenerator 注解指定序列名,MySql 不支持这种方式
    TABLE:通过表产生主键,框架借由表模拟序列产生主键,使用该策略可以使应用更易于数据库移植。

@Column(name="s_name",length=20,unique=true,nullable=false, insertable=true, updatable=true):修饰属性, 指定列名称和相关限制

@Enumerated(EnumType.STRING):修饰枚举类属性,

                      EnumType.STRING: 指定数据库中存储的是字符串类型, 

                       EnumTypee.ORDINAL:指定数据库 存储的类型为枚举的索引(0,1,2,3...)

@Temporal(TemporalType.TIME):修饰日期类型:

                       TemporalType.DATE: 指定映射数据库中的DATE 类型,只存储日期

                       TemporalType.TIME: 指定映射数据库 中的TIME类型, 只存储时间

                       TemporalType.TIMESTAMP:指定映射数据库中的TIMESTAMP类型

@Transient:指定不映射的属性

@Lob:修饰 byte[] 数组,二进制文件

@Basic(fetch=FetchType.LAZY) : 默认注解,如果字段不添加任何注解,则默认添加了此注解。可以通过fetch 属性指定大数据字段延时加载,目前在Hibernate中并未能实现,或许是Hibernate的一个bug。

@NamedQueries({ 
@NamedQuery(name="***",query="*** hql ***"),
@NamedQuery(name="***",query="*** hql ***")
}): 命名查询注解,指定命名查询语句,query字段只能写JPQL 查询语句,不能写普通的sql 语句。

【简单实体对象:PersonEntity.java】

  1 package org.zgf.jpa.entity;  
  2   
  3 import java.util.Date;  
  4   
  5 import javax.persistence.Basic;  
  6 import javax.persistence.Column;  
  7 import javax.persistence.Entity;  
  8 import javax.persistence.EnumType;  
  9 import javax.persistence.Enumerated;  
 10 import javax.persistence.FetchType;  
 11 import javax.persistence.GeneratedValue;  
 12 import javax.persistence.GenerationType;  
 13 import javax.persistence.Id;  
 14 import javax.persistence.Lob;  
 15 import javax.persistence.NamedQueries;  
 16 import javax.persistence.NamedQuery;  
 17 import javax.persistence.Table;  
 18 import javax.persistence.Temporal;  
 19 import javax.persistence.TemporalType;  
 20 import javax.persistence.Transient;  
 21   
 22 import org.zgf.jpa.enumer.Gender;  
 23   
 24   
 25   
 26 @Table(name="tb_person")  
 27 @Entity  
 28 @NamedQueries({ //命名查询注解:只能写JPQL 语句  
 29     @NamedQuery(name="queryAllByJpql",query="from PersonEntity personEntity"),  
 30     @NamedQuery(name="queryByName",query="from PersonEntity personEntity where personEntity.name = :name")  
 31 })  
 32 public class PersonEntity {  
 33       
 34     /** 
 35      * 测试主键生成策略  
 36      * GenerationType.AUTO: 根据数据库的默认规则来生成主键 
 37      * GenerationType.IDENTITY:数据库自增(mysql 适用,Oracle不适用)                                                                                                         
 38      * GenerationType.SEQUENCE:序列生成方式,(Oracle适用,mysql 不适用) 
 39      */  
 40     @Id  
 41     @GeneratedValue(strategy=GenerationType.AUTO)  
 42     private Integer id;  
 43       
 44     /*** 
 45      * 数据库字段限制:  
 46      * Column可以指定数据库 字段的名称 ,长度,唯一性,是否可以为空,是否可以插入,是否可以更新 
 47      */  
 48     @Column(name="s_name",length=20,unique=true,nullable=false, insertable=true, updatable=true)  
 49     private String name;  
 50     private int age;  
 51       
 52     /** 
 53      * 枚举类型: 
 54      * EnumType.STRING: 指定数据库中存储的是字符串类型 
 55      * EnumTypee.ORDINAL:指定数据库 存储的类型为枚举的索引 
 56      */  
 57     @Enumerated(EnumType.STRING)  
 58     private Gender gender;  
 59       
 60     private Double englishScore;  
 61     private Float mathScore;  
 62       
 63     /** 
 64      * 日期类型: TimeStamp 会根据当地的时间做自动转换 
 65      * TemporalType.DATE: 指定映射数据库中的DATE 类型,只存储日期 
 66      * TemporalType.TIME: 指定映射数据库 中的TIME类型, 只存储时间 
 67      * TemporalType.TIMESTAMP:指定映射数据库中的TIMESTAMP类型 
 68      */  
 69     @Temporal(TemporalType.TIME)  
 70     private Date birthdayTime;  
 71     @Temporal(TemporalType.DATE)  
 72     private Date birthdayDate;  
 73     @Temporal(TemporalType.TIMESTAMP)  
 74     private Date birthday;  
 75       
 76     @Lob  //大数据文件  
 77     @Basic(fetch=FetchType.LAZY, optional=true)  //延迟加载为true,貌似是Hibernate的一个bug,并不能实现延迟加载  
 78     private byte[] info;  
 79       
 80     @Transient  //不映射 此字段  
 81     private String transientProperty;  
 82   
 83     public Integer getId() {  
 84         return id;  
 85     }  
 86   
 87     public void setId(Integer id) {  
 88         this.id = id;  
 89     }  
 90   
 91     public String getName() {  
 92         return name;  
 93     }  
 94   
 95     public void setName(String name) {  
 96         this.name = name;  
 97     }  
 98   
 99     public int getAge() {  
100         return age;  
101     }  
102   
103     public void setAge(int age) {  
104         this.age = age;  
105     }  
106   
107     public Gender getGender() {  
108         return gender;  
109     }  
110   
111     public void setGender(Gender gender) {  
112         this.gender = gender;  
113     }  
114   
115     public Double getEnglishScore() {  
116         return englishScore;  
117     }  
118   
119     public void setEnglishScore(Double englishScore) {  
120         this.englishScore = englishScore;  
121     }  
122   
123     public Float getMathScore() {  
124         return mathScore;  
125     }  
126   
127     public void setMathScore(Float mathScore) {  
128         this.mathScore = mathScore;  
129     }  
130   
131     public Date getBirthdayTime() {  
132         return birthdayTime;  
133     }  
134   
135     public void setBirthdayTime(Date birthdayTime) {  
136         this.birthdayTime = birthdayTime;  
137     }  
138   
139     public Date getBirthdayDate() {  
140         return birthdayDate;  
141     }  
142   
143     public void setBirthdayDate(Date birthdayDate) {  
144         this.birthdayDate = birthdayDate;  
145     }  
146   
147     public Date getBirthday() {  
148         return birthday;  
149     }  
150   
151     public void setBirthday(Date birthday) {  
152         this.birthday = birthday;  
153     }  
154   
155     public byte[] getInfo() {  
156         return info;  
157     }  
158   
159     public void setInfo(byte[] info) {  
160         this.info = info;  
161     }  
162   
163     public String getTransientProperty() {  
164         return transientProperty;  
165     }  
166   
167     public void setTransientProperty(String transientProperty) {  
168         this.transientProperty = transientProperty;  
169     }  175       
176 }  

【EntityManger 常用API 使用方法:Test_PersonEntity.java】

  1 package org.zgf.jpa.entity;  
  2   
  3 import java.util.ArrayList;  
  4 import java.util.Date;  
  5 import java.util.List;  
  6   
  7 import javax.persistence.Query;  
  8   
  9 import org.junit.Test;  
 10 import org.zgf.jpa.enumer.Gender;  
 11 /** 
 12  * @Description: 主要测试EntityManager类提供的常用接口 
 13  * @author zonggf 
 14  * @date 2015年11月4日-下午3:38:14 
 15  */  
 16 public class Test_PersonEntity extends BasicJPATest {  
 17       
 18     private PersonEntity getPersonEntity(){  
 19         Date date = new Date();  
 20         PersonEntity person = new PersonEntity();  
 21         person.setName("zhangsan");  
 22         person.setAge(20);  
 23         person.setBirthday(date);  
 24         person.setBirthdayDate(date);  
 25         person.setBirthdayTime(date);  
 26         person.setEnglishScore(20.20);  
 27         person.setMathScore(89.8f);  
 28         person.setGender(Gender.BOY);  
 29         StringBuffer sb = new StringBuffer();  
 30         for(int i=0; i<100;i++){  
 31             sb.append("heladn asndsk nasfjgnas nsd gaksn a sdnkg asdn asndk asnd  ansf asd n  asngjka s");  
 32         }  
 33         person.setInfo(sb.toString().getBytes());  
 34         return person;  
 35     }  
 36       
 37     //Test API 1: 测试persiste  
 38     @Test  
 39     public void test_persist(){  
 40         PersonEntity personEntity = getPersonEntity();  
 41         this.entityManager.persist(personEntity);  
 42     }  
 43       
 44     //Test API 2:测试remove接口  
 45     @Test  
 46     public void test_remove_right(){  
 47         //正确删除方式,必须先从数据库中查询,然后再进行删除,而且查询结果不能为空  
 48         PersonEntity personEntity = new PersonEntity();  
 49         personEntity.setId(3);  
 50         personEntity = this.entityManager.find(PersonEntity.class, personEntity.getId());  
 51         if(null != personEntity){  
 52             this.entityManager.remove(personEntity);;  
 53         }  
 54     }  
 55       
 56     //Test API 2:测试remove接口  
 57     @Test(expected=java.lang.IllegalArgumentException.class)  
 58     public void test_remove_wrong(){  
 59         //如果是自己创建的实体 对象,使用remove方式的时候,将会报错  
 60         PersonEntity personEntity = getPersonEntity();  
 61         personEntity.setId(3);  
 62         this.entityManager.remove(personEntity);;  
 63     }  
 64       
 65     //Test API 3:测试mege 接口  
 66     @Test  
 67     public void test_merge(){  
 68         //先根据主键进行查询,然后根据主键进行更新  
 69         PersonEntity personEntity = getPersonEntity();  
 70         personEntity.setId(7);  
 71         personEntity.setName("zhangsan_merge" + 172);  
 72         this.entityManager.merge(personEntity);  
 73     }  
 74       
 75     //Test API 4:测试find 接口  
 76     @Test  
 77     public void test_find(){  
 78         //find 方法,是根据主键进行查询的,所以传的参数必须是主键  
 79         int id = 5;  
 80         PersonEntity person = this.entityManager.find(PersonEntity.class, id);  
 81         System.out.println(person);  
 82     }  
 83       
 84       
 85     //Test API 5:测试createQuery(String jpql)接口  
 86     @Test  
 87     public void test_createQuery_String(){  
 88         String jpql = "from PersonEntity personEntity";  
 89         Query query = this.entityManager.createQuery(jpql);  
 90         List<PersonEntity> personList = query.getResultList();  
 91         for (PersonEntity personEntity : personList) {  
 92             System.out.println(personEntity);  
 93         }  
 94     }  
 95       
 96     //Test API 6:测试命名查询  
 97     @Test  
 98     public void test_namedQuery_jpql(){  
 99         String namedQueryName = "queryByName";  
100         Query query = this.entityManager.createNamedQuery(namedQueryName);  
101         //设置命名参数  
102         query.setParameter("name", "zhangsan");  
103         PersonEntity person = (PersonEntity) query.getSingleResult();  
104         System.out.println(person);  
105     }  
106       
107     //Test API 7:测试createNativeQuery(String sql)接口  
108     @Test  
109     public void test_sqlQuery(){  
110         List<PersonEntity> personList = new ArrayList<>();  
111         String sql = "select p.id, p.s_name, p.age from tb_person p";  
112         Query query = this.entityManager.createNativeQuery(sql);  
113         List list = query.getResultList();  
114         for(int i=0;i<list.size(); i++){  
115             PersonEntity person = new PersonEntity();  
116             Object[] objectArray = (Object[]) list.get(i);  
117             person.setId((Integer)objectArray[0]);  
118             person.setName((String)objectArray[1]);  
119             person.setAge((Integer)objectArray[2]);  
120             personList.add(person);  
121         }  
122         for(PersonEntity personEntity: personList){  
123             System.out.println(personEntity);  
124         }  
125     }  
126 }  

【辅助类:Gender.java】

 1 package org.zgf.jpa.enumer;  
 2 /** 
 3  * @Description: 枚举类,映射到数据库中的是BOY 而不是"男" 
 4  * @author zonggf 
 5  * @date 2015年11月4日-下午3:39:36 
 6  */  
 7 public enum Gender {  
 8   
 9     BOY("男"),GIRL("女");  
10       
11     private String gender;  
12       
13     Gender(String gender){  
14         this.gender = gender;  
15     }  
16       
17     public static Gender getGender(String gender){  
18         Gender[] genderEnumers = Gender.values();  
19         for (Gender genderEnumer : genderEnumers) {  
20             if(null != gender){  
21                 if(gender.equals(genderEnumer.toString())){  
22                     return genderEnumer;  
23                 }  
24             }  
25         }  
26         return null;  
27     }  
28       
29     @Override  
30     public String toString() {  
31         return this.gender;  
32     }  
33 }  

【辅助类:BasicJPATest.java】

 1 package org.zgf.jpa.entity;  
 2   
 3   
 4 import javax.persistence.EntityManager;  
 5 import javax.persistence.EntityManagerFactory;  
 6 import javax.persistence.Persistence;  
 7 import javax.persistence.Query;  
 8   
 9 import org.junit.After;  
10 import org.junit.Before;  
11 import org.junit.Test;  
12 /** 
13  * 这是一个JPA 的测试类,  该类的功能如下: 
14  * 1. 在每个测试方法之前调用setup 方法,开启事务并获取entityManager 对象。 
15  * 2. 在每个测试方法之后调用teardown 方法, 提交事务,并关闭entityManager 对象 
16  * @author Silence 
17  */  
18 public abstract class BasicJPATest {  
19     protected EntityManagerFactory entityManagerFactory;  
20     protected EntityManager entityManager;  
21           
22     //子类的每个测试方法之前都会调用  
23     @Before  
24     public void setup(){  
25         this.entityManagerFactory = Persistence.createEntityManagerFactory("myJPA");  
26         this.entityManager = this.entityManagerFactory.createEntityManager();  
27         this.entityManager.getTransaction().begin();  
28     }  
29       
30     //子类的每个测试方法之后都会调用  
31     @After  
32     public void tearDown(){  
33         try{  
34             this.entityManager.getTransaction().commit();  
35         }catch(Exception ex){  
36             System.out.println("提交事务等阶段出现了错误哦");  
37         }finally{  
38             this.entityManager.close();  
39             this.entityManagerFactory.close();  
40         }  
41           
42     }  
43       
44     @Test  
45     public void testCreateTables(){  
46         System.out.println("数据库表创建成功。。。");  
47     }  
48       
49     public void recoverData(){  
50         //清空表  
51         String deleteSql = "delete Person";  
52         Query query = this.entityManager.createQuery(deleteSql);  
53         query.executeUpdate();  
54           
55     }  
56 }  

【注意】

1. @Basic(fetch=FetchType.LAZY) 注解在Hibernate 中不能实现,貌似是Hibernate 的一个bug

2. @Enumerated(EnumType.STRING) 注解映射的是枚举类的Key ,不是value

posted @ 2018-01-31 11:31  BeforeYou  阅读(679)  评论(0编辑  收藏  举报