複習_Hibernate_JPA

1.JPA的相關概念

Java Persistence API。是SUN公司推出的一套基於ORM的規範。hibernate框架中提供了JPA的實現。

JPA通過JDK 5.0註解或XML描述對象-關係表的映射關係,並將運行期的實體對象持久化到數據庫中

1.1 JPA的優勢

  • 1.標準化
  • 2.容器級特性的支持
  • 3.簡單方便
  • 4.查詢能力
  • 5.高級特性

1.2 學習JPA要明確的

  • A、JPA是一套ORM規範,hibernate實現了JPA規範
  • B、hibernate中有自己的獨立ORM操作數據庫方式,也有JPA規範實現的操作數據庫方式。
  • C、在數據庫增刪改查操作中,我們hibernate和JPA的操作都要會。

2.JPA入門

導包
在這裏插入圖片描述

package cn.itcast.domain;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
/**
 * 客戶實體類
 * 
 * @author Administrator
 *
 */
@Entity //表示當前類爲實例類
@Table(name="cst_customer")  //建立類和表之間的關係
public class Customer implements Serializable {
	@Id//表示主鍵
	@GeneratedValue(strategy=GenerationType.IDENTITY)//主鍵生成策略
	@Column(name="cust_id")//建立類中屬性和表中字段的映射
	private Long custId;// 客戶ID
	
	@Column(name="cust_name")
	private String custName;// 客戶名稱
	
	@Column(name="cust_source")
	private String custSource;// 客戶來源
	
	@Column(name="cust_industry")
	private String custIndustry;// 客戶所屬行業
	
	@Column(name="cust_level")
	private String custLevel;// 客戶級別
	
	@Column(name="cust_address")
	private String custAddress;// 客戶聯繫地址
	
	@Column(name="cust_phone")
	private String custPhone;// 客戶聯繫方式
	
	public Long getCustId() {
		return custId;
	}
	public void setCustId(Long custId) {
		this.custId = custId;
	}
	public String getCustName() {
		return custName;
	}
	public void setCustName(String custName) {
		this.custName = custName;
	}
	public String getCustSource() {
		return custSource;
	}
	public void setCustSource(String custSource) {
		this.custSource = custSource;
	}
	public String getCustIndustry() {
		return custIndustry;
	}
	public void setCustIndustry(String custIndustry) {
		this.custIndustry = custIndustry;
	}
	public String getCustLevel() {
		return custLevel;
	}
	public void setCustLevel(String custLevel) {
		this.custLevel = custLevel;
	}
	public String getCustAddress() {
		return custAddress;
	}
	public void setCustAddress(String custAddress) {
		this.custAddress = custAddress;
	}
	public String getCustPhone() {
		return custPhone;
	}
	public void setCustPhone(String custPhone) {
		this.custPhone = custPhone;
	}
	@Override
	public String toString() {
		return "Customer [custId=" + custId + ", custName=" + custName
				+ ", custSource=" + custSource + ", custIndustry="
				+ custIndustry + ", custLevel=" + custLevel + ", custAddress="
				+ custAddress + ", custPhone=" + custPhone + "]";
	}
}

常用註解說明:

  • @Entity
    作用:定當前類是實體類。寫上此註解用於在創建SessionFactory/EntityManager時,加載映射配置。
  • @Table
    作用:指定實體類和表之間的對應關係。
    屬性:name:指定數據庫表的名稱
  • @Id
    指定當前字段是主鍵。
  • @GeneratedValue
    作用:指定主鍵的生成方式。
    屬性:strategy :指定主鍵生成策略。JPA支持四種生成策略。
  • @Column
    作用:指定實體類屬性和數據庫表之間的對應關係
    屬性: name:指定數據庫表的列名稱。

2.創建配置文件
在src下建立META-INF文件夾,並在META-INF文件夾下建立xml文件:persistence
在這裏插入圖片描述
要使用JPA,必須滿足兩個條件:

  • 1、在類的根目錄(src)下,創建META-INF文件夾
  • 2、在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_2_0.xsd"
	version="2.0">
<!-- persistence-unit 頂層標籤   配置JPA的單元。
       屬性:
            name: 用於定義持久化單元的名字 (name必選,空值也合法);   
     	   transaction-type: 指定事務類型(可以省略)   
     		                   取值:
     			                       JTA(默認值)
     			                       RESOURCE_LOCAL(數據庫本地的事務)

