Mybatis學習-配置、做用域和生命週期

核心配置文件:Mybatis-config.xml
Mybatis的配置文件包含了會深深影響Mybatis行爲的設置和屬性信息html

配置(configuration)

在mybatis-config.xml文件中標籤都有規定的順序,須要按照如下順序添加
properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,objectWrapperFactory?,reflectorFactory?,plugins?,environments?,databaseIdProvider?,mappers?java

屬性(properties)

咱們能夠經過properties來實現引用文件。Mybatis的一些屬性能夠在外部進行配置,並能夠進行動態替換。你既能夠在典型的 Java 屬性文件中配置這些屬性,也能夠在properties元素的子元素中設置mysql

  1. 編寫一個配置文件(db.properties)
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/learn?serverTimezone=GMT&useSSL=false&useUnicode=true&characterEncoding=UTF-8
username=root
password=123456789
  1. 在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 resource="db.properties">
    	<property name="username" value="root"/>
        <property name="pwd" value="123456789"/>
    </properties>

    <environments default="test">
       
        <environment id="test">
            <transactionManager type="JDBC"/>
            <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>
    </environments>

    <!--每個Mapper.xml都須要在Mybatis核心配置文件中註冊-->
    <mappers>
        <mapper resource="mapper/UserMapper.xml"/>
    </mappers>
</configuration>
  1. 測試
