【Query 接口下的經常使用API】java
【API 測試類:Test_QueryAPI.java】mysql
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
位置參數:執行效率高, 可讀性差,可用於原生sql 和 JPQL 語句中, 格式《?+數字》,數字可任意指定 也能夠不指定,直接用問號
命名參數:執行效率低 ,可讀性強,可用於原生sql 和 JPQL 語句中, 格式《:+ 名稱》,名稱自定義數據庫
2. query.getSigleResult(); 方法必須確保查詢結果有且只有一個放回對象。數組
3. query.excuteUpdate();方法可用於執行更新,刪除語句app
【經常使用註解】框架
使用JPA 指定映射關係時,有兩種方式,一種是使用xml 方式,另外一種是註解方式,筆者推薦使用註解方式。在JPA 映射簡單實體時,經常使用的註解以下:ide
@Entity:修飾實體類對象,表示該實體類對象進行數據庫映射測試
@Table(name="***"):指定實體類對象映射的表名稱fetch
@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