JPA一对多,多对多映射 下载本文

JPA一对多,多对多映射

JPA(Java Persistence API)是Sun官方提出的Java持久化规范。它为Java开发人员提供了一种对象/关系映射工具来管理Java应用中的关系数据。他的出现主要是为了简化现有的持久化开发工作和整合ORM技术

总的来说,JPA包括以下3方面的技术: ORM映射元数据 Java持久化API 查询语言

采用JPA的实现hibernate开发必须的包

hibernate核心包hibernate-distribution-3.3.1.GA hibernate3.jar

lib\\bytecode\\cglib\\hibernate-cglib-repack-2.1_3.jar lib\\required\\*.jar

Hiberante注解包hibernate-annotations-3.4.0.GA hibernate-annotations.jar

lib\\ejb3-persistence.jar、hibernate-commons-annotations.jar Hibernate针对JPA的实现包hibernate-entitymanager-3.4.0.GA hibernate-entitymanager.jar

lib\\test\\log4j.jar、slf4j-log4j12.jar

JPA的配置文件

JPA规范要求在类路径的META-INF目录下放置persistence.xml,文件的名称是固定的,配置模版如下:

http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd\

JPA事务

RESOURCE_LOCAL本地事务、JTA(全局事务)

持久化API EntityManager

persist(Object) 持久化 remove(Object) 删除对象

find(Class entityClass,Object key) 根据主键查询

getReference(Class entityClass,Object key)根据主键查询 flush() 实体与底层同步,执行sql createQuery() 创建JPQL查询对象

createNativeQuery() 根据普通SQL查询

createNamedQuery() 命名查询@NamedQuerie标注

merge(Object) 将一个detached的实体持久化到EntityManager中 close() 关闭管理器

find()与getReference()区别

find()不支持延迟加载,无记录返回NULL

getReference()支持延迟加载,getReference()不会返回null值,而是抛出EntityNotFoundException

javax.persistence.Query

int executeUpdate() 执行更新、删除、添加

Object getSingleResult() 执行查询(返回一条记录) List getResultList() 执行查询(返回结果链表)

Query setParameter(int position,object value) 给Query对象设置参数

Query setMaxResults(int maxResult) 给Query对象设置返回数 分页查询 Query setFirstResult(int firstResult) 给Query对象设置返回偏移

JPA一对多双向

1-m:多的一方为关系维护端,关系维护端负责外键纪录的更新,关系被维护端没有权力更新外键纪录. 维护端注解

拥有mappedBy注解的实体类为关系被维护端,另外的实体类为关系维护端的。顾名思意,关系的维护端对关系(在多对多为中间关联表)的CRUD做操作。关系的被维护端没有该操作,不能维护关系。

