JPA學習(基於hibernate)

參考博客:http://www.javashuo.com/article/p-shtmciay-dd.htmlhtml

 經常使用註解:java

https://blog.csdn.net/eastlift/article/details/2463243mysql

http://www.javashuo.com/article/p-rknybqru-hw.htmlsql

https://blog.csdn.net/u014421556/article/details/52040263數據庫

----------------------session

所需jarapp

 

persistence.xml(注意文件的位置必定要在類路徑下META-INF文件夾下)框架

<persistence version="2.1"
             xmlns="http://xmlns.jcp.org/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
             http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<!-- 事務類型使用本地事務 -->      
<persistence-unit name="simple" transaction-type="RESOURCE_LOCAL">  
      
  <properties>    
   <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect"/>
   <property name="hibernate.hbm2ddl.auto" value="update"/>
    
   <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver" />    
   <property name="hibernate.connection.username" value="root" />    
   <property name="hibernate.connection.password" value="jay571018"/>
   <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3308/jpatest?useUnicode=true&amp;characterEncoding=UTF-8" />    
     <!-- 
   <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />  
   <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3308/jpatest?useUnicode=true&amp;characterEncoding=UTF-8" />  
   <property name="javax.persistence.jdbc.user" value="root" />  
   <property name="javax.persistence.jdbc.password" value="jay571018"></property> 
      -->
  </properties>    
 </persistence-unit>    
</persistence>      
    
    
      
View Code

---------------------------------------ide

實體類:Person測試

package org.model;

import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;



@Entity
//@Table(name="xxx")  建立的表名稱爲xxx  若是不寫 默認爲類名稱首字母小寫
public class Person {
    private Integer id;
    private String name;
    private Date birthday;
    //性別
    private Gender gender=Gender.Man;//默認值爲Man

    public Person() {}

    public Person(String name) {
        super();
        this.id = id;
        this.name = name;
    }
    
    
    
    public Person(String name, Date birthday) {
        super();
        
        this.name = name;
        this.birthday = birthday;
    }

    //可省略  默認爲自動生成策略
    //數據庫中的主鍵字段名稱爲id  主鍵增加類型爲自動選擇
    @Id @GeneratedValue(strategy=GenerationType.AUTO)
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    //數據庫中的字段personame和該實體類中的name屬性進行映射  不爲空  長度爲10 
    @Column(length=10,name="personname",nullable=false)
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    //TemporalType.DATE:數據格式爲2018-04-04  數據庫字段類型爲date
    //TemporalType.TIMESTAMP:數據格式爲2018-04-03 20:56:53   數據庫字段類型爲datetime
    @Temporal(TemporalType.TIMESTAMP)
    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }
    
    //EnumType.STRING保存進數據庫時 是字符串的形式 Man或者Momen
    //EnumType.ORDINAL保存進數據庫時 是以索引值的形式  0或者1
    @Enumerated(EnumType.STRING) @Column(nullable=false,length=5)
    public Gender getGender() {
        return gender;
    }

    public void setGender(Gender gender) {
        this.gender = gender;
    }
    

}
View Code

實體類:Gender

package org.model;
//建立枚舉  性別
public enum Gender {
    Man,Women
}
View Code

建表和插入測試:

    //建表測試
    @Test
    public void createtable() {
        //該方法中的參數就是配置文件中  持久化單元的名稱
        EntityManagerFactory factory=Persistence.createEntityManagerFactory("simple");
        factory.close();
    }
    
    //插入測試
    @Test
    public void save() {
        //該方法中的參數就是配置文件中  持久化單元的名稱
        EntityManagerFactory factory=Persistence.createEntityManagerFactory("simple");
        EntityManager em = factory.createEntityManager();
        em.getTransaction().begin();//開啓事務
        em.persist(new Person("張三",new Date()));//持久化  即保存一個對象到數據庫中
        em.getTransaction().commit();//提交事務
        em.close();
        factory.close();
    }
View Code

數據庫表結構以及數據記錄

 

--------------------------------

