粗淺看Struts2和Hibernate框架

----------------------------------------------------------------------------------------------
[ 版權申明:本文系做者原創,轉載請註明出處
文章出處: http://blog.csdn.net/sdksdk0/article/details/52424578
做者:朱培      ID:sdksdk0      郵箱: zhupei@tianfang1314.cn   

--------------------------------------------------------------------------------------------css

struts2和hibernate分別都是框架是JavaEE中的三大框架之一,同時也是很是「老」的兩個框架,如今不少已經轉換爲springMVC和mybatis來開發javaee應用了,既然sturts2和hibernate能夠成爲經典,那確定仍是有其存在的必要的,對於一些老的項目來講,若是咱們要對其進行維護什麼的,咱們仍是須要了解struts2和hibernate的用法什麼的。從使用角度上面來講的話hibernate對於數據庫的查詢什麼的仍是有必定的不足之處的,雖說寫HQL語句更爲簡潔一點,可是其依然有瓶頸的。雖然慢慢的在一些新的項目中struts2和hibernate可能會用的不多或者被替換爲其餘的,可是其框架的思想仍是對咱們頗有借鑑意義的!使用框架比之前直接用MVC模式的話,解耦合了不少,讓程序更爲健壯,從這個角度來講仍是很是好的。一個設計良好的框架通常分爲三層:(1)接口層,這一層要儘可能使用interface,在這一層中你要考慮到你如今的、未來的可能支持的功能,但不須要去實現它,只定義到接口層次就能夠了。如Struts中的插件接口PlugIn。(2)抽象層,這一層要針對你當前的需求作定製,對你的需求中的通用邏輯作實現。這一層應該出現大量的抽象類。如Struts中的ActionServlet、Action和ActionForm等類。(3)實現層,不用說了,把前面兩層沒有作掉的事情在這一層都作了吧。如Struts中後臺實現的各類功能。html


如下內容是struts2和hibernate的精華知識點,若是有哪一個地方的知識還很模糊的話建議再去複習一下吧!java


struts2篇

簡介

Struts 是 Apache 軟件基金會(Apache Software Foundation)資助的一個爲開發基於MVC模式應用架構的開源框架,是利用Java Servlet和JSP、XML等方面的技術來實現構建Web應用的一項很是有用的技術,它也是基於MVC模式的Web應用最經典框架。mysql


struts和struts2只是名字類似,沒有其餘關係。git

給予spring AOP思想的攔截器機制,更易擴展。github

<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
  </filter>
  <filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
  </filter-mapping>

執行過程web

動做類就是一個POJO,算法

實現Action接口,可使用接口中定義的常量:spring

SUCCESS:一切ok,不返回任何的結果視圖。sql

ERROR:出錯了,服務器忙等。

INPUT:數據回顯。

LOGIN:要求登錄。

動做類通常選擇繼承com.opensymphony.xwork2.ActionSupport。

可使用Action接口中的常量,提供用戶輸入驗證功能,消息國際化。

Action:定義一個動做, name:動做名稱,對應用戶的請求名稱 class:框架要實例化的動做名稱,全名稱。 method:執行的動做類的方法,默認是execute。

動做類的動做方法調用。

DMI動態方法調用。 國際化、用戶輸入數據的校驗。

經常使用常量 default.properties屬性。

在動做類中使用servlrt。

ServletActionContext

通配符:適合有規律的。  多個struts.xml中用 包含進來。 在動做類中訪問servlet的API: ServletActionContext的靜態方法、動做類實現ServletRequestAware接口,注入的方式傳遞進來的,由一個叫servletConfig的攔截器完成的。

結果視圖:  /success.jsp

dispatcher:轉發到一個頁面。默認
    redirect:重定向到一個頁面
    chain:轉發到另一個動做
    redirectAction:重定向到另一個動做



結果視圖

局部邏輯視圖:服務於當前的動做。

<action name="action1" >
                局部邏輯視圖
                <result name="success">/success.jsp</result>
                <result name="error">/error.jsp</result>
            </action>

全局邏輯視圖

<global-results>
                <result name="success">/success.jsp</result>
                <result name="error">/error.jsp</result>

            </global-results>

自定義結果類型

封裝參數

靜態參數注入

原理:由一個叫作staticParams攔截器完成的。

動態參數注入

動做類做爲模型對象,動做類中存儲着用戶輸入的數據。

動做類處理用戶請求,模型封裝數據。

模型驅動

一、動做類和模型分開

由一個ModelDriven的攔截器完成的。

批量添加數據:

用戶註冊

封裝數據的類型轉換

用戶輸入的數據是字符串類型的,而實體bean有其餘類型。 讀數據。 DefaultTypeConverter

註冊類型轉換器: 局部類型轉換器註冊:針對屬性 全局類型轉換器:針對轉換類型。

<s:fieldError /> 或者<s:actionError />

在屬性所屬類的包中,user.properties。

invalid.fieldvalue.birthday=The birthday must be yyyy-MM-dd

用戶輸入的校驗

客戶端校驗,服務端校驗。

動做類繼承ActionSupport.

編程式校驗:

針對動做類中的方法校驗。 StringUtils.isBlank(user.getName()){

} 轉換失敗都會轉向一個name=input的視圖。

聲明式校驗:可插入式的校驗。

針對全部方法:

針對某個動做進行校驗:

<%@ taglib uri="/struts-tags" prefix="s"%>

<s:form action="regist"><!-- 自動加應用名稱,method默認是post。自動加動做的擴展名。自動數據回顯。寫起來很方便 -->
    <s:textfield name="username" label="用戶名" requiredLabel="true" requiredPosition="left"></s:textfield>
    <s:password name="password" label="密碼"></s:password>
    <s:radio list="#{'0':'女','1':'男'}" name="gender" label="性別"></s:radio>
    <s:textfield name="birthday" label="生日"></s:textfield>
    <s:textfield name="email" label="郵箱"></s:textfield>
    <s:submit value="註冊"></s:submit>
</s:form>

OGNL表達式

對象圖導航語言,struts2使用OGNL表達式作爲默認的表達式語言。 支持普通對象的方法調用。

<s:property  value="'abcdf'.length()"/> <br />
    <s:property  value="'abcdf'.charAt(2)"/> <br />

    <s:property  value="@java.lang.Integer@MAX_VALUE"/> <br />
    <s:property  value="@java.lang.Math@abs(-100)"/> <br />

    <!-- 建立List或者Map對象 -->
    <s:radio  list="{'男','女'}"  name="gender"  label="性別"  /><br />

    <s:radio list="#{0:'女',1:'男' }"   name="姓名"></s:radio>

OGNL上下文

就是一個Map<String,Object>數據的中心,每次動做的請求,struts2框架都會爲每一個線程建立一個OGNL上下文對象,存放了全部的有關數據.

根中的數據: <s:property value="username" />username是一個OGNL表達式,搜索根中全部對象的username屬性,直到找到爲止。

其餘contextMap中的數據, <s:property value="#session" />

用戶發出一次動做請求時,Struts2框架每次都會產生ActionContext對象(引用了contextMap),ValueStack對象,同時還會實例化動做類。

ActionContext和ValueStack

互相引用。

private Map<String, Object> context:contextMap
public Map<String, Object> getApplication():獲取ServletContext中的全部Attributes
public Map<String, Object> getContextMap():獲取contextMap的引用
public Map<String, Object> getParameters():獲取請求參數的Map
public Map<String, Object> getSession():獲取HttpSession中的全部Attributes
public ValueStack getValueStack():得到ValueStack對象的引用
public Object get(String key):從contextMap中根據key得到對象
public void put(String key, Object value):向contextMap中存放數據

ValueStack

setValue:以#存在contextMap中,不以#開頭,至關於設置棧中對象的屬性(從棧頂到棧底).

Struts2中的EL表達式

org.apache.struts2.dispatcher.StrutsRequestWrapper

<s:property value="#session.p"/><br/>
${p}<br/>
<hr/>
<s:property value="username"/><br/>
${username}

標籤庫

循環遍歷,相似於<c:forEach >

<s:iterator value=""></s:iterator>

取屬性值: <s:property value="#status.index"/>

value:ognl表達式。要遍歷的數據 var:引用當前遍歷的元素,放到了contextMap中。不是ognl表達式,是一個字符串. 若是不指定var,是把當前遍歷的元素放到了根的棧頂。 status:引用一個對象,該對象記錄着當前遍歷的元素的一些信息.放在了contextMap中 int getIndex(); int getCount(); boolean isLast(); boolean isFirst(); boolean isOdd(); boolean isEven();

點擊跳轉:

<s:a action="action1" >點我啊!</s:a>

動態包含

<s:action name="action1"  executeResult="false"></s:action>

一、把OGNL看成普通字符串對待,要加單引號。 二、把字符串看成ONGL表達式,加上%{} 三、在xml配置文件和properties文件中,使用ONGL表達式,要加上${表達式}

UI標籤和主題

在struts2中的jsp編寫時儘可能使用struts2的標籤。

標籤調查經常使用屬性: 引入css類選擇器. <s:textfield cssClass="odd" cssStyle="" name="" />

<s:form  action="" >
        <s:textfield name="username"  label="用戶名"  requiredLabel="true"></s:textfield>
        <s:password name="password"  label="密碼"  requiredLabel="true"></s:password>
        <!-- 多選框 -->
        <s:checkboxlist name="hobby"  list="{'吃飯','睡覺','逗你玩'}"></s:checkboxlist>
        <s:radio  name="gender" list="#{1:'男',0:'女' }"   value="1"  label="性別"></s:radio>
        <s:select  name="city"   label="城市"   list="#{'HY':'衡陽','CS':'長沙' }"     value="'HY'" headerKey="-1"headerValue="--請選擇--" ></s:select>
        <s:textarea  name="des"   label="描述"></s:textarea>
        <s:submit  value="保存" ></s:submit>
        <s:reset  value="重置"></s:reset>
    </s:form>

主題默認使用的是xhtml. 支持: struts.ui.theme=xhtml struts.ui.templateDir=template

覆蓋主題只須要在職介的項目中創建對應的目錄結構,freemarker的語法。

更改默認主題: 添加theme="simple"

<s:submit  value="保存"   theme="simple"></s:submit>

在form標籤中制定主題

統一主題:

<constant name="struts.ui.theme" value="simple"></constant>

防止表單重複提交

一、儘可能使用提交後重定向 二、令牌機制, 在表單中加入 <s:token></s:token>

配置token攔截器。

<interceptor-ref name="defaultStack"></interceptor-ref>
            <interceptor-ref name="token"></interceptor-ref>

<interceptor-ref name="defaultStack"></interceptor-ref>
        <interceptor-ref name="tokenSession"></intercep


Hibernate篇


簡介

hibernate是輕量級的JAVAEE應用的持久層解決方案,是一個關係型數據庫ORM框架。 ORM:對象關係映射,對象:java中一切皆對象javaBean,關係:數據庫中的表(二維表),映射:配置文件。

編寫步驟

  • 建立java項目
  • 導入jar包
  • 核心配置文件(hibernate.cfg.xml)
  • javaBean +映射文件( bena名稱.hbm.xml),必須將映射文件加入到核心配置文件。

核心配置文件:

驅動、url、username、password、規範

<?xml version="1.0"  encoding="UTF-8" ?>
<!DOCTYPE hibernate-configuration PUBLIC
    "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
    <!-- 至關於鏈接池 -->
    <session-factory>
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/day15</property>
        <property name="hibernate.connection.username">zp</property>
        <property name="hibernate.connection.password">a</property>

        <property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect.class</property>

    </session-factory>

</hibernate-configuration>

映射文件: User.hbm.xml,和javabean同包。

配置javabena屬性和表中字段的對應關係.

<?xml version="1.0"  encoding="UTF-8" ?>

<!DOCTYPE hibernate-mapping PUBLIC 
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
    <class  name="cn.tf.domain.User"  table="t_user">
        <!-- 給表配置主鍵 -->
        <id name="uid">
            <!-- 主鍵生成策略 -->
            <generator class="native"></generator>
        </id>
        <!-- 其餘屬性 -->
        <property name="username"></property>
        <property name="password"></property>   
    </class>
</hibernate-mapping>

API詳解

SessionFactory,單例的,線程安全的,不一樣的線程能夠得到不一樣的session。

configuration。buildSessionFactory():得到實例

openSseeion(),建立一個會話,每執行一次,session都是新的。

Configuration:提供用於去加載配置文件的。

核心配置文件的種類:hibernate.properties(只能配置基本信息) 和hibernate.cfg.xml(能夠配置基本信息,映射文件等)

構造方法:new Configuration().configure(); 去加載hibernate.cfg.xml配置文件。

經過configure(string ),指定自定義的cfg.xml文件。

config.addResource("cn/tf/domain/User.hbm.xml");

或者:

config.addClass(User.class);

Session:

每一個用戶必須獨享本身的session, save,update,delete,createQuery(list/setFirstResult/setMaxResults)

事務操做

  1. 開啓事務:beginTransaction()
  2. 提交事務: commit()
  3. 回滾:rollback()

主配置文件

hibernate.cfg.xml 位置:src(classpath) ,在WEN-INF/classes目錄下

<!-- 顯示生產sql語句 -->
    <property name="hibernate.show_sql">true</property>
    <!-- 格式化方式顯示sql -->
    <property name="hibernate.format_sql">true</property>


    <!-- 表的建立 ,先有表,再有映射,實際開發中經過表自動生成hbm.xml映射文件
        取值:validate:程序運行時,將校驗映射文件和表的對應關係,若是一一對應程序正常運行,若是不正常則拋異常。
             create :每一次都將建立表,若是表已經存在了就刪除,程序結束以後表還在
             create-drop:每一次都將建立表,若是表已經存在了就刪除,程序結束以後表也刪除了, 必須執行factory.close()
             update:若是表不存在就建立,若是存在,將維護映射到表的關係。只負責添加,但不進行刪除。

    -->


    <property name="hibernate.hbm2ddl.auto">update</property>

    <!-- 取消bena校驗 -->
    <property name="javax.persistence.validation.mode">none</property>


    <!-- 將session綁定到本地線程中     
        當在cfg.xml配置了thread,SessionFactory提供的getCurrentSession()將可使用
        get():至關於map.get(Thread)
        set(value): 至關於map.put(Thread,value)
        remove()  :map.remove(Thread)
      -->
    <property name="hibernate.current_session_context_class">thread</property>

映射文件基本配置

<class  name="cn.tf.domain.Person"  table="t_person">
    <!-- 給表配置主鍵 -->
    <id name="pid">
        <!-- 主鍵生成策略 -->
        <generator class="native"></generator>
    </id>
    <!-- 其餘屬性
        name:默認用於配置javabean屬性名稱
        length:配置長度,默認255
        column:當前屬性對應表中字段名稱,默認和name值相同
                column的屬性: <property  column=""  ></property>
                <column  name=""></column>
        type: 數據字段類型
                hibernate類型:例如:string(都是小寫)
                java類型:例如java.lang.String
                mysql類型:例如varchar(50)  ,  <column  name="name"  sql-type="varchar(50)" />

        日期時間類型:
                date:日期,java.util.Date
                time:java.util.Date
                timestamp:java.util.Date,時間戳隨時間變化而變化
                項目中使用datetime表示日期時間
     -->

     <!-- 其餘配置
            access ,用於肯定當前屬性如何進行數據封裝
                property : 默認值,hibernate採用javabean屬性 與 表字段進行對應。在javabean必須提供 getter/setter方法
                field : hibernate採用 javabean 字段 與 表字段進行對應。 能夠沒有getter/setter方法
                    例如:private String username;
                noop : 提供給hibernate hql使用,數據庫沒有對應字段。通常不使用。
            precision 和 scale 給 oracle配置,在mysql沒有做用。
                precision 配置數字位數
                scale 配置小數位數 
                例如:numeric(precision,scale)  , 12.34  numeric(4,2)


      -->


    <property name="name"  length="50"  column="name"  type="string"   access="property">   </property>
    <property name="gender"  ></property>
    <property name="age"  type="integer"></property>
    <property name="photo"  type="binary"   length="200000"></property>
    <property name="birthday" >
        <column name="birthday"  sql-type="datetime"></column>
    </property>
    <property name="desc"  column="`desc`"></property>



</class>

insert="false" 表示生成insert語句沒有當前字段 update="false" 表示生成update語句沒有當前字段

在class中設置動態的添加和修改,默認是false,若是屬性內容爲空,則生成的sql中就沒有該字段。

dynamic-insert="false" dynamic-update="false" 若是使用動態更新,數據必須是查詢得到的。

派生屬性

從數據庫另外一張表查詢得到。 聚合函數:count(),max(),min(),avg(),sum()等。

sql語句:若是使用字段,默認從當前表中得到字段的,若是要得到B表字段,必須使用表的別名。

<property name="orderCount"  formula="(SELECT COUNT(*) FROM t_order  o  WHERE o.book_id=bid)"></property>

生成的sql語句:

select
    book0_.bid as bid1_0_,
    book0_.title as title1_0_,
    book0_.price as price1_0_,
    (SELECT
        COUNT(*) 
    FROM
        t_order  o  
    WHERE
        o.book_id=book0_.bid) as formula0_0_ 
from
    t_book book0_ 
where
    book0_.bid=?

OID映射

hibernate經過OID肯定系統,及OID相同,對象就相同,OID取值爲數據庫主鍵的值。

<id  name="cid" >
        <generator class="identity"></generator>
    </id>


         id屬性配置,
         name:OID屬性名稱
         column:表字段列名
         length:表字段長度
         type:表字段類型
         unsaved-value:save或update方法使用依據
                    String,默認是null,若是使用unsaved-value="abc" ,當執行save方法,設置「abc」至關以前null
         generator:主鍵生成策略
                    increment:類型必須是整型,本身維護表的數據自動增加,在執行insert語句執行以前,先查詢,查詢最大值,加1,可是在高併發或集羣中會有必定的問題。

                    identity:使用數據庫底層的自動增加,auto_increment 

                    sequence:oracle序列
                    hilo:採用高低位算法,不支持自動增加,也不支持序列
                            table ,設置數據庫中,另外一個表A的表名。
                            column,表A的列名
                            max_lo,一次操做多少條記錄。100表示能夠容許一次操做100條記錄。
                            算法:max_lo *  next_value + next_value
                            例如:
                                <generator class="hilo">
                                    <param name="table">hi_value</param>
                                    <param name="column">next_value</param>
                                    <param name="max_lo">100</param>
                                </generator>

            非整型:
                    uuid:隨機字符串32長度      
                    assigned:天然主鍵,手動設置

持久對象狀態

狀態分類:

  • transient:瞬時態,session中沒有緩存數據,數據庫沒有對應的數據。
  • persistent:持久態,session中有緩存數據,數據庫中最終會有該數據,例如save(user).
  • detached:脫管態,session沒有緩存,可是數據庫中有該數據,

瞬時態->持久態 :執行save()和saveOrUpdate()

瞬時態->脫管態 :手動設置OID,若是OID對應的記錄不存在,以後操做將拋出異常

持久態->瞬時態 :當執行delete(),(刪除態)

持久態->脫管態 :close()關閉,clear()清除全部緩存,session.evict(PO)將指定的對象從緩存中移除

脫管態->瞬時態 :手動刪除OID

脫管態->持久態 :執行update,執行了saveOrUpdate()

全部查詢結果,對象都是持久態,查詢結果保存在session中。

一級緩存

session級別的緩存,及將數據保存在session中。 一級緩存內置,不能刪除,必須使用的。

目的:提升性能,減小數據庫的訪問。

一級緩存操做

session提供map容器,用於執行一些指定的操做時,進行相應PO對象緩存。

save方法

當OID類型爲:代理主鍵,執行save方法時,將觸發insert語句,肯定OID的值。直到commit數據才進入數據庫。
當OID類型爲:天然主鍵,執行save方法時,此時不觸發insert語句,直到commit才觸發insert語句,數據進入數據庫。
若是OID在數據庫中已經存在記錄將拋異常。

saveOrUpdate方法

對象時瞬時態,執行saveOrUpdate,底層執行save方法。若是對象時脫管態,執行saveOrUpdate,底層執行update方法。
OID 代理主鍵,OID若是沒有值,執行save方法;若是有值(setUid(,,)),執行update方法。
若是設置oid,但數據庫中沒有對應記錄,將拋異常。
oid天然主鍵,先執行select查詢來得到主鍵的值,若OID不存在,則save,OID存在,則update。

update方法

當執行update時,都會執行update,即便數據沒有變動。

能夠經過映射文件配置:select-before-update,在更新前先查詢,若是數據系統,將不進行update,適用於更新不頻繁的應用。

一級緩存內容的操做

清空緩存

session.clear();

或者

session.evict(user);

一級緩存快照(備份)

提交時要肯定一級緩存的數據是否進行了修改,若是沒有修改,就不進行任何操做,若是修改了,就執行update,將一級緩存的數據同步到數據庫。是否修改的依據就是一級緩存的數據與快照的數據是否一致。

默認提交時,一級緩存的數據將進行刷新,執行update語句,使一級緩存的數據同步到數據庫。刷新時機是能夠修改的:在hibernate中提供了FlushMode進行設置。

刷新時機:一、查詢前,2,提交時,3,執行flush進行手動刷新,4,默認進行commit時,能夠理解爲依據進行了flush了。

關聯關係映射

一對多、多對多、一對一

實體關係

採用ER圖(關係實體圖),開發時進行表之間的描述。

一對多

<!--  一個客戶擁有多個訂單,一對多  
            Set:set
            List:list
            Map:map
            Array:array
            key:用來肯定從表的

    -->
    <set name="orderSet" >
            <key column="customer_id"></key>
            <one-to-many  class="cn.tf.domain.Order" />

    </set>

--

<!-- 多個訂單屬於一個客戶
        每個映射文件均可以完整的描述對象之間的關係
        column,肯定從表外鍵
     -->
    <many-to-one name="customer"   class="cn.tf.domain.Customer"   column="customer_id">

    </many-to-one>

一對多: 多方必須維護外鍵信息,若是一方沒有OID值,將觸發update語句, 一方默認對外鍵信息進行維護,一方將放棄對外鍵的維護 在Customer.hbm.xml中,加入

inverse="true"

級聯操做

級聯保存或更新

save-update:A關聯瞬時態B,當保存A時,自動將瞬時態的B轉換成持久態B

cascade="save-update"

級聯刪除:

<set name="orderSet"  cascade="delete"   >

刪除客戶的時候刪除訂單: 刪除後臺執行的語句:

Hibernate:

select
    customer0_.cid as cid1_0_,
    customer0_.cname as cname1_0_ 
from
    t_customer customer0_ 
where
    customer0_.cid=?

Hibernate:

select
    orderset0_.customer_id as customer3_1_1_,
    orderset0_.oid as oid1_,
    orderset0_.oid as oid2_0_,
    orderset0_.price as price2_0_,
    orderset0_.customer_id as customer3_2_0_ 
from
    t_order orderset0_ 
where
    orderset0_.customer_id=?

Hibernate:

update
    t_order 
set
    customer_id=null 
where
    customer_id=?

Hibernate:

delete 
from
    t_order 
where
    oid=?

Hibernate:

delete 
from
    t_customer 
where
    cid=?

孤兒刪除

<set name="orderSet"  cascade="delete-orphan"   >

解除關係以後,那個表外鍵設置null,從表記錄就是孤兒,一併進行刪除,解除關係時,一併刪除訂單,可是客戶仍是存在的。

多對多

<!-- 多對多
        肯定中間表的表名
        當前表在中間表對應的名稱
        肯定容器中另外一個對象,class來肯定另外一個對象的類型,column肯定的是另外一個表對應的外鍵名稱
     -->
    <set name="studentSet"  table="t_student_course" >
        <key column="course_id"></key>
        <many-to-many class="cn.tf.domain2.Student"   column="student_id"></many-to-many>
    </set>

--

<set name="courseSet"  table="t_student_course">
        <key column="student_id"></key>
        <many-to-many  class="cn.tf.domain2.Course"  column="course_id"></many-to-many>
    </set>

操做

兩個對象不用同時對中間表進行維護,因此須要在多對多中有一方配置放權。

inverse="true"

級聯保存 直接保存便可。

雙向級聯刪除

Student.hbm.xml
 *      <set name="courseSet" table="m_student_course" cascade="delete">
 *  Course.hbm.xml
 *      <set name="studentSet" table="m_student_course" cascade="delete" inverse="true">

集成log4j

hibernate使用的是slf4j日誌框架。

組件映射

經過面向對象角度,使用設計模式,將數據都抽取到一個對象中,將多個對象組合在一塊兒,達到重複利用的目的。

必須肯定組合javabean類型,每個對象屬性必須在表中都存在獨有列名。

<class  name="cn.tf.component.Person"   table="t_person">
    <id  name="pid">
        <generator class="native"></generator>
    </id>
    <property name="name"></property>

    <component name="homeAddress"  class="cn.tf.component.Address">
            <property name="addr"  column="homeAddr"></property>
            <property name="tel"  column="homeTel"></property>
    </component>

    <component name="companyAddress"  class="cn.tf.component.Address">
            <property name="addr"  column="companyAddr"></property>
            <property name="tel"  column="companyTel"></property>
    </component>

繼承映射

繼承方式1:sub-class 全部內容保存一張表,給表提供標識字段,每個子類都具備獨有的字段。

繼承方式1:

<class  name="cn.tf.inherit.subclass.Employee"   table="t_employee"   discriminator-value="員工">
    <id  name="eid">
        <generator class="native"></generator>
    </id>

    <discriminator column="etemp"></discriminator>

    <property name="name"></property>

    <subclass  name="cn.tf.inherit.subclass.SalaryEmployee"  discriminator-value="正式員工">
        <property name="salary"></property>
    </subclass>
    <subclass  name="cn.tf.inherit.subclass.HourEmployee"  discriminator-value="小時工">
        <property name="rate"></property>
    </subclass>

繼承方式2:

<joined-subclass  name="cn.tf.inherit.joinedclass.HourEmployee"  table="j_hour">
    <key column="hid"></key>
    <property name="rate"></property>
</joined-subclass>
<joined-subclass  name="cn.tf.inherit.joinedclass.SalaryEmployee"  table="j_salary">
    <key column="sid"></key>
    <property name="salary"></property>
</joined-subclass>

繼承方式3: 將生成多張表,彼此之間沒有關係,但主鍵值逐漸加強,須要hiberate自動維護三張表之間的主鍵惟一,存在併發問題。

<union-subclass name="cn.tf.inherit.unionclass.HourEmployee"  table="u_hour">
    <property name="rate"></property>
</union-subclass>
<union-subclass name="cn.tf.inherit.unionclass.SalaryEmployee"  table="u_salary">
    <property name="salary"></property>
</union-subclass>

抓取策略

檢索方式

當即檢索:在執行查詢以後,當即執行select語句進行查詢

延遲檢索:在執行查詢方法以後,沒有進行查詢,底層生成代理對象呢,直到須要相應的數據,在進行查詢。 除OID以外的值,關聯的數據

檢索類型

類別級檢索:當前對象全部屬性值。,查詢當前類的全部內容,只查詢一次,優化指查詢時機優化。

關聯級檢索:當前對象關聯對象數據。

多對一,一對一:共同特色都擁有一方

一對多、多對多

<set name="orderSet"   fetch="join"  lazy="true">

fetch用來肯定hibernate生成的sql的樣式,lazy表示制定sql的時間。

fetch="join" ,lazy無效,hibernate 將使用「迫切左外鏈接」,底層執行sql語句就是「左外鏈接」,只執行一條select,將當前對象及關聯對象數據一次性查詢出來。

fetch="select" ,默認值,執行多條select語句

lazy="false" 當即執行,在執行get方法時,當即執行多條select語句。

lazy="true" 延遲執行,在執行get方法時先查詢客戶Customer,直到使用Order數據時才查詢Order

lazy="extra" 極其懶惰,在執行get方法時先查詢客戶Customer(select tcustomer),若是須要order 訂單數,將執行聚合函數只查詢數量(select count() torder),若是須要詳情再查詢詳情(select t_order))。 fetch="subselect" ,採用子查詢

