Hibernate整理

Hibernate是一個開放源代碼的對象關係映射框架(orm),它對JDBC進行了非常輕量級的對象封裝,它將POJO數據庫表建立映射關係,是一個全自動的orm框架.
orm:(Object Relational Mapping) 對象關係映射,orm主要解決面向對象與關係型數據庫存在的概念不匹配問題
pojo:(Plain Old java Object) 也就是javaBean

配置hibernate:
1.jar包
2.配置文件 cfg.xml
<hibernate-configuration>
<session-factory>
//jdbc驅動 ;com.mysql.jdbc.Driver 需要導入jdbc jar包
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql:///數據庫名</property>
<property name="hibernate.connection.username">mysql用戶名</property>
<property name="hibernate.connection.password">mysql密碼</property>
<!-- 顯示底層生成的SQL語句 -->
<property name="hibernate.show_sql">true</property>
<!-- 格式化顯示底層生成的SQL語句 -->
<property name="hibernate.format_sql">true</property>
<!-- 添加映射文件,不寫報錯 -->
<property name="hibernate.current_session_context_class">thread</property>
方言
<!-- 方言 hibernate-release-5.2.10.Final\project\etc\hibernate.properties 裏複製 -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>

<!-- #hibernate.hbm2ddl.auto create-drop 無論是否存在表結構,每次執行都會創建表結 構,之後刪除
#hibernate.hbm2ddl.auto create 無論是否存在表結構,每次都會創建表結構,數據丟失
#hibernate.hbm2ddl.auto update 如果數據庫不存在該表結構,會自動創建
;如果存在該表結構,並且表結構與持久化類一樣,不做修改
;如果存在該表結構,並且表結構與持久化類不一樣,會修改表結構,保留原有字段
#hibernate.hbm2ddl.auto validate 不會自動創建表結構 ,也不會修改表結構,只對表結構進行驗證 表驗證 -->
<property name="hibernate.hbm2ddl.auto">update</property>

配置映射文件
<!-- 映射文件: 配置映射文件路徑 包名之間斜槓隔開
class 配置全限定名(包名+類名)
packge 配置持久化類所在的包名 "Spring 集成項目的時候可以這麼配置" (包名)
-->
<mapping resource="/bean/User.hbm.xml"/>

C3P0
<!-- 連接C3P0
連接池參數 hibernate.connection.provider_class
org.hibernate.connection.C3P0ConnectionProvider
需要自己去找 /hibrnate/lib/hibernate-c3p0-5.2.10.Final.jar
#hibernate.c3p0.max_size 2
#hibernate.c3p0.min_size 2
#hibernate.c3p0.timeout 5000
#hibernate.c3p0.max_statements 100
#hibernate.c3p0.idle_test_period 3000
#hibernate.c3p0.acquire_increment 2
#hibernate.c3p0.validate false -->
<property name="hibernate.connection.provider_class">
org.hibernate.c3p0.internal.C3P0ConnectionProvider
</property>
<property name="hibernate.c3p0.min_size">10</property>


二級緩存
<!-- 二級緩存 默認不開啓
#hibernate.cache.use_second_level_cache false
-->
<property name="hibernate.cache.use_second_level_cache">true</property>
<!-- #hibernate.cache.region.factory_class 路徑:org.hibernate.cache.ehcache-->
<property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
<!-- 開啓查詢緩存 -->
<property name="hibernate.cache.use_query_cache">true</property>

<!-- 配置類緩存,集合緩存 -->
<class-cache usage="read-only" class="bean1.Customer"/>
<class-cache usage="read-only" class="bean1.T_Order"/>
<collection-cache usage="read-only" collection="bean1.Customer.orders"/>