大文本以及延遲加載等註解的使用

    //大文本類型   例如我的信息說明
    private String info;
    //大文本類型  文件
    private Byte[] file;
    //圖片路徑  //需求:該字段不做爲持久化字段  使用@Transient
    private String imgpath;

    //大文本類型 若是沒有特殊的代表 那麼默認255長度 不能知足需求 
    //使用該註解的話String類型映射到數據庫的類型爲:   Byte類型映射到數據庫中的類型爲:
    @Lob
    public String getInfo() {
        return info;
    }

    public void setInfo(String info) {
        this.info = info;
    }
    //該字段內容在執行查詢的時候  按需加載
    @Lob @Basic(fetch=FetchType.LAZY)
    public Byte[] getFile() {
        return file;
    }

    public void setFile(Byte[] file) {
        this.file = file;
    }
    @Transient
    public String getImgpath() {
        return imgpath;
    }
    
    public void setImgpath(String imgpath) {
        this.imgpath = imgpath;
    }
View Code

------------------------------------------

查詢測試

爲了方便觀察,咱們讓查詢的sql語句在控制檯中打印,在persistence.xml配置以下內容:

 <!-- 配置控制檯打印sql -->
   <property name="hibernate.show_sql" value="true"/>
   <!-- sql語句格式化配置 -->
   <property name="hibernate.format_sql" value="true"/>

測試1:

//查詢測試1
    @Test
    public void getPerson1() {
        EntityManagerFactory factory=Persistence.createEntityManagerFactory("simple");
        EntityManager em=factory.createEntityManager();
        System.out.println("---------------0");
        Person p = em.find(Person.class,1);//至關於hibernate中的get方法
        System.out.println("---------------1");
        em.close();
        System.out.println("---------------2");
        System.out.println(p.getName());
    }

測試2:

//查詢測試2
    @Test
    public void getPerson2() {
        EntityManagerFactory factory=Persistence.createEntityManagerFactory("simple");
        EntityManager em=factory.createEntityManager();    
        //至關於hibernate中的load方法
        System.out.println("---------------0");
        Person p = em.getReference(Person.class,1);//該方法和find方法的不一樣再於:第一次訪問對象中的屬性時纔會發生數據的裝載行爲
        System.out.println("---------------1");
        System.out.println(p.getName());
        System.out.println("---------------2");
        //可是必須保證EntityManager沒有關閉
        em.close();
        factory.close();
    }

使用該方法時,若是是第一次加載對象屬性,那麼EntityManager不能關閉  不然異常

    //查詢測試2
    @Test
    public void getPerson2() {
        EntityManagerFactory factory=Persistence.createEntityManagerFactory("simple");
        EntityManager em=factory.createEntityManager();    
        //至關於hibernate中的load方法
        System.out.println("---------------0");
        Person p = em.getReference(Person.class,1);//該方法和find方法的不一樣再於:第一次訪問對象中的屬性時纔會發生數據的裝載行爲
        System.out.println("---------------1");
        //System.out.println(p.getName());
        //System.out.println("---------------2");
        //可是必須保證EntityManager沒有關閉
        em.close();
        factory.close();
        //若是是第一次加載屬性這裏將報錯:nosession異常
        System.out.println(p.getName());
    }

這兩個方法若是在執行查詢的時候,數據庫中沒有查詢的對象時  產生的結果也不一樣  前者不會報異常,然後者會報 

//異常測試  正常執行  輸出null
        Person p = em.find(Person.class,3);
        System.out.println(p);
        em.close();
        factory.close();
View Code

正常執行,輸出null(不是打印地址,這裏須要注意,若是沒有close語句的時候,則會打印對象地址,這個地方我也沒有搞明白)

    //異常測試   出現異常  實體類找不到  並且出現異常的時機在輸出p的時候產生  而不是在執行查詢的時候產生
        Person p = em.getReference(Person.class,3);//
        System.out.println(p);//在執行該語句的時候  產生異常  而不是在查詢的時候
        em.close();
        factory.close();
View Code

 

 -----------------------------

更新測試

    //更新測試
    @Test
    public void updatePerson() {
        //該方法中的參數就是配置文件中  持久化單元的名稱
        EntityManagerFactory factory=Persistence.createEntityManagerFactory("simple");
        EntityManager em = factory.createEntityManager();
        em.getTransaction().begin();//開啓事務
        Person p = em.find(Person.class,1);//此時處於託管態
        p.setName("xx3");
        em.getTransaction().commit();//提交事務  此時會執行批處理程序 把數據更新到數據庫  因此該語句很重要  不能省略
        //em.close();
        //factory.close();
    }
View Code

 

介紹兩個方法