lazy 取值與 fetch="select" 相同。 注意:必須使用Query進行查詢。

檢索方式總結

一、經過OID檢索:get()當即查詢,若是沒有就返回null;load()默認延遲檢查,若是沒有拋出異常。使用以上兩個方法進行查詢,結果都是持久態對象,持久態對象就在以及緩存中。

二、對象導航圖:經過持久對象自動得到關聯對象。例如customer.getOrderSet().size()

三、SQL,session.createSQLQuery("sql語句")

4,QBC,hibernate提供的純面向對象查詢語句。

5,HQL, 提供面向對象的查詢語句。 HQL使用對象和對象屬性,sql語句使用表名和字段名稱,對象和屬性區分大小寫,表名和字段不區分大小寫。

查詢全部

//一、HQL //Query query=session.createQuery("from Customer");

//使用全限定名
    //Query query=session.createQuery("from cn.tf.init.Customer");

    //別名,不能使用*號
    //Query query=session.createQuery("select c  from Customer as c");


    //sql,必須將查詢結果封裝到相應的對象中
    SQLQuery sqlQuery=session.createSQLQuery("select * from t_customer");
    sqlQuery.addEntity(Customer.class);
    List<Customer>  allCustomer=sqlQuery.list();

    //QBC
    Criteria criteria=session.createCriteria(Customer.class);
    List<Customer> allCustomer=criteria.list();

    //List<Customer>  allCustomer=query.list();

    //輸出
    for (Customer customer : allCustomer) {
        System.out.println(customer);
    }