3.核心代碼
Configuration configuration=new Configuration().configure();
SessionFactory factory=configuration.buildSessionFactory();
Session session=factory.openSession();
或者得到當前session
// Session session=factory.getCurrentSession()
Transaction transaction = session.beginTransaction();
//創建對象
User user = new User();
user.setUsername("lining");
user.setPassword("123");
//存儲user --save : 修改--update : 刪除--delete saveorupdate --沒有就存,有就不同修改
session.save(user);
//查詢
/***
1.User user = session.get(User.class , id); id查詢---相當於where id=?;
2.User user = session.load(User.class , id); 懶加載
3.Query query = session.createQuery("from User where id=5");
User user = (User) query.uniqueResult();
4.createCriteria()
5.session.createNativeQuery(“select* from user”):使用原生sql
6.Query query = session.createQuery("from User "); //偏移量查詢:分頁
query.setFirstResult(1);//偏移量
query.setMaxResults(3); //查詢個數
List<User> list = query.list();//返回集合
*/
//提交
transaction.commit();
// 關閉
session.close();
transaction.close();

封裝HibernateUtils;
private static SessionFactory factory;
static{
Configuration configuration=new Configuration().configure("hibernate.cfg.xml");
factory=configuration.buildSessionFactory();
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
@Override
public void run() {
factory.close();
}
}
)
);
}
public static Session openSession(){
return factory.openSession();
}
public static Session getCurrentSession(){
return factory.getCurrentSession();
}


持久化對象的唯一標識 OID
Hibernate使用OID來建立內存中的對象和數據庫中記錄的對應關係
結論:對象的OID和數據庫的表的主鍵對應。爲保證OID的唯一性,應該讓Hibernate來爲OID賦值
主鍵需要具備:不爲空/不能重複/不能改變


hbm.xml 對象配置文件重點(*)
<!-- package:配置持久類所在包
之後在class等標籤中,name屬性直接寫類名
<hibernate-mapping package="domain" > -->
<hibernate-mapping>
<!-- class:配置類與表的映射關係
name:類名
table:表名
dynamic-insert:動態插入 默認值 false
設置爲true ,如果字段爲null,不參與insert語句
dynamic-update:動態修改 默認值 false
設置爲true ,沒有做修改的屬性不參與update語句
-->
<class name="bean.User" table="user">
<!-- 主鍵
id:主鍵
name:屬性名
column:字段名
unsaved-value:指定某個值當null處理
比如0 當做null 但現在規定建議使用包裝類
access:可以指定成員變量名稱(強烈不建議使用)
配置access 當訪問屬性的時候 直接操作成員變量 不會訪問 get set方法
-->
<id name="id" column="id" >
<!-- assigned 指定的 native 自增長的-->
<!-- 指定主鍵的生成策略
generator:生成器
native:主鍵自動增長
increment:數據庫自己維護主鍵,自動生成,先從表中查最大id,在將id+1 作新的主鍵
identity:依賴於數據庫主鍵自增功能 在創建表的時候應勾選主鍵自增
sequence:序列 Orcale維護住建自動生成方式
hilo:hibernate 自定義的維護主鍵的自增方式
native:(三選一)identity sequence hilo
assigned:手動設置自己維護主鍵(主鍵分爲 自然 代理) 當主鍵是自然主鍵時候
uuid:生成32位字符串作主鍵
eg: 將id這隻爲32位字符串 注意修改持久化類的屬性類型
-->
<generator class="native" />
</id>
<!-- 其他屬性與主鍵的映射關係
name:屬性名
column:字段名
type:類型(java,hibernate ,sql)
length:長度
precision:小數點後的位數 精度
scale:有效位數 salary (5,2) 有效數字5 小數點 2
not-null:非空
unique:唯一
insert:該屬性是否參與插入語句 insert
update:該屬性是否參與修改語句 update
-->
<property name="username" column="username"/>
<property name="password" column="password"/>
</class>
</hibernate-mapping>

狀態介紹
 Hibernate對象有三種狀態,session時候緩存對象(一級緩存),數據庫中是否有記錄判斷狀態
1.瞬時狀態Trasient 緩存和數據庫都沒有值
2.持久狀態Persistent 緩存對象有值,數據庫最終會有記錄(事務尚未提交)
3.遊離狀態Detached 數據庫有值, 緩存沒有值

