回家呆了兩個多星期,本該一星期學(xué)完的hibernate框架被拖了這么久。今天才把第二天的教程看完。做個簡單的總結(jié)。
第一節(jié) 常用的主鍵生成策略
主鍵生成策略有幾個,主要使用的是uuid和native
- uuid 通過hibernate自動生成一個32位的16進(jìn)制字符串作為唯一標(biāo)識符 實體類變量類型String
- native hibernate根據(jù)數(shù)據(jù)庫類型自動選擇 生成一個自增的標(biāo)識符 實體類變量類型Integer
測試了一下increment策略,其同樣是產(chǎn)生一個Integer類型自增主鍵,不過在生成時是先查詢主鍵最大的數(shù)字然后根據(jù)這個數(shù)字在添加新的數(shù)據(jù)。sql語句如下
Hibernate: select max(hid) from t_home
Hibernate: insert into t_home (attr, tel, hid) values (?, ?, ?)
如果是native策略 則將主鍵在數(shù)據(jù)庫中設(shè)置為自增。做添加操作時不會對主鍵進(jìn)行設(shè)置,sql語句如下
Hibernate: insert into t_home (attr, tel) values (?, ?)
疑惑: 幾種生成策略中沒有發(fā)現(xiàn)與通過注釋設(shè)置主鍵相同的方式。。。
第二節(jié) CRUD操作
- 增加 session.save(user);
@Test
public void testSave() {
Session session = HbmUtil.getSession();
Transaction tx = session.beginTransaction();
User user = new User();
user.setUid(555); // 需要注意的是這里設(shè)置主鍵是無效的 hibernate會根據(jù)主鍵生成策略自動設(shè)置
user.setName("lee");
user.setPass("333");
session.save(user);
tx.commit();
session.close();
}
- 刪除 session.delete(user);
@Test
public void testDelete() {
Session session = HbmUtil.getSession();
Transaction tx = session.beginTransaction();
// 第一種 獲取持久化對象后刪除
User user = session.get(User.class, 2);
session.delete(user);
// 第二種 通過托管態(tài)對象刪除 不推薦
User user2 = new User();
user2.setUid(1);
session.delete(user2);
tx.commit();
session.close();
}
Hibernate: delete from t_user where uid=?
根據(jù)sql語句可知只要實體類中存在主鍵id且數(shù)據(jù)庫中存在對應(yīng)記錄 就能進(jìn)行刪 若記錄不存在則報錯
- 修改 session.update(user);
@Test
public void testUpdate() {
Session session = HbmUtil.getSession();
Transaction tx = session.beginTransaction();
// 第一種 通過持久化對象自動修改
User user = session.get(User.class, 4);
user.setName("333333");
// 第二中 使用update修改
User user2 = session.get(User.class, 3);
user2.setPass("nihao");
session.update(user2);
// 第三中 通過托管態(tài)對象進(jìn)行修改 必須所有字段都進(jìn)行設(shè)置 不然就會用null代替 且主鍵必須存在不然報錯 不推薦
User user3 = new User();
user3.setUid(11);
user3.setName("托管態(tài)");
user3.setPass("修改");
session.update(user3);
tx.commit();
session.close();
}
Hibernate: update t_user set uname=?, upass=? where uid=?
從sql語句看出每次都是全部更新 因此托管態(tài)的實體類必須對每個值都進(jìn)行設(shè)置
什么是托管態(tài),持久態(tài)下面有介紹
- 查詢 session.get(User.class, id);
@Test
public void testQuery() {
Session session = HbmUtil.getSession();
Transaction tx = session.beginTransaction();
User user = session.get(User.class, 1);
System.out.println(user);
tx.commit();
session.close();
}
Hibernate: select uid, uname, upass from t_user where uid=?
第一個值傳入實體類的class有沒有和DBUtils里的ResultSetHandler接口很像,這只是個簡單的查詢,更復(fù)雜的在后面會有講解
第三節(jié) 實體類的三種狀態(tài)與saveOrUpdate
- 瞬時態(tài) 與session無關(guān) 不存在主鍵id
User user = new User();
user.setName("你好");
user.setPass("瞬時態(tài)");
- 持久態(tài) 與session相關(guān) 存在主鍵id
User user = session.get(User.class, 4);
// 持久態(tài)可實現(xiàn)自動更新 原因是內(nèi)部存在快照 在事務(wù)提交前會進(jìn)行對比 不一樣則更新
user.setName("自動更新");
- 托管態(tài) 與session無關(guān) 存在主鍵id
User user = new User();
user.setUid(6);
user.setName("托管態(tài)");
user.setPass("嗨~");
- 三態(tài)的相互轉(zhuǎn)換
* 瞬時態(tài):執(zhí)行session.save方法轉(zhuǎn)化為持久態(tài) 添加id變托管態(tài)
* 持久態(tài):session.delete轉(zhuǎn)化瞬時 session.clear轉(zhuǎn)化托管
* 托管態(tài):刪除id轉(zhuǎn)發(fā)瞬時 session.update session.saveOrUpdate轉(zhuǎn)化持久
- savaOrUpdate具體執(zhí)行的操作
/**
* 測試SaveOrUpdate具體執(zhí)行方式
* 實體類對象是瞬時態(tài)時做save操作
* 實體類對象是托管態(tài)時做update操作
* 實體類對象是持久態(tài)時做update操作
*/
@Test
public void testSaveOrUpdate() {
Session session = HbmUtil.getSession();
Transaction tx =session.beginTransaction();
// 瞬時態(tài)
User user = new User();
user.setName("你好");
user.setPass("瞬時態(tài)");
// session.saveOrUpdate(user);
// 托管態(tài)
// 托管態(tài)中的id在數(shù)據(jù)庫中不存在則 報錯
User user1 = new User();
user1.setUid(11);
user1.setName("又是托管態(tài)的修改");
user1.setPass("托管態(tài)");
session.saveOrUpdate(user1);
// 持久態(tài)
User user2 = session.get(User.class, 4);
user2.setName("持久態(tài)哈");
// session.saveOrUpdate(user2);
tx.commit();
session.close();
}
總結(jié): 實體類帶有id 且該id對應(yīng)的記錄在數(shù)據(jù)庫中存在進(jìn)行update操作 否則save操作
第四節(jié) 事務(wù)處理的標(biāo)準(zhǔn)寫法
package cn.lkangle.twoday;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import cn.lkangle.entity.User;
import cn.lkangle.util.HbmUtil;
public class Standard {
@Test
public void test() {
Session session = null;
Transaction tx = null;
try {
session = HbmUtil.getSession();
tx = session.beginTransaction();
User user2 = new User();
user2.setName("回滾");
user2.setPass("測試");
session.save(user2);
// int s = 100/0;
User user = session.get(User.class, 2);
user.setName("測試回滾");
session.update(user);
tx.commit();
} catch (Exception e) {
e.printStackTrace();
System.err.println("出現(xiàn)異常 回滾事務(wù)");
tx.rollback();
} finally {
System.out.println("關(guān)閉session");
session.close();
}
}
}
沒有出現(xiàn)異常則正常提交事務(wù),事務(wù)回滾寫在catch中,出現(xiàn)異常則回滾事務(wù),最后關(guān)閉session
第五節(jié) 綁定本地session
通過將session綁定在本地線程中達(dá)到一次事務(wù)中只存在一個session
- 配置hibernate.cfg.xml文件 添加下句
<!-- 綁定本地session 放在本地線程中 共三個值 一般用thread與本地線程綁定 -->
<property name="hibernate.current_session_context_class">thread</property>
- 通過 SessionFactory.getCurrentSession()獲取
- 例子
LocalSession.java類
package cn.lkangle.twoday;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import cn.lkangle.util.HbmUtil;
public class LocalSession {
@Test
public void testLocal(){
Session session = HbmUtil.getCurrentSession();
Transaction tx = session.beginTransaction();
new addUser().saveUser();
tx.commit();
}
}
addUser.java類
package cn.lkangle.twoday;
import org.hibernate.Session;
import cn.lkangle.entity.User;
import cn.lkangle.util.HbmUtil;
public class addUser {
public void saveUser() {
User user = new User();
user.setName("新文件中添加");
user.setPass("測試事務(wù)中session處理");
Session session = HbmUtil.getCurrentSession();
session.save(user);
}
}
綁定本地的session不需要對session進(jìn)行關(guān)閉,在線程結(jié)束后會自動關(guān)閉。
第六節(jié) hibernate緩存
- 一級緩存: 默認(rèn)開啟 作用域在session
測試一級緩存存在
package cn.lkangle.twoday;
/**
* 一級緩存作用域session 從session創(chuàng)建到session關(guān)閉
* 證明存在一級緩存
* @author lbxx
*/
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import cn.lkangle.entity.User;
import cn.lkangle.util.HbmUtil;
public class Cache {
@Test
public void cacheTest() {
Session session = HbmUtil.getSession();
Transaction tx = session.beginTransaction();
User user = session.get(User.class, 1);
System.out.println(user);
/**
* 每次查詢都會先在一級緩存中查找數(shù)據(jù) 如果發(fā)現(xiàn)則直接取出 如果沒有發(fā)現(xiàn)則進(jìn)行數(shù)據(jù)庫查詢
* 一級緩存默認(rèn)打開 保存持久態(tài)的數(shù)據(jù)
*/
User user2 = session.get(User.class, 1);
System.out.println(user2);
tx.commit();
session.close();
}
}
兩次查詢只進(jìn)行一次sql操作,第二次直接從緩存中獲取
Hibernate:
select
user0_.uid as uid1_2_0_,
user0_.uname as uname2_2_0_,
user0_.upass as upass3_2_0_
from
t_user user0_
where
user0_.uid=?
name--> 新文件中添加 pass--> 測試事務(wù)中session處理
name--> 新文件中添加 pass--> 測試事務(wù)中session處理
- 二級緩存: 用戶控制開啟 作用域在SessionFactory
二級緩存暫未介紹
第七節(jié) hibernate查詢api 查詢表中所有數(shù)據(jù)
調(diào)用兩步走
- 創(chuàng)建對象
- 執(zhí)行對象中方法
- Query對象
package cn.lkangle.twoday;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import cn.lkangle.entity.User;
import cn.lkangle.util.HbmUtil;
public class QueryTest {
@Test
public void testQuery() {
Session session = null;
Transaction tx = null;
try {
session = HbmUtil.getSession();
tx = session.beginTransaction();
Query<User> query = session.createQuery("from User");
List<User> list = query.list();
for (User user : list) {
System.out.println(user);
}
tx.commit();
} catch (Exception e) {
tx.rollback();
} finally {
session.close();
}
}
}
- Criteria對象
package cn.lkangle.twoday;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import cn.lkangle.entity.User;
import cn.lkangle.util.HbmUtil;
public class CriteriaTest {
@Test
public void testCriteria() {
Session session = null;
Transaction tx = null;
try {
session = HbmUtil.getSession();
tx = session.beginTransaction();
Criteria criteria = session.createCriteria(User.class);
List<User> list = criteria.list();
for (User user : list) {
System.out.println(user);
}
tx.commit();
} catch (Exception e) {
tx.rollback();
} finally {
session.close();
}
}
}
- SQLQuery對象
該對象默認(rèn)查詢返回值類型是數(shù)組 可以通過addEntity方法設(shè)置為對象類型
package cn.lkangle.twoday;
import java.util.Arrays;
import java.util.List;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import cn.lkangle.entity.User;
import cn.lkangle.util.HbmUtil;
public class SQLQueryTest {
@Test
public void sqlqueryTest() {
Session session = null;
Transaction tx = null;
try {
session = HbmUtil.getSession();
tx = session.beginTransaction();
SQLQuery sqlQuery = session.createSQLQuery("select * from t_user");
List<Object[]> list = sqlQuery.list();
for (Object[] objects : list) {
System.out.println(Arrays.toString(objects));
}
sqlQuery.addEntity(User.class);
List<User> list2 = sqlQuery.list();
for (User user : list2) {
System.out.println(user);
}
tx.commit();
} catch (Exception e) {
tx.rollback();
} finally {
session.close();
}
}
}
更多的查詢操作會在第四天進(jìn)行講解
有點疑惑的是這些方法好像都被棄用了
估計后面會有新的方式吧
end、、、