根據ID查詢

//hql
    //Customer customer=(Customer) session.createQuery("from Customer c where c.cid=1").uniqueResult();

    //sql
    //Customer customer=(Customer) session.createSQLQuery("select * from t_customer c where  c.cid=1").addEntity(Customer.class).uniqueResult();

    //QBC
    Customer customer=(Customer) session.createCriteria(Customer.class)
            .add(Restrictions.eq("cid", 1))
            .uniqueResult();

排序

//hql
    //List<Customer> allCustomer=(List<Customer>) session.createQuery("from Customer c order by  c.cid ").list();

    //sql
    //List<Customer> allCustomer=(List<Customer>) session.createSQLQuery("select * from t_customer order by cid desc").addEntity(Customer.class).list();

    //QBC
    List<Customer> allCustomer=(List<Customer>)  session.createCriteria(Customer.class).addOrder(org.hibernate.criterion.Order.asc("cid")).list();

    for (Customer customer : allCustomer) {
        System.out.println(customer);
    }

查詢部份內容(投影)

hql,默認查詢部分將查詢結果封裝到object數組中,須要封裝到指定的對象中,投影查詢的結果是脫管態的。

List<Customer> allCustomer=(List<Customer>) session.createQuery(" select new Customer(cid,name)  from Customer  ").list();

    //sql
    //List<Customer> allCustomer=(List<Customer>) session.createSQLQuery("select cid,name from t_customer  ").addEntity(Customer.class).list();

    //QBC
    List<Customer> allCustomer = session.createCriteria(Customer.class)
            .setProjection(Projections.projectionList()
                    .add(Projections.alias(Projections.property("cid"), "cid"))
                    .add(Projections.alias(Projections.property("name"), "name"))
                    )
                    .setResultTransformer( new AliasToBeanResultTransformer(Customer.class))
                    .list();

