JPA中一对多和多对一双向关系中,多的一方为关系维护端 。有mappedBy的一方为关系被维护端。
关系维护端负责外键纪录的更新 ,关系被维护端是没有权力更新外键纪录的。只能通过关系维护端设置与关系被维护端的关系。
一对多:
@OneToMany(cascade = { CascadeType.PERSIST, CascadeType.REFRESH,
CascadeType.MERGE, CascadeType.REMOVE, CascadeType.ALL }, fetch = FetchType.EAGER, mappedBy = "order")
cascade:设置级联操作,对JPQL语句进行的操作没有任何影响
CascadeType.PERSIST对应实体管理器的persist()方法
CascadeType.REFRESH对应实体管理器的refresh()方法
CascadeType.MERGE对应实体管理器的merge()方法
CascadeType.REMOVE对应实体管理器的remove()方法
CascadeType.ALL对应实体管理器的以上方法:persist()、refresh()、merge()、remove()方法
fetch:设置是否延迟加载,FetchType.LZAY为延迟加载, FetchType.EAGER时立即加载。如果加载的是多的一方的话,默认的是延迟加载,否则是加载。
多对一:
@ManyToOne(cascade = { CascadeType.MERGE, CascadeType.REFRESH }, optional = false)
@JoinColumn(name = "order_id")
optional:代表外键字段是否可以为空。true可以为空,false不可以为空。
@JoinColumn(name = "order_id"):设置关联外键字段的名称。
例:
1.两个实体的一对多和多对一
使用现实生活中的订单和订单项的关系,代码为:
package com.taoistwar.jpa.entity.onetomany; import java.util.HashSet; import java.util.Set; import javax.persistence.CascadeType; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.OneToMany; import javax.persistence.Table; @Entity @Table(name = "order_info") public class OrderInfo { private Integer id; private String name; private Set<OrderItem> items = new HashSet<OrderItem>(); @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 = "order") //fetch是否延迟加载,mappedBy有它的一方为关系被维护端。 public Set<OrderItem> getItems() { return items; } public void setItems(Set<OrderItem> items) { this.items = items; } public void addOrderItem(OrderItem orderItem) { orderItem.setOrder(this); this.items.add(orderItem); } }
package com.taoistwar.jpa.entity.onetomany; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.Table; @Entity @Table(name = "order_item") 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 = "order_id") // optional是否可以为空 public OrderInfo getOrder() { return order; } public void setOrder(OrderInfo order) { this.order = order; } @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; OrderItem other = (OrderItem) obj; if (Id == null) { if (other.Id != null) return false; } else if (!Id.equals(other.Id)) return false; return true; } }
2.单个实体的一对多和多对一
使用软件开发中的模块为例子,代码如下:
package com.taoistwar.ejb.sys.entity; import java.io.Serializable; import java.util.Set; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.OneToMany; import javax.persistence.Table; /** * @author TaoistWar 模块实体类 (一对多) * JPA中一对多和多对一双向关系中,多的一方为关系维护端。 * 关系维护端负责外键纪录的更新,关系被维护端是没有权力更新外键纪录的。 */ @Entity @Table(name = "s_moudle") public class Moudle implements Serializable { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Integer id; // 模块名(一般中文) @Column(name = "modName") private String modName; // 模块值(英文) @Column(name = "modValue") private String modValue; // 模块排序编码 @Column(name = "orderCode") private Integer orderCode; // 模块是否禁用 @Column(name = "forbidden") private boolean forbidden; // 模块链接路径 @Column(name = "modUrl") private String modUrl; // 父级模块 @ManyToOne(cascade = { CascadeType.REFRESH, CascadeType.REMOVE }, optional=true) @JoinColumn(name="parent_id") // optional关联字段是否可以为空 private Moudle parent; // 子级模块 @OneToMany(cascade = { CascadeType.REFRESH, CascadeType.REMOVE }, fetch=FetchType.LAZY, mappedBy="parent") private Set<Moudle> children; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getModName() { return modName; } public void setModName(String modName) { this.modName = modName; } public String getModValue() { return modValue; } public void setModValue(String modValue) { this.modValue = modValue; } public Integer getOrderCode() { return orderCode; } public void setOrderCode(Integer orderCode) { this.orderCode = orderCode; } public boolean isForbidden() { return forbidden; } public void setForbidden(boolean forbidden) { this.forbidden = forbidden; } public String getModUrl() { return modUrl; } public void setModUrl(String modUrl) { this.modUrl = modUrl; } public Moudle getParent() { return parent; } public void setParent(Moudle parent) { this.parent = parent; } public Set<Moudle> getChildren() { return children; } public void setChildren(Set<Moudle> children) { this.children = children; } }
1-m:多的一方为关系维护端,关系维护端负责外键纪录的更新,关系被维护端没有权力更新外键纪录.
维护端注解
@OneToMany(cascade = { CascadeType.PERSIST, CascadeType.REFRESH, CascadeType.MERGE, CascadeType.REMOVE }, fetch = FetchType.EAGER, mappedBy = "order")
被维护端注解
@ManyToOne(cascade = { CascadeType.MERGE, CascadeType.REFRESH }, optional = false) @JoinColumn(name = "order_id")
对于一对多和多对一关系的现实中的例子是,网上购物时的订单和订单项。一个订单有多个订单项。多个订单项属于一个订单。
订单实体类:
package com.taoistwar.jpa.entity.onetomany; import java.util.HashSet; import java.util.Set; import javax.persistence.CascadeType; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.OneToMany; import javax.persistence.Table; @Entity @Table(name = "order_info") public class OrderInfo { private Integer id; private String name; private Set<OrderItem> items = new HashSet<OrderItem>(); @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 = "order") public Set<OrderItem> getItems() { return items; } public void setItems(Set<OrderItem> items) { this.items = items; } public void addOrderItem(OrderItem orderItem) { orderItem.setOrder(this); this.items.add(orderItem); } }
重点在于:
@OneToMany(cascade = { CascadeType.PERSIST, CascadeType.REFRESH, CascadeType.MERGE, CascadeType.REMOVE }, fetch = FetchType.EAGER, mappedBy = "order") public Set<OrderItem> getItems() { return items; }
订单项实体类:
package com.taoistwar.jpa.entity.onetomany; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.Table; @Entity @Table(name = "order_item") 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 = "order_id") public OrderInfo getOrder() { return order; } public void setOrder(OrderInfo order) { this.order = order; } @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; OrderItem other = (OrderItem) obj; if (Id == null) { if (other.Id != null) return false; } else if (!Id.equals(other.Id)) return false; return true; } }
重点在于:
@ManyToOne(cascade = { CascadeType.MERGE, CascadeType.REFRESH }, optional = false) @JoinColumn(name = "order_id") public OrderInfo getOrder() { return order; }
测试类:
package com.taoistwar.jpa.entity.onetomany; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import org.junit.Test; public class OneToMany { @Test public void save() { EntityManagerFactory emf = Persistence .createEntityManagerFactory("JPAPU"); 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(); } }
维护端注解
@ManyToMany (cascade = CascadeType.REFRESH)
@JoinTable (//关联表
name = "student_teacher" , //关联表名
inverseJoinColumns = @JoinColumn (name = "teacher_id" ),//被维护端外键
joinColumns = @JoinColumn (name = "student_id" ))//维护端外键
被维护端注解
@ManyToMany(
cascade = CascadeType.REFRESH,
mappedBy = "teachers",//通过维护端的属性关联
fetch = FetchType.LAZY)
关系维护端删除时,如果中间表存在些纪录的关联信息,则会删除该关联信息;
关系被维护端删除时,如果中间表存在些纪录的关联信息,则会删除失败 .
以学生和老师的对应关系为例。一个学生可以拥有多个老师,一个老师也可以拥有多个学生。
学生实体类
package com.taoistwar.jpa.entity.manytomany; import java.util.HashSet; import java.util.Set; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.JoinTable; import javax.persistence.ManyToMany; @Entity public class Student { private Integer id; private String name; private Set<Teacher> teachers = new HashSet<Teacher>(); @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 = "student_teacher", inverseJoinColumns = @JoinColumn(name = "teacher_id"), joinColumns = @JoinColumn(name = "student_id")) 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 removeTeachers(Teacher teacher) { this.teachers.remove(teacher); } }
重点在于:
@ManyToMany(cascade = CascadeType.REFRESH) @JoinTable(name = "student_teacher", inverseJoinColumns = @JoinColumn(name = "teacher_id"), joinColumns = @JoinColumn(name = "student_id")) public Set<Teacher> getTeachers() { return teachers; }
老师实体类
package com.taoistwar.jpa.entity.manytomany; import java.util.HashSet; import java.util.Set; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.ManyToMany; @Entity public class Teacher { private Integer id; private String name; private Set<Student> students = new HashSet<Student>(); @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 = "teachers", fetch = FetchType.LAZY) public Set<Student> getStudents() { return students; } public void setStudents(Set<Student> students) { this.students = students; } @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; } }
重点在于:
@ManyToMany(cascade = CascadeType.REFRESH, mappedBy = "teachers", fetch = FetchType.LAZY) public Set<Student> getStudents() { return students; }
拥有mappedBy注解的实体类为关系被维护端,另外的实体类为关系维护端的。顾名思意,关系的维护端对关系(在多对多为中间关联表)的CRUD做操作。关系的被维护端没有该操作,不能维护关系。
测试类
package com.taoistwar.jpa.entity.manytomany; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import org.junit.Test; public class ManyToMany { @Test public void save() { EntityManagerFactory emf = Persistence .createEntityManagerFactory("JPAPU"); 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("JPAPU"); 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("JPAPU"); 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("JPAPU"); 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("JPAPU"); EntityManager em = emf.createEntityManager(); em.getTransaction().begin(); // 关系维护端删除时,如果中间表存在些纪录的关联信息,则会删除该关联信息 em.remove(em.getReference(Student.class, 1)); em.getTransaction().commit(); emf.close(); } }
1.添加jar包
hibernate & jpa jar(15): hibernate-distribution-3.3.1.GA/hibernate3.jar hibernate-distribution-3.3.1.GA/lib/required/antlr-2.7.6.jar hibernate-distribution-3.3.1.GA/lib/required/dom4j-1.6.1.jar hibernate-distribution-3.3.1.GA/lib/required/commons-collections-3.1.jar hibernate-distribution-3.3.1.GA/lib/required/jta-1.1.jar hibernate-distribution-3.3.1.GA/lib/required/javassist-3.4.GA.jar hibernate-distribution-3.3.1.GA/lib/required/slf4j-api-1.5.2.jar hibernate-distribution-3.3.1.GA/lib/bytecode/cglib/hibernate-cglib-repack-2.1_3.jar hibernate-distribution-3.3.1.GA/lib/optional/ehcache-1.2.jar hibernate-annotations-3.4.0.GA/hibernate-annotations.jar hibernate-annotations-3.4.0.GA/lib/hibernate-commons-annotations.jar hibernate-annotations-3.4.0.GA/lib/test/slf4j-log4j12.jar hibernate-annotations-3.4.0.GA/lib/test/log4j.jar hibernate-annotations-3.4.0.GA/lib/ejb3-persistence.jar hibernate-entitymanager-3.4.0.GA/lib/hibernate-entitymanager.jar
2.在src创建META-INF文件夹,在其下面创建persistence.xml文件,其内容如下:
<?xml version="1.0" encoding="UTF-8"?> <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_1_0.xsd" version="1.0"> <persistence-unit name="ssj_unit" transaction-type="RESOURCE_LOCAL"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <properties> <!-- <property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect" /> <property name="hibernate.connection.driver_class" value="oracle.jdbc.driver.OracleDriver" /> <property name="hibernate.connection.username" value="yxuser" /> <property name="hibernate.connection.password" value="yxuser" /> <property name="hibernate.connection.url" value="jdbc:oracle:thin:@192.168.1.96:1521:yxdb" /> --> <!-- 连接参数 --> <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect" /> <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="root" /> <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/ssj?useUnicode=true&characterEncoding=UTF-8" /> <!-- 数据源设置 --> <property name="hibernate.max_fetch_depth" value="3" /> <property name="hibernate.hbm2ddl.auto" value="update" /> <property name="hibernate.jdbc.fetch_size" value="50" /> <property name="hibernate.jdbc.batch_size" value="10" /> <property name="hibernate.show_sql" value="true" /> <property name="hibernate.format_sql" value="true" /> </properties> </persistence-unit> </persistence>
3.创建实体类,其内容如下:
package com.taoistwar.ssj.producty.entity; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; @Entity public class ProductType { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Integer id; private String name; public ProductType() { super(); } 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; } }
4.创建测试类
package test.producty.entity; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import org.junit.Test; import com.taoistwar.ssj.producty.entity.ProductType; public class ProductTypeTest { @Test public void testRun() { try { EntityManagerFactory emf = Persistence .createEntityManagerFactory("ssj_unit"); EntityManager em = emf.createEntityManager(); em.getTransaction().begin(); ProductType pt = new ProductType(); pt.setName("中文"); em.persist(pt); em.getTransaction().commit(); em.close(); } catch (Exception e) { e.printStackTrace(); } } }
联系客服