RESOURCE_LOCAL是數據庫級別的事務,只能針對一種數據庫,不支持分佈式的事務
-->  
<persistence-unit name="myPersistenceUnit" transaction-type="RESOURCE_LOCAL">

	<!-- 配置JPA規範實現的提供商 (可以省略) -->
	<!-- HibernatePersistenceProvider是javax.persistence.PersistenceProvider接口的一個實現類 -->
	<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>

    <!-- 配置創建JPA操作對象時要掃描的類,用於解析註解,生成配置 (可以省略)-->
	<class>cn.itcast.domain.Customer</class>
    
    <!-- 配置Hibernate中的信息 -->
    <properties>
        <!-- 數據庫的連接信息 -->
		<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
		<property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/test"/>
		<property name="hibernate.connection.username" value="root"/>
		<property name="hibernate.connection.password" value="root"/>
		<!-- 指定方言 -->
		<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect"/>
		<!-- 是否顯示SQL語句 -->
		<property name="hibernate.show_sql" value="true"/>
		<!-- 是否格式化SQL語句 -->
		<property name="hibernate.format_sql" value="true"/> 	
		<!-- 生成DDL的策略 -->    
	   <property name="hibernate.hbm2ddl.auto" value="update"/> 
    </properties>

</persistence-unit>
</persistence>

3.編寫工具類,用於獲取JPA的操作數據對象
JPAUtil工具類:

package cn.itcast.util;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.SynchronizationType;
/**
 * JPA的工具類:
 *    加載JPA的persistence.xml文件,用於生成工廠
 *    調用工廠中的方法,創建操作數據庫的對象,並返回
 *   
 * @author Administrator
 *
 */
public class JPAUtil {
   //JPA的實體管理器工廠(相當於Hibernate的SessionFactory)
   private static EntityManagerFactory factory ;
   //使用靜態代碼塊賦值
  static{
	  try{
		  factory = Persistence.createEntityManagerFactory("myPersistenceUnit");
	  }catch(Exception ex){
		  ex.printStackTrace();
	  }
  } 
  /**
   * 使用管理器工廠生產一個管理器對象(獲取一個新的實體管理對象)
   * @return
   */
  public static EntityManager getEntityManager(){
	  //相當於Hibernate中的openSession()
	  return factory.createEntityManager();
  }
}

2.1 常用註解說明

  • @Entity
    作用:指定當前類是實體類。寫上此註解用於在創建SessionFactory/EntityManager時,加載映射配置。
  • @Table
    作用:指定實體類和表之間的對應關係。
    屬性:name:指定數據庫表的名稱
  • @Id
    指定當前字段是主鍵。
  • @GeneratedValue
    作用:指定主鍵的生成方式。
    屬性:strategy :指定主鍵生成策略。JPA支持四種生成策略。
  • @Column
    作用:指定實體類屬性和數據庫表之間的對應關係
    屬性:
    name:指定數據庫表的列名稱。
    unique:是否唯一
    nullable:是否可以爲空
    inserttable:是否可以插入
    updateable:是否可以更新
    columnDefinition: 定義建表時創建此列的DDL
    secondaryTable: 從表名。如果此列不建在主表上(默認建在主表),該屬性定義該列所在從表的名字。

2.2 主鍵生存策略

通過annotation(註解)來映射hibernate實體的,基於annotation的hibernate主鍵標識爲@Id, 其生成規則由@GeneratedValue設定的。這裏的@id和@GeneratedValue都是JPA的標準用法。JPA提供的四種標準用法爲IDENTITY,SEQUENCE,AUTO,TABLE。具體說明如下:

1.IDENTITY
IDENTITY:主鍵由數據庫自動生成。

用法:
@Id  
@GeneratedValue(strategy = GenerationType.IDENTITY) 
private Long custId;

2.SEQUENCE
SEQUENCE:根據底層數據庫的序列來生成主鍵,條件是數據庫支持序列修改時遇到的問題

用法:
@Id  
@GeneratedValue(strategy = GenerationType.SEQUENCE,generator="payablemoney_seq")  	
@SequenceGenerator(name="payablemoney_seq", sequenceName="seq_payment")  

說明:
@SequenceGenerator源碼中的定義 
@Target({TYPE, METHOD, FIELD})   
@Retention(RUNTIME)  
public @interface SequenceGenerator {  
	String name();  
	String sequenceName() default "";  
	int initialValue() default 0;  
	int allocationSize() default 50;  
}  