分頁查詢

//一、HQL
    //List<Customer>  allCustomer=session.createQuery("from Customer").setFirstResult(0).setMaxResults(2).list();

    //sql,必須將查詢結果封裝到相應的對象中
    //List<Customer>  allCustomer=session.createSQLQuery("select * from t_customer").addEntity(Customer.class).setFirstResult(0).setMaxResults(2).list();

    //QBC
    List<Customer>  allCustomer=session.createCriteria(Customer.class).setFirstResult(0).setMaxResults(2).list();;

綁定

佔位符: #屬性=? 從0開始,setXXX(index,oid);第一個參數表述索引號,從0開始,第二個表示oid的值,也可使用.setParameter(0, 1) 別名:

*  屬性=:別名
 *      第一個參數是別名,通常建議使用屬性名稱


Customer  customer=(Customer) session.createQuery("from Customer  c where c.cid= ? ")
            //.setInteger(0, 1)  
            .setParameter(0, 1)
            .uniqueResult();

    Customer  customer=(Customer) session.createQuery("from Customer  c where c.cid=:cid")
            .setInteger("cid", 1)  
            .uniqueResult();

聚合函數

//Object obj=session.createQuery("select count(*) from Customer").uniqueResult();

    //Object obj=session.createQuery("select count(*) from Customer").uniqueResult();

    Long  numLong=(Long) session.createQuery("select count(*) from Customer").uniqueResult();
    int num=numLong.intValue();
    //輸出

    //2 sql
    //BigInteger numObj = (BigInteger) session.createSQLQuery("select count(cid) from t_customer").uniqueResult();

    //3 qbc
    Long numObj = (Long)session.createCriteria(Customer.class)
                .setProjection(
                        Projections.projectionList()
                        .add(Projections.rowCount())
                    )
                .uniqueResult();

