1. 程式人生 > >舊調重彈Hibernate與Ibatis區別——深入架構設計

舊調重彈Hibernate與Ibatis區別——深入架構設計

ring ofo 庫類 服務 配置及使用 src ESS factor 應用

對於一個粗學者而言一言概況就是:ibatis非常簡單易學,hibernate相對較復雜,門檻較高。

但是,hibernate對數據庫結構提供了較為完整的封裝,hibernate的o/r mapping實現了pojo 和數據庫表之間的映射,以及sql 的自動生成和執行。程序員往往只需定義好了pojo 到數據庫表的映射關系,即可通過hibernate 提供的方法完成持久層操作。程序員甚至不需要對sql 的熟練掌握, hibernate/ojb 會根據制定的存儲邏輯,自動生成對應的sql 並調用jdbc 接口加以執行。 hibernate把數據庫和你隔離了,你不需要關註數據庫是mysql還是oracle,hibernate來幫你生成查詢的sql。但問題也來了,如果你就要用某種數據庫特有的功能,或者你就要讓查詢的sql完全符合你的心意,這就難了。

因為hibernate則基本上可以自動生成,偶爾會寫一些hql。同樣的需求,ibatis的工作量比hibernate要大很多。類似的,如果涉及到數據庫字段的修改,hibernate修改的地方很少,而ibatis要把那些sql mapping的地方一一修改。而且,從文檔的豐富性,產品的完善性,版本的開發速度都要強於ibatis。

眾所周知,web開發,性能瓶頸在數據庫。比如12306,我覺得瓶頸還是在數據庫。

系統數據處理量巨大,性能要求極為苛刻,這往往意味著我們必須通過經過高度優化的sql語句(或存儲過程)才能達到系統性能設計指標。在這種情況下ibatis會有更好的可控性和表現。 具體參考《Hibernate與Ibatis比較》——ibatis原理淺析

  1. iBATIS沒有對你的數據庫模型和對象模型的設計做任何假設。不論你的應用中這兩個模型之間是多麽不匹配,iBATIS都能適用。更進一步,iBATIS沒有對你的企業級應用的架構做出任何假設。不論你對數據庫是根據業務功能縱向劃分,還是按照技術橫向劃分,iBATIS都允許你高效地處理數據並將它們整合到你的面向對象的應用中去。

  2. iBATIS的某些特性使得它能夠非常高效地處理大型數據集。iBATIS支持的行處理器(row handler)使得它能夠批處理超大型記錄集,一次一條記錄。iBATIS也支持只獲取某個範圍內的結果,這就使得你可以只獲取那些你當前亟需的數據。例如,假設你獲取了10,000條記錄,而你其實只需要其中的第500至600條,那你就可以簡單的僅獲取這些記錄。iBATIS支持驅動提示使得執行這樣的操作非常高效。

  3. iBATIS允許你用多種方式建立從對象到數據庫的映射關系。一個企業級系統只以一種模式工作的情況是非常少見的。許多企業級系統需要在白天執行事務性的工作,而在晚上執行批處理工作。iBATIS允許你將同一個類以多種方式映射,以保證每一種工作都能以最高效的方式執行。iBATIS同樣支持多種數據獲取策略。例如,你可以選擇對某些數據進行懶加載,也可以將一個復雜的對象圖只用一條聯合查詢SQL語句就同時加載完畢,從而避免嚴重的性能問題。

對於我個人來說,我首選ibatis。比如之前寫jsp,我就堅決不屑於JSTL,你可以用intelliJ idea 智能提示快速開發。至於hql,shift……

二者配置都差不多!無非就是:

  • 編寫配置文檔 hibernate.cfg.xml或SqlMapConfig.xml:

  • 穿件對象—關系映射文件,

  • 編寫實體類(每一個實體類都是和數據庫中的一張表是一一對應的的,設計遵循:javabean規範)

  • 生成對應實體類的映射文件並添加到1中的配置文檔

這裏科普下IBatis的詳細配置及使用情況!節選自趙四的:iBatis開發的一個應用

下面是ibatis全局的文件:SqlMapConfig.xml:

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

<!DOCTYPE sqlMapConfig      
    PUBLIC "-//ibatis.apache.org//DTD SQL Map Config 2.0//EN"      
    "http://ibatis.apache.org/dtd/sql-map-config-2.dtd">