@Test
public void test() {
    //獲取SQLSession對象
    SqlSession sqlSession = MybatisUtil.getSqlSession();

    try {

        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> userList = mapper.getUserList();

        for (User user : userList) {
           System.out.println(user);
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        //關閉SQLSession
        sqlSession.close();
    }
}

Mybatis會先讀取properties元素體內的指定屬性,再根據resource屬性讀取類路徑下屬性文件。因此外部配置文件中編寫的配置會覆蓋內部標籤編寫的配置,外部配置文件擁有更高優先級sql

設置(setting)

這是Mybatis中極爲重要的調整設置,他們會改變Mybatis的運行時行爲數據庫

更多設置請參考:https://mybatis.org/mybatis-3/zh/configuration.html#settingsapache

環境配置(environments)

Mybatis能夠配置成適應多種環境
儘管能夠配置多個環境,但每一個SQLSessionFactory實例只能選擇一種環境
Mybatis默認的事務管理器就是JDBC,數據源是POOLED安全

<environments default="test">	<!--須要使用的環境-->
    
    <!--環境一-->
    <environment id="development">		<!--id:每套environment的惟一標識-->
        <transactionManager type="JDBC"/>	<!--事務管理器的配置-->
        <dataSource type="POOLED">			<!--數據源的配置-->
            <property name="driver" value="com.mysql.jdbc.Driver"/>
            <property name="url" value="jdbc:mysql://localhost:3306/learn?serverTimezone=GMT&amp;useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
            <property name="username" value="root"/>
            <property name="password" value="123456789"/>
        </dataSource>
    </environment>

    <!--環境二-->
    <environment id="test">
        <transactionManager type="JDBC"/>
        <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>
</environments>

類型別名(typeAliases)

類型別名爲Java類型設置一個短的名字,它僅用於XML配置,存在的意義僅在於用來減小類徹底限定名的冗餘bash

<typeAliases>
    <typeAlias alias="User" type="com.luoqing.model.User"/>
</typeAliases>

也能夠指定一個包名,Mybatis會在包名下搜索須要的JavaBeansession

<typeAliases>
    <package name="com.luoqing.model" />
</typeAliases>

每個在包名下的JavaBean,在沒有註解的狀況下,會使用Bean首字母小寫的非限定類名來做爲它的別名
若是有註解則其別名爲其註解值mybatis

//這個類的別名爲user
@Alias("user")
public class User {
    ……
}

在實體類比較少的時候,使用第一種方式。若是實體類十分多,建議使用第二種

類型處理器(typeHandlers)

Mybatis使用typeHandlers將數據庫中字段的類型轉換爲java類中屬性的類型,或將java類中屬性的類型轉換爲數據庫中字段的類型

經過Configuration對象獲取

@Test
public void myTest() {
    SqlSession sqlSession = MybatisUtil.getSqlSession();
    TypeHandlerRegistry typeHandlerRegistry = sqlSession.getConfiguration().getTypeHandlerRegistry();
    Collection<TypeHandler<?>> list = typeHandlerRegistry.getTypeHandlers();
    System.out.println(list.size());
    for (TypeHandler<?> typeHandler : list) {
        System.out.println(typeHandler.getClass().getName());
    }

    sqlSession.close();

}

執行結果以下。如下全部的處理器類位於mybatis-X.X.X.jar/org/apache/ibatis/type中

40
org.apache.ibatis.type.InstantTypeHandler
org.apache.ibatis.type.MonthTypeHandler
org.apache.ibatis.type.JapaneseDateTypeHandler
org.apache.ibatis.type.UnknownTypeHandler
org.apache.ibatis.type.DateTypeHandler
org.apache.ibatis.type.CharacterTypeHandler
org.apache.ibatis.type.BigIntegerTypeHandler
org.apache.ibatis.type.SqlxmlTypeHandler
org.apache.ibatis.type.LocalDateTimeTypeHandler
org.apache.ibatis.type.ArrayTypeHandler
org.apache.ibatis.type.YearTypeHandler
org.apache.ibatis.type.FloatTypeHandler
org.apache.ibatis.type.NStringTypeHandler
org.apache.ibatis.type.BooleanTypeHandler
org.apache.ibatis.type.ByteTypeHandler
org.apache.ibatis.type.ClobTypeHandler
org.apache.ibatis.type.BigDecimalTypeHandler
org.apache.ibatis.type.ByteArrayTypeHandler
org.apache.ibatis.type.BlobTypeHandler
org.apache.ibatis.type.DateOnlyTypeHandler
org.apache.ibatis.type.YearMonthTypeHandler
org.apache.ibatis.type.SqlDateTypeHandler
org.apache.ibatis.type.OffsetTimeTypeHandler
org.apache.ibatis.type.LongTypeHandler
org.apache.ibatis.type.TimeOnlyTypeHandler
org.apache.ibatis.type.ZonedDateTimeTypeHandler
org.apache.ibatis.type.BlobInputStreamTypeHandler
org.apache.ibatis.type.LocalDateTypeHandler
org.apache.ibatis.type.IntegerTypeHandler
org.apache.ibatis.type.StringTypeHandler
org.apache.ibatis.type.BlobByteObjectArrayTypeHandler
org.apache.ibatis.type.ShortTypeHandler
org.apache.ibatis.type.NClobTypeHandler
org.apache.ibatis.type.LocalTimeTypeHandler
org.apache.ibatis.type.ClobReaderTypeHandler
org.apache.ibatis.type.SqlTimestampTypeHandler
org.apache.ibatis.type.SqlTimeTypeHandler
org.apache.ibatis.type.ByteObjectArrayTypeHandler
org.apache.ibatis.type.OffsetDateTimeTypeHandler
org.apache.ibatis.type.DoubleTypeHandler

Mybatis已經爲咱們寫好了40個類型處理器
其中DateTypeHandlers的源碼以下

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.apache.ibatis.type;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Date;

public class DateTypeHandler extends BaseTypeHandler<Date> {
    public DateTypeHandler() {
    }

    /**
    	獲取到對應的java類型的對象,將其轉換爲jdbc類型
    */
    public void setNonNullParameter(PreparedStatement ps, int i, Date parameter, JdbcType jdbcType) throws SQLException {
        ps.setTimestamp(i, new Timestamp(parameter.getTime()));
    }

    /**
    	獲取到對應列的jdbc類型的對象,將其轉換爲java類型
    */
    public Date getNullableResult(ResultSet rs, String columnName) throws SQLException {
        Timestamp sqlTimestamp = rs.getTimestamp(columnName);
        return sqlTimestamp != null ? new Date(sqlTimestamp.getTime()) : null;
    }

    /**
    	根據索引獲取到對應的數據的jdbc類型將其轉換爲java類型
    */
    public Date getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        Timestamp sqlTimestamp = rs.getTimestamp(columnIndex);
        return sqlTimestamp != null ? new Date(sqlTimestamp.getTime()) : null;
    }

    /**
    	這個方法用在存儲過程當中。將jdbc類型轉換爲java類型
    */
    public Date getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        Timestamp sqlTimestamp = cs.getTimestamp(columnIndex);
        return sqlTimestamp != null ? new Date(sqlTimestamp.getTime()) : null;
    }
}