鏈接查詢

  1. 內鏈接:[inner] join
  2. 左外鏈接: left [outer] join
  3. 右外鏈接: right [outer] join
  4. 迫切左外鏈接: left [outer] join fetch
  5. 迫切內鏈接: [inner]join fetch

左外鏈接,將每一條查詢結果封裝到Customer 和Order對象,而後建立 new Object[2]{c,o} 。將全部的數組 存放到另外一個數組返回

List<Customer> allCustomer=session.createQuery("from  Customer  c left outer join  c.orderSet ").list();

迫切左外鏈接,將全部的查詢結果封裝Customer和Order對象,而後將Order 添加到 Customer(customer.getOrderSet().add(order)) ,最後返回Customer對象集合

List<Customer> allCustomer=session.createQuery("select distinct c from Customer  c left outer join fetch  c.orderSet ").list();

命名查詢

將HQL語句存放到配置文件中,以後不須要修改java源碼,服務器tomcat重啓便可。

全局:能夠直接得到,在。hbm.xml文件中配置。與class同級以後

<!-- 配置全局hql -->
<class></class>
    <query name="findAllCustomer">from Customer</query>

使用:

List<Customer>  allCustomer=(List<Customer> )session.getNamedQuery("findAllCustomer").list();

局部:必須經過包名得到