<sqlMapConfig>

  <!-- 配置數據庫連接 -->
  <transactionManager type="JDBC" commitRequired="false">
    <dataSource type="SIMPLE">
        <property name="JDBC.Driver" value="com.mysql.jdbc.Driver"/>
        <property name="JDBC.ConnectionURL" value="jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8"/>
        <property name="JDBC.Username" value="root"/>
        <property name="JDBC.Password" value="jiangwei"/>     
        <property name="Pool.MaximumActiveConnections" value="10" />
        <property name="Pool.MaximumIdleConnections" value="5" />
        <property name="Pool.MaximumCheckoutTime" value="120000" />
        <property name="Pool.TimeToWait" value="500" />
        <property name="Pool.PingQuery" value="select 1 from account" />
        <property name="Pool.PingEnabled" value="false" />
        <property name="Pool.PingConnectionsOlderThan" value="1" />
        <property name="Pool.PingConnectionsNotUsedFor" value="1" />
    </dataSource>
  </transactionManager>
  <!-- 配置SQL查詢的配置文件的Account.xml -->
  <sqlMap resource="/Account.xml"/>
</sqlMapConfig>

對於上面的數據源配置的參數說明:

  • transactionManager節點定義了iBatis的事務管理器,提供三種方式

    JDBC、jta:分布式數據庫、EXTERNAL:itbatis本身不做事務處理由外部進行處理

  • dataSource節點:從屬於transactionManager節點,用於設定ibatis運行期使用的DataSource屬性;

  • type屬性:type屬性指定了dataSource的實現模式,共三種模式,

    1、simple:ibatis提供的較小的連接池

    2、dbcp:是apache實現的連接池

    3、jndi:tomcate或weblogic提供的服務

  • JDBC.Driver:JDBC驅動;

  • JDBC.ConnectionURL:數據庫連接URL,如果用的是SQLServer JDBC Driver,需要在url後追加SelectMethod=Cursor以獲得JDBC事務的多Statement支持;

  • JDBC.Username:數據庫用戶名;

  • JDBC.Password:數據庫用戶密碼;

  • Pool.MaximumActiveConnections:數據庫連接池可維持的最大容量;

  • Pool.MaximumIdleConnections:數據庫連接池中允許的掛起(idle)連接數;

  • Pool.MaximumCheckoutTime數據庫連接池中,連接被某個任務所允許占用的最大時間,如果超過這個時間限定,連接將被強制收回,(毫秒);

  • Pool.TimeToWait:當線程試圖從連接池中獲取連接時,連接池中無可用連接可供使用,此時線程將進入等待狀態,直到池中出現空閑連接。此參數設定了線程所允許等待的最長時間,(毫秒);

  • Pool.PingQuery:數據庫連接狀態檢測語句。某些數據庫在某段時間持續處於空閑狀態時會將其斷開。而連接池管理器將通過此語句檢測池中連接是否可用,

  • 檢測語句應該是一個最簡化的無邏輯SQL。如“select 1 from user”,如果執行此語句成功,連接池管理器將認為此連接處於可用狀態;

  • Pool.PingEnabled:是否允許檢測連接狀態;

  • Pool.PingConnectionsOlderThan:對持續連接時間超過設定值(毫秒)的連接進行檢測;

  • Pool.PingConnectionsNotUsedFor:對空閑超過設定值(毫秒)的連接進行檢測;

再看看Hibernate配置文件

<!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 name="foo">
        <!-- 1. 配置數據庫信息 -->
        <!-- 方言(連接的數據庫類型) -->
        <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
        <property name="connection.url">jdbc:mysql:///hibernate_20160926</property>
        <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="connection.username">root</property>
        <property name="connection.password">yezi</property>
        <!-- 2. 其他配置 -->
        <!-- 顯示生成的SQL語句 -->
        <property name="hibernate.show_sql">true</property>
        <!-- 3. 導入映射文件 -->
        <mapping resource="cn/itcast/a_helloworld/User.hbm.xml" />
    </session-factory>
</hibernate-configuration>

技術分享圖片

這裏只是參考對比下而已,沒有必要較真!

第二步,配置映射文件:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE sqlMap      
    PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"      
    "http://ibatis.apache.org/dtd/sql-map-2.dtd">

