Hibernate總結(基于注解)

開始先對總結分個類。一共包括這幾個方面。

1.獲得工廠方法

2.操作數據庫

3.主鍵生成策略

4.繼承

5.關系映射

6.緩存


1.獲得工廠的方法

//1加載配置?

Configuration? conf =new Configuration().configure();?

//2 根據Configuration 配置信息創建 SessionFactory?

? ? ? ? SessionFactory sf = conf.buildSessionFactory();


還可以用5的新特性

SessionFactory sessionFactory=null;

final StandardServiceRegistry registry = new StandardServiceRegistryBuilder()

.configure().build();

sessionFactory = new MetadataSources(registry).buildMetadata()

.buildSessionFactory();


2.操作數據庫

有多種方法可以操作,我介紹其中兩種

第一:session操作數據庫

基于Session的操作,session擁有一個鏈接,并對數據庫經行操作。這個操作能力很有限,如果要定制可以用下面第二種方法完成

查詢:

get和load方式是根據id取得一個記錄

如果你使用load方法,hibernate認為該id對應的對象(數據庫記錄)在數據庫中是一定存在的,所以它可以放心的使用,它可以放心的使用代理來延遲加載該對象。在用到對象中的其他屬性數據時才查詢數據庫,但是萬一數據庫中不存在該記錄,那沒辦法,只能拋異常。所說的load方法拋異常是指在使用該對象的數據時,數據庫中不存在該數據時拋異常,而不是在創建這個對象時(注意:這就是由于“延遲加載”在作怪)。所以如果你知道該id在數據庫中一定有對應記錄存在就可以使用load方法來實現延遲加載。

session緩存中找到了該id對應的對象,如果剛好該對象前面是被代理過的,如被load方法使用過,或者被其他關聯對象延遲加載過,那么返回的還是原先的代理對象,而不是實體類對象,如果該代理對象還沒有加載實體數據(就是id以外的其他屬性數據),那么它會查詢二級緩存或者數據庫來加載數據,但是返回的還是代理對象,只不過已經加載了實體數據。get方法首先查詢session緩存,沒有的話查詢二級緩存,最后查詢數據庫;反而load方法創建時首先查詢session緩存,沒有就創建代理,實際使用數據時才查詢二級緩存和數據庫。

更新

update()

1、用來更新detached對象,更新完成后轉為persistent狀態。

2、更新transient對象會報錯

3、更新自己設定的唯一標識符(例如:Id)的transient對象且數據庫有對應記錄的可以update。

4、處于persistent狀態的對象,對這個對象的屬性內容進行更改后當commit時會自動觸發Session

update方法。有一點需要注意的是如果更改前后的內容完成一樣,則不會觸發update語句。只有對象在緩存中的內容和數據庫的記錄不一樣時,才會觸發update語句進行更新。

刪除:

delete()

delete()顧名思義刪除,用于從數據庫中刪除java對象對應的記錄。

delete()如果傳入持久化對象,組裝delete語句,執行刪除;如果傳入游離態對象,hibernate先把游離態關聯到session,變成持久態,再生成delete語句,

執行刪除。

都是只有當session緩存清空時,才執行。

以上執行都是一個對象,對應一條記錄。

可以用session.delete("from Customer where ....");后面加上條件刪除多條數據。

狀態介紹:


說到session方法了不妨介紹一下狀態

瞬時狀態就是剛new出來一個對象,還沒有被保存到數據庫中,持久化狀態就是已經被保存到數據庫中,離線狀態就是數據庫中有

如果一個對象以及是持久化狀態了,那么此時對該對象進行各種修改,或者調用多次update、save方法時,hibernate都不會發送sql語句,只有當事物提交的時候,此時hibernate才會拿當前這個對象與之前保存在session中的持久化對象進行比較,如果不相同就發送一條update的sql語句,否則就不會發送update語句

當session調用load、get方法時,此時如果數據庫中有該對象,則該對象也變成了一個持久化對象,被session所托管。因此,這個時候如果對對象進行操作,在提交事務時同樣會去與session中的持久化對象進行比較,因此這里會發送兩條sql語句

然后調用session.clear()方法,這個時候就會將session的緩存對象清空,那么session中就沒有了這個對象,這個時候在提交事務的時候,發現已經session中已經沒有該對象了,所以就不會進行任何操作

對于離線對象,如果要使其變成持久化對象的話,我們不能使用save方法,而應該使用update方法