<class><!-- 局部 -->
        <query name="findAllCustomer2">from Customer</query></class>

使用:

List<Customer>  allCustomer=(List<Customer> )session.getNamedQuery("cn.tf.init.Customer.findAllCustomer2").list();

經常使用配置

整合c3p0

<!-- 整合c3p0 -->
<property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>

事務

一組操做,要麼所有成功,要麼所有失敗。 特性:ACID,原子性,一致性,隔離型,持久性

髒讀,不可重複讀,虛讀

<property name="hibernate.connection.isolation">4</property>

丟失更新 lost update

兩我的都在同時進行數據更新,後面講前面的數據進行覆蓋。

樂觀鎖:丟失更新確定不發生:在表中提供一個字段(版本字段),若是版本一致能夠提交,若是不一致不進行提交。

悲觀鎖:丟失更新確定發生,採用mysql數據庫的鎖機制。讀鎖:共享鎖,多我的能夠一塊兒讀。 寫鎖:排它鎖,

二級緩存

介於應用程序和永久性數據存儲源之間,其做用是下降應用程序直接讀寫永久性存儲源的頻率,從而提升應用的運行性能,其物理介質是內存。

若是緩存不夠用,能夠將緩存寫到文件中。

二級緩存

一級緩存,hibernate實現了,必須使用的。是用戶本身共享數據。