快照:
與一級緩存一樣的存儲位置,對一級緩存進行備份.保證數據庫中的數據與一級緩存中的數據一致,如果一級緩存中數據進行了修改,當提交事務的時候,回自動刷新一級緩存,將數據同步到數據庫
快照的產生:只有查詢數據庫纔會發生,查詢的數據一式兩份,一份存在一級緩存中,一份存在快照中
 

一對一.一對多.多對多:
配置文件
1-1:

第一種形式:
Person表與IdCard表一對一
<!-- name:屬性名稱
class :屬性的類型.全類名
property-ref="" 當前類一對一指向對方的屬性名-->
<one-to-one name="idcard" class="bean2.Idcard" property-ref="person"/>
<!-- 使用外鍵 unique="true" 讓多的一端 爲一.就是一對一 -->
<many-to-one name="person" class="bean2.Person" column="pid" unique="true"/>

第二種形式:
Company表與Address表一對一
<!-- constrained="true" sql:外鍵約束--> 進行主鍵同步 native 自增 assigned 手動設置主鍵
<one-to-one name="company" class="bean2.Company" constrained="true" />
<one-to-one name="address" class="bean2.Address" />

1-多:
Customer表與T_Order表 一對多

Customer表
<!--
set:配置一對多關係
name:集合的屬性名稱
key:用來描述外鍵,
column:外鍵名稱,cid
one-to-many:配置一對多
class:多的一端的全類名
inverse:反轉,由誰來維護主鍵,默認值爲false,不反轉,由一的一端來維護
true:反轉,由多的一端來維護 可以理解爲反客爲主
cascade="save-update" 聯級邏輯.save-update同增改.當沒有存儲,有就修改.
delete 同刪
delete-orphan 刪除時.代表多的一端關聯值爲null時,將會被刪除
-->
<set name="orders" inverse="false" cascade="save-update">
<key>
<column name="cid" />
</key>
<one-to-many class="bean1.T_Order" />
</set>


T_Order表
<!--
many-to-one:配置多對一關係
name:屬性名
column:外鍵名稱,兩個外鍵名稱要求一致
class:一的一端的全類名
-->
<many-to-one name="customer" class="bean1.Customer">
<column name="cid" />
</many-to-one>


多-多
Student表與Course表
需要建立三個表.中間表用來關聯
<!-- inverse ;只能一端設置爲true,不可同時設置true
table="t_student_course" 中間表名
<key column="cid"></key> 外鍵
-->
<set name="students" table="t_student_course" inverse="true">
<key column="cid"></key>
<many-to-many class="bean3.Student" column="sid"></many-to-many>
<!-- many-to-many:多對多 class:對方的全類名,集合中元素的全類名 ;
column:對方的外鍵名稱 -->
</set>


類級別檢索:
Get:立即加載
Load:延遲加載
<class name="bean3.Course" table="COURSE" lazy="true">
關聯級別檢索:
一對多:
Fetch:抓取策略,使用哪種查詢語句
Join:連接查詢
Select:普通查詢語句
Subselect:子查詢
Lazy:是否延遲加載
True:延遲加載
False:立即加載
Extra:極其懶惰,查詢集合中元素個數時,發出查詢個數的語句,count()
多對一:
Fetch:
Join:
select
Lazy:
False:立即加載
Proxy:需要取決於類級別檢索策略,取決於customer
hql:(structured Query Language)
針對hibernate的sql語句; 語句比較多,可以上網查詢. 但語句是重點.以後整理

連接查詢:
交叉連接:
內連接:inner join   on
左外連接:left outer join
右外連接:right outer join
迫切左外連接:left outer join fetch

