SSM框架開發web項目系列(二) MyBatis真正的力量

  前言

  上篇SSM框架環境搭建篇,演示了咱們進行web開發必不可少的一些配置和準備工做,若是這方面還有疑問的地方,能夠先參考上一篇「SSM框架開發web項目系列(一) 環境搭建篇」。本文主要介紹MyBatis的基礎內容,包括基本概念、開發步驟、使用實例等。提及MyBatis,工做中作過SSH/SSM相關Web開發的或者正在學習MyBatis的人或多或少都會接觸到相似「MyBatisHibernate有什麼區別?」,「MyBatisHibernate哪一個更好?」,「爲何Mybatis用的人愈來愈多?」等等...記得面試問題,區別問的最多,有次被面試官問到更喜歡用哪個?明明已經知道這個公司介紹用的是SSM了,我答了個Hibernate,並說先用的也是Hibernate,或許初戀的感受過於深入吧...誰好誰差這種主觀性問題,咱們不爭論,可是不容質疑的是二者都爲企業級開發作出巨大貢獻。同時,帶着問題和求知慾去學習每每會讓學習效率大大提升,由於許多問題在困惑你的同時,也爲你指引了方向。就正如你得會用它,理解它了,才知道它在某方面爲何會不足。html

  MyBatis介紹

  早些時候,Apache有一個開源項目iBatis,後來更名了叫Mybatis,因此咱們在網上有時候會看到一些早期的文章有時候看到iBatis,實際上是同一個東西。同時,你們能夠看下MyBatis源碼工程結構,以下圖,也能發現這個問題。java

 

  MyBatis是一個半自動-ORM-持久層框架,下面分別介紹這三個概念,若是瞭解的的能夠直接跳過以節省時間。mysql

  首先持久層比較好理解,就是針對數據庫的各類操做持久化層面,咱們用jdbc也能夠對數據庫中表進行增刪可查;WEB開發分層結構中,相似的還有業務層、控制層,MyBatis所作用的層,主要是用於與數據庫打交道。web

  其次ORMObject Relational Mapping,對象關係映射)是一種技術,也是思想,若是用過jdbc的原生方式操做數據的應該都知道,其中各類獲取和更新的操做都已有相關的API了,可是這個過程實在太繁瑣,獲取鏈接、構造語句、發送SQL和接收數據、最後是處理數據和關閉流等等...實際的工做開發中,顯然不太適用。也許是有人想到,最麻煩的地方在於獲取數據後的處理過程,爲了簡化這一過程,以Java中面向對象的思惟構造了這一個ORM關係模型,即每張數據表對應一個Java類,數據表中每一條記錄分別對應Java類的一個實體對象,數據表中每一個字段對應Java類中的一個屬性,這樣一來Java中一切皆對象,數據庫裏的東西既然已經對應映射到Java概念中來,咱們再用面向對象的思惟去操做數據庫,就大大簡化了開發流程。面試

  最後,解釋半自動,既然有半自動,應該就有全自動,例如Hibernate就是一個全自動的ORM持久層框架,它在創建數據庫和bean對象關係映射模型的同時,提供的api還會幫助咱們自動生成和發送SQL語句去操做數據庫,而MyBatis略有不一樣,它也創建了對象關係映射模型,可是並不會幫助咱們生成SQL語句,須要咱們本身寫SQL語句,很多人可能會以爲別人均可以幫你自動生成了這還要本身寫,不是沒事找事嗎?可是偏偏相反,不少人由於這點喜歡上了MyBatis,靈活且透明,本身動手不解釋。sql

  MyBatis重要對象

  關於MyBatis的學習使用過程當中,依次要注意的四個對象有SqlSessionFactoryBuilder、SqlSessionFactory、SqlSession、Mapper實例。數據庫

  1.SqlSessionFactoryBuilderapache

  SqlSessionFactoryBuilder是一個類,裏面定義許多重載的build方法,經過build方法能夠獲取SqlSessionFactory對象,即SqlSession工廠實例api

  2.SqlSessionFactorysession

  SqlSessionFactory是一個接口,看名字應該能明白是SqlSession工廠,裏面定義了許多重載的openSession方法,用於獲取SqlSession對象

  3.SqlSession

  SqlSession是一個很關鍵的接口,經過它咱們能夠執行發送SQL語句、得到Mapper實例等等。以它的第一個方法爲例, <T> T selectOne(String statement); 方法名很容易理解,獲取數據表的一條記錄(在Java中對應返回一個實體類對象),前面的泛型對應的就是實體類的類型,關於String類型的參數statement,用過原生的JDBC操做數據庫的應該不會陌生,在使用JDBC過程當中,有個Statement對象,經過該對象的相似 ResultSet executeQuery(String sql) throws SQLException; 等方法能夠發送SQL語句,方法裏的字符串類型參數 sql 就是咱們要發送的sql語句,而前面的String statement 一樣也是表明咱們的sql語句總的來講,selectOne中的statement表明sql語句,JDBC中的statement是能發送sql語句的對象實例,不可混淆。

  4.Mapper實例

  Mapper實例就是咱們在dao層定義的定義的接口實例,咱們在service層中注入dao對象時關聯的是該接口名,而實際上咱們拿到了該接口實例也就是Mapper實例。而咱們在web開發過程當中,持久層的相關方法都定義在Mapper接口中,因此四個對象裏咱們在前面環境搭建篇比較容易發現的也就是這個Mapper實例所屬接口,即PersonMappr接口。Mapper實例能夠經過SqlSession的getMapper方法得到。

  MyBatis配置文件

  

  以上爲MyBatis配置文件下節點的結構分佈圖,熟悉DTD的根據org/apache/ibatis/builder/xml下的約束文件mybatis-*-config.dtd也能夠獲取XML規範。

  environment(環境)

  在開發中,咱們要鏈接到數據庫,每每都須要配置一個數據源,其中包括數據庫url參數,用戶名和密碼等等,另外還有事事務管理器配置。MyBatis中也不例外,在這裏針對一個數據庫的鏈接,有一個environment(環境)與之對應,若是有多個數據庫,咱們能夠在environments下定義多個environment。environment下面經過dataSource和transactionManager的property屬性進行數據源和事務管理器配置。

  typeAliases(類型命名)

  這個是開發中很實用的配置,前面配置篇中mybatis-config.xml中的<typeAlias alias="person" type="com.mmm.pojo.Person" />,給類綁定別名,而後在其餘地方引用時能夠不用寫類的全名(相似com.xxx.Xxx形式),直接寫別名便可,例如後面personMapper.xml映射文件中<resultMap type="person" id="personResultMap" >,這裏的person別名就表明該類了,若是沒有前面的別名綁定,咱們在全部須要類型type指定com.mmm.pojo.Person的時候,都須要寫全名。另外MyBatis中自己已經綁定了許多相似的別名,在Configuration類的構造中已經預先註冊綁定了相關別名,這也是咱們在用Spring集成開發的配置文件中那些特殊別名能獲得解析的關鍵所在,以下所示