第一個方法:

    //更新測試2
    @Test
    public void updatePerson2() {
        //該方法中的參數就是配置文件中  持久化單元的名稱
        EntityManagerFactory factory=Persistence.createEntityManagerFactory("simple");
        EntityManager em = factory.createEntityManager();
        em.getTransaction().begin();//開啓事務
        Person p = em.find(Person.class,1);//此時處於託管態
        em.clear();//把實體管理器中的全部對象變成遊離狀態 而後此時更新就沒法完成了
        p.setName("xx4");
        em.getTransaction().commit();//提交事務
    }

控制檯只有查詢語句而沒有更新語句

第二個方法:

    //更新測試2
    @Test
    public void updatePerson2() {
        //該方法中的參數就是配置文件中  持久化單元的名稱
        EntityManagerFactory factory=Persistence.createEntityManagerFactory("simple");
        EntityManager em = factory.createEntityManager();
        em.getTransaction().begin();//開啓事務
        Person p = em.find(Person.class,1);//此時處於託管態
        em.clear();//把實體管理器中的全部對象變成遊離狀態  而後此時更新就沒法完成了
        p.setName("xx5");
        em.merge(p);//用於把遊離狀態的更新同步回數據庫
        em.getTransaction().commit();//提交事務
    }

控制檯打印:

Hibernate: 
    select
        person0_.id as id1_0_0_,
        person0_.birthday as birthday2_0_0_,
        person0_.file as file3_0_0_,
        person0_.gender as gender4_0_0_,
        person0_.info as info5_0_0_,
        person0_.personname as personna6_0_0_ 
    from
        Person person0_ 
    where
        person0_.id=?
Hibernate: 
    select
        person0_.id as id1_0_0_,
        person0_.birthday as birthday2_0_0_,
        person0_.file as file3_0_0_,
        person0_.gender as gender4_0_0_,
        person0_.info as info5_0_0_,
        person0_.personname as personna6_0_0_ 
    from
        Person person0_ 
    where
        person0_.id=?
Hibernate: 
    update
        Person 
    set
        birthday=?,
        file=?,
        gender=?,
        info=?,
        personname=? 
    where
        id=?
View Code

能夠完成更新操做

----------------------------------------------------

刪除測試

    //刪除
    @Test
    public void deletePerson() {
        //該方法中的參數就是配置文件中  持久化單元的名稱
        EntityManagerFactory factory=Persistence.createEntityManagerFactory("simple");
        EntityManager em = factory.createEntityManager();
        em.getTransaction().begin();//開啓事務
        Person p = em.find(Person.class,1);//此時處於託管態
        em.remove(p);
        em.getTransaction().commit();//提交事務
    }
View Code

完成刪除

控制檯打印:

Hibernate: 
    select
        person0_.id as id1_0_0_,
        person0_.birthday as birthday2_0_0_,
        person0_.file as file3_0_0_,
        person0_.gender as gender4_0_0_,
        person0_.info as info5_0_0_,
        person0_.personname as personna6_0_0_ 
    from
        Person person0_ 
    where
        person0_.id=?
Hibernate: 
    delete 
    from
        Person 
    where
        id=?
View Code

---------------------------------------------

 JPQL語句

--------------------------

HQL:https://www.imooc.com/article/15791

JQPL:https://blog.csdn.net/czp11210/article/details/50799489

查詢測試:

EntityManagerFactory factory=Persistence.createEntityManagerFactory("simple");
        EntityManager em=factory.createEntityManager();
        Query createQuery = em.createQuery("select a from Person a where a.id=:id");
        createQuery.setParameter("id",1);
        
        List<Person> resultList =createQuery.getResultList();//這種返回結果能夠容許查詢的實體不存在
        for(Person p:resultList) {
            System.out.println(p.getName());
        }
View Code

即便查詢不到也沒有關係 ,而下面的這種結果返回狀況就不行了

Object singleResult = createQuery.getSingleResult();

若是查詢的實體不存在  那麼就以下:

--------------------------------

刪除測試:

    //刪除
    @Test
    public void delete() {
        EntityManagerFactory factory=Persistence.createEntityManagerFactory("simple");
        EntityManager em=factory.createEntityManager();
        em.getTransaction().begin();
        Query createQuery = em.createQuery("delete from Person where id=?1");
        createQuery.setParameter(1,2);
        createQuery.executeUpdate();
        em.getTransaction().commit();
    }
View Code

刪除的對象不存在也沒有關係

----------------------------------

更新:

