01-MyBatis的基本使用

wangyongxun1983發表於2020-09-25

01、MyBatis的核心物件

Mapper(實際上是一個代理物件)是從SqlSession中獲取的。它的作用是傳送SQL來運算元據庫的資料。它應該在一個SqlSession事務方法之內。

02、核心程式碼的簡單呼叫

String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

SqlSession session = sqlSessionFactory.openSession();
try {
   Blog blog = (Blog) session.selectOne("com.mybatis.mapper.BlogMapper.selectBlogById", 1);
   System.out.println(blog);
} finally {
   session.close();
}

 

03、MyBatis核心配置

【1】、configuration

整個配置檔案的根標籤,對應的Configuration類,

【2】、properties

用來配置引數資訊,比如最常見的資料庫連線資訊。在xml配置檔案中用${}引用。

【3】、settings

setttings裡面是MyBatis的一些核心配置

<?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>
    <settings>
        <!-- 列印查詢語句 -->
        <setting name="logImpl" value="STDOUT_LOGGING" />

        <!-- 控制全域性快取(二級快取)-->
        <setting name="cacheEnabled" value="true"/>

        <!-- 延遲載入的全域性開關。當開啟時,所有關聯物件都會延遲載入。預設 false  -->
        <setting name="lazyLoadingEnabled" value="true"/>
        <!-- 當開啟時,任何方法的呼叫都會載入該物件的所有屬性。預設 false,可通過select標籤的 fetchType來覆蓋-->
        <setting name="aggressiveLazyLoading" value="false"/>
        <!--  Mybatis 建立具有延遲載入能力的物件所用到的代理工具,預設JAVASSIST -->
        <!--<setting name="proxyFactory" value="CGLIB" />-->
        <!-- STATEMENT級別的快取,使一級快取,只針對當前執行的這一statement有效 -->
        <!--
                <setting name="localCacheScope" value="STATEMENT"/>
        -->
        <setting name="localCacheScope" value="SESSION"/>
    </settings>

</configuration>

【4】、typeAliases

型別的別名。比如我們的引數型別和返回值型別都可能會用到我們的Bean,比如com.mybatis.domain.Blog都只要寫blog就可以了。

【5】、typeHandlers【重點】

自定義Java型別和資料庫的JDBC型別的相互轉換規則。

說明:

1、型別處理器介面:TypeHandler

定義型別處理器的基本作用:從Java型別到JDBC型別和從JDBC型別到Java型別

2、型別引用:TypeReference

用於獲取Java中的原生型別,即byte、short、int、long、float、double、boolean、char八大基本資料型別。為了持有這個具體的型別處理器所處理的Java型別的原生型別。

3、基礎型別處理器:BaseTypeHandler

內部簡單的實現了TypeHandler介面中定義的四個方法中實現了所有型別處理器公共部分

4、案例

public class MyTypeHandler extends BaseTypeHandler<String> {
    public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType)
            throws SQLException {
        // 設定 String 型別的引數的時候呼叫,Java型別到JDBC型別
        // 注意只有在欄位上新增typeHandler屬性才會生效
        // insertBlog name欄位
        System.out.println("---------------setNonNullParameter1:"+parameter);
        ps.setString(i, parameter);
    }

    public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
        // 根據列名獲取 String 型別的引數的時候呼叫,JDBC型別到java型別
        // 注意只有在欄位上新增typeHandler屬性才會生效
        System.out.println("---------------getNullableResult1:"+columnName);
        return rs.getString(columnName);
    }

    public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        // 根據下標獲取 String 型別的引數的時候呼叫
        System.out.println("---------------getNullableResult2:"+columnIndex);
        return rs.getString(columnIndex);
    }

    public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        System.out.println("---------------getNullableResult3:");
        return cs.getString(columnIndex);
    }
}

 

【6】、plugins

外掛。MyBatis預留了外掛的介面,讓MyBatis更容易擴充套件。

外掛可以攔截這四個物件的這些方法,其中4個物件為MyBatis的四大物件。

Executor、ParameterHandler、ResultSetHandler、StatementHandler。

【7】、environments、environment

environments標籤用來管理資料庫的環境。

一個environment標籤就是一個資料來源,代表一個資料庫。

如:

<environments default="development">
    <environment id="development">
        <transactionManager type="JDBC"/><!-- 單獨使用時配置成MANAGED沒有事務 -->
        <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>

【8】、transactionManager

配置事務

JDBC:使用Connection物件的commit()、rollback()、close()管理事務。

MANAGED:把事務交給容器來管理,比如JBOSS,Weblogic。

【9】、dataSource

資料來源

【10】、mappers

對映器:Mapper.xml的路徑。作用是讓MyBatis在啟動的時候去掃描這些對映器,建立對映關係。

總結:

Mybatis九大類全域性配置節點按照如下順序排序,位置不能顛倒。

properties=>settings=>typeAliases=>typeHandlers=>objectFactory=>plugins=>environment=>databaseIdProvider=>mappers

【11】、settings

設定MyBatis的一些最關鍵的配置

04、Mapper.xml對映配置檔案【重點】

對映器裡面最主要的是配置了SQL語句,也解決了我們的引數對映和結果集對映的問題。

8個標籤

cache : 該名稱空間的快取配置

cache-ref : 引用其它名稱空間的快取配置。

resultMap – 描述如何從資料庫結果集中載入物件,是最複雜也是最強大的元素。