public Configuration() {
    typeAliasRegistry.registerAlias(
"JDBC", JdbcTransactionFactory.class); typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class);    typeAliasRegistry.registerAlias("JNDI", JndiDataSourceFactory.class); typeAliasRegistry.registerAlias("POOLED", PooledDataSourceFactory.class); typeAliasRegistry.registerAlias("UNPOOLED", UnpooledDataSourceFactory.class);     typeAliasRegistry.registerAlias("PERPETUAL", PerpetualCache.class); typeAliasRegistry.registerAlias("FIFO", FifoCache.class); typeAliasRegistry.registerAlias("LRU", LruCache.class); typeAliasRegistry.registerAlias("SOFT", SoftCache.class); typeAliasRegistry.registerAlias("WEAK", WeakCache.class);    typeAliasRegistry.registerAlias("DB_VENDOR", VendorDatabaseIdProvider.class); typeAliasRegistry.registerAlias("XML", XMLLanguageDriver.class); typeAliasRegistry.registerAlias("RAW", RawLanguageDriver.class); typeAliasRegistry.registerAlias("SLF4J", Slf4jImpl.class); typeAliasRegistry.registerAlias("COMMONS_LOGGING", JakartaCommonsLoggingImpl.class); typeAliasRegistry.registerAlias("LOG4J", Log4jImpl.class); typeAliasRegistry.registerAlias("LOG4J2", Log4j2Impl.class); typeAliasRegistry.registerAlias("JDK_LOGGING", Jdk14LoggingImpl.class); typeAliasRegistry.registerAlias("STDOUT_LOGGING", StdOutImpl.class); typeAliasRegistry.registerAlias("NO_LOGGING", NoLoggingImpl.class); typeAliasRegistry.registerAlias("CGLIB", CglibProxyFactory.class); typeAliasRegistry.registerAlias("JAVASSIST", JavassistProxyFactory.class); languageRegistry.setDefaultDriverClass(XMLLanguageDriver.class); languageRegistry.register(RawLanguageDriver.class); }

  mappers(映射器)

