Ibatis

  數據訪問層框架,ORM,Object Relation Mapping,將對象映射到關係,通過操作對象來達到操作關係的目的。
  通過hibernate訪問數據層不需要自己編寫sql,簡單智能,調用方法就可完成。ibatis需要自己編寫sql語句,更加靈活,可對sql進行優化。ibatis的最後版本爲2.3.4,從3.x開始,轉投到Google Code門下,並改名爲MyBatis。

===========================================

  ibatis的核心類是SqlMapClient,通過其可完成對數據庫的訪問操作。
  spring提供的SqlMapClientFactoryBean對SqlMapClient進行了封裝,類內提供對SqlMapClient實例進行初始化的方法,並提供返回SqlMapClient實例的方法getObject。SqlMapClientFactoryBean實現FactoryBean接口,spring規定實現該接口的Bean,由框架實例化時,返回的是getObject返回的實例,這也體現了SqlMapClientFactoryBean是SqlMapClient的實例工廠的意義——配置SqlMapClientFactoryBean,要注入configLocation屬性,對應ibatis的配置文件;datasource屬性,對應數據源bean。
  spring提供的SqlMapClientTemplate對SqlMapClient進行了封裝,類內實際是對SqlMapClient的增刪改查方法做了一個外包層,類內SqlMapClient實例的初始化需要外部的注入,本身不提供初始化方法。SqlMapClientTemplate繼承JdbcAccessor,JdbcAccessor內部封裝了DataSource數據源Bean——配置SqlMapClientTemplate,要注入sqlMapClient屬性,對應注入SqlMapClientFactoryBean的實例,因爲其返回的就是SqlMapClient的實例;datasource屬性,對應數據源bean。
  spring提供的SqlMapClientDaoSupport對SqlMapClientTemplate進行了封裝,是一個抽象類,必須繼承才能使用,類內以new的方式生成一個SqlMapClientTemplate的實例。
  
  DataSource可在SqlMapClientFactoryBean內注入,也可在SqlMapClientTemplate內注入,放在SqlMapClientTemplate內更合適。
  實際項目中肯能會有多個數據源,如mysql、sqlserver、oracle等。
  SqlMapClientFactoryBean旨在生成SqlMapClient的實例,與屬性configLocation有關,需要指明映射關係,而SqlMapClient實例的生成與屬性datasource無關,僅在連接數據庫時會用到。
  SqlMapClientTemplate內部使用SqlMapClient的實例進行數據庫操作,需要連接數據庫,必須注入屬性datasource。
  針對不同的數據源,需要對每個數據源配置一個SqlMapClientFactoryBean用於注入對應數據源的映射文件,需要對每個數據源配置一個SqlMapClientTemplate用於注入數據源bean來連接不同的數據庫。

  dao的三種實現方式,根據設計模式能用對象組合不用繼承的原則,不建議使用後兩種方式。
  對象組合方式,dao內部定義SqlMapClientTemplate的實例,SqlMapClientTemplate的實例由spring註冊並注入,SqlMapClientTemplate要注入SqlMapClientFactoryBean與DataSource。
  繼承方式,dao繼承SqlMapClientTemplate,dao的配置也就包括了SqlMapClientTemplate的配置,dao內部可以直接使用繼承的方法操作數據庫,dao配置要注入SqlMapClientFactoryBean與DataSource——類內屬性不加註解,配置文件內也不給類注入,配置文件頭部<beans default-autowire="byName"> 給出default-autowire,spring也能完成注入。
  繼承方式,dao繼承SqlMapClientDaoSupport,同樣dao的配置也包括了SqlMapClientTemplate的配置,dao內部可以直接使用繼承的SqlMapClientTemplate實例操作數據庫,dao配置要注入SqlMapClientFactoryBean與DataSource——類內只給出set方法,不給出屬性定義,spring也能完成注入。

===========================================

  ibatis中一個pojo對應一個dao,一個dao對應一個映射文件,由此項目中通常會有多個映射文件。由於ibatis最終會將所有的映射文件合併到一起,爲防止id衝突,需要命名空間namespace來唯一標識該映射文件。
  以下兩個配置文件在dao層,屬於ibatis的內容。