二級緩存:SessionFactory級別的緩存,hibernate提供了規範(接口),若是須要使用必須有實現類,用戶之間共享數據,

SessionFactory緩存: 內置緩存:自帶的,不可卸載 外置緩存:二級緩存,須要配置

類緩存、集合緩存、時間戳、查詢緩存。

併發訪問策略:read-write、read-only

不多修改的,不重要的數據適合放入二級緩存中,容許偶爾的併發問題。

配置

一、導入jar包 二、開啓二級緩存 三、肯定提供商 四、肯定須要緩存的內容 五、第三方配置文件

<!-- 開啓二級緩存 -->
    <property name="hibernate.cache.use_second_level_cache">true</property>
    <!-- 提供商 -->
    <property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
    <!-- 開啓查詢緩存 -->
    <property name="hibernate.cache.use_query_cache">true</property>
    <!-- 二級緩存監測 -->
    <property name="hibernate.generate_statistics">true</property>

    <!-- 類緩存 -->
    <class-cache usage="read-write" class="cn.tf.init.Customer"/>
    <class-cache usage="read-write" class="cn.tf.init.Order"/>
    <!--  
    -->
    <!-- 集合緩存 -->
    <collection-cache usage="read-write" collection="cn.tf.init.Customer.orderSet"/>