<mappers>
        <mapper resource="com/xxx/xxx/mapper/xxxMapper.xml" />
</mappers>

  以上即爲一個映射器配置樣式,經過該配置,Mybatis會找到相應的SQL映射文件(前面環境搭建篇中爲personMapper.xml),下面詳細介紹SQL映射文件。

  MyBatis真正的力量

  The true power of MyBatis is in the Mapped Statements(MyBatis真正的力量就在SQL映射語句裏)。這是MyBatis對SQL映射文件做介紹的第一句話,足以體現其重要性,前面說到的半自動的MyBatis須要本身寫SQL語句,這個寫SQL語句的地方就在這裏。

  根節點mapper有一個屬性namespace(命名空間),對應的是Mapper接口的全名,經過這個屬性值的設置,MyBatis才能找到該SQL映射文件對象Mapper接口,從而構造相應的Mapper實例對象。  

  以上爲MyBatis的SQL映射xml文件的元素結構,子節點中還有一個parameterMap,不過已經被廢棄了,就沒畫上去。前面四個,看單詞意思,應該不難理解,分別用於定義增刪改查SQL語句。下面以查詢<select>爲例

<!-- 根據主鍵id查找記錄 -->
<select id="selectById" resultType="person">
        select * from `TBL_PERSON` where id = #{id}
</select>    

  上面select節點中id爲該節點的惟一標識,與其它節點區分,另外一方面,id名對應咱們的Mapper接口中的方法名,在這裏對應PersonMapper的以下方法

//根據主鍵id查找Person對象
Person selectById(String id);

  因爲是查詢,會有返回數據內容,基於ORM思想,這裏的T_PERSON表返回記錄有一個實體類與之對應,那麼具體對應哪一個實體類怎麼指定?這裏的resultType即指定返回數據對應類型,而且用到了別名,因此這裏其實就是指定了com.mmm.pojo.Person類做爲對應實體類。另外還有一種resultMap定義方式,也能夠指定返回類型,二者不能同時使用,下面會具體講到。若是方法沒有返回值,也能夠不指定類型。

  節點中的語句即爲該方法對應的SQL語句,這裏的#{id}表示參數,對應PersonMapper接口中對應方法的參數String id。

   另外三種<delete><updata><insert>相似,不過要注意,<insert>做爲插入節點,有幾個特殊屬性,useGeneratedKeys、keyProperty、keyColumn,這三個屬性都是<insert>特有的,也僅對其有效,keyProperty屬性指定數據表主鍵值對應的實體類屬性,這裏爲Person類中的id;keyColumn屬性指定數據表主鍵字段名,這裏爲id;useGeneratedKeys指定是否使用數據表主鍵策略生成的主鍵值,例如在Mysql中主鍵能夠設置自增,而後咱們在插入記錄(或者說是寫SQL語句)時,即便不指定主鍵值,插入也會成功,而且主鍵會自動賦值。爲了以示區別,文中構建示例我會使用MySQL的自增主鍵,而不是以前的隨機字符串做爲主鍵。

  <sql>被用來定義可重用的SQL代碼段,能夠包含在其餘語句中。

  再來看<resultMap>,以前的Person實例中,數據表的字段名和實體類屬性名都是同樣的,id,name,gender。若是不同的話,咱們再採用以前的寫法就會有問題了,resultMap給咱們提供瞭解決辦法,下面咱們經過完整構建一個Mybatis環境來演示總體內容。

  MyBatis實踐

  這裏咱們單獨講Mybatis,並未使用Spring集成環境,也並未用到web層的Spring MVC,因此不須要構建web項目。因此首先經過maven新建一個java項目,pom.xml依賴能夠參考前面的SSM環境搭建,最後項目結構大體以下圖所示

  數據庫中準備一張員工表TBL_EMP,三個字段:主鍵id自增,姓名emp_name,性別emp_gender,插入若干數據,以下圖

  實體類(Emp.java)

