文章目錄
1. 一對一 @OneToOne
@Target({METHOD, FIELD})
@Retention(RUNTIME)
public @interface OneToOne {
/**
* (Optional) The entity class that is the target of
* the association.
*
* <p> Defaults to the type of the field or property
* that stores the association.
*/
Class targetEntity() default void.class;
/**
* (Optional) The operations that must be cascaded to
* the target of the association.
*
* <p> By default no operations are cascaded.
*/
CascadeType[] cascade() default {};
/**
* (Optional) Whether the association should be lazily
* loaded or must be eagerly fetched. The EAGER
* strategy is a requirement on the persistence provider runtime that
* the associated entity must be eagerly fetched. The LAZY
* strategy is a hint to the persistence provider runtime.
*/
FetchType fetch() default EAGER;
/**
* (Optional) Whether the association is optional. If set
* to false then a non-null relationship must always exist.
*/
boolean optional() default true;
/** (Optional) The field that owns the relationship. This
* element is only specified on the inverse (non-owning)
* side of the association.
*/
String mappedBy() default "";
/**
* (Optional) Whether to apply the remove operation to entities that have
* been removed from the relationship and to cascade the remove operation to
* those entities.
* @since 2.0
*/
boolean orphanRemoval() default false;
}
2. 單向一對多(一般不用)
一般不使用單向一對多
,會產生額外update語句,如果需要就使用雙向一對多
雙向一對多
和雙向多對一
是一個意思
<hibernate-mapping package="cn.itsource.hibernate.day2.manytoone">
<class name="ProductDir">
<id name="id">
<generator class="native" />
</id>
<property name="name" />
<!-- 一個產品類型包含多個產品 -->
<!-- private Set<Product> products = new HashSet<Product>(); -->
<set name="products">
<!-- 在一方ProductDir配置外鍵的列名,自動跑到多方Product的表中 -->
<key column="dir_id"/>
<one-to-many class="Product"/>
</set>
</class>
<class name="Product">
<id name="id">
<generator class="native" />
</id>
<property name="name" />
</class>
</hibernate-mapping>
set說明
name: java屬性
column: 外鍵名稱
class: 多方的類名
2.1. 保存
必定會產生額外update語句,因爲是一方維護外鍵值
// 一方
ProductDir dir = new ProductDir();
dir.setName("類型1");
// 多方
Product product = new Product();
product.setName("產品1");
Product product2 = new Product();
product2.setName("產品2");
// 只能由一方建立到多方的關係(設置外鍵)
dir.getProducts().add(product);
dir.getProducts().add(product2);
Session session = HibernateUtils.getSession();
session.beginTransaction();
session.save(product);
session.save(product2);
session.save(dir);
session.getTransaction().commit();
session.close();
2.2. 查詢
先獲取一方再獲取多方
默認是延遲加載多方
2.3. 坑
dir.getProducts() 不會爲 null
ProductDir dir = (ProductDir) session.get(ProductDir.class, 1L);
System.out.println(dir); 36. System.out.println(dir.getProducts().getClass());
if (dir.getProducts() == null) {
System.out.println("當前產品類型沒有產品");
} else {
System.out.println("當前產品類型有產品");
}
原因:只會發一條sql查詢productDir,不會查詢product表,所以dir.getProducts() 永遠不爲null
正確用法:會發兩條sql
if (dir.getProducts().size() > 0) {
2.4. @OneToMany
3. 單向多對一
<hibernate-mapping package="cn.itsource.hibernate.day2.manytoone">
<class name="ProductDir">
<id name="id">
<generator class="native" />
</id>
<property name="name" />
</class>
<class name="Product">
<id name="id">
<generator class="native" />
</id>
<property name="name" />
<!-- 多個Product屬於一個ProductDir,外鍵在那個表,這個表就是多 -->
<!-- private ProductDir dir; -->
<many-to-one name="dir" class="ProductDir" column="dir_id" lazy="true"/>
</class>
</hibernate-mapping>
many-to-one說明
name: java的屬性
class: 唯一一個地方可以不配置class,反射獲取
column: 外鍵的列名,可以不配置,默認使用name屬性值
lazy: 延遲加載,爲false時立即加載
3.1. 保存
先保存一方,再保存多方,否則出現多個update語句
// 一方
ProductDir dir = new ProductDir();
dir.setName("類型1");
// 多方
Product product = new Product();
product.setName("產品1");
Product product2 = new Product();
product2.setName("產品2");
// 設置外鍵,多方到一方的關係
product.setDir(dir);
product2.setDir(dir);
Session session = HibernateUtils.getSession(); session.beginTransaction();
session.save(dir);
session.save(product);
session.save(product2);
session.getTransaction().commit();
session.close();
先保存多方,再保存一行(錯誤用法)
,commit提交時發現多方出現髒數據,會發出額外的update(髒數據更新)
session.save(product);
session.save(product2);
session.save(dir);
3.2. 查詢
先獲取多方再獲取一方
默認是延遲加載一方
3.3. 報錯
org.hibernate.LazyInitializationException
延遲加載異常
原因:提前關閉了session
session.close();
System.out.println(product.getDir());
org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: cn.i tsource.hibernate.day2.manytoone.ProductDir
保存了一個臨時(瞬時)對象
原因:在多方實例化了一方,因爲實例化之後一方沒有主鍵,也就是多方沒有外鍵值,保存會出錯
public class Product
private Long id;
private String name;
//錯誤用法,hibernate處理時認爲有id,但是本質沒id
private ProductDir dir = new ProductDir();
//ProductDir dir = new ProductDir()建立了關聯,所以註銷下面2行
//product.setDir(dir);
//product2.setDir(dir);
session.save(product);
session.save(product2);
正確用法
private ProductDir dir;
3.4 @ManyToOne
4. 單向多對多
@ManyToMany