hibernate(20170731)
1.導(dǎo)包:hibernate-distribution-3.5.6-Final/hibernate3.jar
hibernate-distribution-3.5.6-Final\lib\required里面所有的包必須的包
再導(dǎo)入log4j-1.2.16, slf4j-log4j12-1.6.1, mysql驅(qū)動的包
2.在做了國際化的說明文檔中找到hibernate.cfg.xml配置文件的相關(guān)內(nèi)容,然后在src文件夾下面建立
hibernate.cfg.xml的總配置文件,然后復(fù)制相關(guān)內(nèi)容并更改相關(guān)配置
3.創(chuàng)建實體類,并創(chuàng)建實體類與表的映射文件,并設(shè)置dtd約束
4.將映射文件配置到總配置文件(注意里面用的是斜杠)
5,如有需要創(chuàng)建hibernateUtil類,來獲得session工廠
對象的三種狀態(tài)瞬時態(tài),持久態(tài),托管態(tài)
對象被new出來,還沒有和session建立關(guān)系的時候,那么此時就是瞬時態(tài),和session建立關(guān)系此時就是持久態(tài),和session沒有建立關(guān)系,但是數(shù)據(jù)庫有相應(yīng)的記錄,就是托管態(tài)
getCurrentSession()得到同一個session對象
openSession();每次都會創(chuàng)建一個session對象
load和get的區(qū)別;
load方式,類似懶加載,不會立即發(fā)送sql去查詢,只有查詢除了id以外的數(shù)據(jù),才會發(fā)送sql語句,而get是全部查詢,
/get方式去取不存在的數(shù)據(jù),會返回一個null
//load方式去取不存在的數(shù)據(jù),會報錯
以下操作都要在事務(wù)中進行
添加操作
session.save(user); 返回的是剛添加進去的ID
刪除操作
User user=new User(); 需要先new對象再進行刪除
user.setId(5);
session.delete(user);
更新操作
User user=(User)session.get(User.class, 1); //獲得對象再進行修改
user.setName("強哥");
session.update(user);
User user=new User(); //new對象進行修改
user.setId(2);
user.setName("xiaohon");
session.update(user);
查詢操作:
單個查詢get或者load
查詢多個
Query query = session.createQuery("from User"); //HQL語句
List<User> list = query.list();
一對多(兩張表情況):
[圖片上傳中。。。(1)]
[圖片上傳中。。。(2)]
配置過程:
1,從一開始,用set標(biāo)簽,name為set對象的引用,里面加上key標(biāo)簽,里面column屬性為外鍵,one-to-many的class為多的那一方類名
2。從多開始,直接配置many-to-one ,name為本類中一的一方的引用,里面的column標(biāo)簽name屬性為外鍵
這樣存儲先把多放進一的set集合里面,無法直接將訂單依賴著客戶保存進入數(shù)據(jù)庫,那么這些對象都需要用session保存一次變?yōu)槌志脩B(tài),才能讓訂單依賴客戶保存進入數(shù)據(jù)庫,并且是這樣的執(zhí)行流程,通過session先保存訂單,再保存客戶,保存完客戶再更新訂單的id,這樣的話sql語句較多,影響效率
inverse 管理關(guān)系由一的一方交給多的一方,不寫默認(rèn)false由一的一方管理,由多的一方來管理后,就不需要打印后面的那兩句更新ID的語句了,效率提高了
那么此時的關(guān)系由多的一方來維護,那么此時要注意inverse加到哪里和測試類聯(lián)系起來
查詢的時候不會級聯(lián)查詢主要是為了資源和性能的考慮,采用的是懶加載,用到的時候才會去加載
save-update:一的一方保存,同時保存多的一方
delete:刪除一的一方,同時刪除多的一方
delete-orphan:孤兒刪除,解除一和多的關(guān)系,同時將多的一方刪除
如果需要配置多項,使用逗號分隔。<set cascade="save-update,delete">
all : save-update 和 delete 整合
all-delete-orphan : 三個整合
如果我們在刪除的時候,刪除一的一方時,由于級聯(lián)刪除的關(guān)系,會將多的一方也刪除,但是我們只想讓一的一方刪除,不想將多的一方刪除,那么此時可以通過一來查詢與之相關(guān)的多,然后將他們的外鍵設(shè)置為null,再將級聯(lián)刪除配置刪除才能進行刪除操作。
commit(); 提交事務(wù);關(guān)閉session clear();清空session
多對多的表關(guān)系:
多對多不用在實體類表中添加外鍵字段,而是創(chuàng)建中間表來生成外鍵字段,并且多對多的配置兩邊都是相同的,用配置文件自動創(chuàng)建中間表的時候,可能會無法添加進入數(shù)據(jù),要用原始的save方式,添加一次數(shù)據(jù)后才會能夠添加進入數(shù)據(jù)
[圖片上傳中。。。(3)]
抓取策略:
get和load的區(qū)別,都是從數(shù)據(jù)庫獲得數(shù)據(jù)后封裝成的對象
但是load是懶加載,get不是,load是要用到除了id以外的數(shù)據(jù)才會主動去加載,這樣有利于提高性能
抓取策略(要么加在類上面,要么加在set上面,默認(rèn)true,關(guān)閉懶加載將其置為false即可)只能影響load,不能影響get ;
lazy="extra",極其懶惰(延遲),先查詢客戶select, 如果只需要擁有的訂單數(shù),使用聚合函數(shù)(不查詢詳情)
[圖片上傳中。。。(4)]
[圖片上傳中。。。(5)]
[圖片上傳中。。。(6)]
HQL查詢語句:
from entityname 查詢?nèi)?/p>
只有jdbc比較特殊是從1開始的,其他的都是從0開始的
from entityname where id =? 查詢單個 uniqueResult();
綁定參數(shù)query.setinteger(0,5);從0開始
from entityname where id =:id;
綁定參數(shù)query.setinteger(“id”,5);從0開始
select c.name from entityanme c 查詢部分字段 返回字符串
select c.id,c.name from entityname c 查詢兩個字段,返回object數(shù)組
select new entity(c.name,c.id) from entityname c 和上面的一樣,要有對應(yīng)得構(gòu)造方法
from entityname c order by c.id; 排序
from entityname c order by c.id desc; 降序 排序
分頁
[圖片上傳中。。。(7)]
聚合函數(shù):
總條數(shù):select count(*) from entityname;
連接查詢:
from entityname1,entityname2; 笛卡爾積,用途不大
隱式內(nèi)連接:
from Custom c,OrderInfo o where o.custom=c; 外鍵關(guān)聯(lián)
hibernate會參照映射文件查找數(shù)據(jù)庫
顯示內(nèi)連接
from Customer c inner join c.orderSet
迫切內(nèi)連接
from Customer c inner join fetch c.orderSet,返回對象不是數(shù)組
distinct c 去重復(fù)
左連接
QBC: 標(biāo)準(zhǔn)查詢
QBC運算符
含義
=
Restrictions.eq()
<>
Restrictions.ne()
Restrictions.gt()
=
Restrictions.ge()
<
Restrictions.lt()
<=
Restrictions.le()
is null
Restrictions.isnull()
is not null
Restrictions.isNotNull()
like
Restrictions.like()
and
Restrictions.and()
and
Restrictions.conjunction()
or
Restrictions.or()
or
Restrictions.disjunction()
not
Restrictions.not()
in(列表)
Restrictions.in()
[圖片上傳中。。。(8)]
@Test
public void qbc1() {
SessionFactory sessionFactory= HibernateUtil.getSessionFactory();
Session session=sessionFactory.getCurrentSession();
session.beginTransaction();
Criteria criteria=session.createCriteria(OrderInfo.class);
criteria.setFirstResult(0);
criteria.setMaxResults(2);
List<Customer> list=criteria.list();
System.out.println(list);
session.getTransaction().commit();
}
集合查詢:
Criteria criteria=session.createCriteria(Customer.class);
List<Customer> list=criteria.list();
System.out.println(list);
分頁查詢
Criteria criteria=session.createCriteria(OrderInfo.class);
criteria.setFirstResult(0);
criteria.setMaxResults(2);
List<Customer> list=criteria.list();
排序查詢
Criteria criteria=session.createCriteria(Customer.class);
criteria.addOrder(Order.desc("id")); asc也行
List<Customer> list=criteria.list();
條件/多條件組合查詢
Criteria criteria=session.createCriteria(OrderInfo.class);
//下面的條件可以組合起來求得交集的集合
criteria.add(Restrictions.eq("address", "南山"));//準(zhǔn)確查詢
criteria.add(Restrictions.like("address", "%山"));//模糊查詢,%可以加在任何位置
criteria.add(Restrictions.gt("id",2)); //數(shù)字查詢
List<Customer> list=criteria.list();
采用集合的方式進行多條件組合查詢
Criteria criteria=session.createCriteria(OrderInfo.class);
//下面的條件可以組合起來求得交集的集合
HashMap<String,String> hashmap=new HashMap<>();
hashmap.put("detail", "訂單2");
hashmap.put("address","南山");
criteria=criteria.add(Restrictions.allEq(hashmap));
List<OrderInfo> list=criteria.list();
模糊查詢的一種模式:
Criteria criteria=session.createCriteria(OrderInfo.class);
criteria.add(Restrictions.ge("id",16));
criteria.add(Restrictions.like("address", "寶安", MatchMode.EXACT));
List<OrderInfo> list=criteria.list();
MatchMode.START:字符串在最前面的位置.相當(dāng)于"like 'key%'"
MatchMode.END:字符串在最后面的位置.相當(dāng)于"like '%key'"
MatchMode.ANYWHERE:字符串在中間匹配.相當(dāng)于"like '%key%'"
MatchMode.EXACT:字符串精確匹配.相當(dāng)于"like 'key'"
in的范圍查詢:
Criteria criteria=session.createCriteria(OrderInfo.class);
criteria.add(Restrictions.in("address",new String[]{"寶安","南山"}));
List<OrderInfo> list=criteria.list();
and查詢:
Criteria criteria=session.createCriteria(OrderInfo.class);
Criterion c1=Restrictions.like("address", "%山", MatchMode.END);
Criterion c2=Restrictions.gt("id", 16);
criteria.add(Restrictions.and(c1,c2));
List<OrderInfo> list=criteria.list();
or查詢:
Criteria criteria=session.createCriteria(OrderInfo.class);
Criterion c1=Restrictions.like("address", "安", MatchMode.ANYWHERE);
Criterion c2=Restrictions.eq("id", 15);
criteria.add(Restrictions.or(c1,c2));
List<OrderInfo> list=criteria.list();
聚合函數(shù)求總條數(shù)
Criteria criteria=session.createCriteria(OrderInfo.class);
ProjectionList project=Projections.projectionList();
project.add(Projections.rowCount());
criteria.setProjection(project);
Long a=(Long)criteria.uniqueResult();
System.out.println(a);
分組查詢:
Criteria criteria=session.createCriteria(OrderInfo.class);
ProjectionList project=Projections.projectionList();
project.add(Projections.groupProperty("address"));
criteria.setProjection(project);
List<OrderInfo> list=criteria.list();
去重查詢:
Criteria criteria=session.createCriteria(Customer.class);
criteria.createAlias("hashSet", "h");
criteria.setResultTransformer(criteria.DISTINCT_ROOT_ENTITY);
List<OrderInfo> list=criteria.list();
System.out.println(list);
左外連接
Criteria criteria=session.createCriteria(Customer.class);
criteria.createAlias("hashSet", "h", CriteriaSpecification.LEFT_JOIN);
criteria.setResultTransformer(criteria.DISTINCT_ROOT_ENTITY);
List<OrderInfo> list=criteria.list();
返回一個對象數(shù)組
Criteria criteria=session.createCriteria(Customer.class);
criteria.createAlias("hashSet", "h");
criteria.setResultTransformer(CriteriaSpecification.PROJECTION);
List<Object[]> list=criteria.list();
離線查詢:
離線查詢
- 就是在session還沒創(chuàng)建的時候,就先組裝好查詢的相關(guān)條件
- 然后再傳遞給dao層去執(zhí)行
public void qbc10() {
DetachedCriteria detachedCriteria=DetachedCriteria.forClass(Customer.class);
detachedCriteria.createAlias("hashSet", "h");
detachedCriteria.setResultTransformer(CriteriaSpecification.PROJECTION);
SessionFactory sessionFactory=HibernateUtil.getSessionFactory();
Session session=sessionFactory.getCurrentSession();
session.beginTransaction();
Criteria criteria=detachedCriteria.getExecutableCriteria(session);
List<Object[]> list=criteria.list();
for (Object[] objects : list) {
System.out.println(objects[0]+":"+objects[1]);
}
session.getTransaction().commit();
}
二級緩存:
a) 一級緩存:session級別緩存,在一次請求中共享數(shù)據(jù)。
b) 二級緩存:sessionFactory級別緩存,整個應(yīng)用程序共享一個會話工廠,共享一個二級緩存。
導(dǎo)入jar包:ehcache-1.5.0.jar/ commons-logging.jar/ backport-util-concurrent.jar開啟二級緩存確定二級緩存提供商確定需要緩存內(nèi)容
1> 配置需要緩存的類
2> 配置需要緩存的集合
配置ehcache自定義配置文件
[圖片上傳中。。。(9)]
注意在設(shè)置需要緩存的內(nèi)容和權(quán)限時要放在映射文件的下面這樣的順序
查詢二級緩存:
先配置<property name="hibernate.cache.use_query_cache">true</property>
public void query() {
SessionFactory sessionFactory=HibernateUtil.getSessionFactory();
Session session=sessionFactory.getCurrentSession();
session.beginTransaction();
Query query=session.createQuery("from Customer");
query.setCacheable(true); 每次使用時先開啟
List<Customer> l=query.list();
System.out.println(l);
session.getTransaction().commit();
Session session1=sessionFactory.getCurrentSession();
session1.beginTransaction();
Query query1=session1.createQuery("from Customer");
query1.setCacheable(true); 每次使用時先開啟
List<Customer> l1=query1.list();
System.out.println(l1);
session1.getTransaction().commit();
sessionFactory.close();
}
hihernate的批處理:
采用這樣的配置
[圖片上傳中。。。(10)]
那么程序就會采用in的方式進行這種范圍的查詢
但是hibernate還是建議我們使用jdbc api進行查詢,這樣速度比較快
采用實現(xiàn)work();接口來進行批處理,比hibernate自帶的批處理快
session.doWork(new Work() {
@Override
public void execute(Connection connection) throws SQLException {
PreparedStatement ps=connection.prepareStatement("insert into user(name)values(?)");
for(int i=0;i<10000;i++){
ps.setString(1, "小明"+i);
ps.addBatch();
if(i%500==0){
ps.executeBatch();
}}
}
});
session.getTransaction().commit();
long end=System.currentTimeMillis();
System.out.println(end-start);
}
hibernate采用c3p0連接池
1.導(dǎo)包C:\Users\Administrator\Desktop\hibernate-distribution-3.5.6-Final\lib\optional\c3p0
2.配置配置文件
<property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
<property name="hibernate.c3p0.max_size">3</property>
<property name="hibernate.c3p0.mix_size">3</property>
<property name="hibernate.c3p0.timeout ">4000</property>
設(shè)置事務(wù)的隔離級別:
<property name="hibernate.connection.isolation">4</property>
事務(wù)的特性:
⑴ 原子性(Atomicity)
原子性是指事務(wù)包含的所有操作要么全部成功,要么全部失敗回滾,這和前面兩篇博客介紹事務(wù)的功能是一樣的概念,因此事務(wù)的操作如果成功就必須要完全應(yīng)用到數(shù)據(jù)庫,如果操作失敗則不能對數(shù)據(jù)庫有任何影響。
⑵ 一致性(Consistency)
一致性是指事務(wù)必須使數(shù)據(jù)庫從一個一致性狀態(tài)變換到另一個一致性狀態(tài),也就是說一個事務(wù)執(zhí)行之前和執(zhí)行之后都必須處于一致性狀態(tài)。
拿轉(zhuǎn)賬來說,假設(shè)用戶A和用戶B兩者的錢加起來一共是5000,那么不管A和B之間如何轉(zhuǎn)賬,轉(zhuǎn)幾次賬,事務(wù)結(jié)束后兩個用戶的錢相加起來應(yīng)該還得是5000,這就是事務(wù)的一致性。
⑶ 隔離性(Isolation)
隔離性是當(dāng)多個用戶并發(fā)訪問數(shù)據(jù)庫時,比如操作同一張表時,數(shù)據(jù)庫為每一個用戶開啟的事務(wù),不能被其他事務(wù)的操作所干擾,多個并發(fā)事務(wù)之間要相互隔離。
即要達到這么一種效果:對于任意兩個并發(fā)的事務(wù)T1和T2,在事務(wù)T1看來,T2要么在T1開始之前就已經(jīng)結(jié)束,要么在T1結(jié)束之后才開始,這樣每個事務(wù)都感覺不到有其他事務(wù)在并發(fā)地執(zhí)行。
關(guān)于事務(wù)的隔離性數(shù)據(jù)庫提供了多種隔離級別,稍后會介紹到。
⑷ 持久性(Durability)
持久性是指一個事務(wù)一旦被提交了,那么對數(shù)據(jù)庫中的數(shù)據(jù)的改變就是永久性的,即便是在數(shù)據(jù)庫系統(tǒng)遇到故障的情況下也不會丟失提交事務(wù)的操作。
例如我們在使用JDBC操作數(shù)據(jù)庫時,在提交事務(wù)方法后,提示用戶事務(wù)操作完成,當(dāng)我們程序執(zhí)行完成直到看到提示后,就可以認(rèn)定事務(wù)以及正確提交,即使這時候數(shù)據(jù)庫出現(xiàn)了問題,也必須要將我們的事務(wù)完全執(zhí)行完成,否則就會造成我們看到提示事務(wù)處理完畢,但是數(shù)據(jù)庫因為故障而沒有執(zhí)行事務(wù)的重大錯誤。
以上介紹完事務(wù)的四大特性(簡稱ACID),現(xiàn)在重點來說明下事務(wù)的隔離性,當(dāng)多個線程都開啟事務(wù)操作數(shù)據(jù)庫中的數(shù)據(jù)時,數(shù)據(jù)庫系統(tǒng)要能進行隔離操作,以保證各個線程獲取數(shù)據(jù)的準(zhǔn)確性,在介紹數(shù)據(jù)庫提供的各種隔離級別之前,我們先看看如果不考慮事務(wù)的隔離性,會發(fā)生的幾種問題:
1,臟讀
臟讀是指在一個事務(wù)處理過程里讀取了另一個未提交的事務(wù)中的數(shù)據(jù)。
當(dāng)一個事務(wù)正在多次修改某個數(shù)據(jù),而在這個事務(wù)中這多次的修改都還未提交,這時一個并發(fā)的事務(wù)來訪問該數(shù)據(jù),就會造成兩個事務(wù)得到的數(shù)據(jù)不一致。例如:用戶A向用戶B轉(zhuǎn)賬100元,對應(yīng)SQL命令如下
update account set money=money+100 where name=’B’; (此時A通知B) update account set money=money - 100 where name=’A’;
當(dāng)只執(zhí)行第一條SQL時,A通知B查看賬戶,B發(fā)現(xiàn)確實錢已到賬(此時即發(fā)生了臟讀),而之后無論第二條SQL是否執(zhí)行,只要該事務(wù)不提交,則所有操作都將回滾,那么當(dāng)B以后再次查看賬戶時就會發(fā)現(xiàn)錢其實并沒有轉(zhuǎn)。
2,不可重復(fù)讀
不可重復(fù)讀是指在對于數(shù)據(jù)庫中的某個數(shù)據(jù),一個事務(wù)范圍內(nèi)多次查詢卻返回了不同的數(shù)據(jù)值,這是由于在查詢間隔,被另一個事務(wù)修改并提交了。
例如事務(wù)T1在讀取某一數(shù)據(jù),而事務(wù)T2立馬修改了這個數(shù)據(jù)并且提交事務(wù)給數(shù)據(jù)庫,事務(wù)T1再次讀取該數(shù)據(jù)就得到了不同的結(jié)果,發(fā)送了不可重復(fù)讀。
不可重復(fù)讀和臟讀的區(qū)別是,臟讀是某一事務(wù)讀取了另一個事務(wù)未提交的臟數(shù)據(jù),而不可重復(fù)讀則是讀取了前一事務(wù)提交的數(shù)據(jù)。
在某些情況下,不可重復(fù)讀并不是問題,比如我們多次查詢某個數(shù)據(jù)當(dāng)然以最后查詢得到的結(jié)果為主。但在另一些情況下就有可能發(fā)生問題,例如對于同一個數(shù)據(jù)A和B依次查詢就可能不同,A和B就可能打起來了……
3,虛讀(幻讀)
幻讀是事務(wù)非獨立執(zhí)行時發(fā)生的一種現(xiàn)象。例如事務(wù)T1對一個表中所有的行的某個數(shù)據(jù)項做了從“1”修改為“2”的操作,這時事務(wù)T2又對這個表中插入了一行數(shù)據(jù)項,而這個數(shù)據(jù)項的數(shù)值還是為“1”并且提交給數(shù)據(jù)庫。而操作事務(wù)T1的用戶如果再查看剛剛修改的數(shù)據(jù),會發(fā)現(xiàn)還有一行沒有修改,其實這行是從事務(wù)T2中添加的,就好像產(chǎn)生幻覺一樣,這就是發(fā)生了幻讀。
幻讀和不可重復(fù)讀都是讀取了另一條已經(jīng)提交的事務(wù)(這點就臟讀不同),所不同的是不可重復(fù)讀查詢的都是同一個數(shù)據(jù)項,而幻讀針對的是一批數(shù)據(jù)整體(比如數(shù)據(jù)的個數(shù))。
現(xiàn)在來看看MySQL數(shù)據(jù)庫為我們提供的四種隔離級別:
① Serializable (串行化):可避免臟讀、不可重復(fù)讀、幻讀的發(fā)生。
?、?Repeatable read (可重復(fù)讀):可避免臟讀、不可重復(fù)讀的發(fā)生。
?、?Read committed (讀已提交):可避免臟讀的發(fā)生。
?、?Read uncommitted (讀未提交):最低級別,任何情況都無法保證。
以上四種隔離級別最高的是Serializable級別,最低的是Read uncommitted級別,當(dāng)然級別越高,執(zhí)行效率就越低。像Serializable這樣的級別,就是以鎖表的方式(類似于Java多線程中的鎖)使得其他的線程只能在鎖外等待,所以平時選用何種隔離級別應(yīng)該根據(jù)實際情況。在MySQL數(shù)據(jù)庫中默認(rèn)的隔離級別為Repeatable read (可重復(fù)讀)。
在MySQL數(shù)據(jù)庫中,支持上面四種隔離級別,默認(rèn)的為Repeatable read (可重復(fù)讀);而在Oracle數(shù)據(jù)庫中,只支持Serializable (串行化)級別和Read committed (讀已提交)這兩種級別,其中默認(rèn)的為Read committed級別。
在MySQL數(shù)據(jù)庫中查看當(dāng)前事務(wù)的隔離級別:
select @@tx_isolation;
在MySQL數(shù)據(jù)庫中設(shè)置事務(wù)的隔離 級別:
set [glogal | session] transaction isolation level 隔離級別名稱; set tx_isolation=’隔離級別名稱;’
例1:查看當(dāng)前事務(wù)的隔離級別:
[圖片上傳中。。。(11)]
例2:將事務(wù)的隔離級別設(shè)置為Read uncommitted級別:
[圖片上傳中。。。(12)]
或:
[圖片上傳中。。。(13)]
記?。涸O(shè)置數(shù)據(jù)庫的隔離級別一定要是在開啟事務(wù)之前!
如果是使用JDBC對數(shù)據(jù)庫的事務(wù)設(shè)置隔離級別的話,也應(yīng)該是在調(diào)用Connection對象的setAutoCommit(false)方法之前。調(diào)用Connection對象的setTransactionIsolation(level)即可設(shè)置當(dāng)前鏈接的隔離級別,至于參數(shù)level,可以使用Connection對象的字段:
[圖片上傳中。。。(14)]
在JDBC中設(shè)置隔離級別的部分代碼:
[圖片上傳中。。。(15)]
后記:隔離級別的設(shè)置只對當(dāng)前鏈接有效。對于使用MySQL命令窗口而言,一個窗口就相當(dāng)于一個鏈接,當(dāng)前窗口設(shè)置的隔離級別只對當(dāng)前窗口中的事務(wù)有效;對于JDBC操作數(shù)據(jù)庫來說,一個Connection對象相當(dāng)于一個鏈接,而對于Connection對象設(shè)置的隔離級別只對該Connection對象有效,與其他鏈接Connection對象無關(guān)。
樂觀鎖和悲觀鎖
a) 悲觀鎖(數(shù)據(jù)庫提供實現(xiàn)) . 悲觀的認(rèn)為認(rèn)為一定發(fā)生別人要修改我使用的數(shù)據(jù). 那我就可以為我讀取的數(shù)據(jù)加鎖.
采用這樣的方式對正在操作的數(shù)據(jù)上鎖,在本線程提交事務(wù)之前,其他線程要想操作這個數(shù)據(jù)必須要等到當(dāng)前線程操作完了并且提交事務(wù)時候才能操作那個數(shù)據(jù)
User user=(User) session.get(User.class, 20, LockOptions.UPGRADE); 給id為20的user的數(shù)據(jù)上鎖
b)樂觀鎖,樂觀鎖(Optimistic Lock), 顧名思義,就是很樂觀,每次去拿數(shù)據(jù)的時候都認(rèn)為別人不會修改,所以不會上鎖,但是在更新的時候會判斷一下在此期間別人有沒有去更新這個數(shù)據(jù),可以使用版本號等機制。
做法:在類里面添加一個Integer類型的version屬性,然后在配置文件里面添加一個version配置,對應(yīng)的表也要添加一個version字段<version name="version" />,這個標(biāo)簽必須加在id之后
它提交的時候主要是對比version的值,如果這個值和當(dāng)時取出來的不一致就會提交失敗,如果能夠提交成功那么它就會將那個version的值加1。
在使用新版的hibernate的時候在獲得sessionfactory的時候推薦使用這個工具類,新版的沒有hibernate3.jar這個jar包,把必須的包導(dǎo)進去就行了
public class HibernateUtil {
private static final SessionFactory sessionFactory = buildSessionFactory();
private static SessionFactory buildSessionFactory() {
try {
Configuration cfg = new Configuration().configure();
StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()
.applySettings(cfg.getProperties()).build();
SessionFactory sessionFactory = cfg.buildSessionFactory(serviceRegistry);
return sessionFactory;
}
catch (Throwable ex) {
// Make sure you log the exception, as it might be swallowed
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
}
注解實現(xiàn)映射關(guān)系:
[圖片上傳中。。。(16)]
[圖片上傳中。。。(17)]
[圖片上傳中。。。(18)]
[圖片上傳中。。。(19)]
[圖片上傳中。。。(20)]
使用注解的時候需要更換獲得sessionFactory的方式,采用注解的方式
package com.qianfeng.forum.common;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
public class HibnateUtils {
private static final SessionFactory sessionFactory = buildSessionFactory();
private static SessionFactory buildSessionFactory() {
try {
//return new Configuration().configure().buildSessionFactory();
return new AnnotationConfiguration().configure().buildSessionFactory();
}
catch (Throwable ex) {
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
}
采用攔截器
作用:控制session的關(guān)閉時機,等頁面加載完數(shù)據(jù)之后再關(guān)閉session
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
SessionFactory factory = HibnateUtils.getSessionFactory();
Session session = factory.getCurrentSession();
Transaction transaction = null;
try {
transaction = session.beginTransaction();
// 放行
chain.doFilter(request, response);// action--index.jsp
//
transaction.commit();
} catch (Exception e) {
e.printStackTrace();
if (transaction != null) {
transaction.rollback();
}
}
}