saveOrUpdate這個方法,這個方法其實是一個"偷懶"的方法,如果對象是一個離線對象,那么在執行這個方法后,其實是調用了update方法,如果對象是一個瞬時對象,則會調用save方法,記住:如果對象設置了ID值,例如u.setId(4),那么該對象會被假設當作一個離線對象,此時就會執行update操作

總結:持久化狀態對象update()或者commit()保存時,會和先前Session中保存的持久化對象比較,不同就會更新。刪除了Session后再對對象經行操作都是無效的不會改變數據庫數據。seesion中不能同時擁有兩個持續化對象個,不能在已有id=x的情況下,再save()一個id=x的持續化對象。

第二,HQL語句操作數據庫

執行HQL語句的步驟:

(1)、獲取Session對象

(2)、編寫HQL語句

(3)、創建Query

session.createQuery(hql);

(4)、執行查詢,得到查詢結果。


1.使用預處理Sql

好處防注入,增加效率

SQLQuery query = session.createSQLQuery("select * from note where id = ?");//設置第一個參數的值為12,即查詢ID=12的notequery.setParameter(0,12);

需要注意的是就是,下標是從0開始,和原生是從1開始

2.轉化器

Transformers,它提供了一些常用的轉換器,能夠幫助我們快速轉換結果集,如Transformers.aliasToBean(Note.class)能夠將查詢結果依別名注入到Note實體中。

3.實體查詢

把查詢的數據直接映射要一個Bean上

session.createSQLQuery("selectid,note,createtime,authorfromnotewhereid = ?").addEntity(Note.class);

author字段即為Note實體和Author實體的關聯字段,只需在查詢時得到該字段的值,Hibernate即可使用該值找到對應的關聯實體。如上例中,note.getAuthor()即可返回當前Note所屬的Author對象。

4.query對象的一些實用接口

list();返回查詢結果,并把查詢結果轉換成list對象;

executeUpdate();執行更新和刪除語句



3.主鍵生成策略

1.jpa通用策略生成器

Jpa提供了4種標準法

TABLE,SEQUENCE,IDENTITY,AUTO

介紹常用的。SEQUENCE:根據數據庫的序列來生成主鍵,條件是數據庫支持序列

IDENTITY:主鍵由數據庫自動生成(自動遞增)

用法:直接寫出GeneratedValue 和其屬性strategy就可以了

@Id

@GeneratedValue(strategy = GenerationType.IDENTITY)


2.GenericGenerator hibernate主鍵策略生成器

簡單介紹幾個:

native: 對于 oracle 采用 Sequence 方式,對于MySQL 和 SQL Server 采用identity(自增主鍵生成機制),native就是將主鍵的生成工作交由數據庫完成,hibernate不管(很常用)。

uuid: 采用128位的uuid算法生成主鍵,uuid被編碼為一個32位16進制數字的字符串。占用空間大(字符串類型)。

identity: 使用SQL Server 和 MySQL 的自增字段,這個方法不能放到 Oracle 中,Oracle 不支持自增字段,要設定sequence(MySQL 和 SQL Server 中很常用); 等同于JPA中的INDENTITY。

ncrement: 插入數據的時候hibernate會給主鍵添加一個自增的主鍵,但是一個hibernate實例就維護一個計數器,所以在多個實例運行的時候不能使用這個方法。

具體了解:Hibernate各種主鍵生成策略與配置詳解 - starskyhu - 博客園

用法:@GenericGenerator注解配合@GeneratedValue一起使用,@GeneratedValue注解中的"generator"屬性要與@GenericGenerator注解中name屬性一致,strategy屬性表示hibernate的主鍵生成策略

@Id

@GeneratedValue(generator="increment")

@GenericGenerator(name="increment", strategy = "increment")



4.繼承

hibernate應用中,繼承的用途或目的主要有兩點:

組件化:故明思義,把重復性的代碼抽取成組件,以便重用和維護。hibernate應用中,一些重復的字段,重復的映射配置,就需要抽取成組件。

多態性:類的多態性是指下層業務所需一個父類對象,而上層業務根據所需的父類對象,傳遞一個子類對象。hibernate應用中,下層業務操作父類對象進行持久操作,如增刪改查,上層業務則傳遞一個子類對象。


所以,在應用hibernate的繼承時,需要明確設計所需,即究竟是組件化需求,還是多態性需求。

@MappedSuperclass:組件化需求的繼承注解。雖然它可以應用于類的多態性業務中,但它不能應用于hibernate持久操作的多態性業務中。

