「Mybatis系列」Mybatis開發方式和配置

雙哥發表於2020-02-20

本系列文章Github 後端進階指南 已收錄,此專案正在完善中,歡迎star。

1. Mybatis的開發方式

此處使用的是JDK的動態代理方式,延遲載入使用的cglib動態代理方式

1.1 代理理解

代理分為靜態代理和動態代理。此處先不說靜態代理,因為Mybatis中使用的代理方式是動態代理。

動態代理分為兩種方式:

  • 基於JDK的動態代理--針對有介面的類進行動態代理
  • 基於CGLIB的動態代理--通過子類繼承父類的方式去進行代理。

1.2 XML方式

  • 開發方式

    只需要開發Mapper介面(dao介面)和Mapper對映檔案,不需要編寫實現類。

  • 開發規範

    Mapper介面開發方式需要遵循以下規範:

    1、 Mapper介面的類路徑與Mapper.xml檔案中的namespace相同。

    2、 Mapper介面方法名稱和Mapper.xml中定義的每個statement的id相同。

    3、 Mapper介面方法的輸入引數型別和mapper.xml中定義的每個sql 的parameterType的型別相同。

    4、 Mapper介面方法的返回值型別和mapper.xml中定義的每個sql的resultType的型別相同。

  • mapper對映檔案

<?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="com.kkb.mybatis.mapper.UserMapper">
<!-- 根據id獲取使用者資訊 -->
    <select id="findUserById" parameterType="int" resultType="com.kkb.mybatis.po.User">
        select * from user where id = #{id}
    </select>
</mapper>
複製程式碼
  • mapper介面
/**
 * 使用者管理mapper
 */

public interface UserMapper {
    //根據使用者id查詢使用者資訊
    public User findUserById(int id) throws Exception;
}
複製程式碼
  • 全域性配置檔案中載入對映檔案
<!-- 載入對映檔案 -->
  <mappers>
    <mapper resource="mapper/UserMapper.xml"/>
  </mappers>
複製程式碼
  • 測試程式碼
public class UserMapperTest{

    private SqlSessionFactory sqlSessionFactory;

@Before
    public void setUp() throws Exception {
        //mybatis配置檔案
        String resource = "SqlMapConfig.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        //使用SqlSessionFactoryBuilder建立sessionFactory
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    }
    @Test
    public void testFindUserById() throws Exception {
        //獲取session
        SqlSession session = sqlSessionFactory.openSession();
        //獲取mapper介面的代理物件
        UserMapper userMapper = session.getMapper(UserMapper.class);
        //呼叫代理物件方法
        User user = userMapper.findUserById(1);
        System.out.println(user);
        //關閉session
        session.close();

    }
}
複製程式碼

1.3 註解方式

  • 開發方式

    只需要編寫mapper介面檔案介面。

  • mapper介面

public interface AnnotationUserMapper {
    // 查詢
    @Select("SELECT * FROM user WHERE id = #{id}")
    public User findUserById(int id);

    // 模糊查詢使用者列表
    @Select("SELECT * FROM user WHERE username LIKE '%${value}%'")
    public List<User> findUserList(String username);

    // 新增並實現主鍵返回
    @Insert("INSERT INTO user (username,birthday,sex,address) VALUES (#{username},#{birthday},#{sex},#{address})")
    @SelectKey(statement = "SELECT LAST_INSERT_ID()", keyProperty = "id", resultType = int.class, before = false)
    public void insertUser(User user);

}
複製程式碼
  • 測試程式碼
public class AnnotationUserMapperTest {

    private SqlSessionFactory sqlSessionFactory;

    /**
     * @Before註解的方法會在@Test註解的方法之前執行
     * 
     * @throws Exception
     */

    @Before
    public void init() throws Exception {
        // 指定全域性配置檔案路徑
        String resource = "SqlMapConfig.xml";
        // 載入資原始檔(全域性配置檔案和對映檔案)
        InputStream inputStream = Resources.getResourceAsStream(resource);
        // 還有構建者模式,去建立SqlSessionFactory物件
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    }

    @Test
    public void testFindUserById() {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        AnnotationUserMapper userMapper = sqlSession.getMapper(AnnotationUserMapper.class);

        User user = userMapper.findUserById(1);
        System.out.println(user);
    }

    @Test
    public void testFindUserList() {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        AnnotationUserMapper userMapper = sqlSession.getMapper(AnnotationUserMapper.class);

        List<User> list = userMapper.findUserList("老郭");
        System.out.println(list);
    }