//更新
    @Test
    public void update() {
        EntityManagerFactory factory=Persistence.createEntityManagerFactory("simple");
        EntityManager em=factory.createEntityManager();
        em.getTransaction().begin();
        //命名參數
        Query createQuery = em.createQuery("update Person set name=:name where id=:id");
        createQuery.setParameter("name","xx3");
        createQuery.setParameter("id",3);
        createQuery.executeUpdate();
        
        //第二條更新語句  使用位置參數
        createQuery = em.createQuery("update Person set name=?100 where id=?250");
        createQuery.setParameter(100, "xx4");
        createQuery.setParameter(250,4);
        createQuery.executeUpdate();
        
        em.getTransaction().commit();//提交事務  執行了兩次更新
    }
View Code

-------------------------------------

命名查詢

實體類:

測試代碼:

//命名查詢  在實體上邊直接寫JPQL語句
    @Test
    public void update2() {
        EntityManagerFactory factory=Persistence.createEntityManagerFactory("simple");
        EntityManager em=factory.createEntityManager();
        em.getTransaction().begin();
        Query createNamedQuery = em.createNamedQuery("updateSiggle");
        createNamedQuery.setParameter("name","fffff");
        createNamedQuery.setParameter(1,4);
        createNamedQuery.executeUpdate();
        em.getTransaction().commit();//提交事務  執行了兩次更新
    }
    @Test
    public void execute() {
        EntityManagerFactory factory=Persistence.createEntityManagerFactory("simple");
        EntityManager em=factory.createEntityManager();
        em.getTransaction().begin();
        //執行查詢
        Query createNamedQuery = em.createNamedQuery("queryPersonById");
        createNamedQuery.setParameter("id",4);
        List<Person> resultList = createNamedQuery.getResultList();
        for(Person p:resultList) {
            System.out.println(p.getName());
        }
        //執行更新
        Query createNamedQuery2 = em.createNamedQuery("updatePersonById");
        createNamedQuery2.setParameter("name","hhhh");
        createNamedQuery2.setParameter("id",4);
        createNamedQuery2.executeUpdate();
        em.getTransaction().commit();//提交事務  執行了兩次更新
    }
View Code

----------------------------

一對多

實體代碼

order

 

package org.model;

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.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
@Entity
@Table(name="orders")//由於在mysql中有關鍵字order  因此這裏指定創建的表名稱
public class Order{
    private String orderid;
    private Float amount=0f;
    //建立多方屬性
    private Set<OrderItem> items=new HashSet<OrderItem>();
    //fetch加載策略:懶加載  在一方配置時默認爲此方式  可不寫
    //出現mappedBy時  表示該實體爲被維護方  裏邊的屬性名稱表示:由OrderItem這個實體中的order屬性來維護該關係
    @OneToMany(cascade= {CascadeType.MERGE,CascadeType.PERSIST,CascadeType.REFRESH,CascadeType.REMOVE}
    ,fetch=FetchType.LAZY,mappedBy="order")
    public Set<OrderItem> getItems() {
        return items;
    }
    public void setItems(Set<OrderItem> items) {
        this.items = items;
    }
    
    @Id @Column(length=12)
    public String getOrderid() {
        return orderid;
    }
    public void setOrderid(String orderid) {
        this.orderid = orderid;
    }
    @Column(nullable=false)
    public Float getAmount() {
        return amount;
    }
    public void setAmount(Float amount) {
        this.amount = amount;
    }
    //相互創建關聯的過程
    public void addOrderItem(OrderItem orderItem) {
        orderItem.setOrder(this);
        this.items.add(orderItem);
        
    }

    

}
View Code

 

orderitem

package org.model;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;

import org.hibernate.boot.model.source.spi.CascadeStyleSource;

//訂單項實體
@Entity
public class OrderItem {
    private Integer id;
    private String productName;
    private Float productPrice=0f;
    //建立一方屬性
    private Order order;
    //級聯方式:選擇級聯更新  級聯刷新  級聯保存不須要:通常都是在保存訂單的時候去保存訂單項
    //使用多對一註解的時候  默認加載方式爲當即加載
    //optional:表示該外鍵字段是否能夠爲空   true 反映在數據庫中表示該字段容許爲空    false表示該字段 不能夠爲空 必須存在
    //JoinColumn指定生成的外鍵字段的名稱
    @ManyToOne(cascade= {CascadeType.MERGE,CascadeType.REFRESH},optional=false)
    @JoinColumn(name="order_id")
    public Order getOrder() {
        return order;
    }
    public void setOrder(Order order) {
        this.order = order;
    }
    @Id @GeneratedValue
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    @Column(length=20,nullable=false)
    public String getProductName() {
        return productName;
    }
    public void setProductName(String productName) {
        this.productName = productName;
    }
    @Column(nullable=false)
    public Float getProductPrice() {
        return productPrice;
    }
    public void setProductPrice(Float productPrice) {
        this.productPrice = productPrice;
    }
    


}
View Code

