Hibernate 使用注解做元數(shù)據(jù)
1. 前言
本節(jié)課將和大家一起講解元數(shù)據(jù)概念,通過(guò)注解的方式實(shí)現(xiàn) Hibernate 操作數(shù)據(jù)庫(kù)。
這一切,會(huì)讓工作變得更加簡(jiǎn)單、直接??!本節(jié)課程你將學(xué)習(xí)到:
- 什么是元數(shù)據(jù);
- Hibernate 中有哪些注解;
- JPA 是什么。
2. 元數(shù)據(jù)
什么是元數(shù)據(jù)
先舉一個(gè)生活中的例子:你買了一袋面粉,想用來(lái)揉幾個(gè)包子,發(fā)幾個(gè)饅頭……
可以把面粉當(dāng)成原始數(shù)據(jù),包子、饅頭是你運(yùn)用你的技能加工之后的成品數(shù)據(jù)。這里的技能相當(dāng)于開(kāi)發(fā)者的編程能力。
但是!元數(shù)據(jù)到底是什么?。?!
買面粉的時(shí)候面粉袋上有很多說(shuō)明,面粉出自何地、面粉的凈重量有多少……
這些信息對(duì)于你的加工過(guò)程有很大的參考價(jià)值。面粉的出生地讓你知道什么地方出產(chǎn)的面粉適合做饅頭、什么地方出產(chǎn)的面粉適合做面包……
凈重量能告訴你最后能生產(chǎn)幾個(gè)包子、幾個(gè)饅頭……如果人多,就應(yīng)該多買幾袋,至少能讓你在款待客人時(shí)表現(xiàn)的美麗又大方。
元數(shù)據(jù)的標(biāo)準(zhǔn)概念是用來(lái)描述數(shù)據(jù)的數(shù)據(jù)!
換一句容易理解的話,面粉是數(shù)據(jù),用來(lái)包裝面粉的面粉袋上的說(shuō)明信息就是元數(shù)據(jù)。
大家知道持久化對(duì)象吧:POJO+XML。XML描述的映射信息就是用來(lái)描述學(xué)生對(duì)象數(shù)據(jù)的元數(shù)據(jù)。
3. Hibernate 中使用注解
Hibernate 中,通過(guò)元數(shù)據(jù)的方式描述映射關(guān)系,其表達(dá)語(yǔ)法有 2 種:
- 其一: XML 語(yǔ)法;
- 其二: 本節(jié)課程要給大家隆重推薦的是注解語(yǔ)法。
注解語(yǔ)法本質(zhì)就是 Java 語(yǔ)法。
3.1 什么是注解
注解相當(dāng)于開(kāi)發(fā)者給代碼添加的注釋,對(duì),注釋也是元數(shù)據(jù),但注釋是開(kāi)發(fā)者之間進(jìn)行交流用的,編譯器和JVM都會(huì)當(dāng)它不存在。
注解就不同了:
- 告訴編譯器和 JVM 如何正確使用其所標(biāo)注的數(shù)據(jù);
- 注解是 JAVA5.0 后推出的一種新的編程思想;
- 在 Java 里面可以用來(lái)和 public、static 等關(guān)鍵字一樣來(lái)修飾類名、方法名、變量名。
3.2 使用注解重構(gòu)代碼
現(xiàn)在使用注解方式重構(gòu)前面代碼,使用之前先秀出 Hiernate 中常用的幾個(gè)注解:
- @Table:描述實(shí)體類對(duì)應(yīng)的表名;
- @Idclass:指定充當(dāng)主鍵的類;
- @Entity: 標(biāo)注類是實(shí)體類;
- @Id: 描述哪個(gè)屬性對(duì)應(yīng)表中的主鍵字段;
- @Column:指定與屬性對(duì)應(yīng)的字段名;
- @Basic:等價(jià)于沒(méi)有定義注解的屬性;
- @Transient :屬性不被持久化。
不要指望一下記住它們,還是通過(guò)使用的過(guò)程逐步理解為上策。
友情提示:心急吃不了熱豆腐??!
修改學(xué)生類
@Entity
public class Student {
private Integer stuId;
private String stuName;
private String stuSex;
public Student(Integer stuId, String stuName, String stuSex) {
super();
this.stuId = stuId;
this.stuName = stuName;
this.stuSex = stuSex;
}
public Student(String stuName, String stuSex) {
super();
this.stuName = stuName;
this.stuSex = stuSex;
}
public Student() {
super();
}
@Id
public Integer getStuId() {
return stuId;
}
public void setStuId(Integer stuId) {
this.stuId = stuId;
}
public String getStuName() {
return stuName;
}
public void setStuName(String stuName) {
this.stuName = stuName;
}
public String getStuSex() {
return stuSex;
}
public void setStuSex(String stuSex) {
this.stuSex = stuSex;
}
}
這樣可以嗎?是的,可以啦。
用放大鏡掃描一下上面的學(xué)生類,好不容易看到 2 個(gè)注解:
- @Entity:標(biāo)注這個(gè)類是持久化類;
- @Id:標(biāo)注這個(gè)屬性是標(biāo)識(shí)屬性,必須給出。
不要懷疑,對(duì)于 Hibernate 來(lái)說(shuō)已經(jīng)足夠,需要知道的常識(shí)是:
對(duì)于其它沒(méi)有標(biāo)注任何注解的屬性,Hibernate 默認(rèn)為數(shù)據(jù)庫(kù)的表中有與屬性同名的字段。
替換主配置文件
<mapping resource="com/mk/po/Student.hbm.xml" />
替換成:
<mapping class="com.mk.po.Student" />
運(yùn)行測(cè)試實(shí)例
// 配置對(duì)象
Configuration configuration = new Configuration().configure();
// 服務(wù)注冊(cè)
ServiceRegistry serviceRegistry =new ServiceRegistryBuilder().applySettings(configuration.getProperties()) .buildServiceRegistry();
// 會(huì)話工廠
SessionFactory sessionFactory = configuration.buildSessionFactory(serviceRegistry);
// 會(huì)話對(duì)象
Session session = sessionFactory.openSession();
// 事務(wù)對(duì)象
Transaction transaction = null;
try {
// 打開(kāi)事務(wù)
transaction = session.beginTransaction();
// 添加一條學(xué)生信息
Student student = new Student(2, "Configuration02", "男");
session.save(student);
transaction.commit();
} catch (Exception e) {
transaction.rollback();
} finally {
session.close();
}
}
測(cè)試代碼還是原來(lái)的測(cè)試代碼!只是新增了一條數(shù)據(jù)!進(jìn)入 MySQL 瞧一瞧,數(shù)據(jù)如假包換的插入成功。
是不是感覺(jué)如春風(fēng)般溫暖!對(duì) Hibernater 的感受又增加了很多。
簡(jiǎn)直讓人無(wú)法相信,2 個(gè)注解就映射成功。但是,這是有前提條件的:
-
應(yīng)用程序中的類名和關(guān)系數(shù)據(jù)庫(kù)中的表名同名時(shí),使用一個(gè)@Entity 注解足夠;
-
類名和表名不一樣時(shí),則需使用 @Table(表名)注解告訴 Hibernate;
-
應(yīng)用程序中類中的屬性名和數(shù)據(jù)庫(kù)表中的字段名同名時(shí),Hibernate自會(huì)心領(lǐng)意會(huì)。
實(shí)質(zhì)是沒(méi)有提供注解的屬性默認(rèn)使用了@Basic 注解。
-
如果屬性名與字段名不同名時(shí),請(qǐng)使用 @Column ( name=“stuName”) 注解明確告訴 Hibernate。
-
如果類中某一個(gè)屬性本就沒(méi)有對(duì)應(yīng)字段名,僅僅是方便程序中某些需求,這時(shí)需要在此屬性上加上 @Transient,讓 Hibernate 對(duì)此屬性視之不理。
3.3 注解的位置
注解說(shuō):我可不是隨便的代碼!
每一個(gè)注解都有自己位置。
- 如同 @Entity、@Table 是類級(jí)別注解,對(duì)類做整體說(shuō)明;
- 如同 @Id、@Column、@Transient 這幾個(gè)注解是屬性、方法級(jí)別的,可對(duì)屬性或方法做說(shuō)明,如下:
@Id
private Integer stuId;
@Column
private String stuName;
或
@Id
public Integer getStuId() {
return stuId;
}
@Column
public String getStuName() {
return stuName;
}
如上 2 種方式都可告訴 Hibernate 如何映射表中的對(duì)應(yīng)字段。既然有 2 種方案,必然會(huì)有優(yōu)劣之分(有比較就會(huì)有差別的哲學(xué))。
提問(wèn)時(shí)間:建議使用哪一種方式?
-------------------啟動(dòng)自問(wèn)自答模式----------------------
建議把注解放在屬性對(duì)應(yīng)的 get 方法上。
為什么?
----------------------讓你思考0.5秒鐘------------------
時(shí)間到!公布答案。
不管是放在屬性上面還是放在 get 方法上面,Hibernate 都要使用反射機(jī)制,如果直接反射屬性,則是對(duì) OOP 封裝特性的挑戰(zhàn)。
雖然使用反射可以在底層為所欲為,但作為有良知的開(kāi)發(fā)者來(lái)講,則要從規(guī)范上杜絕破壞 OOP 規(guī)則的事情。
當(dāng)然這只是建議!最后的選擇由你決定。
3.4 XML 還是注解
這個(gè)可沒(méi)有人能給出最終答案!俗語(yǔ)說(shuō)得好,即使是低微如一粒塵土,也有自己的價(jià)值,XML 映射和注解映射都有自己的應(yīng)用場(chǎng)景。
但注解相對(duì)而言集中性較好,在一個(gè)類文件中,且符合 Java 語(yǔ)法規(guī)范,更易獲得開(kāi)發(fā)者喜歡。
4. JPA
考查觀察力的時(shí)刻,請(qǐng)問(wèn) @Entity 注解在哪一個(gè)包中?
不是使用 Hibernate 注解嗎,還用問(wèn),肯定是在 Hibernate 相關(guān)聯(lián)的包中!
恭喜你!答錯(cuò)了。
前面所使用的注解清一色都在 javax.persistence 包中,標(biāo)準(zhǔn)的 Java 包,這個(gè)包全稱 Java Persistence API(持久化API)。
奇怪了吧?這么厲害,Java 官方在推出 JDK 類庫(kù)時(shí)就為Hibernate 準(zhǔn)備了這些注解,不是吧,難不成 Java 語(yǔ)言研發(fā)者能預(yù)測(cè) Hibernate 將會(huì)橫空出世,且能成為 “網(wǎng)紅”(互聯(lián)網(wǎng)網(wǎng)絡(luò)上知名的軟件)提前做了擁抱 Hibernate 的準(zhǔn)備?
NO,事情的原因是這樣子的。
Jdbc 大家都在用,且都感受到其冗余、無(wú)腦的操作流程,于是針對(duì)優(yōu)化 Jdbc 操作的框架如雨后春筍(此處使用夸張修飾)。
框架的出現(xiàn)是好事情,但多了,就不一定是好事情,對(duì)于開(kāi)發(fā)者來(lái)說(shuō)因業(yè)務(wù)需求可能需要在不同規(guī)范的框架中切過(guò)來(lái)切過(guò)去,開(kāi)發(fā)者的時(shí)間都浪費(fèi)在框架選擇上了。
Java 官方要管一管了,于是在 J2EE5.0 后推出了 JPA 注解規(guī)范:
- JPA 是 Java 持久化解決方案,與 Hibernate 一樣負(fù)責(zé)把數(shù)據(jù)保存進(jìn)數(shù)據(jù)庫(kù);
- 但 JPA 只是一種標(biāo)準(zhǔn)、規(guī)范,而不是框架;
- JPA 自身并沒(méi)有具體的實(shí)現(xiàn),類似于Jdbc規(guī)范;
- 旨在是規(guī)范 ORM 框架,使 ORM 框架有統(tǒng)一的接口、統(tǒng)一的用法。
一句話概之,以后不管是開(kāi)發(fā) Jdbc 框架也好,升級(jí)框架也好,請(qǐng)遵循JPA接口規(guī)范。
JPA是想當(dāng)任我行,一統(tǒng) Jdbc 框架混亂的局面。
對(duì)開(kāi)發(fā)者是好事,以 Java JPA 的統(tǒng)一接口方式使用框架。
Hibernate 在 3.x 版本后開(kāi)始支持JPA規(guī)范?。?!
老板也不用為開(kāi)發(fā)者切換框架的時(shí)間付出報(bào)酬了。
5. 小結(jié)
本節(jié)課了解了元數(shù)據(jù)概念,并使用注解的方式重構(gòu)了前面的代碼,完成了類似的數(shù)據(jù)插入操作。
本節(jié)課中也探討了某些注解的使用,更多注解一起期待在后面的課堂內(nèi)容中再相逢。
最后和大家聊了聊 JPA,一個(gè)官方的持久化方案!值得擁有。