// 交叉連接
@Test
public void test01() {
Session session = HibernateUtils.openSession();
session.beginTransaction();
Query query = session.createQuery("from Customer c,Order o");
List<Object[]> list = query.list();
for(Object[] obj : list) {
System.out.println(Arrays.toString(obj));
}

session.getTransaction().commit();
session.close();
}
//內連接,隱式內連接
@Test
public void test02() {
Session session = HibernateUtils.openSession();
session.beginTransaction();

Query query = session.createQuery("from Customer c,Order o"
+ " where c=o.customer");
List<Object[]> list = query.list();
for(Object[] obj : list) {
System.out.println(Arrays.toString(obj));
}

session.getTransaction().commit();
session.close();
}
//內聯接,customer c inner join order o on c.id = o.cid
@Test
public void test03() {
Session session = HibernateUtils.openSession();
session.beginTransaction();
//面向對象思想
Query query = session.createQuery("from Customer c inner join c.orders");
List<Object[]> list = query.list();
for(Object[] obj : list) {
System.out.println(Arrays.toString(obj));
}
session.getTransaction().commit();
session.close();
}
//左外連接,left outer join
/*
* 將左表數據全部顯示,
* 與右邊沒有關聯的顯示爲null
*/
@Test
public void test04() {
Session session = HibernateUtils.openSession();
session.beginTransaction();
Query query = session.createQuery("from Customer c left outer join c.orders");
List<Object[]> list = query.list();
for(Object[] obj : list) {
System.out.println(Arrays.toString(obj));
}
session.getTransaction().commit();
session.close();
}
//迫切左外連接,將Order數據封裝到Customer中
@Test
public void test05() {
Session session = HibernateUtils.openSession();
session.beginTransaction();
Query query = session.createQuery("from Customer c left outer join fetch c.orders");
List<Customer> list = query.list();
for(Customer obj : list) {
System.out.println(obj);
}
session.getTransaction().commit();
session.close();
}
//右外連接
@Test
public void test06() {
Session session = HibernateUtils.openSession();
session.beginTransaction();

Query query = session.createQuery("from Customer c right outer join c.orders");
List<Object[]> list = query.list();
for(Object[] obj : list) {
System.out.println(Arrays.toString(obj));
}

session.getTransaction().commit();
session.close();
}
//迫切右連接
@Test
public void test07() {
Session session = HibernateUtils.openSession();
session.beginTransaction();
Query query = session.createQuery("from Order o right outer join fetch o.customer");
List<Object> list = query.list();
for(Object obj : list) {
System.out.println(obj);
}

session.getTransaction().commit();
session.close();
}
命名查詢:
有的hql語句使用比較頻繁,可以將hql語句存儲到配置文件中,使用時提取hql語句即可
配置文件:
class裏寫局部變量
<query name="localQuery">
<!--[CDATA[ ]] 處理大於小於 > < 問題
[CDATA[ from Customer c where c.id>10 ]]-->
                           <![CDATA[ from Customer c ]]>
                  </query>
         </class>
class外協全局變量
         <query name="globalQuery">
                  <![CDATA[ from Customer c]]>
         </query>
java:
public void test01() {
                  Session session = HibernateUtils.openSession();
                  session.beginTransaction();
                  //獲得全局命名查詢的hql語句
                  // Query query = session.getNamedQuery("globalQuery");
  //獲取局部命名查詢
                  Query query = session.getNamedQuery("com.qf.domain.Customer.localQuery");
                  List<Customer> list = query.list();
                  for (Customer c : list) {
                           System.out.println(c);
                  }
                  session.getTransaction().commit();
                  session.close();
         }
qbc:
-------- Query by Criteria,標準查詢
@Test
public void test01() {
Session session = HibernateUtils.openSession();
session.beginTransaction();
List<Customer> list = session.createCriteria(Customer.class).list();
for (Customer c : list) {
System.out.println(c);
}
session.getTransaction().commit();
session.close();
}

// 排序
@Test
public void test02() {
Session session = HibernateUtils.openSession();
session.beginTransaction();
List<Customer> list = session.createCriteria(Customer.class)
.addOrder(Order.desc("id")).list();
for (Customer c : list) {
System.out.println(c);
}
session.getTransaction().commit();
session.close();
}