一、類緩存:數據爲散裝數據,一級緩存是對象,二級緩存是數據。

二、集合緩存,只緩存oid,若是須要數據就從類緩存得到。

三、時間戳:任何操做都會在時間戳中留下記錄,但不要使用一級緩存特性,一級緩存同步數據庫,同時一級緩存同步到二級緩存。保持二級緩存和數據庫一致。

執行update語句,跳過一級緩存更新數據庫,此時時間戳將記錄修改的時間。

session1.createQuery("update Customer c set c.name = ? where c.cid = ?")
    .setString(0, "王曉綠")
    .setInteger(1, 1)
    .executeUpdate();

四、查詢緩存:默認狀況查詢緩存不能使用。 Query進行查詢結果存放到二級緩存,但不從二級緩存獲取。經過HQL語句和查詢結果造成一一對應關係,以後經過HQL語句能夠直接得到查詢結果。

存放或得到數據, 查詢全部 -- 將結果存放一級緩存,同時保存二級緩存

List<Customer> allCustomer = session1.createQuery("from Customer").setCacheable(true).list();

ehcache.xml配置

肯定緩存內容的硬盤位置:

<diskStore path="D:\cache"/>

<defaultCache
        maxElementsInMemory="5"
        eternal="false"
        timeToIdleSeconds="120"
        timeToLiveSeconds="120"
        overflowToDisk="true"
        maxElementsOnDisk="10000000"
        diskPersistent="false"
        diskExpiryThreadIntervalSeconds="120"
        memoryStoreEvictionPolicy="LRU"
        />

性能檢測

二級緩存監測 ,先須要在配置文件中配置

<property name="hibernate.generate_statistics">true</property>


Statistics statistics = factory.getStatistics();

撞擊數:

statistics.getSecondLevelCacheHitCount()

丟失:

statistics.getSecondLevelCacheMissCount()


總結:軟件系統發展到今天已經很複雜了,特別是服務器端軟件,設計到的知識,內容,問題太多。在某些方面使用別人成熟的框架,就至關於讓別人幫你完成一些基礎工做,你只須要集中精力完成系統的業務邏輯設計。並且框架通常是成熟,穩健的,他能夠處理系統不少細節問題,好比,事物處理,安全性,數據流控制等問題。還有框架通常都通過不少人使用,因此結構很好,因此擴展性也很好,並且它是不斷升級的,你能夠直接享受別人升級代碼帶來的好處。框架通常處在低層應用平臺(如J2EE)和高層業務邏輯之間的中間層。


struts2案例:  員工信息管理系統:https://github.com/sdksdk0/PMSystem

整合案例:貼吧:https://github.com/sdksdk0/TieBa

相關文章
相關標籤/搜索