<resultMap id="BaseResultMap" type="blog">
    <id column="bid" property="bid" jdbcType="INTEGER"/>
    <result column="name" property="name" jdbcType="VARCHAR"/>
    <result column="author_id" property="authorId" jdbcType="INTEGER"/>
</resultMap>

sql : 可被其它語句引用的可重用語句塊。

<sql id="Base_Column_List">
    bid, name, author_id
</sql>

insert :對映插入語句

update : 對映更新語句

delete : 對映刪除語句

select : 對映查詢語句

 05、動態SQL

MyBaits的動態SQL基於OGNL表達。

【1】、if:需要判斷的時候,條件寫在test中

<select id="selectByExample" parameterType="com.BlogExample" resultMap="BaseResultMap">
    select
    *
    from blog
    <if test="_parameter != null">
        <include refid="Example_Where_Clause" />
    </if>
    <if test="orderByClause != null AND parameter != null">
        order by ${orderByClause}
    </if>
</select>

【2】、choose(when,otherwise):需要選擇一個條件的時候

<select id="getEmpList_choose" resultMap="empResultMap" parameterType="com.Employee">
SELECT * FROMtbl_emp e
<where>
<choose>
    <when test="emp_id!=null">
        e.emp_id=#{emp_id,jdbcType=INTEGER}
    </when>
    <when test="emp_name!=null">
        AND e.emp_nameLIKE CONCAT(CONCAT('%',#{emp_name,jdbcType=VARCHAR}),'%')
    </when>
    <otherwise>
        
    </otherwise>
</choose>
</where>
</select>

【3】、trim(where,set):需要去掉where、and、逗號之類的符號的時候。

<update id="updateByPrimaryKeySelective" parameterType="com.Employee">
update tbl_emp
<set>
    <if test="empName!=null">
    emp_name=#{empName,jdbcType=VARCHAR},
    </if>
    <if test="dId!=null">
    d_id=#{dId,jdbcType=INTEGER},
    </if>
</set>
where emp_id=#{empId,jdbcType=INTEGER}
</update>

<insert id="insertSelective"  parameterType="com.Employee">
insert into tbl_emp
<trim prefix="(" suffix=")" suffixOverrides=",">
    <if test="empName!=null">
    emp_name,
    </if>
    <if test="dId!=null">
    d_id,
    </if>
</trim>
<trim prefix="values(" suffix=")" suffixOverrides=",">
    <if test="empName!=null">
    #{empName,jdbcType=VARCHAR},
    </if>
    <if test="dId!=null">
    #{dId,jdbcType=INTEGER},
    </if>
</trim>
</insert>

【4】、foreach:需要遍歷集合的時候

<delete id="deleteByList"parameterType="java.util.List">
delete from tbl_emp where emp_idin
<foreach collection="list" item="item" open="(" separator="," close=")">
#{item.empId,jdbcType=VARCHAR}
</foreach>
</delete>

06、批量插入

MyBatis的動態標籤的批量操作也是存在一定的缺點的,比如資料量特別大的時候,拼接出來的SQL語句過大。

MySQL的服務端對於接收的資料包有大小限制,max_allowed_packet預設是4M,需要修改預設配置才可以解決這個問題。

當然:在我們的全域性配置檔案中,可以配置預設的Executor的型別。其中有一種BatchExecutor。

<setting   name="defaultExecutorType"   value="BATCH"/>

也可以在建立會話的時候指定執行器型別:

SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH);

案例:

<insert id="batchInsert" parameterType="java.util.List" useGeneratedKeys="true">
insert into tbl_emp(emp_id,emp_name)
values         
<foreach collection="list" item="emps" index="index" separator=",">
(#{emps.empId},#{emps.empName})
</foreach>
</insert>

07、巢狀(關聯)查詢/N+1/延遲載入

【1】、resultType和resultMap的區別

resultMap功能更強大,可以通過設定typeHander來自定義實現功能。

【2】、一對一的關聯查詢有兩種配置方式

1、巢狀結果

<!-- 根據文章查詢作者,一對一查詢的結果,巢狀查詢 -->
<resultMap id="BlogWithAuthorResultMap" type="com.gupaoedu.domain.associate.BlogAndAuthor">
    <id column="bid" property="bid" jdbcType="INTEGER"/>
    <result column="name" property="name" jdbcType="VARCHAR"/>
    <!-- 聯合查詢,將author的屬性對映到ResultMap -->
    <association property="author" javaType="com.gupaoedu.domain.Author">
        <id column="author_id" property="authorId"/>
        <result column="author_name" property="authorName"/>
    </association>
</resultMap>

2、巢狀查詢

<!-- 另一種聯合查詢(一對一)的實現,但是這種方式有“N+1”的問題 -->
<resultMap id="BlogWithAuthorQueryMap" type="com.gupaoedu.domain.associate.BlogAndAuthor">
    <id column="bid" property="bid" jdbcType="INTEGER"/>
    <result column="name" property="name" jdbcType="VARCHAR"/>
    <association property="author" javaType="com.gupaoedu.domain.Author"
                 column="author_id" select="selectAuthor"/> <!-- selectAuthor 定義在下面-->
</resultMap>
<!-- 巢狀查詢 -->
<select id="selectAuthor" parameterType="int" resultType="com.gupaoedu.domain.Author">
    select author_id authorId, author_name authorName
    from author where author_id = #{authorId}
</select>

08、翻頁

PageHelper分頁外掛

原理攔截器,主要攔截Executor物件中的query(MappedStatement ms,Object o,RowBounds ob ResultHandler rh)這個方法。

09、mybatis-plus

參考:https://www.jianshu.com/p/ceb1df475021