// Computer.xml
// namespace,通常用pojo名
<sqlMap namespace="Computer">
    // alias,類型別名,通常爲首字母小寫的pojo名
    <typeAlias alias="computer" type="xx.Computer" />

    // 對應一類查詢結果集
    // class,指明查詢結果要映射的pojo類
    <resultMap id="all" class="computer">
        // 指明pojo類的屬性與關係表中字段的對應關係
        // jdbcType與javaType的對應關係用時去網上查一下,不要背
        <result property="id" column="id" jdbcType="INT" javaType="java.lang.Integer" />
        <result property="name" column="name" jdbcType="VARCHAR" javaType="java.lang.String" />
        <result property="price" column="price" jdbcType="VARCHAR" javaType="java.lang.String"/>
    </resultMap>

    <resultMap id="part" class="computer">
        <result property="name" column="name" jdbcType="VARCHAR" javaType="java.lang.String" />
        <result property="price" column="price" jdbcType="VARCHAR" javaType="java.lang.String"/>
    </resultMap>

    // id,指出該sql語句的名字,代碼中會用到,用時必須加命名空間
    // parameterClass,指出參數類型
    <insert id="insert" parameterClass="computer">
        // CDATA中的內容被定義爲純文本,以防與xml標籤混淆
        // 在#之間的爲變量
        <![CDATA[
            insert into computer(name, price) values(#name#, #price#)
        ]]>
        // selectKey,用於在插入時自動生成主鍵
        // keyProperty,定義主鍵名字
        // resultClass,定義返回類型
        <selectKey resultClass="java.lang.Long" keyProperty="id">
            // 返回上次插入自動生成的id
            select @@IDENTITY as id
        </selectKey>
    </insert>

    // 項目中不要用基本類型,要用類包裝
    // 也有將刪除操作放在update標籤內的,沒多大區別
    <delete id="delete" parameterClass="java.lang.Long">
        delete from computer where id = #id#
    </delete>

    <update id="update" parameterClass="computer">
        update computer set name = #name#, price = #price# where id = #id#

        // 或
        // dynamic的prepend值會覆蓋條件標籤中第一個條件爲真的prepend的值
        // 前提是條件標籤prepend的值被設置且長度 > 0
        update computer
        <dynamic prepend="set">
            <isNotEmpty property="name" prepend=','>
                name = #name#
            </isNotEmpty>
            <isNotEmpty property="price" prepend=','>
                price  = #price #
            </isNotEmpty>
        </dynamic>
        where id = #id#
    </update>

    // select查詢出的字段必須和resultMap配置的字段對應,多了、少了或不對應都會拋出異常
    // ibatis內部會將查詢結果依次賦值到resultMap配置的pojo實例內對應的屬性上
    // resultMap,爲前面定義的resultMap的id
    <select id="list" resultMap="all">
        select id, name, price from computer
    </select>

    // 或
    // resultMap是顯示映射,pojo屬性與關係字段映射明確,性能更好,推薦使用
    // resultClass,指出查詢結果要映射的類,爲隱式映射,若pojo的屬性名與關係的字段名不同,查詢結果就不會映射到類
    <select id="list" resultClass="computer">
        select id, name, price from computer
    </select>

    // 查詢結果僅一個字段
    <select id="getName" parameterClass="java.lang.Long" resultClass="java.lang.String">
        select name from computer where id = #id#
    </select>

    // sql標籤用來定義sql語句片段
    // id,爲sql片段標識,後面可根據此id拼接sql語句
    <sql id="list_where">
        // isNotNull,指當property設置的變量name不爲空時,執行標籤裏內容
        // prepend,表示將其內容and追加在isNotNull標籤的內容之前
        <isNotNull property="name" prepend="and">
            name = #name#
        </isNotNull>
        <isNotNull property="price" prepend="and">
            price = #price#
        </isNotNull>

        // 上述打印內容爲 and name = xx and price = xx
        // 通過設置dynamic標籤的prepend來覆蓋第一個條件爲真的and
        // 打印內容爲where name = xx and price = xx
        <dynamic prepend="where">
            <isNotNull property="name" prepend="and">
                name = #name#
            </isNotNull>
            <isNotNull property="price" prepend="and">
                price = #price#
            </isNotNull>
        </dynamic>
    </sql>

    // parameterClass,參數爲map類型
    <select id="list_2" parameterClass="map" resultMap="part">
        // where 1 = 1,用於巧妙的連接name之前的and,若用dynamic可以不用此
        // include,用於包含sql片段
        // start,屬性值來自map類型的參數
        // limit start, rows 返回查詢結果的第start行,偏移從0開始,共返回rows行
        // limit start, -1 返回查詢結果的第start,及其之後的所有行
        // limit end 等價於 limit 0, end 返回查詢結果第end行,及其之前的所有行
        // #與$的區別,#之間放變量,$用於字符串之間的拼接,$間不要放字符或字符串變量,否則出錯
        select name, price from computer
        where 1 = 1
        <include refid="list_where" />
        order by id asc
        <isNotNull property="start" prepend=" ">
            limit $start$, $rows$
        </isNotNull>
    </select>
</sqlMap>

// sqlmap-config-mysql.xml
// 用於配置數據源信息,以及整合全部的映射文件
// 若有其它異構數據庫,應單獨建立另一個文件,如sqlmap-config-sqlserver.xml
<sqlMapConfig>
    // useStatementNamespaces,設爲true表示開啓映射文件的命名空間
    <settings useStatementNamespaces="true"/>

    // 配置數據源,與spring整合後,該部分移植到spring配置文件
    ....

    // 以當前目錄爲相對路徑,加載映射文件
    <sqlMap resource="xx/mysql/xx.xml" />
</sqlMapConfig>

===========================================

  以下配置文件在web層,屬於spring與ibatis的整合內容。

// spring-config-datasource-dbcp.xml
// 所有的數據源在此配置
<beans>
    // 將數據源註冊爲bean
    <bean id="mysqlDataSource" class="..BasicDataSource">
        // 屬性的名字都是在BasicDataSource裏定義好的,不要自定義
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <property name="url" value="jdbc:mysql://localhost:3306/xxdb" />
        <property name="username" value="root" />
        <property name="password" value="123" />
    </bean>

    // 其它的數據源,如sqlserver、oracle、分庫的
</beans>

// spring-dao.xml
// 註冊項目所有的dao
<beans>
    // 註冊SqlMapClientFactoryBean
    <bean id="sqlMapClient" class="..SqlMapClientFactoryBean">
        // SqlMapClientFactoryBean源碼內定義了屬性dataSource和configLocation
        // dataSource放在SqlMapClientTemplate內注入
        // configLocation在此注入,看爲與ibatis整合的入口
        <property name="configLocation" value="classpath:sqlmap-config-mysql.xml" />
    </bean>

    // 針對不同的數據源,要再次配置新的SqlMapClientFactoryBean
    ....

    // 配置SqlMapClientTemplate
    <bean id="mysqlSqlMapClientTemplate" class="..SqlMapClientTemplate">
        <property name="dataSource" ref="mysqlDataSource">
        // SqlMapClientTemplate源碼內定義了ibatis的SqlMapClient類型的屬性sqlMapClient
        <property name="sqlMapClient" ref="sqlMapClient">
    </property>

    // 針對不同的數據源,要再次配置新的SqlMapClientTemplate
    ....

    // 放到項目用註解完成
    <bean id="xxDaoImpl" class="xx.xxDaoImpl">  
        <property name="myClientTemplate" ref="mysqlSqlMapClientTemplate" />
    </bean>
</beans>

// spring-config.xml
// 將上述xml文件整合到一起

@Repository("computerDao ")
public class ComputerDaoImpl implements ComputerDao {
    @Resource(name = "mysqlSqlMapClientTemplate")
    private SqlMapClientTemplate mysqlTool;
    ..

    public Integer insertComputer(Computer computer) {
        // 加命名空間
        return (Integer)mysqlTool.insert("Computer.insert", computer);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章