測試類:

@Test
    public void save() {
        EntityManagerFactory entityManagerFactory=Persistence.createEntityManagerFactory("simple");
        //建立訂單對象
        Order order=new Order();
        order.setOrderid("123");
        order.setAmount(123.3f);
        //建立多個訂單項對象
        OrderItem orderItem1=new OrderItem();
        orderItem1.setProductName("A商品");
        orderItem1.setProductPrice(33.5f);
        OrderItem orderItem2=new OrderItem();
        orderItem2.setProductName("B商品");
        orderItem2.setProductPrice(66f);
        //須要相互創建關聯   這個代碼寫在order實體中
        /*
        HashSet<OrderItem> hashSet=new HashSet<OrderItem>();
        hashSet.add(orderItem1);
        hashSet.add(orderItem2);
        order.setItems(hashSet);
        orderItem1.setOrder(order);
        orderItem2.setOrder(order);
        */
        order.addOrderItem(orderItem1);
        order.addOrderItem(orderItem2);
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        entityManager.getTransaction().begin();//必須開啓事務  不然沒法保存
        entityManager.persist(order);
        //entityManager.merge(order);若是表中order記錄已經存在  而訂單項中的記錄不存在  即便如今已經相互關聯了
        //可是調用persist方法的時候  訂單項的數據並不會更新到數據庫  由於只有調用merge時級聯更新纔會起做用
        entityManager.getTransaction().commit();
        entityManagerFactory.close();
    }
View Code

----------------------------

一對一

實體類代碼

person

package org.OneToOne;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;

@Entity
public class Person {
    private Integer pid;
    private String pname;
    //規定該實體做爲外鍵的維護端
    private Card card;
    @Id @GeneratedValue
    public Integer getPid() {
        return pid;
    }
    public void setPid(Integer pid) {
        this.pid = pid;
    }
    @Column(length=4,nullable=false)
    public String getPname() {
        return pname;
    }
    public void setPname(String pname) {
        this.pname = pname;
    }
    //外鍵不能爲空  外鍵名稱card_id
    @OneToOne(cascade={CascadeType.ALL},optional=false)
    @JoinColumn(name="card_id")
    public Card getCard() {
        return card;
    }
    public void setCard(Card card) {
        this.card = card;
    }
    
}
View Code

card

package org.OneToOne;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToOne;

@Entity
public class Card {
    private Integer cid;
    private String code;
    private Person person;
    @Id @GeneratedValue
    public Integer getCid() {
        return cid;
    }
    public void setCid(Integer cid) {
        this.cid = cid;
    }
    @Column(length=18,nullable=false)
    public String getCode() {
        return code;
    }
    public void setCode(String code) {
        this.code = code;
    }
    //mappedBy指定關係的維護端爲person  card爲被維護端 屬性值表示 由Person這個實體中的card屬性來維護該關係
    //該實體是被維護端  主鍵在維護端person中  因此person表是參考該表中的主鍵  因此這個地方不用配置optional=false屬性  也最好不要配置
    @OneToOne(cascade= {CascadeType.PERSIST,CascadeType.MERGE,CascadeType.REFRESH},mappedBy="card")
    public Person getPerson() {
        return person;
    }
    public void setPerson(Person person) {
        this.person = person;
    }
    

}
View Code

測試:

    //1對1 在配置文件中建立第二個持久化單元  使用新的數據庫
    @Test
    public void save2() {
        EntityManagerFactory entityManagerFactory=Persistence.createEntityManagerFactory("simple2");
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        entityManager.getTransaction().begin();
        //建立對象
        Person person=new Person();
        person.setPname("張三");
        Card card=new Card();
        card.setCode("112254563");
        person.setCard(card);//一對一的時候 不用互相關聯  保存維護端的時候  被維護端能夠通知時保存
        entityManager.persist(person);
        entityManager.getTransaction().commit();
        entityManager.close();
    }
View Code

 --------