    @Test
    public void testInsertUser() {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        AnnotationUserMapper userMapper = sqlSession.getMapper(AnnotationUserMapper.class);

        User user = new User();
        user.setUsername("開課吧-2");
        user.setSex("1");
        user.setAddress("致真大廈");
        userMapper.insertUser(user);
        System.out.println(user.getId());
    }

}
複製程式碼

2. 全域性配置檔案

2.1 配置內容

SqlMapConfig.xml中配置的內容和順序如下:

properties(屬性)

settings(全域性配置引數)

typeAliases(型別別名)

typeHandlers(型別處理器)--Java型別--JDBC型別--->資料庫型別轉換

objectFactory(物件工廠)

plugins(外掛)--可以在Mybatis執行SQL語句的流程中,橫叉一腳去實現一些功能增強,比如PageHelper分頁外掛,就是第三方實現的一個外掛

environments(環境集合屬性物件)

environment(環境子屬性物件)
       transactionManager(事務管理)
       dataSource(資料來源)
mappers(對映器)
複製程式碼

2.2 properties標籤

SqlMapConfig.xml可以引用java屬性檔案中的配置資訊。

1、在classpath下定義db.properties檔案,

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssm?characterEncoding=utf-8
jdbc.username=root
jdbc.password=root
複製程式碼

2、在SqlMapConfig.xml檔案中,引用db.properties中的屬性,具體如下:

   <properties resource="db.properties"/>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>
複製程式碼

properties標籤除了可以使用resource屬性,引用properties檔案中的屬性。還可以在properties標籤內定義property子標籤來定義屬性和屬性值,具體如下:

<properties>
    <property name="driver" value="com.mysql.jdbc.Driver"/>
</properties>
複製程式碼

注意: MyBatis 將按照下面的順序來載入屬性

  • 讀取properties 元素體內定義的屬性。
  • 讀取properties 元素中resource或 url 載入的屬性,它會覆蓋已讀取的同名屬性。

2.3 typeAlias標籤

別名的作用:就是為了簡化對映檔案中parameterType和ResultType中的POJO型別名稱編寫。

2.3.1 預設支援別名

別名 對映的型別
_byte byte
_long long
_short short
_int int
_integer int
_double double
_float float
_boolean boolean
string String
byte Byte
long Long
short Short
int Integer
integer Integer
double Double
float Float
boolean Boolean
date Date
decimal BigDecimal
bigdecimal BigDecimal
map Map

2.3.2 自定義別名

在SqlMapConfig.xml中進行如下配置:

<typeAliases>
    <!-- 單個別名定義 -->
    <typeAlias alias="user" type="com.kkb.mybatis.po.User"/>
    <!-- 批量別名定義,掃描整個包下的類,別名為類名(首字母大寫或小寫都可以) -->
    <package name="com.kkb.mybatis.po"/>
</typeAliases>
複製程式碼

2.4 mappers標籤

<mapper resource=""/>

使用相對於類路徑的資源

如:

<mapper resource="sqlmap/User.xml" />
複製程式碼

<mapper url="">

使用絕對路徑載入資源

如:

<mapper url="file://d:/sqlmap/User.xml" />
複製程式碼

<mapper class=""/>

使用mapper介面類路徑,載入對映檔案。

如:

<mapper class="com.kkb.mybatis.mapper.UserMapper"/>
複製程式碼

注意:此種方法要求mapper介面名稱和mapper對映檔名稱相同,且放在同一個目錄中。

<package name=""/>

註冊指定包下的所有mapper介面,來載入對映檔案。

如:

<package name="com.kkb.mybatis.mapper"/>
複製程式碼

注意:此種方法要求mapper介面名稱和mapper對映檔名稱相同,且放在同一個目錄中。

3. 輸入對映和輸出對映

3.1 parameterType(輸入型別)

parameterType屬性可以對映的輸入引數Java型別有:簡單型別、POJO型別、Map型別、List型別(陣列)

  • Map型別和POJO型別的用法類似,這裡只講POJO型別的相關配置。

  • List型別在動態SQL部分進行講解。

傳遞簡單型別

參考《Mybatis基礎》(在我的主頁內查詢)中使用者查詢的案例。

傳遞pojo物件

參考《Mybatis基礎》(在我的主頁內查詢)中的新增使用者的案例。

傳遞pojo包裝物件

包裝物件:pojo類中巢狀pojo。

需求

通過包裝POJO傳遞引數,完成使用者查詢。

QueryVO

定義包裝物件QueryVO

public class QueryVO {
     private User user;
}
複製程式碼
SQL語句
SELECT * FROM user where username like '%小明%'
複製程式碼
Mapper檔案
    <!-- 使用包裝型別查詢使用者 
        使用ognl從物件中取屬性值,如果是包裝物件可以使用.操作符來取內容部的屬性
    -->

    <select id="findUserList" parameterType="queryVo" resultType="user">
        SELECT * FROM user where username like '%${user.username}%'
    </select>