package com.mmm.pojo;
//員工實體類
public class Emp {
    private Integer id;            //主鍵
    private String name;        //員工姓名
    private String gender;        //員工性別
    
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getGender() {
        return gender;
    }
    public void setGender(String gender) {
        this.gender = gender;
    }
}

  配置文件(mybatis-config.xml)

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!-- 這裏能夠定義類的別名,在mapper.xml文件中應用會方便不少 -->
    <typeAliases>
        <typeAlias alias="emp" type="com.mmm.pojo.Emp" />
    </typeAliases>
    <!-- 環境配置 -->
    <environments default="envir">
        <environment id="envir">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://127.0.0.1:3306/ssm?characterEncoding=utf-8"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="com/mmm/mapper/empMapper.xml"/>
    </mappers>
</configuration>

  Mapper接口(EmpMapper.java)

package com.mmm.mapper;

import java.util.List;

import com.mmm.pojo.Emp;

public interface EmpMapper {
    
    //新增一個Emp對象
    void insert(Emp p);
    
    //根據主鍵id刪除Emp對象
    void deleteById(Integer id);
    
    //修改一個Emp對象
    void update(Emp p);
    
    //根據主鍵id查找Emp對象
    Emp selectById(Integer id);
    
    //查找全部Emp對象,返回集合類型
    List<Emp> selectAll();
}

  SQL映射文件(EmpMapper.xml)

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!-- namespace命名空間綁定Mapper接口 -->
<mapper namespace="com.mmm.mapper.EmpMapper">
    
    <!-- resultMap定義,property對應實體類中屬性,column對應數據表字段名 -->
    <resultMap type="emp" id="empResultMap" >
        <id property="id" column="id"></id>
        <result property="name" column="emp_name"></result>
        <result property="gender" column="emp_gender"></result>
    </resultMap>
    
    <!-- 新增一條記錄,這裏並未在SQL語句中設置主鍵id值 -->
    <insert id="insert" parameterType="emp" useGeneratedKeys="true" keyProperty="id" keyColumn="id"  >
        insert into `TBL_EMP`(emp_name,emp_gender) values (#{name},#{gender})
    </insert>
    
    <!-- 刪除一條記錄 -->
    <delete id="deleteById">
        delete from `TBL_EMP` where id = #{id}
    </delete>
    
    <!-- 更新一條記錄 -->
    <update id="update" parameterType="EMP">
        update `TBL_EMP` set emp_name = #{name}, emp_gender = #{gender}
    </update>
    
    <!-- 查找全部記錄 -->
    <select id="selectAll" resultMap="empResultMap">
        select * from `TBL_EMP`
    </select>
    
    <!-- 根據主鍵id查找記錄 -->
    <select id="selectById" resultMap="empResultMap">
        select * from `TBL_EMP` where id = #{id}
    </select>
</mapper>

  測試(TestMyBatis.java)

package com.mmm.test;

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

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;

import com.mmm.mapper.EmpMapper;
import com.mmm.pojo.Emp;

public class TestMyBatis {
    
    
    
    @Test
    public void testCore() throws IOException {
        //直接實例SqlSessionFactoryBuilder對象
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        //MyBatis配置文件路徑
        String path = "mybatis-config.xml";
        //經過路徑獲取輸入流
        Reader reader = Resources.getResourceAsReader(path);
        //經過reader構建sessionFactory
        SqlSessionFactory sessionFactory = builder.build(reader);
        //獲取SqlSession對象
        SqlSession sqlSession = sessionFactory.openSession();
        //獲取Mapper實例
        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
        
        //獲取全部記錄並遍歷展現
        List<Emp> list = mapper.selectAll();
        for(Emp emp:list) {
            System.out.println("姓名:"+emp.getName()+",性別:"+emp.getGender());
        }
        
    }
}

  運行程序成功,結果以下

  小結

  本文主要介紹了單獨以MyBatis構建數據庫訪問程序的方法步驟,涉及的都是MyBatis基礎和核心的內容,數據庫也是針對的單表操做。MyBatis的關聯查詢、動態SQL、事務管理和Spring集成MyBatis等內容準備梳理一番了以後寫出來。

相關文章
相關標籤/搜索