1-m
多的一方爲關係維護端,關係維護端負責外鍵記錄的更新(出現mappedBy時 表示該實體爲被維護方),關係被維護端是沒有權利更新外鍵記錄
-----------------
級聯類型:如下幾種操做都是在執行實體管理器中封裝的方法時纔會執行的
CascadeType.REFRESH 級聯刷新:在查詢order的時候 對orderItem進行查詢 在執行find時起做用
(在調用 object.reflush時纔會觸發的操做)
CascadeType.PERSIST 級聯保存:在執行保存order的時候 同時執行orderItem對象的保存工做 (在執行persist方法時起做用)
CascadeTppe.MERGE 級聯合並:在更新order的時候,同時更新orderItem對象 (在執行merge方法時起做用)
CascadeType.REMOVE 級聯刪除:沒有主外鍵約束的狀況下 在執行order刪除的時候,同時執行orderItem對象的刪除 不然不刪除 (在執行romove方法時才起做用)
---------
以上4種級聯可使用:CascadeType.ALL代替
-----------------
一對多:在一方配置的時候 默認的延遲加載 在多方配置的時候,默認的是當即加載

--------------------
一對一:一對一的時候 不用互相關聯 保存維護端的時候 被維護端能夠同時進行保存

------

---------------------------------------

多對多

基本配置

實體類:

student:

@Entity
public class Student {
    private Integer id;
    private String name;
    private Set<Teacher> teachers=new HashSet<Teacher>();
    @Id @GeneratedValue
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    @Column(length=10,nullable=false)
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    //規定:學生爲關係的維護端
    //@JoinTable指定中間表的名稱爲t_s
    @ManyToMany(cascade= {CascadeType.REFRESH})
    @JoinTable(name="t_s")
    public Set<Teacher> getTeachers() {
        return teachers;
    }
    public void setTeachers(Set<Teacher> teachers) {
        this.teachers = teachers;
    }
    
}
View Code

teacher:

@Entity
public class Teacher {
    private Integer id;
    private String name;
    private Set<Student> students=new HashSet<Student>();
    
    @Id @GeneratedValue
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    @Column(length=10,nullable=false)
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @ManyToMany(cascade= {CascadeType.REFRESH},mappedBy="teachers")
    public Set<Student> getStudents() {
        return students;
    }
    public void setStudents(Set<Student> students) {
        this.students = students;
    }
    
}
View Code

建表測試:

EntityManagerFactory entityManagerFactory=Persistence.createEntityManagerFactory("simple");
entityManagerFactory.close();

下面是所建立的數據庫表:

若是不喜歡框架自動生成的字段名稱,咱們能夠本身控制

在定義中間表的時候,加上以下屬性:

//@JoinTable指定中間表的名稱爲t_s
    //inverseJoinColumns關係被維護端teacher 在中間表將要對應的外鍵名稱
    //joinColumns關係維護端  即本類student  在中間表中將要對應的外鍵名稱
    @ManyToMany(cascade= {CascadeType.REFRESH})
    @JoinTable(name="t_s",inverseJoinColumns=@JoinColumn(name="tid"),joinColumns=@JoinColumn(name="sid"))
    public Set<Teacher> getTeachers() {
        return teachers;
    }

而後從新生成的表字段:

------------------------------------------------------------

插入數據:向student和teacher表中各插入一條記錄

    //數據插入
    @Test
    public void insert() {
        EntityManagerFactory entityManagerFactory=Persistence.createEntityManagerFactory("simple");
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        entityManager.getTransaction().begin();
        //建立對象
        Student student=new Student();
        student.setName("肖戰");
        Teacher teacher=new Teacher();
        teacher.setName("張老師");
        //保存
        entityManager.persist(student);
        entityManager.persist(teacher);
        entityManager.getTransaction().commit();
        entityManagerFactory.close();
    }
View Code

數據庫:

目前中間表是沒有數據的,如今進行2個對象之間的關聯,而後向中間表插入數據(創建關係,即插入數據)

插入以前,爲了更加方便的創建和解除關係,因此咱們在student方(關係維護方,增長以下代碼)

   public void addTeacher(Teacher teacher) {
        this.teachers.add(teacher);
    }
    public void removeTeacher(Teacher teacher) {
        /*if(this.teachers.contains(teacher)) {//
            this.teachers.remove(teacher);
        }*/
        //若是集合中沒有   不移除   不會報錯
        this.teachers.remove(teacher);
    }

