MyBatis==>簡介

1、概述html

  MyBatis 是一款優秀的持久層框架,它支持定製化 SQL、存儲過程以及高級映射。MyBatis 避免了幾乎全部的 JDBC 代碼和手動設置參數以及獲取結果集。MyBatis 可使用簡單的 XML 或註解來配置和映射原生信息,將接口和 Java 的 POJO(Plain Ordinary Java Object,普通的 Java對象)映射成數據庫中的記錄。 java

2、MyBatis的優缺點sql

優勢:數據庫

  • MyBatis是最簡單的持久化框架,小巧而且簡單易學;
  • MyBatis至關靈活,不會對應用程序或者數據庫的現有設計強加任何影響,SQL寫在XML裏,從程序代碼中完全分離,下降耦合度,便於統一管理和優化,並可重用;
  • 提供XML標籤,支持編寫動態SQL語句;
  • 提供映射標籤,支持對象與數據庫的ORM字段關係映射;
  • 與JDBC相比,減小了50%以上的代碼量。(對JDBC進行了封裝);

缺點:api

  • 編寫SQL語句時工做量很大,尤爲是字段多、關聯表多時,更是如此;
  • SQL語句依賴於數據庫,致使數據庫移植性差,不能更換數據庫;

3、MyBatis功能架構緩存

Mybatis的功能架構分爲三層:安全

  • API接口層:提供給外部使用的接口API,開發人員經過這些本地API來操縱數據庫。接口層一接收到調用請求就會調用數據處理層來完成具體的數據處理。
  • 數據處理層:負責具體的SQL查找、SQL解析、SQL執行和執行結果映射處理等。它主要的目的是根據調用的請求完成一次數據庫操做。
  • 基礎支撐層:負責最基礎的功能支撐,包括鏈接管理、事務管理、配置加載和緩存處理,這些都是共用的東西,將他們抽取出來做爲最基礎的組件。爲上層的數據處理層提供最基礎的支撐。

MyBatis層次架構圖:mybatis

4、MyBatis工做原理架構

先來看看下面這個圖app

工做原理解析:

  • 加載mybatis全局配置文件(數據源、mapper映射文件等),解析配置文件,MyBatis基於XML配置文件生成Configuration,和一個個MappedStatement(包括了參數映射配置、動態SQL語句、結果映射配置),其對應着<select | update | delete | insert>標籤項;
  • SqlSessionFactoryBuilder經過Configuration對象生成SqlSessionFactory,用來開啓SqlSession;
  • SqlSession對象完成和數據庫的交互;
    • 用戶程序調用mybatis接口層api(即Mapper接口中的方法);
    • SqlSession經過調用api的Statement ID找到對應的MappedStatement對象;
    • 經過Executor(負責動態SQL的生成和查詢緩存的維護)將MappedStatement對象進行解析,sql參數轉化、動態sql拼接,生成jdbc Statement對象;
    • JDBC執行 SQL;
    • 藉助 MappedStatement 中的結果映射關係,將返回結果轉化成 HashMap、JavaBean 等存儲結構並返回;

5、詳細流程

  • MyBatis 應用程序經過 SqlSessionFactoryBuilder 從 mybatis-config.xml 配置文件中構建出 SqlSessionFactory(SqlSessionFactory是線程安全的);
  • SqlSessionFactory的實例直接開啓一個SqlSession,再經過 SqlSession 實例得到 Mapper 對象並運行 Mapper 映射的 SQL 語句,完成對數據庫的 CRUD 和事務提交;
  • 關閉SqlSession;

下面這段代碼可以幫你們進一步理解這個流程

public class MyBatisTest { public static void main(String[] args) { // 指定全局配置文件
    String resource = "mybatis-config.xml"; InputStream inputStream = null; SqlSessionFactory sqlSessionFactory = null; SqlSession sqlSession = null; try { // 讀取配置文件
      inputStream = Resources.getResourceAsStream(resource); // 構建sqlSessionFactory
      sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); // 獲取sqlSession
      sqlSession = sqlSessionFactory.openSession(); /** * 執行SQL語句 * 第一個參數:接口全路徑 + 方法名,對應mapper映射文件中的namespace和標籤的id * 第二個參數:指定傳入sql的參數:這裏是用戶id */ String str = sqlSession.selectOne("com.jack.course.mybatis.dao.UserDao.findNameById",1); System.out.println(str); }catch (IOException ie) { ie.printStackTrace(); }finally { if (null != sqlSession) { sqlSession.close(); } } } }
MyBatisTest

