【常用注解】
使用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 语句。
【JPA 常用API】
【简单实体对象:PersonEntity.java】
package org.zgf.jpa.entity;
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.GenerationType;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;
import org.zgf.jpa.enumer.Gender;
@Table(name="tb_person")
@Entity
@NamedQueries({ //命名查询注解:只能写JPQL 语句
@NamedQuery(name="queryAllByJpql",query="from PersonEntity personEntity"),
@NamedQuery(name="queryByName",query="from PersonEntity personEntity where personEntity.name = :name")
})
public class PersonEntity {
/**
* 测试主键生成策略
* GenerationType.AUTO: 根据数据库的默认规则来生成主键
* GenerationType.IDENTITY:数据库自增(mysql 适用,Oracle不适用)
* GenerationType.SEQUENCE:序列生成方式,(Oracle适用,mysql 不适用)
*/
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
/***
* 数据库字段限制:
* Column可以指定数据库 字段的名称 ,长度,唯一性,是否可以为空,是否可以插入,是否可以更新
*/
@Column(name="s_name",length=20,unique=true,nullable=false, insertable=true, updatable=true)
private String name;
private int age;
/**
* 枚举类型:
* EnumType.STRING: 指定数据库中存储的是字符串类型
* EnumTypee.ORDINAL:指定数据库 存储的类型为枚举的索引
*/
@Enumerated(EnumType.STRING)
private Gender gender;
private Double englishScore;
private Float mathScore;
/**
* 日期类型: TimeStamp 会根据当地的时间做自动转换
* TemporalType.DATE: 指定映射数据库中的DATE 类型,只存储日期
* TemporalType.TIME: 指定映射数据库 中的TIME类型, 只存储时间
* TemporalType.TIMESTAMP:指定映射数据库中的TIMESTAMP类型
*/
@Temporal(TemporalType.TIME)
private Date birthdayTime;
@Temporal(TemporalType.DATE)
private Date birthdayDate;
@Temporal(TemporalType.TIMESTAMP)
private Date birthday;
@Lob //大数据文件
@Basic(fetch=FetchType.LAZY, optional=true) //延迟加载为true,貌似是Hibernate的一个bug,并不能实现延迟加载
private byte[] info;
@Transient //不映射 此字段
private String transientProperty;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Gender getGender() {
return gender;
}
public void setGender(Gender gender) {
this.gender = gender;
}
public Double getEnglishScore() {
return englishScore;
}
public void setEnglishScore(Double englishScore) {
this.englishScore = englishScore;
}
public Float getMathScore() {
return mathScore;
}
public void setMathScore(Float mathScore) {
this.mathScore = mathScore;
}
public Date getBirthdayTime() {
return birthdayTime;
}
public void setBirthdayTime(Date birthdayTime) {
this.birthdayTime = birthdayTime;
}
public Date getBirthdayDate() {
return birthdayDate;
}
public void setBirthdayDate(Date birthdayDate) {
this.birthdayDate = birthdayDate;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public byte[] getInfo() {
return info;
}
public void setInfo(byte[] info) {
this.info = info;
}
public String getTransientProperty() {
return transientProperty;
}
public void setTransientProperty(String transientProperty) {
this.transientProperty = transientProperty;
}
@Override
public String toString() {
return "PersonEntity [id=" + id + ", name=" + name + ", age=" + age + ", gender=" + gender + ", englishScore=" + englishScore + ", mathScore=" + mathScore + ", birthdayTime=" + birthdayTime + ", birthdayDate=" + birthdayDate + ", birthday=" + birthday + ", transientProperty=" + transientProperty + "]";
}
}
【EntityManger 常用API 使用方法:Test_PersonEntity.java】
package org.zgf.jpa.entity;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.persistence.Query;
import org.junit.Test;
import org.zgf.jpa.enumer.Gender;
/**
* @Description: 主要测试EntityManager类提供的常用接口
* @author zonggf
* @date 2015年11月4日-下午3:38:14
*/
public class Test_PersonEntity extends BasicJPATest {
private PersonEntity getPersonEntity(){
Date date = new Date();
PersonEntity person = new PersonEntity();
person.setName("zhangsan");
person.setAge(20);
person.setBirthday(date);
person.setBirthdayDate(date);
person.setBirthdayTime(date);
person.setEnglishScore(20.20);
person.setMathScore(89.8f);
person.setGender(Gender.BOY);
StringBuffer sb = new StringBuffer();
for(int i=0; i<100;i++){
sb.append("heladn asndsk nasfjgnas nsd gaksn a sdnkg asdn asndk asnd ansf asd n asngjka s");
}
person.setInfo(sb.toString().getBytes());
return person;
}
//Test API 1: 测试persiste
@Test
public void test_persist(){
PersonEntity personEntity = getPersonEntity();
this.entityManager.persist(personEntity);
}
//Test API 2:测试remove接口
@Test
public void test_remove_right(){
//正确删除方式,必须先从数据库中查询,然后再进行删除,而且查询结果不能为空
PersonEntity personEntity = new PersonEntity();
personEntity.setId(3);
personEntity = this.entityManager.find(PersonEntity.class, personEntity.getId());
if(null != personEntity){
this.entityManager.remove(personEntity);;
}
}
//Test API 2:测试remove接口
@Test(expected=java.lang.IllegalArgumentException.class)
public void test_remove_wrong(){
//如果是自己创建的实体 对象,使用remove方式的时候,将会报错
PersonEntity personEntity = getPersonEntity();
personEntity.setId(3);
this.entityManager.remove(personEntity);;
}
//Test API 3:测试mege 接口
@Test
public void test_merge(){
//先根据主键进行查询,然后根据主键进行更新
PersonEntity personEntity = getPersonEntity();
personEntity.setId(7);
personEntity.setName("zhangsan_merge" + 172);
this.entityManager.merge(personEntity);
}
//Test API 4:测试find 接口
@Test
public void test_find(){
//find 方法,是根据主键进行查询的,所以传的参数必须是主键
int id = 5;
PersonEntity person = this.entityManager.find(PersonEntity.class, id);
System.out.println(person);
}
//Test API 5:测试createQuery(String jpql)接口
@Test
public void test_createQuery_String(){
String jpql = "from PersonEntity personEntity";
Query query = this.entityManager.createQuery(jpql);
List<PersonEntity> personList = query.getResultList();
for (PersonEntity personEntity : personList) {
System.out.println(personEntity);
}
}
//Test API 6:测试命名查询
@Test
public void test_namedQuery_jpql(){
String namedQueryName = "queryByName";
Query query = this.entityManager.createNamedQuery(namedQueryName);
//设置命名参数
query.setParameter("name", "zhangsan");
PersonEntity person = (PersonEntity) query.getSingleResult();
System.out.println(person);
}
//Test API 7:测试createNativeQuery(String sql)接口
@Test
public void test_sqlQuery(){
List<PersonEntity> personList = new ArrayList<>();
String sql = "select p.id, p.s_name, p.age from tb_person p";
Query query = this.entityManager.createNativeQuery(sql);
List list = query.getResultList();
for(int i=0;i<list.size(); i++){
PersonEntity person = new PersonEntity();
Object[] objectArray = (Object[]) list.get(i);
person.setId((Integer)objectArray[0]);
person.setName((String)objectArray[1]);
person.setAge((Integer)objectArray[2]);
personList.add(person);
}
for(PersonEntity personEntity: personList){
System.out.println(personEntity);
}
}
}
【辅助类:Gender.java】
package org.zgf.jpa.enumer;
/**
* @Description: 枚举类,映射到数据库中的是BOY 而不是"男"
* @author zonggf
* @date 2015年11月4日-下午3:39:36
*/
public enum Gender {
BOY("男"),GIRL("女");
private String gender;
Gender(String gender){
this.gender = gender;
}
public static Gender getGender(String gender){
Gender[] genderEnumers = Gender.values();
for (Gender genderEnumer : genderEnumers) {
if(null != gender){
if(gender.equals(genderEnumer.toString())){
return genderEnumer;
}
}
}
return null;
}
@Override
public String toString() {
return this.gender;
}
}
【辅助类:BasicJPATest.java】
package org.zgf.jpa.entity;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
/**
* 这是一个JPA 的测试类, 该类的功能如下:
* 1. 在每个测试方法之前调用setup 方法,开启事务并获取entityManager 对象。
* 2. 在每个测试方法之后调用teardown 方法, 提交事务,并关闭entityManager 对象
* @author Silence
*/
public abstract class BasicJPATest {
protected EntityManagerFactory entityManagerFactory;
protected EntityManager entityManager;
//子类的每个测试方法之前都会调用
@Before
public void setup(){
this.entityManagerFactory = Persistence.createEntityManagerFactory("myJPA");
this.entityManager = this.entityManagerFactory.createEntityManager();
this.entityManager.getTransaction().begin();
}
//子类的每个测试方法之后都会调用
@After
public void tearDown(){
try{
this.entityManager.getTransaction().commit();
}catch(Exception ex){
System.out.println("提交事务等阶段出现了错误哦");
}finally{
this.entityManager.close();
this.entityManagerFactory.close();
}
}
@Test
public void testCreateTables(){
System.out.println("数据库表创建成功。。。");
}
public void recoverData(){
//清空表
String deleteSql = "delete Person";
Query query = this.entityManager.createQuery(deleteSql);
query.executeUpdate();
}
}
【注意】
1. @Basic(fetch=FetchType.LAZY) 注解在Hibernate 中不能实现,貌似是Hibernate 的一个bug
2. @Enumerated(EnumType.STRING) 注解映射的是枚举类的Key ,不是value