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