6、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>
    <!-- 引入數據庫鏈接配置文件 -->
    <properties resource="db.properties"></properties>
    <!-- 環境,能夠配置多個,default:指定採用哪一個環境 -->
    <environments default="test">
        <!-- id:惟一標識 -->
        <environment id="test">
            <!-- 事務管理器,JDBC類型的事務管理器 -->
            <transactionManager type="JDBC"></transactionManager>
            <!-- 數據源,池類型的數據源 -->
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
        <environment id="dev">
            <!-- 事務管理器,JDBC類型的事務管理器 -->
            <transactionManager type="JDBC"></transactionManager>
            <!-- 數據源,池類型的數據源 -->
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${usname}"/>
                <property name="password" value="${passwd}"/>
            </dataSource>
        </environment>
    </environments>
    <!-- 映射的mapper文件,SQL語句寫在這類文件中 -->
    <mappers>
        <mapper resource="mapper/UserMapper.xml"/>
    </mappers>
</configuration>
mybatis-config.xml

properties標籤

  • 主要做用就是引入外部的properties是文件,通常是數據庫的鏈接配置;

environments標籤

  • 數據庫的鏈接配置在該標籤內,能夠配置多套;
  • 使用 default 來指明使用哪套環境,對應下面具體環境的 id;

mapper標籤

  • 指明 mapper 映射文件,具體的 SQL 語句在該文件中編寫;

7、Mapper.java 接口文件

public interface UserMapper { String findNameById(User user); String findNameByIdAndPasswd(User user); User findUserById(@Param("id") Integer id); int insertUser(@Param("id") Integer id, @Param("name") String name, @Param("passwd") String passwd); int insertAuto(@Param("name") String name, @Param("passwd") String passwd); int updateNameById(@Param("id") Integer id, @Param("name") String name); int deleteById(@Param("id") Integer id); List<User> findAllUsers(); List<User> findUsersByPasswd(@Param("password") String passwd,@Param("user_id") Integer id); }
UserMapper

該接口主要定義查詢數據庫的方法,對應下面 mapper.xml 文件中的 SQL語句的 id。參數能夠傳自定義類型和 Java自帶的類型,若是是自定義類型會自動匹配自定義類中的屬性,若是是 Java 自帶的類型,須要在參數前面加上 @Param 註解。

8、mapper.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">

