今天做东西的时候使用到了JPA,在这里把JPA需要注意的知道的体系结构,给大家罗列一遍。如果能帮到大家一点,希望大家,点个赞关注一下,后期还会更新更多技术。
3.persistence.xml
4. 执行持久化操作
5. JPA 基本注解
@Entity:@Entity 标注用于实体类声明语句之前,指出该Java 类为实体类,将映射到指定的数据库表。如声明一个实体类 Customer,它将映射到数据库中的 customer 表上。
@Table:当实体类与其映射的数据库表名不同名时需要使用 @Table 标注说明,该标注与 @Entity 标注并列使用,置于实体类声明语句之前,可写于单独语句行,也可与声明语句同行。@Table 标注的常用选项是 name,用于指明数据库的表名,@Table标注还有一个两个选项 catalog 和 schema 用于设置表所属的数据库目录或模式,通常为数据库名。uniqueConstraints 选项用于设置约束条件,通常不须设置。
@Transient:
表示该属性并非一个到数据库表的字段的映射,ORM框架将忽略该属性.
如果一个属性并非数据库表的字段映射,就务必将其标示为@Transient,否则,ORM框架默认其注解为@Basic
@Temporal: 在核心的 Java API 中并没有定义 Date 类型的精度(temporal precision). 而在数据库中,表示 Date 类型的数据有 DATE, TIME, 和 TIMESTAMP 三种精度(即单纯的日期,时间,或者两者 兼备). 在进行属性映射时可使用@Temporal注解来调整精度.
@Id:@Id 标注用于声明一个实体类的属性映射为数据库的主键列。该属性通常置于属性声明语句之前,可与声明语句同行,也可写在单独行上。@Id标注也可置于属性的getter方法之前。
@GeneratedValue:@GeneratedValue 用于标注主键的生成策略,通过 strategy 属性指定。默认情况下,JPA 自动选择一个最适合底层数据库的主键生成策略:SqlServer 对应 identity,MySQL 对应 auto increment。
在 javax.persistence.GenerationType 中定义了以下几种可供选择的策略:
IDENTITY:采用数据库 ID自增长的方式来自增主键字段,Oracle 不支持这种方式;
AUTO: JPA自动选择合适的策略,是默认选项;
SEQUENCE:通过序列产生主键,通过 @SequenceGenerator 注解指定序列名,MySql 不支持这种方式
TABLE:通过表产生主键,框架借由表模拟序列产生主键,使用该策略可以使应用更易于数据库移植。
@Column:
当实体的属性与其映射的数据库表的列不同名时需要使用@Column 标注说明,该属性通常置于实体的属性声明语句之前,还可与 @Id 标注一起使用。
@Column 标注的常用属性是 name,用于设置映射数据库表的列名。此外,该标注还包含其它多个属性,如:unique 、nullable、length 等。
@Column 标注的 columnDefinition 属性: 表示该字段在数据库中的实际类型.通常 ORM 框架可以根据属性类型自动判断数据库中字段的类型,但是对于Date类型仍无法确定数据库中字段类型究竟是DATE,TIME还是TIMESTAMP.此外,String的默认映射类型为VARCHAR, 如果要将 String 类型映射到特定数据库的 BLOB 或TEXT 字段类型.
@Column标注也可置于属性的getter方法之前
@Basic:
@Basic 表示一个简单的属性到数据库表的字段的映射,对于没有任何标注的 getXxxx() 方法,默认即为@Basic
fetch: 表示该属性的读取策略,有 EAGER 和 LAZY 两种,分别表示主支抓取和延迟加载,默认为 EAGER.
FetchType.LAZY:懒加载,加载一个实体时,定义懒加载的属性不会马上从数据库中加载。
FetchType.EAGER:急加载,加载一个实体时,定义急加载的属性会立即从数据库中加载。
optional:表示该属性是否允许为null, 默认为true
6. 用 table 来生成主键详解
将当前主键的值单独保存到一个数据库的表中,主键的值每次都是从指定的表中查询来获得
这种方法生成主键的策略可以适用于任何数据库,不必担心不同数据库不兼容造成的问题。
示例:
二、JPA API
Persistence
Persistence 类是用于获取 EntityManagerFactory 实例。该类包含一个名为 createEntityManagerFactory 的 静态方法 。
createEntityManagerFactory 方法有如下两个重载版本。
带有一个参数的方法以 JPA 配置文件 persistence.xml 中的持久化单元名为参数
带有两个参数的方法:前一个参数含义相同,后一个参数 Map类型,用于设置 JPA 的相关属性,这时将忽略其它地方设置的属性。Map 对象的属性名必须是 JPA 实现库提供商的名字空间约定的属性名。
2. EntityManagerFactory
EntityManagerFactory 接口主要用来创建 EntityManager 实例。该接口约定了如下4个方法:
createEntityManager():用于创建实体管理器对象实例。
createEntityManager(Map map):用于创建实体管理器对象实例的重载方法,Map 参数用于提供 EntityManager 的属性。
isOpen():检查 EntityManagerFactory 是否处于打开状态。实体管理器工厂创建后一直处于打开状态,除非调用close()方法将其关闭。
close():关闭 EntityManagerFactory 。 EntityManagerFactory 关闭后将释放所有资源,isOpen()方法测试将返回 false,其它方法将不能调用,否则将导致IllegalStateException异常。
3.EntityManager
在 JPA 规范中, EntityManager 是完成持久化操作的核心对象。实体作为普通 Java 对象,只有在调用 EntityManager 将其持久化后才会变成持久化对象。EntityManager 对象在一组实体类与底层数据源之间进行 O/R 映射的管理。它可以用来管理和更新 Entity Bean, 根椐主键查找 Entity Bean, 还可以通过JPQL语句查询实体。
实体的状态:
新建状态: 新创建的对象,尚未拥有持久性主键。
持久化状态:已经拥有持久性主键并和持久化建立了上下文环境
游离状态:拥有持久化主键,但是没有与持久化建立上下文环境
删除状态: 拥有持久化主键,已经和持久化建立上下文环境,但是从数据库中删除。
find (Class
getReference (Class
persist (Object entity):用于将新创建的 Entity 纳入到 EntityManager 的管理。该方法执行后,传入 persist() 方法的 Entity 对象转换成持久化状态。
如果传入 persist() 方法的 Entity 对象已经处于持久化状态,则 persist() 方法什么都不做。
如果对删除状态的 Entity 进行 persist() 操作,会转换为持久化状态。
如果对游离状态的实体执行 persist() 操作,可能会在 persist() 方法抛出 EntityExistException(也有可能是在flush或事务提交后抛出)。
remove (Object entity):删除实例。如果实例是被管理的,即与数据库实体记录关联,则同时会删除关联的数据库记录。
merge (T entity):merge() 用于处理 Entity 的同步。即数据库的插入和更新操作
flush ():同步持久上下文环境,即将持久上下文环境的所有未保存实体的状态信息保存到数据库中。
setFlushMode (FlushModeType flushMode):设置持久上下文环境的Flush模式。参数可以取2个枚举
FlushModeType.AUTO 为自动更新数据库实体,
FlushModeType.COMMIT 为直到提交事务时才更新数据库记录。
getFlushMode ():获取持久上下文环境的Flush模式。返回FlushModeType类的枚举值。
refresh (Object entity):用数据库实体记录的值更新实体对象的状态,即更新实例的属性值。
clear ():清除持久上下文环境,断开所有关联的实体。如果这时还有未提交的更新则会被撤消。
contains (Object entity):判断一个实例是否属于当前持久上下文环境管理的实体。
isOpen ():判断当前的实体管理器是否是打开状态。
getTransaction ():返回资源层的事务对象。EntityTransaction实例可以用于开始和提交多个事务。
close ():关闭实体管理器。之后若调用实体管理器实例的方法或其派生的查询对象的方法都将抛出 IllegalstateException 异常,除了getTransaction 和 isOpen方法(返回 false)。不过,当与实体管理器关联的事务处于活动状态时,调用 close 方法后持久上下文将仍处于被管理状态,直到事务完成。
createQuery (String qlString):创建一个查询对象。
createNamedQuery (String name):根据命名的查询语句块创建查询对象。参数为命名的查询语句。
createNativeQuery (String sqlString):使用标准 SQL语句创建查询对象。参数为标准SQL语句字符串。
createNativeQuery (String sqls, String resultSetMapping):使用标准SQL语句创建查询对象,并指定返回结果集 Map的 名称。
3. EntityTransaction
begin ()
用于启动一个事务,此后的多个数据库操作将作为整体被提交或撤消。若这时事务已启动则会抛出 IllegalStateException 异常。
commit ()
用于提交当前事务。即将事务启动以后的所有数据库更新操作持久化至数据库中。
rollback ()
撤消(回滚)当前事务。即撤消事务启动后的所有数据库更新操作,从而不对数据库产生影响。
setRollbackOnly ()
使当前事务只能被撤消。
getRollbackOnly ()
查看当前事务是否设置了只能撤消标志。
isActive ()
查看当前事务是否是活动的。如果返回true则不能调用begin方法,否则将抛出 IllegalStateException 异常;如果返回 false 则不能调用 commit、rollback、setRollbackOnly 及 getRollbackOnly 方法,否则将抛出 IllegalStateException 异常。
三、关联映射
1. 双向一对多及多对一映射
双向一对多关系中,必须存在一个关系维护端,在 JPA 规范中,要求 many 的一方作为关系的维护端(owner side), one 的一方作为被维护端(inverse side)。
可以在 one 方指定 @OneToMany 注释并设置 mappedBy 属性,以指定它是这一关联中的被维护端,many 为维护端。
在 many 方指定 @ManyToOne 注释,并使用 @JoinColumn 指定外键名称
2. 双向一对一映射
基于外键的 1-1 关联关系:在双向的一对一关联中,需要在关系被维护端(inverse side)中的 @OneToOne 注释中指定 mappedBy,以指定是这一关联中的被维护端。同时需要在关系维护端(owner side)建立外键列指向关系被维护端的主键列。
3. 双向 1-1 不延迟加载的问题
如果延迟加载要起作用, 就必须设置一个代理对象.
Manager 其实可以不关联一个 Department
如果有 Department 关联就设置为代理对象而延迟加载, 如果不存在关联的 Department 就设置 null, 因为外键字段是定义在 Department 表中的,Hibernate 在不读取 Department 表的情况是无法判断是否有关联有 Deparmtment, 因此无法判断设置 null 还是代理对象, 而统一设置为代理对象,也无法满足不关联的情况, 所以无法使用延迟加载,只 有显式读取 Department.
4. 双向多对多关联关系
在双向多对多关系中,我们必须指定一个关系维护端(owner side),可以通过 @ManyToMany 注释中指定 mappedBy 属性来标识其为关系维护端。
以上是JPA在做Demo 之前需要知道的知识体系。以下使用Demo实例的方式,介绍一下具体的使用方式。项目的目录结构如下:
package com.nyist.Jpa.Entity;
import java.util.Date;
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.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;
import org.hibernate.engine.internal.Cascade;
@Table(name="JPA_CUSTOMER") //需要生成的数据表名称
@Entity //表明这是一个持久化类 对象
public class Customer {
@Id
@Column(name="jpa_id",nullable=false,unique=true,length=50) //映射得 列名 //Id 主键
// strategy 主键的生成策略改变成功为 用table表的方式生成主键
// generator 指定生成器
// @GeneratedValue(strategy=GenerationType.TABLE,generator="ID_GENERATOR") //生成值得策略
// name ID_GENERATOR 表生成策略的名称 table 生成主键策略的表 pkColumnName 生成主键的列 pkColumnValue 生成值
// allocationSize 增长幅度 为 1 initalValue 初始化值为1
// @TableGenerator(name="ID_GENERATOR",
// table="JPA_GENERATOR_ID",
// pkColumnName="person_id",
// pkColumnValue="ID_VAL",
// allocationSize=1,
// initialValue=1)
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
@Column(name="jpa_last_name",length=50,nullable=false) //映射数据库字段
private String lastName;
@Column(length=50,nullable=false,name="jpa_email")
private String email;
@Column(name="jpa_age",length=10,nullable=false)
private Integer age;
@Temporal(TemporalType.TIMESTAMP)
@Column(name="jap_createTime")
private Date createTime;
@Temporal(TemporalType.DATE)
@Column(name="jpa_birth")
private Date birth;
//映射 单向一对多的关联映射
//使用 @OneToMany 来映射 1-n 的关联关系
//@OneToMany 可以使用属性 fetch 属性来指定 加载方式 懒加载和急加载
//注意:在1的一端的@OneToMany 中使用 mapperedBy 属性,则@OneToMany端就不能使用@JoinColumn属性了 但是 也没有外键约束关联了
//@JoinColumn(name="customer_id")
//可以通过 修改 cascade 的属性 来修改删除策略。cascade = {CascadeType.REMOVE} 实现级联删除策略
//指定 mappedBy 表示该类是 1的一端,不维护关联关系,需要使用mapperedBy 指定维护关联关系的一方
@OneToMany(fetch=FetchType.EAGER,cascade={CascadeType.REMOVE},mappedBy="customer")
private Set orders = new HashSet();
public Set getOrders() {
return orders;
}
public void setOrders(Set orders) {
this.orders = orders;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public Date getBirth() {
return birth;
}
public void setBirth(Date birth) {
this.birth = birth;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Customer() {
super();
// TODO Auto-generated constructor stub
}
//这种工具方法 不需要映射为数据裤的 字段
//@Transient 用来指定 不被映射成数据裤的字段
@Transient
public String getInfo(){
return "lastName:"+lastName+", email:"+email;
}
public Customer(Integer id, String lastName, String email, Integer age) {
super();
this.id = id;
this.lastName = lastName;
this.email = email;
this.age = age;
}
@Override
public String toString() {
return "Customer [id=" + id + ", lastName=" + lastName + ", email=" + email + ", age=" + age + "]";
}
}
package com.nyist.Jpa.Entity;
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.Table;
@Table(name="jpa_order")
@Entity
public class Order {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
private String orderName;
//如何映射 单项 多对一 的 n-1的关系
//@JoinColumn 外键列的列名称
//使用@ManyToOne 来映射多对一
//使用@JoinColumn 映射外键
//@ManyToOne 使用fetch 方法来改变默认关联属性的加载策略
/**fetch: 表示该属性的读取策略,有 EAGER 和 LAZY 两种,分别表示主支抓取和延迟加载,默认为 EAGER.
* FetchType.LAZY:懒加载,加载一个实体时,定义懒加载的属性不会马上从数据库中加载。
FetchType.EAGER:急加载,加载一个实体时,定义急加载的属性会立即从数据库中加载。
*/
@JoinColumn(name="customer_id")
@ManyToOne(fetch=FetchType.LAZY)
private Customer customer;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getOrderName() {
return orderName;
}
public void setOrderName(String orderName) {
this.orderName = orderName;
}
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
public Order(Integer id, String orderName, Customer customer) {
super();
this.id = id;
this.orderName = orderName;
this.customer = customer;
}
public Order() {
super();
// TODO Auto-generated constructor stub
}
@Override
public String toString() {
return "Order [id=" + id + ", orderName=" + orderName + "]";
}
}
package com.nyist.Jpa.Test;
import java.util.Date;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.nyist.Jpa.Entity.Customer;
import com.nyist.Jpa.Entity.Order;
//测试 关联映射
public class TestIncidenceMapping {
private EntityManagerFactory entityManagerFactory;
private EntityManager entityManager;
private EntityTransaction entityTransaction;
@Before
public void init(){
String persistenceUnitName = "Jpa_01";
entityManagerFactory = Persistence.createEntityManagerFactory(persistenceUnitName);
entityManager = entityManagerFactory.createEntityManager();
entityTransaction = entityManager.getTransaction();
entityTransaction.begin();
}
@After
public void destory(){
//提交事务
entityTransaction.commit();
//关闭entityManager
entityManager.close();
//关闭entityManagerFactory
entityManagerFactory.close();
}
/**
* 保存多对一时候,建议先保存1的一端,后保存n的端,这样不会额外多处update 语句
*/
//若是双向 一对多的关联关系 若先保存 n 的一端,再保存1的一端口。默认情况下,会多出4条Update语句
//若先保存1的一段,则会多出2条update 语句
//在进行双向 1-n关联映射的时,建议使用 n 的一方的来维护关联关系,而1的一方不维护关联关系。这样会有效的减少SQL语句
@Test
public void ManyToOne(){
Customer cs = new Customer();
cs.setAge(22);
cs.setBirth(new Date());
cs.setCreateTime(new Date());
cs.setEmail("[email protected]");
cs.setLastName("PQQP");
Order order = new Order();
order.setOrderName("OP-MM-1");
Order order2 = new Order();
order2.setOrderName("PO-MM2");
//设置关联关系
// order.setCustomer(cs);
// order2.setCustomer(cs);
//持久化到数据表中
entityManager.persist(cs);
entityManager.persist(order);
entityManager.persist(order2);
}
//默认情况下,使用左外连接的方式获取n的一端,和其关联的1 的一端的对象
//@ManyToOne 使用fetch 方法来改变默认关联属性的加载策略
/**fetch: 表示该属性的读取策略,有 EAGER 和 LAZY 两种,分别表示主支抓取和延迟加载,默认为 EAGER.
* FetchType.LAZY:懒加载,加载一个实体时,定义懒加载的属性不会马上从数据库中加载。
FetchType.EAGER:急加载,加载一个实体时,定义急加载的属性会立即从数据库中加载。
*/
@Test
public void testManyToOneFind(){
// Order order = entityManager.find(Order.class,1);
// System.out.println(order.getOrderName());
//不能直接删除 1 的一端,因为有外键约束
Customer customer = entityManager.find(Customer.class,7);
entityManager.remove(customer);
// System.out.println(customer.getCustomer().getLastName());
}
@Test
public void testManyToOneRemove(){
Order order = entityManager.find(Order.class,1);
entityManager.remove(order);
}
// @Test
// public void testManyToOneUpdate(){
// Order order = entityManager.find(Order.class,2);
// order.getCustomer().setLastName("AAA");
// }
/*****************************************************一对多***********************************************/
@Test
public void testOneToMany(){
}
//单向 1-n 关联 关系执行保存的时候,一定会多出Update 语句。
//因为 n 的 一端口,在插入的时候不会同时插入外键列
@Test
public void testOneToManyPersist(){
Customer cs = new Customer();
cs.setAge(18);
cs.setBirth(new Date());
cs.setCreateTime(new Date());
cs.setEmail("[email protected]");
cs.setLastName("XX");
//处理关联映射
Order order = new Order();
order.setOrderName("DD-WW-ZZ");
Order order2 = new Order();
order2.setOrderName("XX-WW-DD");
//建立关联关系
cs.getOrders().add(order);
cs.getOrders().add(order2);
//持久化 到数据裤中
entityManager.persist(cs);
entityManager.persist(order);
entityManager.persist(order2);
}
@Test
public void testOnToManyFind(){
Customer Customer = entityManager.find(Customer.class,8);
System.out.println(Customer.getLastName());
System.out.println(Customer.getOrders().size());
}
//删除
//默认情况下,若删除 1 的一端,则会把关联的多的一端的外键置空,然后进行删除。
@Test
public void OneToManyRemove(){
//删除 Customer
Customer customer = entityManager.find(Customer.class,6);
entityManager.remove(customer);
}
//修改
@Test
public void testOneToManyUpdate(){
Customer customer = entityManager.find(Customer.class,7);
customer.getOrders().iterator().next().setOrderName("O-XXX-10");
}
}
一对一映射,但是在部门表中需要维护一个外键关联关系,因为部门是由经理管理的,所以知道部门的时候应该能找到相应的经理。
package com.nyist.Jpa.Entity;
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.OneToOne;
import javax.persistence.Table;
@Table(name="jpa_manager")
@Entity
public class Manager {
@GeneratedValue(strategy=GenerationType.AUTO)
@Id
private Integer id;
@Column(name="mgr_name")
private String mgrName;
//对于不维护 关联关系的一方,使用@OneToOne 来进行映射关联属性,建议设置mapperBy=true
@OneToOne(mappedBy="mgr",fetch=FetchType.LAZY)
private Department dept;
public Department getDept() {
return dept;
}
public void setDept(Department dept) {
this.dept = dept;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getMgrName() {
return mgrName;
}
public void setMgrName(String mgrName) {
this.mgrName = mgrName;
}
protected Manager(Integer id, String mgrName) {
this.id = id;
this.mgrName = mgrName;
}
public Manager() {
super();
}
@Override
public String toString() {
return "Manager [id=" + id + ", mgrName=" + mgrName + ",dept="+dept+"]";
}
}
package com.nyist.Jpa.Entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.Table;
@Table(name="jpa_department")
@Entity
public class Department {
@Id
@GeneratedValue
private Integer id;
@Column(name="dept_name")
private String deptName;
//使用@OneToOne 来映射 一对一 关系
//若需要在当前数据表中添加主键则使用 @JOinColumn() 来映射,注意 一对一关联关系 需要添加 unique=true
//注意: @Column 和 @OneToOne 、@ManyToOne 等注解 不能一块使用
//@Column(name="mgr")
@JoinColumn(name="mgr_id",unique=true,nullable=false)
@OneToOne(fetch=FetchType.LAZY)
private Manager mgr;
public Manager getMgr() {
return mgr;
}
public void setMgr(Manager mgr) {
this.mgr = mgr;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getDeptName() {
return deptName;
}
public void setDeptName(String deptName) {
this.deptName = deptName;
}
public Department(Integer id, String deptName,Manager mgr) {
this.id = id;
this.deptName = deptName;
this.mgr=mgr;
}
public Department() {
}
@Override
public String toString() {
return "Department [id=" + id + ", deptName=" + deptName +",mgr="+mgr+"]";
}
}
package com.nyist.Jpa.Test;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.nyist.Jpa.Entity.Department;
import com.nyist.Jpa.Entity.Manager;
public class TestOneToOne {
private EntityManagerFactory entityManagerFactory;
private EntityManager entityManager;
private EntityTransaction entityTransaction;
@Before
public void init(){
String persistenceUnitName = "Jpa_01";
entityManagerFactory = Persistence.createEntityManagerFactory(persistenceUnitName);
entityManager = entityManagerFactory.createEntityManager();
entityTransaction = entityManager.getTransaction();
entityTransaction.begin();
}
@After
public void destory(){
//提交事务
entityTransaction.commit();
//关闭entityManager
entityManager.close();
//关闭entityManagerFactory
entityManagerFactory.close();
}
@Test
public void testOneToOne(){}
//双向 1-1 的关系映射,建议先保存不维护关联关系的一方,即没有外键的一方,这样不会多出UPDATE 语句
@Test
public void testOneToOnePersistence(){
Manager manager = new Manager();
manager.setMgrName("M-CC");
Department department = new Department();
department.setDeptName("D-CC");
//设置 关联关系
manager.setDept(department);
department.setMgr(manager);
//持久化 到数据裤
entityManager.persist(manager);
entityManager.persist(department);
}
//默认情况下
//1.若获取维护关联关系的一方,则会通过左外连接获取关联对象
//可以通过 @OneToOne fetch 的策略 改为 懒加载 可以改变
@Test
public void testOneToOneFind(){
Manager manager = entityManager.find(Manager.class,1);
System.out.println(manager.getMgrName());
System.out.println(manager.getDept().getClass().getName());
}
//1.若获取维护关联关系的一方,则会通过左外连接获取关联对象
//可以通过 @OneToOne fetch 的策略 改为 懒加载 可以改变,但以然会在发送SQL 语句来初始化其关联对象
//这说明 在不维护关系的一方,不建议修改fetch 属性
@Test
public void testOneToOneFind1(){
Department department = entityManager.find(Department.class,2);
System.out.println(department.getDeptName());
System.out.println(department.getMgr().getClass().getName());
}
}
package com.nyist.Jpa.Entity;
import java.util.HashSet;
import java.util.Set;
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;
import javax.persistence.Table;
@Table(name="jpa_item")
@Entity
public class Item {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
@Column(name="item_name")
private String itemName;
/**
* 使用 @ManyToMany 注解来映射多对多关联映射关系
* 使用@JoinTable 来映射中间表
* 1.name 指向中间表的名称
* 2.joinColumns 映射当前类所在的表在中间表的外键
* 2.1 name 制定外键列名
* 2.2 referencedColumnName 指定外键列关联当前表的那一列
* 3.inverseJoinColumns 映射关联的类所在中间表的外键
* 当前类所在的表在中间表的外键
*/
@JoinTable(name="jpa_item_category",
joinColumns={@JoinColumn(name="item_id",referencedColumnName="id")},
inverseJoinColumns={@JoinColumn(name="category_id",referencedColumnName="id")})
@ManyToMany
private Set categories = new HashSet();
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getItemName() {
return itemName;
}
public void setItemName(String itemName) {
this.itemName = itemName;
}
public Set getCategories() {
return categories;
}
public void setCategories(Set categories) {
this.categories = categories;
}
@Override
public String toString() {
return "Item [id=" + id + ", itemName=" + itemName + ", categories=" + categories + "]";
}
}
package com.nyist.Jpa.Entity;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
@Table(name="jpa_category")
@Entity
public class Category {
@GeneratedValue(strategy=GenerationType.AUTO)
@Id
private Integer id;
@Column(name="category_name")
private String categoryName;
@ManyToMany(mappedBy="categories")
private Set- items = new HashSet
- ();
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getCategoryName() {
return categoryName;
}
public void setCategoryName(String categoryName) {
this.categoryName = categoryName;
}
public Set
- getSet() {
return items;
}
public void setSet(Set
- set) {
this.items = set;
}
public Category(Integer id, String categoryName, Set
- set) {
super();
this.id = id;
this.categoryName = categoryName;
this.items = set;
}
public Category() {
super();
}
@Override
public String toString() {
return "Category [id=" + id + ", categoryName=" + categoryName + ", set=" + items + "]";
}
}
package com.nyist.Jpa.Test;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.nyist.Jpa.Entity.Category;
import com.nyist.Jpa.Entity.Item;
public class TestManyToMany {
private EntityManagerFactory entityManagerFactory;
private EntityManager entityManager;
private EntityTransaction entityTransaction;
@Before
public void init(){
String persistenceUnitName = "Jpa_01";
entityManagerFactory = Persistence.createEntityManagerFactory(persistenceUnitName);
entityManager = entityManagerFactory.createEntityManager();
entityTransaction = entityManager.getTransaction();
entityTransaction.begin();
}
@After
public void destory(){
//提交事务
entityTransaction.commit();
//关闭entityManager
entityManager.close();
//关闭entityManagerFactory
entityManagerFactory.close();
}
@Test
public void testManyToMany(){
}
@Test
public void testManyToManyPersistence(){
Item item = new Item();
item.setItemName("I-AA");
Item item2 = new Item();
item2.setItemName("I—BB");
Category category = new Category();
category.setCategoryName("C-AA");
Category category2 = new Category();
category2.setCategoryName("C-BB");
//设置关联关系映射
item.getCategories().add(category);
item.getCategories().add(category2);
item2.getCategories().add(category);
item2.getCategories().add(category2);
category.getSet().add(item);
category.getSet().add(item2);
category2.getSet().add(item);
category2.getSet().add(item2);
//持久化 到数据裤中
entityManager.persist(item);
entityManager.persist(item2);
entityManager.persist(category);
entityManager.persist(category2);
}
//对于关联的集合对象 默认使用懒加载策略
//使用维护关联关系的一方获取,还是使用不维护关系一方获取,SQL 语句相同。
@Test
public void testManyToManyFind(){
// Item item = entityManager.find(Item.class,1);
// System.out.println(item.getItemName());
// System.out.println(item.getCategories().size());
Category category = entityManager.find(Category.class,1);
System.out.println(category.getCategoryName());
System.out.println(category.getSet().size());
}
}