@Inheritance:多態性需求的繼承注解。雖然它可以達到組件化的目的,但它要比@MappedSuperclass多負出一些代價。


@Inheritance的默認繼承策略為SINGLE_TABLE,三種繼承策略的區別在于:

SINGLE_TABLE:公共屬性公共表,獨立屬性公共表。

需要使用監別器區分具體的子類,注解@DiscriminatorColumn設置監別器列,注解@DiscriminatorValue設置監別器值。

子類的屬性映射配置時,需要設置為允許為空或默認值。

JOINED:公共屬性公共表,獨立屬性獨立表。

子類的獨立表生成后,其主鍵是一個共享主鍵,意味著這是一對一的關聯,默認名稱與父類的主鍵一致,使用注解@PrimaryKeyJoinColumn可改變名稱。

TABLE_PER_CLASS:公共屬性獨立表,獨立屬性獨立表。

主鍵生成策略不能使用GenerationType.IDENTITY。


1.SINGLE_TABLE

是將父類和其所有的子類集合在一塊,存在一張表中,并創建一個新的字段來判斷對象的類型。

有兩個注釋要寫

@DiscriminatorColumn在父類書寫,它有兩個屬性,第一個是name,即區分子類的列名,discriminatorType 是指用什么方式區別(其實就是區分的數據類型),它可填DiscriminatorType.CHAR,DiscriminatorType.INTEGER,DiscriminatorType.STRING

@DiscriminatorValue (*)來修飾每個類 ,*號內就可以填一些可以區分該類的數據(該數據的類型由DiscriminatorType決定)

例:@Inheritance(strategy = InheritanceType.SINGLE_TABLE)

@DiscriminatorColumn(name="person_type",? ? discriminatorType=DiscriminatorType.STRING)

@DiscriminatorValue("普通人")

@DiscriminatorValue("顧客")


2.JOINED

是將父類、子類分別存放在不同的表中,并且建立相應的外鍵,以確定相互之間的關系。


3.TABLE_PER_CLASS

是為每一個類創建一個表,這些表是相互獨立的。



后兩種用法就是@Inheritance(strategy = InheritanceType.***)



5.關系映射

一對一時:如果兩張表是以主鍵關聯的,比如Person表主鍵是id,Address表主鍵是address_id,則運用如下注釋:

@OneToOne(cascade={CascadeType.ALL})

外鍵鏈接@JoinColumn(name="setid")

@PrimaryKeyJoinColumn(name = "id", referencedColumnName="address_id")//referencedColumnName是引用

主鍵鏈接@PrimaryKeyJoinColumn(name = "id")


在一對多單向關系中,多的一方(Person)沒有注解,一的一方(Country)有注解,如果一的一方不加@JoinColumn指定外鍵字段的話,Hibernate會自動生成一張中間表Country_PERSON來對Person和Country進行綁定。放一個set集合用來裝Many對象(注解也是在get set上書寫)。@OneToMany描述一個一對多的關聯,該屬性應該為集體類型,在數據庫中并沒有實際字段.

@OneToMany(cascade=CascadeType.ALL)

@JoinColumn(name="setid")


多對一單向,相反。多的一方放單個對象即可(注解也是寫在get 對象上)。

ManyToOne(cascade= {CascadeType.REFRESH,CascadeType.PERSIST})

@JoinColumn(name="jobid")


一對多雙向,兩邊都放外鍵,都擁有彼此信息。其實就是一的一方加onetomany,多的一方manytoone

@OneToMany(cascade=CascadeType.ALL)

@JoinColumn(name="setid")

ManyToOne(cascade= {CascadeType.REFRESH,CascadeType.PERSIST})

@JoinColumn(name="jobid")


一般多對多的關系都是用中間表來維護的,中間創一個表,放入兩方的關系,外鍵指向關系表

@ManyToMany//多對多外鍵關聯的配置

@JoinTable(name="teachers_students",//中間表的表名

joinColumns={@JoinColumn(name="sid")},//本表的主鍵

inverseJoinColumns={@JoinColumn(name="tid")})//所映射表的主鍵


屬性介紹

https://www.cnblogs.com/whgk/p/6135591.html? ? ? 屬性inverse和cascade及其關系

1.cascade

該屬性定義類和類之間的級聯關系。定義的級聯關系將被容器視為對當前類對象及其關聯類對象采取相同的操作,而且這種關系是遞歸調用的。