<!-- mapper:根標籤,namespace:命名空間,隨便寫,通常保證命名空間惟一 -->
<mapper namespace="com.jack.course.mybatis.dao.UserMapper">
    <resultMap id="userMap" type="com.jack.course.mybatis.pojo.User">
        <result property="user_id" column="id"></result>
        <result property="name" column="name"></result>
        <result property="password" column="passwd"></result>
    </resultMap>

    <select id="findNameById" resultType="java.lang.String"> select name from user where id = #{id} </select>

    <select id="findNameByIdAndPasswd" resultType="java.lang.String"> select name from user where id = #{id} and passwd = #{passwd} </select>

    <select id="findUserById" resultType="com.jack.course.mybatis.pojo.User"> select * from user where id = #{id} </select>

    <insert id="insertUser"> insert into user(id,name,passwd) values (#{id},#{name},#{passwd}) </insert>

    <insert id="insertAuto" useGeneratedKeys="true" keyProperty="id"> insert into user(name,passwd) values (#{name},#{passwd}) </insert>

    <update id="updateNameById"> update user set name = #{name} where id = #{id} </update>

    <delete id="deleteById"> delete from user where id = #{id} </delete>

    <select id="findAllUsers" resultMap="userMap"> select * from user </select>

    <select id="findUsersByPasswd" resultMap="userMap"> select * from user where passwd = #{password} and id > #{user_id} </select>

</mapper>
UserMapper.xml

注意:

  • mapper 標籤中的 namespace 對應的是上面 UserMapper 接口的全路徑;
  • select 標籤中的 id 對應的是 UserMapper 接口中的方法,resultType 對應的是該方法的返回值類型,若是是自定義類型,則要寫全路徑;
  • 當咱們自定義類中的屬性和數據庫表字段不同時,咱們能夠用 resultMap 來映射其對應關係;
    • id 爲咱們爲這個 resultMap 自定義的名稱,type 爲咱們自定義類的全路徑;
    • resultMap 中的 result 標籤,property 爲自定義類中的屬性名,column 爲數據庫表中的字段名;
    • 使用時就能夠將 resultType 替換 爲 resultMap,其值就對應上面咱們爲 resultMap 自定義的 id;
    • 當咱們使用 resultMap 之後,SQL語句的參數就不能用數據庫的字段名,而是要用其對應的自定義類的屬性名;
    • 同時,UserMapper 接口中 @Param 註解後面帶的參數也要跟着變化;

最後來看下測試程序:

public class App { private UserMapper userMapper; private InputStream inputStream = null; private SqlSession sqlSession = null; @Before public void setUp() throws IOException { // 指定全局配置文件
    String resource = "mybatis-config.xml"; // 讀取配置文件
    inputStream = Resources.getResourceAsStream(resource); // 構建sqlSessionFactory
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); // 獲取sqlSession
    sqlSession = sqlSessionFactory.openSession(true); // 1. 映射文件的命名空間(namespace)必須是mapper接口的全路徑 // 2. 映射文件的statement的id必須和mapper接口的方法名保持一致 // 3. Statement的resultType必須和mapper接口方法的返回類型一致 // 4. statement的parameterType必須和mapper接口方法的參數類型一致
    userMapper = sqlSession.getMapper(UserMapper.class); } @Test public void findNameById() { User user = new User(); user.setId(1); String name = userMapper.findNameById(user); System.out.println("name = " + name); } @Test public void findNameByIdAndPasswd() { User user = new User(); user.setId(8); user.setPasswd("123459"); String name = userMapper.findNameByIdAndPasswd(user); System.out.println("name = " + name); } @Test public void findUserById() { User user = userMapper.findUserById(6); System.out.println(user); } @Test public void insertUser() { int i = userMapper.insertUser(3,"大叔","111222"); System.out.println("i = " + i); } @Test public void insertAuto() { int i = userMapper.insertAuto("大叔","111222"); System.out.println("i = " + i); } @Test public void updateNameById() { int i = userMapper.updateNameById(3,"牛牛"); System.out.println("i = " + i); } @Test public void deleteById() { int i = userMapper.deleteById(3); System.out.println("i = " + i); } @Test public void findAllUsers() { List<User> users = userMapper.findAllUsers(); for (User user : users) { System.out.println(user); } } @Test public void findUsersByPasswd() { List<User> users = userMapper.findUsersByPasswd("111222",13); for (User user : users) { System.out.println(user); } System.out.println("users = " + users); } @After public void tearDown(){ try { if (null != sqlSession) { sqlSession.close(); } if (null != inputStream) { inputStream.close(); } }catch (IOException ie) { ie.printStackTrace(); } } }
App 測試程序

9、動態SQL

動態SQL是MyBatis框架中特性之一,在一些組合查詢頁面須要根據用戶輸入的條件生成不一樣的查詢SQL語句,在JDBC中須要在代碼中拼接sql,容易出錯,MyBatis能夠解決這種問題。動態SQL經常使用的包括下面幾類:

  • if
  • choose (when, otherwise)
  • foreach
  • trim (if, where)

動態 SQL 仍是在 mapper.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">

<!-- mapper:根標籤,namespace:命名空間,隨便寫,通常保證命名空間惟一 -->
<mapper namespace="com.jack.course.mybatis.dao.UserMapper">
    <resultMap id="userMap" type="com.jack.course.mybatis.pojo.User">
        <result property="user_id" column="id"></result>
        <result property="name" column="name"></result>
        <result property="password" column="passwd"></result>
    </resultMap>

    <!-- 動態SQL -->
    <!-- 當 passwd傳入null時,則不執行 "and passwd = #{password}", 只執行"select * from user where name = #{name}" -->
    <select id="findAllUsersByNameAndPassword" resultMap="userMap"> select * from user where name = #{name} <if test="password != null"> and passwd = #{password} </if>

    </select>

    <!-- choose標籤是按順序判斷其內部when標籤中的test條件出否成立, 若是有一個成立,則 choose 結束。當 choose 中全部 when 的條件都不滿則時, 則執行 otherwise 中的sql -->
    <select id="findAllUsersByIdAndNameAndPassword" resultMap="userMap"> select * from user where id > #{id} <choose>
            <when test="name != null"> and name = #{name} </when>
            <when test="password != null"> and passwd = #{password} </when>
            <otherwise> order by id desc </otherwise>
        </choose>
    </select>

    <!-- 當where下面的兩個條件都不成立時,where關鍵字也會去掉 若是標籤返回的內容是以AND 或OR 開頭的,則它會剔除掉-->
    <select id="findAllUsersByIdAndName" resultMap="userMap"> select * from user <where>
            <if test="id != null"> id > #{id} </if>
            <if test="name != null"> and name = #{name} </if>
        </where>
    </select>

    <!-- 當id取值是一個list時使用 -->
    <select id="findAllUsersByIds" resultMap="userMap"> select * from user where id in <foreach collection="list" item="item" index="index" open="(" separator="," close=")"> #{item} </foreach>
    </select>

    <!-- 使用set標籤,最後一個條件「password != null」不知足的話也不會報錯 -->
    <update id="updateNameAndPasswordById"> update user <set>
                <if test="name != null"> name = #{name}, </if>
                <if test="password != null"> passwd = #{password}, </if>
            </set> where id = #{id} </update>


    <!-- prefix:給sql語句拼接的前綴 -->
    <!-- prefixOverrides:去除sql語句前面的關鍵字或者字符,該關鍵字或者字符由prefixOverrides屬性指定 -->
    <!-- suffix:給sql語句拼接的後綴 -->
    <!-- suffixOverrides:去除sql語句後面的關鍵字或者字符,該關鍵字或者字符由suffixOverrides屬性指定 -->
    <select id="findUsersByIdAndNameAndPasswd" resultMap="userMap"> select * from user <trim prefix="where" prefixOverrides="or | and">
            <if test="user_id != null"> id > #{user_id} </if>
            <if test="name != null"> and name = #{name} </if>
            <if test="password != null"> and passwd = #{password} </if>
        </trim>
    </select>

    <insert id="insertUserTrim"> insert into user <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="name != null"> name, </if>
            <if test="password != null"> passwd </if>
        </trim>
        <trim prefix="values(" suffix=")" suffixOverrides=",">
            <if test="name != null"> #{name}, </if>
            <if test="password != null"> #{password} </if>
        </trim>
    </insert>

</mapper>
UserMapper.xml
public class App2 { private UserMapper userMapper; private InputStream inputStream = null; private SqlSession sqlSession = null; @Before public void setUp() throws IOException { // 指定全局配置文件
    String resource = "mybatis-config.xml"; // 讀取配置文件
    inputStream = Resources.getResourceAsStream(resource); // 構建sqlSessionFactory
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); // 獲取sqlSession,參數true表明自動提交
    sqlSession = sqlSessionFactory.openSession(true); // 1. 映射文件的命名空間(namespace)必須是mapper接口的全路徑 // 2. 映射文件的statement的id必須和mapper接口的方法名保持一致 // 3. Statement的resultType必須和mapper接口方法的返回類型一致 // 4. statement的parameterType必須和mapper接口方法的參數類型一致
    userMapper = sqlSession.getMapper(UserMapper.class); } /** * name傳入爲null * UserMapper文件中使用if條件判斷 */ @Test public void findAllUsersByNameAndPassword() { String passwd = null; // String passwd = "123456";
    List<User> users = userMapper.findAllUsersByNameAndPassword("大叔",passwd); for (User user : users) { System.out.println(user); } } @Test public void findAllUsersByIdAndNameAndPassword() { // String name = "jack"; // String passwd = null;
 String name = null; String passwd = "123455"; List<User> users = userMapper.findAllUsersByIdAndNameAndPassword(3, name,passwd); for (User user : users) { System.out.println(user); } } @Test public void findAllUsersByIdAndName() { // Integer id = null; // String name = null;
 Integer id = null; String name = "jack"; List<User> users = userMapper.findAllUsersByIdAndName(id,name); for (User user : users) { System.out.println(user); } } @Test public void findAllUsersByIds() { ArrayList<Integer> list = new ArrayList<>(); list.add(10); list.add(11); list.add(12); List<User> users = userMapper.findAllUsersByIds(list); for (User user : users) { System.out.println(user); } } @Test public void updateNameAndPasswordById() { Integer id = 1; String name = null; String passwd = "111222"; int i = userMapper.updateNameAndPasswordById(id, name, passwd); System.out.println("i = " + i); } @Test public void findUsersByIdAndNameAndPasswd() { Integer id = 1; String name = "jack"; String passwd = null; List<User> users = userMapper.findUsersByIdAndNameAndPasswd(id, name, passwd); for (User user : users) { System.out.println(user); } } @Test public void insertUserTrim() { String name = "牛牛"; String passwd = null; int i = userMapper.insertUserTrim(name, passwd); System.out.println("i = " + i); } @After public void tearDown(){ try { if (null != sqlSession) { sqlSession.close(); } if (null != inputStream) { inputStream.close(); } }catch (IOException ie) { ie.printStackTrace(); } } }
App 測試程序

但在實際項目中,不建議使用動態SQL,緣由是:判斷一個字段是否爲空,是否傳值,最好在代碼中進行判斷,這樣能使代碼更具有可讀性。

10、MyBatis使用步驟總結

一、build.gradle:文件中導入依賴包,包括 MyBatis 和 MySql;

二、mybatis-config.xml:配置數據源,mapper映射文件等信息,通常放在src/main/resource目錄下;

三、POJO類:創建與數據庫字段對應的POJO類;

四、編寫 Mapper 接口,使用接口中的方法操做數據庫;

五、mapper.xml:映射文件,編寫SQL語句,mapper標籤中的 namespace 對應實體類的全路徑

六、執行類:讀取配置文件、構建sqlSessionFactory、獲取sqlSession,經過sqlSession操做數據庫。

另外,使用純註解來使用 MyBatis 比較簡單,使用方法在如下這篇文章中已經介紹過,歡迎你們查看

SpringBoot==>簡介

相關文章
相關標籤/搜索