複製程式碼
Mapper介面
/**
 * 使用者管理mapper
 */

public interface UserMapper {
     //綜合查詢使用者列表
    public List<User> findUserList(QueryVo queryVo)throws Exception
}
複製程式碼
測試方法

在UserMapperTest測試類中,新增以下測試程式碼:

@Test
    public void testFindUserList() throws Exception {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //獲得mapper的代理物件
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        //建立QueryVo物件
        QueryVo queryVo = new QueryVo();
        //建立user物件
        User user = new User();
        user.setUsername("小明");

        queryVo.setUser(user);
        //根據queryvo查詢使用者
        List<User> list = userMapper.findUserList(queryVo);
        System.out.println(list);
        sqlSession.close();
    }
複製程式碼

3.2 resultType(輸出型別)

resultType屬性可以對映的java型別有:簡單型別、POJO型別、Map型別

不過Map型別和POJO型別的使用情況類似,所以只需講解POJO型別即可。

3.2.1 使用要求

使用resultType進行輸出對映時,要求sql語句中查詢的列名和要對映的pojo的屬性名一致。

3.2.2 對映簡單型別

案例需求

查詢使用者記錄總數。

Mapper對映檔案
<!-- 獲取使用者列表總數 -->
    <select id="findUserCount" resultType="int">
       select count(1) from user
    </select>
複製程式碼
Mapper介面
    //查詢使用者總數
    public int  findUserCount() throws Exception
複製程式碼
測試程式碼

在UserMapperTest測試類中,新增以下測試程式碼:

     @Test
    public void testFindUserCount() throws Exception {
        SqlSession sqlSession = sessionFactory.openSession();
        //獲得mapper的代理物件
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

         int count = userMapper.findUserCount(queryVo);
         System.out.println(count);

        sqlSession.close();
    }
複製程式碼

注意:輸出簡單型別必須查詢出來的結果集只有一列。

3.2.3 對映pojo物件

注意:不管是單個POJO還是POJO集合,在使用resultType完成對映時,用法一樣。

參考《Mybatis基礎》(在我的主頁內查詢)中根據使用者ID查詢使用者資訊和根據名稱模糊查詢使用者列表的案例

4. resultMap

4.1 使用要求

如果sql查詢列名和pojo的屬性名可以不一致,通過resultMap將列名和屬性名作一個對應關係,最終將查詢結果對映到指定的pojo物件中。

注意:resultType底層也是通過resultMap完成對映的。

4.2 需求

將以下sql的查詢結果進行對映:

SELECT id id_,username username_,birthday birthday_ FROM user
複製程式碼

4.3 Mapper介面

// resultMap入門
public List<User> findUserListResultMap() throws Exception
複製程式碼

4.4 Mapper對映檔案

由於sql查詢列名和User類屬性名不一致,所以不能使用resultType進行結構對映。

需要定義一個resultMap將sql查詢列名和User類的屬性名對應起來,完成結果對映。

    <!-- 定義resultMap:將查詢的列名和對映的pojo的屬性名做一個對應關係 -->
    <!-- 
        type:指定查詢結果要對映的pojo的型別
        id:指定resultMap的唯一標示
     -->

    <resultMap type="user" id="userListResultMap">
        <!-- 
        id標籤:對映查詢結果的唯一列(主鍵列)
            column:查詢sql的列名
            property:對映結果的屬性名
        -->

        <id column="id_" property="id"/>
        <!-- result標籤:對映查詢結果的普通列 -->
        <result column="username_" property="username"/>
        <result column="birthday_" property="birthday"/>
    </resultMap>

    <!-- resultMap入門 -->
    <select id="findUserListResultMap" resultMap="userListResultMap">
        SELECT id id_,username username_,birthday birthday_ FROM user
    </select>
複製程式碼
  • <id/>:表示查詢結果集的唯一標識,非常重要。如果是多個欄位為複合唯一約束則定義多個

  • Property:表示User類的屬性。

  • Column:表示sql查詢出來的欄位名。

  • Column和property放在一塊兒表示將sql查詢出來的欄位對映到指定的pojo類屬性上。

  • <result/>:普通結果,即pojo的屬性。

本系列文章Github 後端進階指南 已收錄,此專案正在完善中,歡迎star。

公眾號內文章都是博主原創,並且會一直更新。如果你想見證或和博主一起成長,歡迎關注!

歡迎掃碼關注哦!!!
歡迎掃碼關注哦!!!

相關文章