以下是添加記錄的測試類:

    @Test
    public void update() {
        EntityManagerFactory entityManagerFactory=Persistence.createEntityManagerFactory("simple");
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        entityManager.getTransaction().begin();
        //獲得對象
        Student student = entityManager.getReference(Student.class,3);
        Teacher teacher = entityManager.getReference(Teacher.class,4);
        //創建關係
        student.addTeacher(teacher);
        //創建了關係  提交以後  自動向中間表插入一條數據
        entityManager.getTransaction().commit();
        entityManagerFactory.close();
    }
View Code

如今開始解除關係,即刪除中間表的數據:

測試類:

@Test
    public void remove() {
        EntityManagerFactory entityManagerFactory=Persistence.createEntityManagerFactory("simple");
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        entityManager.getTransaction().begin();
        //找出兩個須要解除關係的對象
        Student student = entityManager.getReference(Student.class,3);
        Teacher teacher = entityManager.getReference(Teacher.class,4);
        //調用的是已經定義好的方法  解除關係
        student.removeTeacher(teacher);
        entityManager.getTransaction().commit();
        entityManagerFactory.close();
    }
View Code

能夠看到解除關係以後,執行代碼,中間表的數據已經被刪除

----------------------

思考:當中間表數據存在時,刪除teacher對象 ,是否能夠刪除成功

【不能夠,由於存在外鍵約束,因此在刪除中間表數據以後,才能刪除老師對象

刪除老師 (注意老師是被維護端 因此沒有權利刪除外鍵的記錄 即中間表的數據
若是非要刪除 那麼必須刪除中間表數據(解除關係) 而後刪除老師】

先看有問題的代碼,直接刪老師對象,以下:

    @Test
    public void removeTeacher() {
        EntityManagerFactory entityManagerFactory=Persistence.createEntityManagerFactory("simple");
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        entityManager.getTransaction().begin();
        Teacher teacher = entityManager.getReference(Teacher.class,4);    
        entityManager.remove(teacher);
        entityManager.getTransaction().commit();
        entityManagerFactory.close();
    }
View Code

提示,存在外鍵約束,不能正常刪除

下面是正確的代碼:

    @Test
    public void removeTeacher() {
        EntityManagerFactory entityManagerFactory=Persistence.createEntityManagerFactory("simple");
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        entityManager.getTransaction().begin();
        Student student = entityManager.getReference(Student.class,3);
        Teacher teacher = entityManager.getReference(Teacher.class,4);
        //先解除關係
        student.removeTeacher(teacher);
        //而後執行刪除
        entityManager.remove(teacher);
        entityManager.getTransaction().commit();
        entityManagerFactory.close();
    }
View Code

 

 

這樣就刪除成功了

---------------------------------------

 刪除學生對象,能夠直接進行刪除,由於該對象是關係維護端,有對中間表進行操做的權限,因此在執行刪除的時候,是先刪除中間表,而後刪除學生

    //刪除學生
    public void removeStudent() {
        EntityManagerFactory entityManagerFactory=Persistence.createEntityManagerFactory("simple");
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        entityManager.getTransaction().begin();
        Student student = entityManager.getReference(Student.class,3);
        //刪除學生
        entityManager.remove(student);
        entityManager.getTransaction().commit();
        entityManagerFactory.close();
    }
View Code

刪除了學生表中的對象,以及相關的中間表的數據

-------------------------

聯合主鍵

 聯合主鍵類:AirLinePK

package org.model.pk;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Embeddable;

//複合主鍵類
//有3個要求:1.必須提供無參的構造方法  2.實現序列化接口 3.覆寫equals和hashCode方法
@Embeddable
public class AirLinePK implements Serializable{
    private String start;
    private String end;
    @Column(length=10)
    public String getStart() {
        return start;
    }
    public void setStart(String start) {
        this.start = start;
    }
    @Column(length=10)
    public String getEnd() {
        return end;
    }
    public void setEnd(String end) {
        this.end = end;
    }
    @Override
    public int hashCode() {
        // TODO Auto-generated method stub
        return super.hashCode();
    }
    @Override
    public boolean equals(Object obj) {
        // TODO Auto-generated method stub
        return super.equals(obj);
    }
    
    public AirLinePK(String start, String end) {
        super();
        this.start = start;
        this.end = end;
    }
    
    

}
View Code

AirLine類中的主鍵是上邊的聯合主鍵

package org.model.pk;

import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;

@Entity
public class AirLine {
    //聯合主鍵
    private AirLinePK id;
    private String name;
    
    
    
    public AirLine(AirLinePK id, String name) {
        super();
        this.id = id;
        this.name = name;
    }
    
    //標識複合主鍵的註解
    @EmbeddedId
    public AirLinePK getId() {
        return id;
    }
    public void setId(AirLinePK id) {
        this.id = id;
    }
    @Column(length=10)
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    

}
View Code

測試:

    //聯合主鍵測試
    @Test
    public void build() {
        EntityManagerFactory entityManagerFactory=Persistence.createEntityManagerFactory("simple2");
        EntityManager createEntityManager = entityManagerFactory.createEntityManager();
        //開啓事務
        createEntityManager.getTransaction().begin();
        //建立對象
        AirLinePK airLinePK=new AirLinePK("北京","上海");
        AirLine airline=new AirLine(airLinePK,"北京飛往上海");
        createEntityManager.persist(airline);    
        //提交事務
        createEntityManager.getTransaction().commit();
    }
View Code

數據庫:

----------------------------------------------

繼承註解配置  

參考博客:http://cjnetwork.iteye.com/blog/974686

多方:Employee是父類,他有兩個子類Sales,Skiller   一方:Department

 

Employee:

package org.model;

import javax.persistence.Column;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.swing.text.IconView;

import org.hibernate.annotations.ManyToAny;
@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)//映射類型:單表  即因此繼承的子類字段都在一個表中  默認此方式
@DiscriminatorColumn(name="type")//鑑別器的列  
//:區別不一樣的類  由於存在Employee Sales Skiller的數據未來都會存入employee表 區別某條數據究竟是哪一個類的對象
@DiscriminatorValue("0")//鑑別器的值
public class Employee {
    private int id;
    private String name;
    private Department department;
    @Id @GeneratedValue()
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    @Column(length=10,nullable=false)
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @ManyToOne()
    //@JoinColumn(name="depart_id")//外鍵名  不指定的狀況下 默認: 字段名_id
    public Department getDepartment() {
        return department;
    }
    public void setDepartment(Department department) {
        this.department = department;
    }
    
    
    
}