cascade的值只能從CascadeType.PERSIST(級聯新建)、CascadeType.REMOVE(級聯刪除)、CascadeType.REFRESH(級聯刷新)、CascadeType.MERGE(級聯更新)中選擇一個或多個。還有一個選擇是使用CascadeType.ALL,表示選擇全部四項。

2.fatch

可選擇項包括:FetchType.EAGER和FetchType.LAZY。前者表示關系類在主類加載的時候同時加載,后者表示關系類在被訪問時才加載。默認值是FetchType.LAZY。

3.targetEntity

放入目標的對象即可

4.@joincolumn(外鍵)

外鍵永遠指向多的一方,在ManyToMany時指向中間表


6.緩存

Hibernate中提供了兩級緩存,一級緩存是Session級別的緩存,它屬于事務范圍的緩存,該級緩存由hibernate管理,應用程序無需干預;二級緩存是SessionFactory級別的緩存,該級緩存可以進行配置和更改,并且可以動態加載和卸載,hibernate還為查詢結果提供了一個查詢緩存,它依賴于二級緩存;


緩存的概念

緩存是位于應用程序和永久性數據存儲源之間用于臨時存放復制數據的內存區域,緩存可以降低應用程序之間讀寫永久性數據存儲源的次數,從而提高應用程序的運行性能;

hibernate在查詢數據時,首先會到緩存中查找,如果找到就直接使用,找不到時才從永久性數據存儲源中檢索,因此,把頻繁使用的數據加載到緩存中,可以減少應用程序對永久性數據存儲源的訪問,使應用程序的運行性能得以提升;


緩存的范圍

緩存范圍決定了緩存的生命周期,緩存范圍分為3類:

1>事務范圍

緩存只能被當前事務訪問,緩存的生命周期依賴于事務的生命周期,事務結束時,緩存的生命周期也結束了;

2>進程范圍

緩存被進程內的所有事務共享,這些事務會并發訪問緩存,需要對緩存采用必要的事務隔離機制,緩存的生命周期取決與進程的生命周期,進程結束,緩存的生命周期也結束了;

3>集群范圍

緩存被一個或多個計算機的進程共享,緩存中的數據被復制到集群中的每個進行節點,進程間通過遠程通信來保證緩存中數據的一致性;

在查詢時,如果在事務范圍內的緩存中沒有找到,可以到進程范圍或集群范圍的緩存中查找,如果還沒找到,則到數據庫中查詢;


Hibernate中的第一級緩存

Hibernate的一級緩存由Session提供,只存在于Session的生命周期中,當應用程序調用Session接口的save(),update(),saveOrupDate(),get(),load()或者Query和Criteria實例的list(),iterate()等方法時,如果Session緩存中沒有相應的對象,hibernate就會把對象加入到一級緩存中,當session關閉時,該Session所管理的一級緩存也會立即被清除;

Hibernate中的第二級緩存

二級緩存是一個可插拔的緩存插件,它是由SessionFactory負責管理的;

由于SessionFactory對象的生命周期與應用程序的整個過程對應,通常一個應用程序對應一個SessionFactory,因此,二級緩存是進程范圍或者集群范圍的緩存;

與一級緩存一樣,二級緩存也是根據對象的id來加載與緩存,當執行某個查詢獲得結果集為實體對象集時,hibernate就會把它們按照對象id加載到二級緩存中,在訪問指定的id的對象時,首先從一級緩存中查找,找到就直接使用,找不到則轉到二級緩存中查找(必須配置且啟用二級緩存),如果二級緩存中找到,則直接使用,否則會查詢數據庫,并將查詢結果根據對象的id放到緩存中;


總結

1.hibernate 總共有三種形式的緩存,分為二級:一級session級別的緩存,二級sessionfactory級別的緩存。二級緩存有兩種形式,一是外部插件(EHCache),二是查詢緩存,查詢緩存基于外部插件存在,要使用查詢緩存,必須先配置好二級緩存。

2.一級緩存不會緩存普通屬性,只會緩存整個對象,所以查詢緩存可以進行補救,專門用于緩存查詢普通屬性的結果集,而用查詢緩存來保存整個對象時,就只會保存Id

3.一級緩存和二級緩存都是根據Id來加載于緩存的

4.查詢緩存大多數是用來緩存實體屬性的結果集的,如果查詢結果為實體對象的集合時,查詢緩存里就只有實體對象的Id

5.當訪問指定id的對象時,查找順序是:一級緩存 --->? 查詢緩存(實體Id)? ---> 外部緩存(實體數據)--->數據庫

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容