name:表示該表主鍵生成策略的名稱,它被引用在@GeneratedValue中設置的”generator”值中。
sequenceName:屬性表示生成策略用到的數據庫序列名稱。
initialValue:表示主鍵初識值,默認爲0。
allocationSize:表示每次主鍵值增加的大小,例如設置1,則表示每次插入新記錄後自動加1,默認爲50。

3.AUTO
AUTO:主鍵由程序控制

用法:
@Id  
@GeneratedValue(strategy = GenerationType.AUTO)  

4.TABLE
TABLE:使用一個特定的數據庫表格來保存主鍵

用法:
@Id  
@GeneratedValue(strategy = GenerationType.TABLE, generator="pk_gen")  
@TableGenerator(name = "pk_gen",  
    table="tb_generator",  
    pkColumnName="gen_name",  
    valueColumnName="gen_value",  
    pkColumnValue="PAYABLEMOENY_PK",  
    allocationSize=1  
) 

這裏應用表tb_generator,定義爲 :
CREATE TABLE  tb_generator (  
  id NUMBER NOT NULL,  
  gen_name VARCHAR2(255) NOT NULL,  
  gen_value NUMBER NOT NULL,  
  PRIMARY KEY(id)  
) 

插入紀錄,供生成主鍵使用:
INSERT INTO tb_generator(id, gen_name, gen_value)VALUES (1,PAYABLEMOENY_PK', 1);
在主鍵生成後,這條紀錄的value值,按allocationSize遞增。

@TableGenerator的定義:
@Target({TYPE, METHOD, FIELD})   
@Retention(RUNTIME)  
public @interface TableGenerator {  
  String name();  
  String table() default "";  
  String catalog() default "";  
  String schema() default "";  
  String pkColumnName() default "";  
  String valueColumnName() default "";  
  String pkColumnValue() default "";  
  int initialValue() default 0;  
  int allocationSize() default 50;  
  UniqueConstraint[] uniqueConstraints() default {};  
} 
其中屬性說明: 
	name:
		表示該表主鍵生成策略的名稱,它被引用在@GeneratedValue中設置的“generator”值中。 
	table:
		表示表生成策略所持久化的表名,例如,這裏表使用的是數據庫中的“tb_generator”。 
	catalog和schema:
		具體指定表所在的目錄名或是數據庫名。 
	pkColumnName:
		屬性的值表示在持久化表中,該主鍵生成策略所對應鍵值的名稱。例如在“tb_generator”中將“gen_name”作爲主鍵的鍵值 
	valueColumnName:
		屬性的值表示在持久化表中,該主鍵當前所生成的值,它的值將會隨着每次創建累加。例如,在“tb_generator”中將“gen_value”作爲主鍵的值 
	pkColumnValue:
		屬性的值表示在持久化表中,該生成策略所對應的主鍵。例如在“tb_generator”表中,將“gen_name”的值爲“CUSTOMER_PK”。 
	initialValue:
		表示主鍵初識值,默認爲0。 
	allocationSize:
		表示每次主鍵值增加的大小,例如設置成1,則表示每次創建新記錄後自動加1,默認爲50。 
	UniqueConstraint:
		與@Table標記中的用法類似。

2.3 JPA的CRUD操作

1.保存

@Test
public void testSave() {
	// 創建客戶對象
	Customer c = new Customer();
	c.setCustName("JPA-傳智黑馬2");

	EntityManager em = null;// JPA數據庫操作對象
	EntityTransaction tx = null;// JPA事務對象
	try {
		// 第1步:獲取操作數據庫對象(相當於Hibernate中的Session)
		em = JPAUtil.getEntityManager();
		// 第2步:獲取JPA中的事務對象 並開啓事務
		tx = em.getTransaction();// 此時沒有開啓事務
		tx.begin();// 開啓事務
		// 第3步:執行操作
		em.persist(c);
		// 第4步:提交事務
		tx.commit();
	} catch (Exception ex) {
		tx.rollback();// 事務回滾
		ex.printStackTrace();
	} finally {
		// 第5步:釋放資源
		em.close();
	}
}

2.修改

@Test
public void testUpdate() {
	EntityManager em = null;//JPA數據庫操作對象
	EntityTransaction tx = null;//JPA事務對象
	try {
		// 第1步:獲取操作數據庫對象
		em = JPAUtil.getEntityManager();
		// 第2步:獲取JPA中的事務對象 並開啓事務
		tx = em.getTransaction();// 此時沒有開啓事務
		tx.begin();// 開啓事務
		// 第3步:執行操作
		Customer c = em.find(Customer.class, 97L);
		c.setCustName("傳智專修學院");
		// 第4步:提交事務
		tx.commit();//使用JPA中快照機制實現更新
	} catch (Exception ex) {
		tx.rollback();// 事務回滾
		ex.printStackTrace();
	} finally {
		// 第5步:釋放資源
		em.close();
	}
}

// 第二種實現修改的方式:利用EntityManager對象中的merge()方法
@Test
public void testUpdate2() {
	EntityManager em = null;//JPA數據庫操作對象
	EntityTransaction tx = null;//JPA事務對象
	try {
		// 第1步:獲取操作數據庫對象
		em = JPAUtil.getEntityManager();
		// 第2步:獲取JPA中的事務對象 並開啓事務
		tx = em.getTransaction();// 此時沒有開啓事務
		tx.begin();// 開啓事務
		// 第3步:執行操作
		Customer c = em.find(Customer.class, 97L);
		c.setCustName("傳智專修學院");
		em.merge(c);
		// 第4步:提交事務
		tx.commit();//使用JPA中快照機制實現更新
	} catch (Exception ex) {
		tx.rollback();// 事務回滾
		ex.printStackTrace();
	} finally {
		// 第5步:釋放資源
		em.close();
	}
}

3.刪除

@Test
public void testDelete() {
	EntityManager em = null;//JPA數據庫操作對象
	EntityTransaction tx = null;//JPA事務對象
	try {
		// 第1步:獲取操作數據庫對象
		em = JPAUtil.getEntityManager();
		
		// 第2步:獲取JPA中的事務對象 並開啓事務
		tx = em.getTransaction();// 此時沒有開啓事務
		tx.begin();// 開啓事務
		
		// 第3步:執行操作
		Customer c = em.find(Customer.class, 94L);//先查詢
		em.remove(c);//刪除
		
		// 第4步:提交事務
		tx.commit();//使用JPA中快照機制實現更新
	} catch (Exception ex) {
		tx.rollback();// 事務回滾
		ex.printStackTrace();
	} finally {
		// 第5步:釋放資源
		em.close();
	}
}

4.查詢一個

@Test
public void testGetOne(){
	EntityManager em = null;//JPA數據庫操作對象
	EntityTransaction tx = null;//JPA事務對象
	try {
		// 第1步:獲取操作數據庫對象
		em = JPAUtil.getEntityManager();
		// 第2步:獲取JPA中的事務對象 並開啓事務
		tx = em.getTransaction();// 此時沒有開啓事務
		tx.begin();// 開啓事務
		// 第3步:執行操作
		Customer c = em.find(Customer.class, 97L);	
		// 第4步:提交事務
		tx.commit();
		
		System.out.println(c);
	} catch (Exception e) {
		tx.rollback();//事務回滾
		e.printStackTrace();
	}finally{
		// 第5步:釋放資源
		em.close();
	}
}

/**
 * 查詢一個客戶(使用延遲加載的策略)
 */
@Test
public void testLoadOne(){
	EntityManager em = null;//JPA數據庫操作對象
	EntityTransaction tx = null;//JPA事務對象
	try {
		// 第1步:獲取操作數據庫對象
		em = JPAUtil.getEntityManager();
		// 第2步:獲取JPA中的事務對象 並開啓事務
		tx = em.getTransaction();// 此時沒有開啓事務
		tx.begin();// 開啓事務
		// 第3步:執行操作
		Customer c = em.getReference(Customer.class, 97L);	
		// 第4步:提交事務
		tx.commit();
		
		System.out.println(c);
	} catch (Exception e) {
		tx.rollback();//事務回滾
		e.printStackTrace();
	}finally{
		// 第5步:釋放資源
		em.close();
	}
}

5.查詢所有

@Test
public void testFindAll(){
	EntityManager em = null;//JPA數據庫操作對象
	EntityTransaction tx = null;//JPA事務對象
	try {
		// 第1步:獲取操作數據庫對象
		em = JPAUtil.getEntityManager();
		// 第2步:獲取JPA中的事務對象 並開啓事務
		tx = em.getTransaction();// 此時沒有開啓事務
		tx.begin();// 開啓事務
		// 第3步:執行操作   Query對象不是之前Hibernate中的,而是屬於JPA下的對象(javax.persistence.Query)
             /*使用EntityManager對象下的createQuery()方法獲得Query對象
查詢所有時,不能使用*號,而是需要在from關鍵字後面的類名上加別名
例如: select c from Customer c
             */
		Query query =em.createQuery("select c from Customer c where custName like ?");
		query.setParameter(1, "%傳智%");
		List list = query.getResultList();
		//第4步:提交事務
		tx.commit();
		
		for(Object obj : list){
			System.out.println(obj);
		}
	}catch(Exception e){
		tx.rollback();//事務回滾
		e.printStackTrace();
	}finally{
		// 第5步:釋放資源
		em.close();
	}
}

獲取結果集常用方法:
getResultList() : 查詢結果是一個List集合
getSingleResult() : 查詢結果是一個對象


3.JPA一對多操作

3.1 常用註解

@OneToMany

  • 作用:建立一對多的關係映射
  • 屬性:
    targetEntity:指定一對多中屬於多的那方實體類的字節碼
    mappedBy:指定從表實體類中引用主表對象的名稱。
    cascade:指定要使用的級聯操作
    fetch:指定是否採用延遲加載
    orphanRemoval:是否使用孤兒刪除

@ManyToOne

  • 作用:建立多對一的關係
  • 屬性:
    targetEntity:指定一對多中屬於一的那方實體類的字節碼
    cascade:指定要使用的級聯操作
    fetch:指定是否採用延遲加載
    optional:關聯是否可選。如果設置爲false,則必須始終存在非空關係。

@JoinColumn

  • 作用:用於定義主鍵字段和外鍵字段的對應關係。
  • 屬性:
    name:指定外鍵字段的名稱
    referencedColumnName:指定引用主表的主鍵字段名稱
    unique:是否唯一。默認值不唯一
    nullable:是否允許爲空。默認值允許。
    insertable:是否允許插入。默認值允許。
    updatable:是否允許更新。默認值允許。
    columnDefinition:列的定義信息。

3.2 配置代碼

Customer配置,代碼如下:

package cn.itcast.domain;
import java.io.Serializable;
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.OneToMany;
import javax.persistence.Table;
/**
 * 客戶實體類
 * 
 * @author Jackie
 *
 */
@Entity //表示當前類爲實例類
@Table(name="cst_customer") //建立類和表之間的關係
public class Customer implements Serializable {
	@Id//表示主鍵
	@GeneratedValue(strategy=GenerationType.IDENTITY)//主鍵生成策略
	@Column(name="cust_id")//建立類中屬性和表中字段的映射
	private Long custId;// 客戶ID
	
	@Column(name="cust_name")
	private String custName;// 客戶名稱
	
	@Column(name="cust_source")
	private String custSource;// 客戶來源
	
	@Column(name="cust_industry")
	private String custIndustry;// 客戶所屬行業
	
	@Column(name="cust_level")
	private String custLevel;// 客戶級別
	
	@Column(name="cust_address")
	private String custAddress;// 客戶聯繫地址
	
	@Column(name="cust_phone")
	private String custPhone;// 客戶聯繫方式
	
     // 一對多映射
	@OneToMany(targetEntity=LinkMan.class,mappedBy="customer")
	private Set<LinkMan> linkmans = new HashSet<LinkMan>(0);
	
	public Set<LinkMan> getLinkmans() {
		return linkmans;
	}
	public void setLinkmans(Set<LinkMan> linkmans) {
		this.linkmans = linkmans;
	}
	public Long getCustId() {
		return custId;
	}
	public void setCustId(Long custId) {
		this.custId = custId;
	}
	public String getCustName() {
		return custName;
	}
	public void setCustName(String custName) {
		this.custName = custName;
	}
	public String getCustSource() {
		return custSource;
	}
	public void setCustSource(String custSource) {
		this.custSource = custSource;
	}
	public String getCustIndustry() {
		return custIndustry;
	}
	public void setCustIndustry(String custIndustry) {
		this.custIndustry = custIndustry;
	}
	public String getCustLevel() {
		return custLevel;
	}
	public void setCustLevel(String custLevel) {
		this.custLevel = custLevel;
	}
	public String getCustAddress() {
		return custAddress;
	}
	public void setCustAddress(String custAddress) {
		this.custAddress = custAddress;
	}
	public String getCustPhone() {
		return custPhone;
	}
	public void setCustPhone(String custPhone) {
		this.custPhone = custPhone;
	}
	@Override
	public String toString() {
		return "Customer [custId=" + custId + ", custName=" + custName
				+ ", custSource=" + custSource + ", custIndustry="
				+ custIndustry + ", custLevel=" + custLevel + ", custAddress="
				+ custAddress + ", custPhone=" + custPhone + "]";
	}
}

LinkMan配置,代碼如下:

package cn.itcast.domain;
import java.io.Serializable;
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;
/**
 * 聯繫人實體類
 * 
 * @author Administrator
 *
 */
@Entity
@Table(name="cst_linkman")
public class LinkMan implements Serializable {
	@Id
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	@Column(name="lkm_id")
	private Long lkmId;//聯繫人編號(主鍵)
	
	@Column(name="lkm_name")
	private String lkmName;//聯繫人姓名
	
	@Column(name="lkm_gender")
	private String lkmGender;//聯繫人性別
	
	@Column(name="lkm_phone")
	private String lkmPhone;//聯繫人辦公電話
	
	@Column(name="lkm_mobile")
	private String lkmMobile;//聯繫人手機
	
	@Column(name="lkm_email")
	private String lkmEmail;//聯繫人郵箱
	
	@Column(name="lkm_position")
	private String lkmPosition;//聯繫人職位
	
	@Column(name="lkm_memo")
	private String lkmMemo;//聯繫人備註
	
     //多對一映射
	@ManyToOne(targetEntity=Customer.class)
	@JoinColumn(name="lkm_cust_id", referencedColumnName="cust_id")
	private Customer customer;//對應聯繫人表中的外鍵
	
	public Customer getCustomer() {
		return customer;
	}
	public void setCustomer(Customer customer) {
		this.customer = customer;
	}
    public Long getLkmId() {
		return lkmId;
	}
	public void setLkmId(Long lkmId) {
		this.lkmId = lkmId;
	}
	public String getLkmName() {
		return lkmName;
	}
	public void setLkmName(String lkmName) {
		this.lkmName = lkmName;
	}
	public String getLkmGender() {
		return lkmGender;
	}
	public void setLkmGender(String lkmGender) {
		this.lkmGender = lkmGender;
	}
	public String getLkmPhone() {
		return lkmPhone;
	}
	public void setLkmPhone(String lkmPhone) {
		this.lkmPhone = lkmPhone;
	}
	public String getLkmMobile() {
		return lkmMobile;
	}
	public void setLkmMobile(String lkmMobile) {
		this.lkmMobile = lkmMobile;
	}
	public String getLkmEmail() {
		return lkmEmail;
	}
	public void setLkmEmail(String lkmEmail) {
		this.lkmEmail = lkmEmail;
	}
	public String getLkmPosition() {
		return lkmPosition;
	}
	public void setLkmPosition(String lkmPosition) {
		this.lkmPosition = lkmPosition;
	}
	public String getLkmMemo() {
		return lkmMemo;
	}
	public void setLkmMemo(String lkmMemo) {
		this.lkmMemo = lkmMemo;
	}
	@Override
	public String toString() {
		return "LinkMan [lkmId=" + lkmId + ", lkmName=" + lkmName
				+ ", lkmGender=" + lkmGender + ", lkmPhone=" + lkmPhone
				+ ", lkmMobile=" + lkmMobile + ", lkmEmail=" + lkmEmail
				+ ", lkmPosition=" + lkmPosition + ", lkmMemo=" + lkmMemo + "]";
	}
}

3.3 增刪改操作

1.保存操作

@Test
public void testOneToMany() {
	// 創建客戶對象
	Customer c = new Customer();// 瞬時態
	c.setCustName("TBD雲集中心");
	c.setCustLevel("VIP客戶");
	c.setCustSource("網絡");
	c.setCustIndustry("商業辦公");
	c.setCustAddress("金沙江路1340弄");
	c.setCustPhone("021-84389340");
	// 創建聯繫人對象
	LinkMan lkm = new LinkMan();// 瞬時態
	lkm.setLkmName("TBD聯繫人");
	lkm.setLkmGender("男");
	lkm.setLkmMobile("13811111111");
	lkm.setLkmPhone("021-34785348");
	lkm.setLkmEmail("[email protected]");
	lkm.setLkmPosition("業務經理");
	lkm.setLkmMemo("做事比較保守");
	lkm.setCustomer(c);//建立單向關係 (沒有建立雙向關係)
	
	EntityManager em = null;//JPA數據庫操作對象
	EntityTransaction tx = null;//JPA事務對象
	try {
		em = JPAUtil.getEntityManager();//獲取JPA操作對象
		tx = em.getTransaction();//獲取JPA事務對象(事務未開啓)
		tx.begin();//開啓事務
		//保存操作   先保存客戶,再保存聯繫人
		em.persist(c);//保存客戶
		em.persist(lkm);//保存聯繫人
           //提交事務
		tx.commit();			
	} catch (Exception e) {
	  tx.rollback();//事務回滾
	  e.printStackTrace();
	}finally{
	  em.close();//釋放資源	
	}
}

執行程序後:
在這裏插入圖片描述
數據庫:
在這裏插入圖片描述在這裏插入圖片描述
案例:使用雙向關係的保存客戶代碼:

package cn.itcast.test;
import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import org.junit.Test;
import cn.itcast.domain.Customer;
import cn.itcast.domain.LinkMan;
import cn.itcast.util.JPAUtil;
/**
 * 測試類  用於測試JPA一對多映射關係
 * 
 * @author Administrator
 */
public class JPATest2 {
	/**
	 * 保存客戶 (一對多映射關係)
	 *   保存一個客戶、一個聯繫人
	 */
	@Test
	public void testOneToManySave() {
		// 創建客戶對象
		Customer c = new Customer();// 瞬時態
		c.setCustName("TBD雲集中心2");
		c.setCustLevel("VIP客戶");
		c.setCustSource("網絡");
		c.setCustIndustry("商業辦公");
		c.setCustAddress("金沙江路1340弄");
		c.setCustPhone("021-84389340");
		// 創建聯繫人對象
		LinkMan lkm = new LinkMan();// 瞬時態
		lkm.setLkmName("TBD聯繫人2");
		lkm.setLkmGender("女");
		lkm.setLkmMobile("13800000000");
		lkm.setLkmPhone("021-34785348");
		lkm.setLkmEmail("[email protected]");
		lkm.setLkmPosition("業務經理");
		lkm.setLkmMemo("沒有什麼好說的");
		
		//建立一對多雙向關聯關係
		lkm.setCustomer(c); 
		c.getLinkmans().add(lkm);
		
		EntityManager em = null;//JPA數據庫操作對象
		EntityTransaction tx = null;//JPA事務對象
		try {
			em = JPAUtil.getEntityManager();//獲取JPA操作對象
			tx = em.getTransaction();//獲取JPA事務對象(事務未開啓)
			tx.begin();//開啓事務
			//保存操作   先保存客戶,再保存聯繫人
			em.persist(c);//保存客戶
			em.persist(lkm);//保存聯繫人
            //提交事務
			tx.commit();			
		} catch (Exception e) {
		  tx.rollback();//事務回滾
		  e.printStackTrace();
		}finally{
		  em.close();//釋放資源	
		}
	}
}

執行程序後:
JPA註解的配置方式:不涉及多一條update語句的問題
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
結論:在JPA環境下,雙向關聯後,進行保存時,不會出現多餘update語句

2.修改操作

@Test
public void testOnToManyUpdate(){
	// 創建聯繫人對象
	LinkMan lkm = new LinkMan();// 瞬時態
	lkm.setLkmName("TBD聯繫人3");
	lkm.setLkmGender("男");
	lkm.setLkmMobile("13800138000");
	lkm.setLkmPhone("021-34785348");
	lkm.setLkmEmail("[email protected]");
	lkm.setLkmPosition("業務員");
	lkm.setLkmMemo("還可以");
	
	EntityManager em = null;//JPA數據庫操作對象
	EntityTransaction tx = null;//JPA事務對象
	try {
		em = JPAUtil.getEntityManager();//獲取JPA操作對象
		tx = em.getTransaction();//獲取JPA事務對象(事務未開啓)
		tx.begin();//開啓事務
		//根據id查詢客戶
		Customer c1 = em.find(Customer.class, 5L);
		//建立雙向關聯關係
		c1.getLinkmans().add(lkm);
		lkm.setCustomer(c1);
		
		//更新操作有兩種方案:
		//第一種使用JPA提交事務自動更新機制(JPA中的快照)
		//第二種使用EntityManager對象中的merge()方法
		
		//此處使用提交事務自動更新機制
		tx.commit();			
		
	} catch (Exception e) {
	  tx.rollback();//事務回滾
	  e.printStackTrace();
	}finally{
	  em.close();//釋放資源	
	}
}

執行程序後,發現沒有更新成功。
解決方案:設置級聯更新

在這裏插入圖片描述
案例:使用單向關聯實現客戶更新

@Test
public void testOnToManyUpdate(){
	// 創建聯繫人對象
	LinkMan lkm = new LinkMan();// 瞬時態
	lkm.setLkmName("TBD聯繫人3");
	lkm.setLkmGender("男");
	lkm.setLkmMobile("13800138000");
	lkm.setLkmPhone("021-34785348");
	lkm.setLkmEmail("[email protected]");
	lkm.setLkmPosition("業務員");
	lkm.setLkmMemo("還可以");
	
	EntityManager em = null;//JPA數據庫操作對象
	EntityTransaction tx = null;//JPA事務對象
	try {
		em = JPAUtil.getEntityManager();//獲取JPA操作對象
		tx = em.getTransaction();//獲取JPA事務對象(事務未開啓)
		tx.begin();//開啓事務
		//根據id查詢客戶
		Customer c1 = em.find(Customer.class, 5L);
		//建立單向關聯關係
		lkm.setCustomer(c1);
		
		//更新操作有兩種方案:
		//第一種使用JPA提交事務自動更新機制(JPA中的快照)
		//第二種使用EntityManager對象中的merge()方法
		
		em.merge(lkm);//此處使用merge()方法
		
		tx.commit();				
	} catch (Exception e) {
	  tx.rollback();//事務回滾
	  e.printStackTrace();
	}finally{
	  em.close();//釋放資源	
	}
}

不需要設置級聯,因爲我們只需要操作linkman表,不會去改動客戶表

3.刪除操作
需求:刪除客戶

/**
 * 刪除客戶
 * 
 * 刪除操作
 * 	刪除從表數據:可以隨時任意刪除。
 * 	刪除主表數據:
 * 		有從表數據引用
 * 			1、不能刪除
 * 			2、如果還想刪除,使用級聯刪除
 * 		沒有從表數據引用:隨便刪
 * 
 * 注意:在實際開發中請慎用級聯刪除
 */
@Test
public void testOneToManyDelete(){
	EntityManager em = null;//JPA數據庫操作對象
	EntityTransaction tx = null;//JPA事務對象
	try {
		em = JPAUtil.getEntityManager();//獲取JPA操作對象
		tx = em.getTransaction();//獲取JPA事務對象(事務未開啓)
		tx.begin();//開啓事務
		//查詢客戶
		Customer c = em.find(Customer.class,5L);
		em.remove(c);
		
		tx.commit();//提交事務
	}catch(Exception e){
		tx.rollback();//事務回滾
		e.printStackTrace();
	}finally{
		em.close();//釋放資源
	}
}

執行程序後: 在未設置級聯的情況下,僅刪除了客戶表中的數據
在這裏插入圖片描述
數據庫: 主表中數據已刪除,從表(外鍵表)中的數據未刪除
在這裏插入圖片描述
在這裏插入圖片描述
案例:使用級聯刪除
在這裏插入圖片描述
在這裏插入圖片描述

4.JPA多對多操作

4.1 常用註解

  • @ManyToMany
    作用:用於映射多對多關係
    屬性:
    • mappedBy:
    • cascade:配置級聯操作。
    • fetch:配置是否採用延遲加載。
    • targetEntity:配置目標的實體類。映射多對多的時候不用寫。
  • @JoinTable
    作用:針對中間表的配置
    屬性:
    • name:配置中間表的名稱
    • joinColumns:中間表的外鍵字段關聯當前實體類所對應表的主鍵字段
    • inverseJoinColumn:中間表的外鍵字段關聯對方表的主鍵字段
  • @JoinColumn
    作用:用於定義主鍵字段和外鍵字段的對應關係。
    屬性:
    • name:指定外鍵字段的名稱
    • referencedColumnName:指定引用主表的主鍵字段名稱
    • unique:是否唯一。默認值不唯一
    • nullable:是否允許爲空。默認值允許。
    • insertable:是否允許插入。默認值允許。
    • updatable:是否允許更新。默認值允許。
    • columnDefinition:列的定義信息。

5.JPA其他說明

6.總結

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章