jpa
一、概述
java persistence api,jpa,是sun提出的java持久化规范。它提供了一种orm工具来管理java应用中的关系数据。jpa的总体思想和常见的orm框架大体一致。包括3方面的技术,orm映射元数据,支持xml和jdk5.0注解两种元数据的形式,元数据描述对象和表之间的映射关系,框架根据元元数据将实体对象持久化到数据表中;持久化api,用来操作实体对象,执行crud操作;查询语言,通过面向对象而不是面向数据库的查询语言查询数据。
二、入门案例
基于hibernate的案例。
步骤:
1.创建一个java工程jpaabc
2.自定义个jar库,放相关的jar
add library>user libray>user libraries>new>取个名字>add external jars>选择jar文件,注意路径中不要中文或空格>ok>finish
3.在src文件夹下创建META-INF文件夹,编写persistence.xml配置文件,文件名是固定的这个。
<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_2_0.xsd"
version="2.0">
<persistence-unit name="jpaabc" transaction-type="RESOURCE_LOCAL" >
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect">
<property name="hibernate.hbm2ddl.auto" value="update">
<property name="hibernate.connection.driver_class" value="org.gjt.mm.mysql.Driver">
<property name="hibernate.connection.username" value="root">
<property name="hibernate.connection.password" value="1234">
<property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/jpa20181110? characterEncoding=UTF-8">
</properties>
</persistence-unit>
</persistence>
4.编写实体类
**
* person实体bean
*
* @author Administrator
*
*/
@Entity
@Table(name = "t_person")
public class Person {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "person_name", length = 10, nullable = false)
private String name;
@Column(name = "birthday")
@Temporal(TemporalType.DATE) // 指定时间的格式
private Date birthday;
@Enumerated(EnumType.STRING)
@Column(name = "gendar", length = 6, nullable = false)
private Gendar gendar;
@Lob
private String info;
@Lob
@Basic(fetch = FetchType.LAZY) // 对于大文件属性字段延迟加载,优化性能
private Byte[] file;
@Transient
private String picture;
// 提供无参构造函数,供反射创建对象
public Person() {
}
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 Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public Gendar getGendar() {
return gendar;
}
public void setGendar(Gendar gendar) {
this.gendar = gendar;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
public Byte[] getFile() {
return file;
}
public void setFile(Byte[] file) {
this.file = file;
}
public String getPicture() {
return picture;
}
public void setPicture(String picture) {
this.picture = picture;
}
@Override
public String toString() {
return "Person [id=" + id + ", name=" + name + ", birthday=" + birthday + ", gendar=" + gendar + ", info="
+ info + ", file=" + Arrays.toString(file) + ", picture=" + picture + "]";
}
}
5.测试
/**
* jpa测试类
*
* @author Administrator
*
*/
public class PersonTest {
/**
* 测试保存
*/
@Test
public void save() {
// 创建实体类管理工厂
EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpaabc");
// 创建实体管理类
EntityManager manager = emf.createEntityManager();
// 获取事务管理类
EntityTransaction transaction = manager.getTransaction();
// 开启事务
transaction.begin();
// 提供存入的数据
Person person = new Person();
person.setName("张三");
person.setBirthday(new Date());
person.setGendar(Gendar.FEMALE);
person.setInfo("介绍下自己");
// 使用保存方法
manager.persist(person);
// 提交事务
transaction.commit();
// 关闭管理类
manager.close();
// 关闭工厂
emf.close();
}
/**
* 测试获取
*/
@Test
public void findPerson1() {
// 创建实体类管理工厂
EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpaabc");
// 创建实体管理类
EntityManager manager = emf.createEntityManager();
// 查找,find方法相当于hibernate的get方法
Person person = manager.find(Person.class, 1);
System.out.println(person);
// 关闭管理类
manager.close();
// 关闭工厂
emf.close();
}
/**
* 测试获取
*/
@Test
public void findPerson2() {
// 创建实体类管理工厂
EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpaabc");
// 创建实体管理类
EntityManager manager = emf.createEntityManager();
// 查找,find方法相当于hibernate的load方法,只有在session关闭之前,第一次访问对象的属性时,才加载对象
// 第二个特点是,如果查询的数据不存在,则报出实体没找到异常
Person person = manager.getReference(Person.class, 2);
System.out.println(person);
// 关闭管理类
manager.close();
// 关闭工厂
// 如果关闭对象后,才第一次访问对象,则报出延迟加载异常
// System.out.println(person.getName());
emf.close();
}
/**
* 测试获取
*/
@Test
public void updatePerson() {
// 创建实体类管理工厂
EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpaabc");
// 创建实体管理类
EntityManager manager = emf.createEntityManager();
// 获取事务管理类
EntityTransaction transaction = manager.getTransaction();
// 开启事务
transaction.begin();
// 现获取要更新的对象
Person person = manager.find(Person.class, 1);
person.setName("李四");
// 由于orm的持久对象的托管态的批处理机制,当关闭session时,可以自动更新数据到数据库
// manager.persist(person);
// System.out.println(person);
// 提交事务
transaction.commit();
// 关闭管理类
manager.close();
// 关闭工厂
emf.close();
}
/**
* 测试获取,游离态的实体对象,不能更新数据库
*/
@Test
public void updatePerson2() {
// 创建实体类管理工厂
EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpaabc");
// 创建实体管理类
EntityManager manager = emf.createEntityManager();
// 获取事务管理类
EntityTransaction transaction = manager.getTransaction();
// 开启事务
transaction.begin();
// 现获取要更新的对象
Person person = manager.find(Person.class, 1);
// 清楚实体管理器内的所有实体,也就是置为游离态
manager.clear();
person.setName("李五");
// 由于orm的持久对象的托管态的批处理机制,当关闭session时,可以自动更新数据到数据库
// manager.persist(person);
// System.out.println(person);
// 调用管理器的merge方法,将游离态的实体对象同步回管理器,可以将更新的数据到数据库
manager.merge(person);
// 提交事务
transaction.commit();
// 关闭管理类
manager.close();
// 关闭工厂
emf.close();
}
/**
* 测试删除
*/
@Test
public void deletePerson() {
// 创建实体类管理工厂
EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpaabc");
// 创建实体管理类
EntityManager manager = emf.createEntityManager();
// 获取事务管理类
EntityTransaction transaction = manager.getTransaction();
// 开启事务
transaction.begin();
// 现获取要删除的对象
Person person = manager.find(Person.class, 1);
// 删除对象
manager.remove(person);
// 提交事务
transaction.commit();
// 关闭管理类
manager.close();
// 关闭工厂
emf.close();
}
}
关于refresh方法,当用户通过find方法获取一条数据,在操作一条数据库期间,如果有另一个用户也操作修改了这条数据。那么,前面那个操作的用户,通过find方法是不能获取这条数据的最新数据的。因为,entitymanagy会把用户第一次find获取的数据结果放在一级缓存,如果后面又find一次,也是从一级缓存取得数据,而不是数据库。这时,使用refresh方法,这条数据,可以从数据库获取最新的数据结果。
三、jpa查询语句
使用上面入门案例的项目,在测试类中测试
/**
* jpa测试类
*
* @author Administrator
*
*/
public class PersonTest {
/**
* 测试查询语句
*/
@Test
public void query() {
// 创建实体类管理工厂
EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpaabc");
// 创建实体管理类
EntityManager manager = emf.createEntityManager();
// 查询语句
Query query = manager.createQuery("select p from Person p where p.id = ?1");
query.setParameter(1, 2);
// 获取查询结果
// List<Person> list = query.getResultList();
// System.out.println(list);
// 获取查询结果
Person person = (Person) query.getSingleResult();
System.out.println(person);
// 关闭管理类
manager.close();
// 关闭工厂
emf.close();
}
/**
* 测试使用查询语句删除
*/
@Test
public void querydelete() {
// 创建实体类管理工厂
EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpaabc");
// 创建实体管理类
EntityManager manager = emf.createEntityManager();
// 开启事务
manager.getTransaction().begin();
// 查询语句
Query query = manager.createQuery("delete from Person p where p.id = ?1");
query.setParameter(1, 2);
// 执行更新
query.executeUpdate();
// 提交事务
manager.getTransaction().commit();
// 关闭管理类
manager.close();
// 关闭工厂
emf.close();
}
/**
* 测试使用查询语句更新
*/
@Test
public void queryupdate() {
// 创建实体类管理工厂
EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpaabc");
// 创建实体管理类
EntityManager manager = emf.createEntityManager();
// 开启事务
manager.getTransaction().begin();
// 查询语句
Query query = manager.createQuery("update Person p set p.name=:name where p.id=:id");
query.setParameter("name", "马六");
query.setParameter("id", 3);
// 执行更新
query.executeUpdate();
// 提交事务
manager.getTransaction().commit();
// 关闭管理类
manager.close();
// 关闭工厂
emf.close();
}
}
四、一对多双向关联
jpa规范,一对多双向关联中,多方为关系维护端,负责外键记录的更新删除,关系被维护端没有维护外键字段的权利。
一方中的设置:
常用级联操作,类型有CascadeType.REFRESH, CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE。只有调用对应的方法,才能发生相应的级联操作,比如调用persist方法,设置的CascadeType.PERSIST起作用。
延迟加载设置,fetch=FetchType.LAZY。使用延迟加载,当获取了一方的数据时,不会立即获取到多方的数据,只有当操作多方数据才会获取多方的数据,前提是entitymanager没有被关闭。如果entitymanager被关闭了,那么会报出异常。如果是一对多,或者多对多,就是当对多时,加载方式的默认值是lazy,即延迟加载,目的是潜在提高效率。
设置关系的被维护端,指明是这个类中的哪个属性来被维护,也就是多方的类中的一方类对象定义的属性。使用mappedBy来设置。 mappedBy = "order",设置被维护端为这个对象的属性是order。
多方中的设置:
级联设置,一般不设置保存和删除,设置更新和刷新就可以。
加载设置,多对一,默认是立即加载。
可选性,optional,如果为true,那么外键值在表中可以为null;如果为false,则外键值在数据表中非空。
设置外键字段名称,@JoinColumn(name = "order_id")
例子,订单表和订单明细表的一对多关系案例
创建java项目,导入jar包,编写persistence.xml文件
编写order实体类
/**
* 订单实体类
*
* @author Administrator
*
*/
@Entity
@Table(name = "orders")
public class Order {
@Id
@Column(length = 32)
private String orderId;
@Column(nullable = false)
private Float totalPrice = 0f;
@OneToMany(cascade = { CascadeType.REFRESH, CascadeType.PERSIST, CascadeType.MERGE,
CascadeType.REMOVE }, fetch = FetchType.LAZY, mappedBy = "order") // 默认就是懒加载,可以不设置延迟
private Set<OrderItem> orderItems = new HashSet<OrderItem>();
public String getOrderId() {
return orderId;
}
public void setOrderId(String orderId) {
this.orderId = orderId;
}
public Float getTotalPrice() {
return totalPrice;
}
public void setTotalPrice(Float totalPrice) {
this.totalPrice = totalPrice;
}
public Set<OrderItem> getOrderItems() {
return orderItems;
}
public void setOrderItems(Set<OrderItem> orderItems) {
this.orderItems = orderItems;
}
}
订单明细实体类
/**
* 订单项实体类
*
* @author Administrator
*
*/
@Entity
@Table(name = "orderItem")
public class OrderItem {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(length = 64, nullable = false)
private String itemName;
@Column(nullable = false)
private Float price = 0f;
@ManyToOne(cascade = { CascadeType.MERGE, CascadeType.REFRESH }, optional = false)
@JoinColumn(name = "order_id")
private Order order;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getItemName() {
return itemName;
}
public void setItemName(String itemName) {
this.itemName = itemName;
}
public Float getPrice() {
return price;
}
public void setPrice(Float price) {
this.price = price;
}
public Order getOrder() {
return order;
}
public void setOrder(Order order) {
this.order = order;
}
}
测试,添加订单,级联保存订单明细
/**
* 测试一对多关联
*
* @author Administrator
*
*/
public class One2ManyTest {
@Test
public void testSave() {
// 获取实体管理工厂
EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpaone2many");
// 获取管理类
EntityManager manager = emf.createEntityManager();
// 获取事务管理对象
EntityTransaction transactionManager = manager.getTransaction();
// 开启事务
transactionManager.begin();
// 准备数据
Order order = new Order();
OrderItem item1 = new OrderItem();
item1.setItemName("硬盘");
item1.setPrice(120f);
item1.setOrder(order);
OrderItem item2 = new OrderItem();
item2.setItemName("内存卡");
item2.setPrice(20f);
item2.setOrder(order);
OrderItem item3 = new OrderItem();
item3.setItemName("线卡");
item3.setPrice(220f);
item3.setOrder(order);
order.setTotalPrice(item1.getPrice() + item2.getPrice() + item3.getPrice());
Set<OrderItem> items = new HashSet<>();
items.add(item1);
items.add(item2);
items.add(item3);
order.setOrderItems(items);
// 设置id
String id = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
id = id + "_" + UUID.randomUUID().toString().substring(0, 10);
order.setOrderId(id);
// 因为在一方设置了级联保存,所以保存一方就保存了多方
manager.persist(order);
// 提交事务
transactionManager.commit();
// 关闭管理类
manager.close();
// 关闭工厂
emf.close();
}
}
五、一对一双向关联
被维护端的设置:
需要在OneToOne注解中,设置mappedBy,设置维护方类中被维护方属性的值,比如,mappedBy = "idCard"。级联根据业务需要设置。
维护端的设置:
在OneToOne注解中,设置optional为false。级联根据需要设置。
人和身份证一对一的案例。
人实体类
/**
* 人的实体类
*
* @author Administrator
*
*/
@Entity
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(length = 16, nullable = false)
private String name;
@OneToOne(optional = false, cascade = CascadeType.ALL)
@JoinColumn(name = "idcard_id")
private IDCard idCard;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public IDCard getIdCard() {
return idCard;
}
public void setIdCard(IDCard idCard) {
this.idCard = idCard;
}
}
身份证实体类
/**
* 身份证实体类
*
* @author Administrator
*
*/
@Entity
public class IDCard {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(length = 18, nullable = false)
private String idNumber;
@OneToOne(mappedBy = "idCard", cascade = { CascadeType.PERSIST, CascadeType.MERGE,
CascadeType.REFRESH }, optional = false)
private Person person;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getIdNumber() {
return idNumber;
}
public void setIdNumber(String idNumber) {
this.idNumber = idNumber;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
}
注意,作为被维护端的实体中,optional = false,可以省略,因为维护端已经设置了外键。
测试
/**
* 测试一对一双向关联
* @author Administrator
*
*/
public class One2OneTest {
@Test
public void save() {
// 准备数据
Person person = new Person();
person.setName("张思");
IDCard idCard = new IDCard();
idCard.setPerson(person);
String idnumber = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
idCard.setIdNumber(idnumber);
person.setIdCard(idCard);
// 获取工厂
EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpaone2one");
// 获取管理类
EntityManager manager = emf.createEntityManager();
// 开启事务
manager.getTransaction().begin();
// 保存人
manager.persist(person);
// 提交事务
manager.getTransaction().commit();
// 关闭管理类
manager.close();
// 关闭工厂
emf.close();
}
}
六、多对多双向关联
被维护端的设置:
级联设置,根据业务要求,慎重设置级联删除。
使用mappedBy,设置被维护端。
加载,对端默认是懒加载,可以不设置。
维护端设置:
级联设置,根据需要,慎重级联删除。
设置中间表,比如,@JoinTable(name = "student_teacher", inverseJoinColumns = @JoinColumn(name = "teacher_id"), joinColumns = @JoinColumn(name = "student_id"))
关系维护端可以操作外键,关系被维护端没有权力修改外键。
学生和老师的多对多案例
学生实体类
/**
* 学生实体类
*
* @author Administrator
*
*/
@Entity
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(length = 16, nullable = false)
private String name;
@ManyToMany(cascade = CascadeType.REFRESH)
@JoinTable(name = "student_teacher", inverseJoinColumns = @JoinColumn(name = "teacher_id"), joinColumns = @JoinColumn(name = "student_id"))
private Set<Teacher> teachers = new HashSet<Teacher>();
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 Set<Teacher> getTeachers() {
return teachers;
}
public void setTeachers(Set<Teacher> teachers) {
this.teachers = teachers;
}
/**
* 添加教师
*/
public void addTeacher(Teacher teacher) {
this.teachers.add(teacher);
}
/**
* 删除教师
*/
public void removeTeacher(Teacher teacher) {
if (this.teachers.contains(teacher)) {
this.teachers.remove(teacher);
}
}
}
教师实体类
/**
* 教师实体类
*
* @author Administrator
*
*/
@Entity
public class Teacher {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(length = 16, nullable = false)
private String name;
@ManyToMany(cascade = CascadeType.REFRESH, mappedBy = "teachers")
private Set<Student> students = new HashSet<Student>();
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 Set<Student> getStudents() {
return students;
}
public void setStudents(Set<Student> students) {
this.students = students;
}
/**
* 重写hashCode和equals方法
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Teacher other = (Teacher) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
}
测试
/**
* 多对多关联测试
*
* @author Administrator
*
*/
public class Many2ManyTest {
/**
* 添加学生和老师
*/
@Test
public void save() {
// 获取工厂
EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpamany2many");
// 获取管理类
EntityManager manager = emf.createEntityManager();
// 开启事务
manager.getTransaction().begin();
// 准备数据
Teacher teacher1 = new Teacher();
teacher1.setName("张师");
Teacher teacher2 = new Teacher();
teacher2.setName("李师");
Teacher teacher3 = new Teacher();
teacher3.setName("王师");
Student student1 = new Student();
student1.setName("刘雪");
Student student2 = new Student();
student2.setName("孙雪");
manager.persist(teacher1);
manager.persist(teacher2);
manager.persist(teacher3);
manager.persist(student1);
manager.persist(student2);
// 提交事务
manager.getTransaction().commit();
// 关闭管理类
manager.close();
// 关闭工厂
emf.close();
}
/**
* 建立学生和老师的关系
*/
@Test
public void setStudentAndTeacher() {
// 获取工厂
EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpamany2many");
// 获取管理类
EntityManager manager = emf.createEntityManager();
// 开启事务
manager.getTransaction().begin();
// 获取要建立关系的学生
Student student1 = manager.find(Student.class, 1);
Student student2 = manager.find(Student.class, 2);
// 获取要建立关系的老师
Teacher teacher1 = manager.find(Teacher.class, 1);
Teacher teacher2 = manager.find(Teacher.class, 2);
Teacher teacher3 = manager.find(Teacher.class, 3);
// 为学生添加老师
student1.addTeacher(teacher1);
student1.addTeacher(teacher2);
student2.addTeacher(teacher2);
student2.addTeacher(teacher3);
// 提交事务
manager.getTransaction().commit();
// 关闭管理类
manager.close();
// 关闭工厂
emf.close();
}
/**
* 解除学生和老师的关系
*/
@Test
public void removeTeacherFromStudent() {
// 获取工厂
EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpamany2many");
// 获取管理类
EntityManager manager = emf.createEntityManager();
// 开启事务
manager.getTransaction().begin();
// 获取要建立关系的学生
Student student1 = manager.find(Student.class, 2);
// 获取要建立关系的老师
Teacher teacher1 = manager.find(Teacher.class, 2);
// 为学生解除老师
student1.removeTeacher(teacher1);
// 提交事务
manager.getTransaction().commit();
// 关闭管理类
manager.close();
// 关闭工厂
emf.close();
}
/**
* 删除被维护端数据,直接删除是无法删除的,需要先解除维护端与被维护端的关系,再删除
*/
@Test
public void deleteTeacher() {
// 获取工厂
EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpamany2many");
// 获取管理类
EntityManager manager = emf.createEntityManager();
// 开启事务
manager.getTransaction().begin();
// 获取要删除的对象
Teacher teacher1 = manager.getReference(Teacher.class, 2);
// 先解除关系
Query query = manager.createQuery("select s from Student s");
List<Student> students = query.getResultList();
for (Student student : students) {
student.removeTeacher(teacher1);
}
// 删除老师的数据
manager.remove(teacher1);
// 提交事务
manager.getTransaction().commit();
// 关闭管理类
manager.close();
// 关闭工厂
emf.close();
}
/**
* 删除维护端数据,直接删除即可,不需要手动解除外键约束
*/
@Test
public void deleteStudent() {
// 获取工厂
EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpamany2many");
// 获取管理类
EntityManager manager = emf.createEntityManager();
// 开启事务
manager.getTransaction().begin();
// 获取要删除的对象
Student student = manager.getReference(Student.class, 2);
// 删除学生的数据
manager.remove(student);
// 提交事务
manager.getTransaction().commit();
// 关闭管理类
manager.close();
// 关闭工厂
emf.close();
}
}
七、联合主键
也称复合主键,有的事物,需要通过两个字段来作为主键,比如飞机航线,需要一个发出地和目的地作为主键确定一条航线;一场球赛,需要两个队伍作为主键,确定这场比赛。
需要定义一个复合主键类,要求是:1,有无参构造方法;2,重写hashCode和equals方法;3,继承Serializable接口。类上添加注解@Embeddable,表示可以嵌入到另一个类中。
在使用复合主键的实体类中,将复合主键属性添加注解@EmbeddedId
飞机航线的案例
复合主键类
/**
* 复合主键类
*
* @author Administrator
*
*/
@Embeddable
public class AirlinePK implements Serializable {
@Column(length = 3)
private String originalCity;
@Column(length = 3)
private String destCity;
public AirlinePK() {
}
public String getOriginalCity() {
return originalCity;
}
public void setOriginalCity(String originalCity) {
this.originalCity = originalCity;
}
public String getDestCity() {
return destCity;
}
public void setDestCity(String destCity) {
this.destCity = destCity;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((destCity == null) ? 0 : destCity.hashCode());
result = prime * result + ((originalCity == null) ? 0 : originalCity.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
AirlinePK other = (AirlinePK) obj;
if (destCity == null) {
if (other.destCity != null)
return false;
} else if (!destCity.equals(other.destCity))
return false;
if (originalCity == null) {
if (other.originalCity != null)
return false;
} else if (!originalCity.equals(other.originalCity))
return false;
return true;
}
}
航线实体类
/**
* 航线类
*
* @author Administrator
*
*/
@Entity
public class Airline {
@EmbeddedId
private AirlinePK id;
@Column(length = 32)
private String name;
public AirlinePK getId() {
return id;
}
public void setId(AirlinePK id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
测试
/**
* 测试复合主键类的使用
*
* @author Administrator
*
*/
public class CompositePKTest {
@Test
public void test() {
// 获取工厂
EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpacompositepk");
// 获取管理类
EntityManager manager = emf.createEntityManager();
// 开启事务
manager.getTransaction().begin();
// 准备数据
AirlinePK aPk = new AirlinePK();
aPk.setOriginalCity("pek");
aPk.setDestCity("sha");
Airline airline = new Airline();
airline.setId(aPk);
airline.setName("北京-上海");
manager.persist(airline);
// 提交事务
manager.getTransaction().commit();
// 关闭管理类
manager.close();
// 关闭工厂
emf.close();
}
}