它的父類BaseTypeHandler<T>

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.apache.ibatis.type;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.apache.ibatis.executor.result.ResultMapException;
import org.apache.ibatis.session.Configuration;

public abstract class BaseTypeHandler<T> extends TypeReference<T> implements TypeHandler<T> {
    /** @deprecated */
    @Deprecated
    protected Configuration configuration;

    public BaseTypeHandler() {
    }

    /** @Deprecated表示此方法或者類不推薦使用,可是不表明不能用*/
    /** @deprecated */
    @Deprecated
    public void setConfiguration(Configuration c) {
        this.configuration = c;
    }

    
    public void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
        if (parameter == null) {
            if (jdbcType == null) {
                throw new TypeException("JDBC requires that the JdbcType must be specified for all nullable parameters.");
            }

            try {
                /** jdbcType是一個枚舉類型 */
                /** 將對應的jdbc類型設置爲null */
                ps.setNull(i, jdbcType.TYPE_CODE);
            } catch (SQLException var7) {
                throw new TypeException("Error setting null for parameter #" + i + " with JdbcType " + jdbcType + " . Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. Cause: " + var7, var7);
            }
        } else {
            try {
                this.setNonNullParameter(ps, i, parameter, jdbcType);
            } catch (Exception var6) {
                throw new TypeException("Error setting non null for parameter #" + i + " with JdbcType " + jdbcType + " . Try setting a different JdbcType for this parameter or a different configuration property. Cause: " + var6, var6);
            }
        }

    }

    public T getResult(ResultSet rs, String columnName) throws SQLException {
        try {
            return this.getNullableResult(rs, columnName);
        } catch (Exception var4) {
            throw new ResultMapException("Error attempting to get column '" + columnName + "' from result set.  Cause: " + var4, var4);
        }
    }

    public T getResult(ResultSet rs, int columnIndex) throws SQLException {
        try {
            return this.getNullableResult(rs, columnIndex);
        } catch (Exception var4) {
            throw new ResultMapException("Error attempting to get column #" + columnIndex + " from result set.  Cause: " + var4, var4);
        }
    }

    public T getResult(CallableStatement cs, int columnIndex) throws SQLException {
        try {
            return this.getNullableResult(cs, columnIndex);
        } catch (Exception var4) {
            throw new ResultMapException("Error attempting to get column #" + columnIndex + " from callable statement.  Cause: " + var4, var4);
        }
    }

    //定義了四個抽象方法,並在上面接口方法的實現中使用了它們
    //具體的實現交給子類去完成
    public abstract void setNonNullParameter(PreparedStatement var1, int var2, T var3, JdbcType var4) throws SQLException;

    public abstract T getNullableResult(ResultSet var1, String var2) throws SQLException;

    public abstract T getNullableResult(ResultSet var1, int var2) throws SQLException;

    public abstract T getNullableResult(CallableStatement var1, int var2) throws SQLException;
}

