首先,上圖...

上面的是hibernate中經(jīng)常用到的知識點,我們一個一個看.
一 工作流程
- 讀取并解析配置文件
- 讀取并解析映射信息,創(chuàng)建SessionFactory
- 打開Sesssion
- 創(chuàng)建事務(wù)Transation
- 持久化操作
- 提交事務(wù)
- 關(guān)閉Session
- 關(guān)閉SesstionFactory
jdbc 流程:
- 加載驅(qū)動mysql
- 獲取連接
- 預(yù)編譯
- 執(zhí)行sql
- 將數(shù)據(jù)存入結(jié)果集
- 關(guān)閉數(shù)據(jù)庫
jdbc和hibernate區(qū)別:
jdbc優(yōu)點:
SQL應(yīng)用靈活
數(shù)據(jù)庫移植
jdbc缺點:
不便于維 代碼繁瑣 護 效率低
hibernate 框架 優(yōu)點:
真正基于ORM模型
脫離java代碼 降低耦合度
操作簡單,易用
缺點:
不便于操作表結(jié)構(gòu)復(fù)雜的sql
不便于數(shù)據(jù)庫移植(跨數(shù)據(jù)庫移植)
代替了jdbc技術(shù),是一個全封裝的框架,不便于調(diào)試bug
什么時候用hibernate框架
表數(shù)量少 結(jié)構(gòu)不復(fù)雜,快速應(yīng)用它來開發(fā)
hibernate中的緩存技術(shù):
1.只是一次連接數(shù)據(jù)庫,多次使用
- 數(shù)據(jù)是存在緩存區(qū)里的,操作:session.get() session.save(),session.delete().
3.分為二級緩存:
一級緩存:session 存在 內(nèi)存的緩存區(qū)中
清理一級緩存的方式:
clear() 方法清理緩存直接從硬盤中的數(shù)據(jù)庫讀取
evict(對象) 執(zhí)行的是數(shù)據(jù)庫中的查詢,第一次查詢會失效
二級緩存:sessionFactort 存在 硬盤中
Hibernate 緩存執(zhí)行順序
當(dāng) Hibernate 根據(jù) ID 訪問數(shù)據(jù)對象時,首先會從一級緩存 Session 中查找。若查 不到且配置了二級緩存,則會從二級.
緩存中查找;若還查不到,就會查詢數(shù)據(jù)庫,把結(jié) 果按照 ID 放入到緩存中。執(zhí)行增、刪、改操作時,會同步更新緩存。
二級緩存內(nèi)容分類
根據(jù)緩存內(nèi)容的不同,可以將 Hibernate 二級緩存分為三類: (1)類緩存:緩存對象為實體類對象 (2)集合緩存:緩存對象為集合類對象 (3)查詢緩存:緩存對象為查詢結(jié)果
hibernate框架中g(shù)et方法和load方法獲取對象的方式有什么不同:
get和load方法都是根據(jù)id去獲得對應(yīng)數(shù)據(jù)的,但是獲得機制不同:如果使用get方法,hibernate會去確認該id對應(yīng)的數(shù)據(jù)是否存在,它首先會去session中去查詢(session緩存其實就hibernate的一級緩存),如果沒有,再去二級緩存中去查詢,如果再沒有,就去數(shù)據(jù)庫中查詢,仍然沒有找到的話,就返回null
而使用load方法的話,hibernate會認定該id對應(yīng)的數(shù)據(jù)一定存在,它也會先去session緩存中去查找,如果沒有找到,hibernate會根據(jù)lazy屬性值來確定是否使用延遲加載。如果lazy=‘true’ ,就使用延遲加載,返回該代理對象,等到真正訪問到該對象的屬性時才會去二級緩存中查詢,如果沒有,再去數(shù)據(jù)庫中查詢,如果還沒有,就拋出org.hibernate.ObjectNotFoundException異常。如果lazy='false' 則不使用延遲加載,這是load的訪問機制就和get一樣了。
事物的特性:
1.原子性(不許分割)
2.一致性(兩個事物可以有添加和減少)
3.隔離性(兩個事物在執(zhí)行過程中,相互不影響)
4.持久性: (兩個事物執(zhí)行完畢后,影響一直有效)
hibernate對象的狀態(tài)
1.對象的臨時狀態(tài) Emp e = new Emp("hah", 1000.0, 21, date);
2.對象的持久化狀態(tài) session.save(e);
st.commit();
3.對象的游離狀態(tài)session.close();
事物是連接java代碼和數(shù)據(jù)庫的橋梁
hibernate框架中表之間的關(guān)系:
一對多
hibernate中級聯(lián)刪除:更改級聯(lián)關(guān)系為 cascade="delect";
刪除班級,刪除學(xué)生 有外鍵
直接刪除:班級信息置為null 學(xué)生信息不變
:更改級聯(lián)關(guān)系為 cascade="delect" 根據(jù)外鍵,刪除當(dāng)前表及其有關(guān)系的其他表,刪除有外鍵有關(guān)系的表
一對多
在進行解除關(guān)系或者刪除的時候 One-to-many比較簡單,執(zhí)行的效率高 其他操作的時候many_to-one效率高
One-to-many 類和集合的關(guān)系
many-to-one 類和對象的關(guān)系
多對一(雙向)
以Student-classes表為例 一個班級有更多學(xué)生同樣更多學(xué)生在一個班級
建立 Student 和Classes的實體類
//Classes表中的屬性 注意學(xué)生集合
private Integer c_id;
private String c_name;
private Set<Student> stus;
//student表中的屬性
private Integer s_id;
private String s_name;
//建立關(guān)系: 多個學(xué)生 一個班級
private Classes cls;
//classes表的映射文件
<hibernate-mapping>
<class name="cn.lanou3g.vo.Classes" >
<id name="c_id">
<generator class="increment" />
</id>
<property name="c_name"/>
<!-- 搭建一對多的關(guān)系 inverse是否維系關(guān)系 默認false
cascade 級聯(lián)關(guān)系 save-update 保存或更新的時候維系關(guān)系
delete 級聯(lián)刪除-->
<set name="stus" inverse="false" cascade="save-update">
<!--從表的外鍵 -->
<key column="c_id"></key>
<!-- 指定對應(yīng)關(guān)系 它是stus對應(yīng)的實體類-->
<one-to-many class="cn.lanou3g.vo.Student"/>
</set>
</class>
</hibernate-mapping>
//Student的映射文件
<hibernate-mapping>
<class name="cn.lanou3g.vo.Student">
<id name="s_id">
<generator class="increment"/>
</id>
<property name="s_name"/>
<!-- 建立關(guān)系 cls 多對一 cascade 級聯(lián)關(guān)系-->
<many-to-one name="cls" class="cn.lanou3g.vo.Classes" cascade="save-update">
<!-- 這里的外鍵,要與one-to-many對應(yīng)的外鍵一致 -->
<!-- column 指定從表的外鍵-->
<column name="c_id"></column>
</many-to-one>
</class>
</hibernate-mapping>
public class TextCon {
Session session=HibernateSessionFactory.getSession();
Transaction ts=session.beginTransaction();
@Test
public void textConn(){
//新建配置對象 目的是自動加載配置文件
Configuration cfg = new Configuration();
cfg.configure();//自動加載主配置文件
//開啟session工廠
SessionFactory sf=cfg.buildSessionFactory();
}
//保存學(xué)生 保存班級
//@Test
public void textaddStuandcls(){
//新增班級
Student stu = new Student();
stu.setS_name("momo");
//新增班級
Classes cls = new Classes();
cls.setC_name("java");
//通過學(xué)生保存班級
stu.setCls(cls);
session.save(stu);
ts.commit();
}
//更新學(xué)生 級聯(lián)保存班級
//@Test
public void textupdateStuandcls(){
Student stu = (Student)session.get(Student.class, 1);
stu.setS_name("lida");
session.save(stu);
ts.commit();
}
//給學(xué)生賦班級
//@Test
public void testUpdateStu(){
Student stu = (Student)session.get(Student.class, 2);
Classes cls = (Classes)session.get(Classes.class, 1);
stu.setCls(cls);
session.save(stu);
ts.commit();
}
//解除一個班級和所有學(xué)生之間的關(guān)系(注意保存班級)
// delect() 兩表都刪除
//update 外鍵為null
@Test
public void testdelStuandcla(){
Classes cls = (Classes)session.get(Classes.class, 1);
//Student stu = (Student)session.get(Student.class, 1);
//cls.setStus(null);//級聯(lián)關(guān)系改為null
session.update(cls);
ts.commit();
}
}
多對多:
以course-student表為例 很多課程被很多學(xué)生選擇
//student表中的屬性
private Integer s_id;
private String s_name;
private Set<Course> cours;
//coutse表中的屬性
private Integer c_id;
private String c_name;
//建立聯(lián)系 多對多 多個課程被多了學(xué)生選擇
private Set<Student> stus;
//Course表中映射文件
<hibernate-mapping>
<class name="cn.lanou3g.vo.Student">
<id name="s_id">
<generator class="increment"/>
</id>
<property name="s_name"/>
<!-- 建立關(guān)系 cls 多對一 cascade 級聯(lián)關(guān)系-->
<set name="cours" table="student_course" cascade="all">
<key column="s_id"/>
<many-to-many class="cn.lanou3g.vo.Course" column="c_id"/>
</set>
</class>
</hibernate-mapping>
//student的映射文件
<hibernate-mapping>
<class name="cn.lanou3g.vo.Course">
<id name="c_id">
<generator class="increment"/>
</id>
<property name="c_name"/>
<!-- 建立關(guān)系 cls 多對一 cascade 級聯(lián)關(guān)系-->
<set name="stus" table="student_course" cascade="all">
<key column="c_id"/>
<many-to-many class="cn.lanou3g.vo.Student" column="s_id"/>
</set>
</class>
</hibernate-mapping>
public class TextCon {
Session session=HibernateSessionFactory.getSession();
Transaction ts=session.beginTransaction();
@Test
public void textConn(){
Configuration cfg = new Configuration();
cfg.configure();
SessionFactory sf = cfg.buildSessionFactory();
}
//添加一個新課程 添加一個新學(xué)生
//先保存主表 在保存從表
//@Test
public void textinsert(){
Student stu = new Student();
Course cours =new Course();
stu.setS_name("box");
cours.setC_name("java");
Set<Student> stus = new HashSet<Student>();
stus.add(stu);
cours.setStus(stus);
session.save(cours);
ts.commit();
}
//獲取學(xué)生 修改學(xué)生姓名 課程中添加修改后的學(xué)生姓名
//@Test
public void textUpdatestu(){
Student stu = (Student)session.get(Student.class, 1);
stu.setS_name("燦烈");
Course cours = (Course)session.get(Course.class, 1);
Set<Student> stus = new HashSet<Student>();
stus.add(stu);
cours.setStus(stus);
session.save(cours);
ts.commit();
}
//解除課程1和所有學(xué)生的關(guān)系
//解除課程1和所欲學(xué)生之間的關(guān)系
//多對多關(guān)系的刪除,只影響中間表,其他關(guān)聯(lián)表不動
//設(shè)置學(xué)生為null
//@Test
public void textdel(){
Course cours = (Course)session.get(Course.class, 1);
cours.setStus(null);
session.save(cours);
ts.commit();
}
//刪除課程1下編號為1 的人
//解除一個學(xué)生和一個課程的關(guān)系(值刪除中間表)
//多對多中單條刪除用集合中的remove()進行刪除
@Test
public void textdelmid(){
Course cours = (Course)session.get(Course.class, 2);
Student stu = (Student)session.get(Student.class, 2);
Set<Course> c = stu.getCours();
c.remove(cours);
session.save(cours);
ts.commit();
}
}
一對一
以person-card為例 一個人只有一個身份證
//card的屬性
private Integer c_id;
private String c_name;
private Person c_p;
//person的屬性
private Integer p_id;//主鍵
private String p_name;
private Card p_c;
//card的映射文件
<hibernate-mapping>
<!-- 引入實體類的全類名 -->
<class name="cn.lanou3g.entity.Card">
<!-- 主鍵字段 -->
<id name="c_id">
<generator class="increment"/>
</id>
<!--普通字段 -->
<property name="c_name"/>
<!-- 直接指定對應(yīng)關(guān)系
name 在當(dāng)前類中存在的類類型
class name屬性對應(yīng)的全類型
cascade 對當(dāng)前表的操作crud
constrained="false"代表當(dāng)前表是主表-->
<one-to-one name="c_p" class="cn.lanou3g.entity.Person" cascade="all" constrained="true"/>
</class>
//Person的映射文件
<hibernate-mapping>
<!-- 引入實體類的全類名 -->
<class name="cn.lanou3g.entity.Person">
<!-- 主鍵字段 -->
<id name="p_id">
<generator class="increment"/>
</id>
<!--普通字段 -->
<property name="p_name"/>
<!-- 直接指定對應(yīng)關(guān)系
name 在當(dāng)前類中存在的類類型
class name屬性對應(yīng)的全類型
cascade 對當(dāng)前表的操作crud
constrained="false"代表當(dāng)前表是主表
true 代表從表-->
<one-to-one name="p_c" class="cn.lanou3g.entity.Card" cascade="all" constrained="false"/>
</class>
</hibernate-mapping>
public class text {
Session session = HibernateSessionFactory.getSession();
Transaction ts=session.beginTransaction();
//自動建表
@Test
public void textConn(){
//新建配置對象 目的是自動加載配置文件
Configuration cfg = new Configuration();
cfg.configure();//自動加載主配置文件
//開啟session工廠
SessionFactory sf=cfg.buildSessionFactory();
}
// 同時添加人(主表)和身份證
// @Test
public void textInser(){
Person p = new Person("梁靖");
Card c = new Card("152727199603111025");
//先保存從表中的關(guān)聯(lián)字段
c.setC_p(p);
// p.setP_c(c);
//保存從表
session.save(c);
ts.commit();
}
//修改id為1的姓名
// @Test
public void textUpdate(){
Person p = (Person)session.get(Person.class, 2);
p.setP_name("梁敏");
session.save(p);
ts.commit();
}
//刪除用戶 刪除身份證 從主表中刪除 從表的也刪除
//思路:通過主表獲取關(guān)聯(lián)字段
//關(guān)聯(lián)字段放入主表
// 刪除主表
// @Test
public void textdelect(){
Person p = (Person)session.get(Person.class, 2);
// Card p_c =p.getP_c();
// p.setP_c(p_c);
session.delete(p);
ts.commit();
}
}
懶加載
映射文件中加入屬性lazy="true"
為什么用它:
防止內(nèi)存溢出,遞歸調(diào)出方法
- 解決:
1.去掉任何一方的toString()
2.在不需要查詢的一方的配置文件中加入lazy="true"
HQL語句:
- 是指hibernate sql
- 查詢?nèi)?/li>
- 查詢某一個字段
- 按條件查詢0
//分頁
Query q = session.createQuery("from User");
//起始位置
q.setFirstResult(0);
//一次展示多少條
q.setMaxResults(5);
//把查詢到的結(jié)果放入list集合
List list = q.list();
System.out.println(list);//遍歷并且輸出集合