@ManyToOne(cascade = { CascadeType.MERGE, CascadeType.REFRESH }, optional = false) @JoinColumn(name = \ 被维护端注解

@OneToMany(cascade = { CascadeType.PERSIST, CascadeType.REFRESH, CascadeType.MERGE, CascadeType.REMOVE },  fetch = FetchType.EAGER,  mappedBy = \

@Entity

@Table(name = \ public class OrderInfo { private Integer id; private String name;

private Set items = new HashSet(); @Id

@GeneratedValue(strategy = GenerationType.AUTO) 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; }

@OneToMany(cascade = { CascadeType.PERSIST, CascadeType.REFRESH,

CascadeType.MERGE, CascadeType.REMOVE }, fetch = FetchType.EAGER, mappedBy = \ public Set getItems() { return items; }

public void setItems(Set items) { this.items = items; }

public void addOrderItem(OrderItem orderItem) { orderItem.setOrder(this); this.items.add(orderItem); } }

@Entity

@Table(name = \ public class OrderItem { private Integer Id; private String name; private OrderInfo order; @Id

@GeneratedValue(strategy = GenerationType.AUTO)

public Integer getId() { return Id; }

public void setId(Integer id) { Id = id; }

@Column(length = 20, nullable = true) public String getName() { return name; }

public void setName(String name) { this.name = name; }

@ManyToOne(cascade = { CascadeType.MERGE, CascadeType.REFRESH }, optional = false) @JoinColumn(name = \ public OrderInfo getOrder() { return order; }

public void setOrder(OrderInfo order) { this.order = order; } }

测试

public class OneToMany { @Test

public void save() {

EntityManagerFactory emf = Persistence .createEntityManagerFactory(\ EntityManager em = emf.createEntityManager(); em.getTransaction().begin(); OrderInfo o = new OrderInfo(); o.setName(\订单一\

OrderItem oi1 = new OrderItem(); oi1.setName(\产品一\ o.addOrderItem(oi1);

OrderItem oi2 = new OrderItem(); oi2.setName(\产品一\ o.addOrderItem(oi2);

OrderItem oi3 = new OrderItem(); oi3.setName(\产品一\ o.addOrderItem(oi3);

OrderItem oi4 = new OrderItem(); oi4.setName(\产品一\

o.addOrderItem(oi4); em.persist(o);

// UUID.randomUUID().toString(); em.getTransaction().commit(); emf.close(); } }

JPA多对多双向 维护端注解

@ManyToMany (cascade = CascadeType.REFRESH) @JoinTable (//关联表

name = \关联表名

inverseJoinColumns = @JoinColumn (name = \被维护端外键 joinColumns = @JoinColumn (name = \维护端外键 被维护端注解 @ManyToMany(

cascade = CascadeType.REFRESH,

mappedBy = \通过维护端的属性关联 fetch = FetchType.LAZY) @Entity

public class Student { private Integer id; private String name;

private Set teachers = new HashSet(); @Id

@GeneratedValue(strategy = GenerationType.AUTO) public Integer getId() { return id; }

public void setId(Integer id) { this.id = id; }

@Column(nullable = false, length = 16) public String getName() { return name; }

public void setName(String name) { this.name = name; }

@ManyToMany(cascade = CascadeType.REFRESH)

@JoinTable(name = \inverseJoinColumns = @JoinColumn(name = \ public Set getTeachers() {

return teachers; }

public void setTeachers(Set teachers) { this.teachers = teachers; }

public void addTeacher(Teacher teacher) { this.teachers.add(teacher); }

public void removeTeachers(Teacher teacher) { this.teachers.remove(teacher); } }

@Entity

public class Teacher { private Integer id; private String name;

private Set students = new HashSet(); @Id

@GeneratedValue(strategy = GenerationType.AUTO) public Integer getId() { return id; }

public void setId(Integer id) { this.id = id; }

@Column(nullable = false, length = 16) public String getName() { return name; }

public void setName(String name) { this.name = name; }

@ManyToMany(cascade = CascadeType.REFRESH, mappedBy = \fetch = FetchType.LAZY)

public Set getStudents() { return students; }

public void setStudents(Set students) { this.students = students; } }

测试

public class ManyToMany {

@Test

public void save() {

EntityManagerFactory emf = Persistence .createEntityManagerFactory(\ EntityManager em = emf.createEntityManager(); em.getTransaction().begin(); Student student = new Student(); student.setName(\小李\

Teacher teacher = new Teacher(); teacher.setName(\大李\ em.persist(student); em.persist(teacher);

em.getTransaction().commit(); emf.close(); }

@Test

public void bind() {

EntityManagerFactory emf = Persistence .createEntityManagerFactory(\ EntityManager em = emf.createEntityManager(); em.getTransaction().begin();

Student student = em.find(Student.class, 1); Teacher teacher = em.find(Teacher.class, 1); student.addTeacher(teacher); em.persist(student);

em.getTransaction().commit(); emf.close(); }

@Test

public void unbind() {

EntityManagerFactory emf = Persistence .createEntityManagerFactory(\ EntityManager em = emf.createEntityManager(); em.getTransaction().begin();

Student student = em.find(Student.class, 1); Teacher teacher = em.find(Teacher.class, 1); student.removeTeachers(teacher); em.persist(student);

em.getTransaction().commit(); emf.close(); }

@Test

public void removeTeacher() {

EntityManagerFactory emf = Persistence .createEntityManagerFactory(\ EntityManager em = emf.createEntityManager(); em.getTransaction().begin();

// 关系被维护端删除时,如果中间表存在些纪录的关联信息,则会删除失败 em.remove(em.getReference(Teacher.class, 1)); em.getTransaction().commit(); emf.close(); }

@Test

public void removeStudent() {

EntityManagerFactory emf = Persistence .createEntityManagerFactory(\ EntityManager em = emf.createEntityManager(); em.getTransaction().begin();

// 关系维护端删除时,如果中间表存在些纪录的关联信息,则会删除该关联信息 em.remove(em.getReference(Student.class, 1)); em.getTransaction().commit(); emf.close(); } }

常见异常

1、异常信息:org.hibernate.hql.ast.QuerySyntaxException: person is not mapped 异常环境:查询

异常原因:查询语句中Person类没有大写

2、java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to java.lang.String 异常环境:查询、遍历显示 异常原因:转型出错

3、javax.persistence.NonUniqueResultException: result returns more than one elements 异常环境:查询、getSingleResult

异常原因:getSingleResult只能获取一条数据,而查询语句返回的是多条数据

4、 org.hibernate.PropertyValueException: not-null property references a null or transient value: com.sunyard.entities.Person.name 异常环境:数据插入

异常原因:JPA的Entity中一个属性定义为nullable=false,插入数据该字段为null

5、 执行添加没反应、没异常

异常原因:没有开启事务、没有提交事务

6、javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: com.sunyard.entities.Person 异常环境:OneToOne 共享主键关联

异常原因:一对一中,一个提供主键、另一个共享其主键,共享主键的对象可以set 提供主键的对象 然后添加到数据库中 方向弄反了 后果就是没人提供主键

7、org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: 异常环境:多对一添加

异常原因:在多的一端维护 ,没有添加级联

8、javax.persistence.PersistenceException: [PersistenceUnit: JPA] Unable to configure EntityManagerFactory

异常原因:很多、实体管理器Factory没有成功创建,是注解的问题

9、org.hibernate.MappingException: Unable to find column with logical name: sid in org.hibernate.mapping.

异常环境:添加表做多对一关联映射

异常原因:表字段写反了,name添加表字段名referencedColumnName指向本表字段名