Sales:

package org.model;

import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;

@Entity
@DiscriminatorValue("2")//鑑別器的值
public class Sales extends Employee {
    private int sell;//出售額
    
    public int getSell() {
        return sell;
    }

    public void setSell(int sell) {
        this.sell = sell;
    }
    
}

Skiller:

package org.model;

import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;

@Entity
@DiscriminatorValue("3")//鑑別器的值
public class Skiller extends Employee {
    private String Skill;//技能

    public String getSkill() {
        return Skill;
    }

    public void setSkill(String skill) {
        Skill = skill;
    }
    
}

Department:

 

package org.model;

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.Id;
import javax.persistence.OneToMany;
@Entity
public class Department {
    private int id;
    private String name;
    //private Set<Employee> emps=new HashSet<Employee>();
    private Set<Employee> emps;
    @Id @GeneratedValue()
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    @Column(length=10)
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @OneToMany(cascade= {CascadeType.MERGE,CascadeType.PERSIST},fetch=FetchType.LAZY,mappedBy="department")//mappedBy出如今該類,表示該類爲關係被維護方
    public Set<Employee> getEmps() {
        return emps;
    }
    public void setEmps(Set<Employee> emps) {
        this.emps = emps;
    }
    

}

 

測試:

public void t1() {
        EntityManager em = rtn();
        Department department=new Department();
        department.setName("銷售部");
        
        Employee e1=new Employee();
        e1.setName("張");
        e1.setDepartment(department);
        
        //建立employee的子類對象
        Sales e2=new Sales();
        e2.setName("王");
        e2.setSell(10);
        e2.setDepartment(department);
        
        Skiller e3=new Skiller();
        e3.setName("孫");
        e3.setSkill("會唱歌");
        e3.setDepartment(department);
        
        //建立員工集合
        Set<Employee> emps=new HashSet<Employee>();
        emps.add(e1);
        emps.add(e2);
        emps.add(e3);
        //互相關聯  添加進部門實體中
        department.setEmps(emps);
        
        em.getTransaction().begin();
        em.persist(department);
        em.getTransaction().commit();
    }
View Code

數據庫:

---------------------------------

相關文章
相關標籤/搜索