<sqlMap namespace="Account">//命名空間

  <!-- 給Account實體類起一個別名 -->
  <typeAlias alias="Account" type="com.ibatis.demo.domain.Account"/>

  <!-- 將Account實體類中的屬性和mysql中的account表中的字段對應起來 -->
  <resultMap id="AccountResult" class="Account">
    <result property="id" column="_id"/>
    <result property="firstName" column="first_name"/>
    <result property="lastName" column="last_name"/>
    <result property="emailAddress" column="emall"/>
  </resultMap>

  <!-- 查詢account表中所有數據,其中id是這條查詢語句的id號,在代碼中用到,具有唯一性 -->
  <select id="selectAllAccounts" resultMap="AccountResult">
    select * from account
  </select>

  <!-- 通過id來查詢account表中的數據 -->
  <select id="selectAccountById" parameterClass="int" resultClass="Account">
    select
      id as _id,
      first_name as firstName,
      last_name as lastName,
      emall as emailAddress
    from account
    where _id = #id#
  </select>
   
  <!--插入語句-->
  <insert id="insertAccount" parameterClass="Account">
    insert into accout (
      _id,
      first_name,
      last_name,
      emall
    values (
      #id#, #firstName#, #lastName#, #emailAddress#
    )
  </insert>

  <!-- 更新語句 -->
  <update id="updateAccount" parameterClass="Account">
    update account set
      first_name = #firstName#,
      last_name = #lastName#,
      emall = #emailAddress#
    where
      _id = #id#
  </update>

  <!-- 刪除語句 -->
  <delete id="deleteAccountById" parameterClass="int">
    delete from account where _id = #id#
  </delete>

</sqlMap>

hibernate的:

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

<hibernate-mapping package="cn.itcast.a_helloworld">
    <class name="account" table="account">
        <id name="id" type="int" column="id">
            <generator class="native"/>
        </id>
        <property name="firstName" type="string" column="first_name" />
        <property name="lastName" type="string" column="last_name" />
        <property name="emailAddress" type="string" column="emall" />
    </class>
</hibernate-mapping>

創建實體類,其實就是javaBean,沒有什麽好說的。

再看看iBatis訪問數據的類:

package com.ibatis.demo.data;

import com.ibatis.sqlmap.client.SqlMapClient;
import com.ibatis.sqlmap.client.SqlMapClientBuilder;
import com.ibatis.common.resources.Resources;
import com.ibatis.demo.domain.Account;

import java.io.Reader;
import java.io.IOException;
import java.util.List;
import java.sql.SQLException;

public class IbaitsData {

  private static SqlMapClient sqlMapper;

  static {
    try {
      //讀取iBatis的配置文件:SqlMapConfig.xml
      Reader reader = Resources.getResourceAsReader("/SqlMapConfig.xml");
      sqlMapper = SqlMapClientBuilder.buildSqlMapClient(reader);
      reader.close(); 
    } catch (IOException e) {
      throw new RuntimeException("Something bad happened while building the SqlMapClient instance." + e, e);
    }
  }

  //查詢account表中的所有記錄
  @SuppressWarnings("unchecked")
  public static List selectAllAccounts () throws SQLException {
    return sqlMapper.queryForList("selectAllAccounts");
  }

  //查詢account表中_id為id的記錄
  public static Account selectAccountById  (int id) throws SQLException {
    return (Account) sqlMapper.queryForObject("selectAccountById", id);
  }

  //插入一條記錄
  public static void insertAccount (Account account) throws SQLException {
    sqlMapper.insert("insertAccount", account);
  }

  //更新一條記錄
  public static void updateAccount (Account account) throws SQLException {
    sqlMapper.update("updateAccount", account);
  }

  //刪除一條記錄
  public static void deleteAccount (int id) throws SQLException {
    sqlMapper.delete("deleteAccount", id);
  }

}

但是,到這裏就不想再對比了。個人覺得ibatis比hibernate簡單。畢竟寫slq就可以了。

下面是Ibatis項目結構圖!

技術分享圖片

參考文章:

Hibernate與Ibatis比較

【SSH進階之路】Hibernate基本原理(一)

【SSH進階之路】Hibernate搭建開發環境+簡單實例(二)

iBatis開發的一個應用

Hibernate框架基礎——Hibernate入門

文章內容如有侵權,請告知以悉刪除,謝謝!

舊調重彈Hibernate與Ibatis區別--深入架構設計 - java連接數據庫 - 周陸軍的個人網站

轉載註明來源。

舊調重彈Hibernate與Ibatis區別——深入架構設計