// 查詢條件
@Test
public void test03() {
Session session = HibernateUtils.openSession();
session.beginTransaction();
Criteria criteria = session.createCriteria(Customer.class);
// id>10
// criteria.add(Restrictions.gt("id", 10));
// 含有s
// criteria.add(Restrictions.like("name", "%s%"));
// id<5 or id>15
criteria.add(Restrictions.or(Restrictions.lt("id", 5),
Restrictions.gt("id", 15)));
List<Customer> list = criteria.list();
for (Customer c : list) {
System.out.println(c);
}
session.getTransaction().commit();
session.close();
}

離線查詢:
DetachedCriteria,不需要使用session可以拼接條件
service層使用DetachedCriteria,拼接條件,之後將DetachedCriteria對象傳到dao層進行查詢
@Test
public void test01() {
//service層
DetachedCriteria dCriteria = DetachedCriteria.forClass(Customer.class);
dCriteria.add(Restrictions.ge("id", 16));
//dao,findByCriteria(DetachedCriteria dc); dao層
Session session = HibernateUtils.openSession();
session.beginTransaction();
Criteria criteria = dCriteria.getExecutableCriteria(session);
List<Customer> list = criteria.list();
for(Customer c:list) {
System.out.println(c);
}
session.getTransaction().commit();
session.close();
}
二級緩存:
/**
* 二級緩存 二級緩存的不是對象,是對象的散列(屬性)
* 之後查詢是,從二級緩存中獲得屬性,那那麼在一級緩存中封裝對象
*/
/**
* 類緩存/集合緩存
* 只輸出一套查詢..走第二緩存
* 配置
* <class-cache usage="read-only" class="bean1.Customer"/> 類緩存
* <class-cache usage="read-only" class="bean1.T_Order"/>
* <collection-cache usage="read-only" collection="bean1.Customer.orders"/> 集合緩存
*/
@Test
public void test(){
Session session = HibernateUtil.openSession();
session.beginTransaction();
Customer c=session.get(Customer.class, 1);
for(T_Order o:c.getOrders()){
System.out.println(o.getName());
}
session.clear();
Customer c2=session.get(Customer.class, 1);
for(T_Order o2:c.getOrders()){
System.out.println(o2.getName());
}
session.getTransaction().commit();
session.close();
}
/**
* 查詢緩存 針對hql語句
* 配置:
* <property name="hibernate.cache.use_query_cache">true</property>
* select
customer0_.ID as ID1_3_,
customer0_.NAME as NAME2_3_
from
CUSTOMER customer0_
只打印了一回sql
在查詢緩存中 ,保存id 根據類緩存中存儲的id去查詢數據庫
*/


/**<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">

<!-- 硬盤 -->
<diskStore path="java.io.tmpdir"/>
<!-- 二級緩存默認配置
eternal="false" 是否永久存儲在內存
-->
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
maxElementsOnDisk="10000000"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
<!-- 清除原則 least recently used
棧:FILO
隊列:FIFO
-->
<persistence strategy="localTempSwap"/>
</defaultCache>
</ehcache>
*/
@Test
public void test1(){
Session session = HibernateUtil.openSession();
session.beginTransaction();
Query query = session.createQuery("from Customer");
query.setCacheable(true);//二級緩存是否可用
List<Customer> list = query.list();
session.clear();
Query query1 = session.createQuery("select c from Customer c");
query.setCacheable(true);//二級緩存是否可用
List<Customer> list1 = query.list();
session.getTransaction().commit();
session.close();
}
/**
* 時間戳;對數據庫操作的時間
* 用來判斷相同語句的操作,防止緩存影響查詢結果, 所以每次去查詢都是新的查詢
*
*/
@Test
public void test2(){
Session session = HibernateUtil.openSession();
session.beginTransaction();
Customer customer=session.get(Customer.class, 1);
session.createQuery("update Customer set name= :name"
+" where id= :id").setParameter("name", "huafei")
.setParameter("id", 11).executeUpdate();
session.clear();
Customer customer1=session.get(Customer.class, 1);
session.getTransaction().commit();
session.close();
}





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章