BaseTypeHandler是一個抽象類,也是類型處理器的基類。它做爲TypeHandler接口的初步實現,實現了TypeHandler的四個方法;還另外定義了四個抽象方法,也就是DateTypeHandler中的四個方法。系統定義的40個TypeHandler方法都繼承自BaseTypeHandler

實現的接口TypeHandler<T>

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.apache.ibatis.type;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public interface TypeHandler<T> {
    void setParameter(PreparedStatement var1, int var2, T var3, JdbcType var4) throws SQLException;

    T getResult(ResultSet var1, String var2) throws SQLException;

    T getResult(ResultSet var1, int var2) throws SQLException;

    T getResult(CallableStatement var1, int var2) throws SQLException;
}

若是咱們要自定義typeHandler時:

  • 繼承BaseTypeHandler類
  • 實現TypeHandler接口

通常不須要自定義,使用默認的就夠了

映射器(mappers)

MapperRegistry:註冊綁定咱們的Mapper文件

方式一:

<!-- 使用相對於類路徑的資源引用,在resource文件夾中 -->
<mappers>
  <mapper resource="com/luoqing/dao/UserMapper.xml"/>
</mappers>

方式二:使用class文件綁定註冊

<!-- 使用映射器接口實現類的徹底限定類名 -->
<mappers>
  <mapper class="com.luoqing.dao.UserMapper.xml"/>
</mappers>

注意:

  • 接口和它的Mapper配置文件必須同名
  • 接口和它的Mapper配置文件必須在同一個包下

方式三:

<!-- 將包內的映射器接口實現所有註冊爲映射器 -->
<mappers>
  <package name="com.luoqing.dao"/>
</mappers>

注意:

  • 接口和它的Mapper配置文件必須同名
  • 接口和它的Mapper配置文件必須在同一個包下

方式四:使用映射器接口實現類的徹底限定名(由於基本不使用,在此很少贅述,如要學習請移步官方文檔)
https://mybatis.org/mybatis-3/zh/configuration.html#mappers

做用域(Scope)和生命週期

不一樣做用域和生命週期類別是相當重要的,由於錯誤的使用會致使很是嚴重的併發問題

SqlSessionFactoryBuilder

一旦建立了 SqlSessionFactory,就再也不須要它了。所以 SqlSessionFactoryBuilder 實例的最佳做用域是方法做用域(也就是局部方法變量)。你能夠重用 SqlSessionFactoryBuilder 來建立多個 SqlSessionFactory 實例,但最好仍是不要一直保留着它,以保證全部的 XML 解析資源能夠被釋放給更重要的事情。

SqlSessionFactory

SqlSessionFactory 一旦被建立就應該在應用的運行期間一直存在,沒有任何理由丟棄它或從新建立另外一個實例。使用 SqlSessionFactory 的最佳實踐是在應用運行期間不要重複建立屢次。所以 SqlSessionFactory 的最佳做用域是應用做用域。最簡單的就是使用單例模式或者靜態單例模式。

SqlSession

每一個線程都應該有它本身的 SqlSession 實例。SqlSession 的實例不是線程安全的,所以是不能被共享的,因此它的最佳的做用域是請求或方法做用域。絕對不能將 SqlSession 實例的引用放在一個類的靜態域,甚至一個類的實例變量也不行。 也毫不能將 SqlSession 實例的引用放在任何類型的託管做用域中,好比 Servlet 框架中的 HttpSession。每次收到 HTTP 請求,就能夠打開一個 SqlSession,返回一個響應後,就關閉它。這個關閉操做很重要,爲了確保每次都能執行關閉操做,你應該把這個關閉操做放到 finally 塊中。下面的示例就是一個確保 SqlSession 關閉的標準模式:

try (SqlSession session = sqlSessionFactory.openSession()) {
  // 你的應用邏輯代碼
}

在全部代碼中都遵循這種使用模式,能夠保證全部數據庫資源都能被正確地關閉。

相關文章
相關標籤/搜索