天天看點

MyBatis的配置方式

MyBatis的配置方式有兩種,一種是XML,一種是代碼方式,下面我們都簡單介紹下,先從xml方式開始:

建構 SqlSessionFactory 最常見的方式是基于 XML 配置的構造方式 。下面的 mybatis-config.xml 展示了一個典型的 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="mysql.properties"/>
    <settings>
        <setting name="cacheEnabled" value="true" />
    </settings>
    <typeAliases>
        <typeAlias alias="Student" type="com.neucloud.domain.Student"/>
        <package name="com.neucloud.domain"/>
    </typeAliases>
    <typeHandlers>
        <typeHandler handler="com.neucloud.typehandlers.MyTypeHandler" />
        <package name="com.neucloud.typehandlers" />
    </typeHandlers>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driverClassName}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="com/neucloud/mappers/StudentMapper.xml"/>
    </mappers>
</configuration>           

下面讓我們逐個讨論上述配置檔案的組成部分,先從最重要的部分開始,即 environments:

environment

MyBatis 支援配置多個 dataSource 環境, 可以将應用部署到不同的環境上, 如 DEV(開發環境), TEST (測試環境) ,QA(品質評估環境),UAT(使用者驗收環境),PRODUCTION(生産環境) ,可以通過将預設 environment 值設定成想要的 environment id 值。

在上述的配置中,預設的環境 environment 被設定成 development。當需要将程式部署到生産伺服器上時,你不需要修改什麼配置,隻需要将預設環境 environment 值設定成生産環境的 environment id 屬性即可。 有時候,我們可能需要在相同的應用下使用多個資料庫。比如我們可能有 SHOPPING-CART 資料庫來存儲所有的訂單明細;使用 REPORTS 資料庫存儲訂單明細的合計,用作報告。

如果你的應用需要連接配接多個資料庫,你需要将每個資料庫配置成獨立的環境,并且為每一個資料庫建立一個SqlSessionFactory。

XML Code:

<environments default="development"> 
  <environment id="development"> 
    <transactionManager type="JDBC" /> 
    <dataSource type="POOLED"> 
      <property name="driver" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
    </dataSource> 
  </environment> 
  <environment id="development2"> 
    <transactionManager type="MANAGED" /> 
    <dataSource type="JNDI"> 
      <property name="data_source" value="java:comp/jdbc/ReportsDS" /> 
    </dataSource> 
  </environment> 
</environments>            

我們可以如下為每個環境建立一個 SqlSessionFactory

建立 SqlSessionFactory 時,如果沒有明确指定環境 environment id,則會使用預設的環境 environment 來建立。在上述的源碼中,預設的 SqlSessionFactory 便是使用 development環境設定建立的。

對于每個環境 environment,我們都需要配置 dataSource 和 transactionManager 元素

資料源 DataSource

dataSource 元素被用來配置資料庫連接配接屬性,dataSource 的類型可以配置成其内置類型之一,如 UNPOOLED,POOLED,JNDI。

● 如果将類型設定成 UNPOOLED,MyBatis 會為每一個資料庫操作建立一個新的連接配接,并關閉它。該方式适用于隻有小規模數量并發使用者的簡單應用程式上,在多使用者并發應用中, 不建議使用。

● 如果将屬性設定成 POOLED,MyBatis 會建立一個資料庫連接配接池,對使用者的每一個請求,會使用緩沖池中的一個可用的Connection對 象 , 這樣可以提高應用的性能。一旦資料庫操作完成,MyBatis 會将此連接配接傳回給連接配接池。在開發或測試環境中,經常使用此種方式。

● 如果将類型設定成 JNDI,MyBatis使用應用伺服器的資料庫連接配接池,并且使用JNDI查找來擷取資料庫連接配接。在生産環境中,優先考慮這種方式。

事務管理器 TransactionManager

MyBatis 支援兩種類型的事務管理器: JDBC and MANAGED.

● JDBC 事務管理器被用作當應用程式負責管理資料庫連接配接的生命周期(送出、回退等等)的時候。當你将TransactionManager 屬性設定成 JDBC,MyBatis 内部将使用 JdbcTransactionFactory 類建立TransactionManager。例如,部署到 Apache Tomcat 的應用程式,需要應用程式自己管理事務。

● MANAGED 事務管理器是當由應用伺服器負責管理資料庫連接配接生命周期的時候使用。當你将TransactionManager 屬性設定成 MANAGED 時, MyBatis 内部使用ManagedTransactionFactory 類建立事務管理器TransactionManager。 例如, 當一個JavaEE的應用程式部署在類似 JBoss, WebLogic,GlassFish 應用伺服器上時,它們會使用 EJB 進行應用伺服器的事務管理能力。在這些管理環境中,你可以使用

MANAGED 事務管理器。(Managed 可以了解為托管的意思,即是應用本身不去管理事務,而是把事務管理交給應用所在的伺服器進行管理)

屬性 Properties

屬性配置元素可以将配置值具體化到一個屬性檔案中,并且使用屬性檔案的 key 名作為占位符。在上述的配置中,我們将資料庫連接配接屬性具體化到了 mysql.properties 檔案中,并且為 driver,URL 等屬性使用了占位符。

1. 在 mysql.properties 檔案中配置資料庫連接配接參數,如下所示:

jdbc.driverClassName=com.mysql.cj.jdbc.Driver

jdbc.url=jdbc:mysql://localhost:3306/first_db

jdbc.username=root

jdbc.password=9958

2.在 mybatis-config.xml 檔案中,為屬性使用 mysql.properties 檔案中定義的占位符:

<properties resource="mysql.properties"> 
  <property name="jdbc.username" value="root" /> 
  <property name="jdbc.password" value="9958" /> 
</properties> 
<dataSource type="POOLED"> 
  <property name="driver" value="${jdbc.driverClassName}" /> 
  <property name="url" value="${jdbc.url}" /> 
  <property name="username" value="${jdbc.username}" /> 
  <property name="password" value="${jdbc.password}" /> 
</dataSource>           

在<properties>元素中可以配置預設參數的值。 如果<properties>中定義的元素和屬性檔案定義元素的 key值相同,它們會被屬性檔案中定義的值覆寫,也就是如果mysql.properties 檔案包含值 jdbc.username 和 jdbc.password,則上述定義的 username 和password 的值 root和 9958将會被 mysql.properties 中定義的對應的 jdbc.username 和jdbc.password

值覆寫。

類型别名 typeAliases

在 SQLMapper 配置檔案中,對于 resultType 和 parameterType 屬性值,我們需要使用 JavaBean 的完全限定名:

<select id="findStudentById" parameterType="int"  
    resultType="com.neucloud.domain.Student"> 
       select stud_id as studId, name, email, dob from Students where stud_id=#{studId}
</select> 
<update id="updateStudent" parameterType="com.neucloud.domain.Student"> 
  UPDATE STUDENTS SET NAME=#{name}, EMAIL=#{email}, DOB=#{dob} WHERE STUD_ID=#{studId}
</update>            

這裡我們為 resultType 和 parameterType 屬性值設定為 Student 類型的完全限定名:

com.neucloud.domain.Student

我們可以為完全限定名取一個别名(alias) ,然後其需要使用完全限定名的地方使用别名,而不是到處使用完全限定名。如下例子所示,為完全限定名起一個别名:

<typeAliases>
    <typeAlias alias="Student" type="com.neucloud.domain.Student"/>
    <package name="com.neucloud.domain"/>
</typeAliases>            

然後在 SQL Mapper 映射檔案中, 直接使用 Student就可以了

通過提供需要取别名的 JavaBean 所在的包(package),你可以不用為每一個 JavaBean 單獨定義别名, MyBatis會自動掃描包内定義的 JavaBeans,然後分别為 JavaBean 注冊一個小寫字母開頭的非完全限定的類名形式的别名。

還有另外一種方式為 JavaBeans 起别名,使用注解@Alias:

@Alias("StudentAlias") 
public class Student 
{ 
}            

@Alias 注解将會覆寫配置檔案中的<typeAliases>定義。

類型處理器 typeHandlers

MyBatis 通過抽象 JDBC 來簡化了資料持久化邏輯的實作。MyBatis 在其内部使用 JDBC,提供了更簡潔的方式實作了資料庫操作。

當 MyBatis 将一個 Java 對象作為輸入參數執行 INSERT 語句操作時,它會建立一個 PreparedStatement 對象,并且使用 setXXX()方式對占位符設定相應的參數值。

這裡,XXX 可以是 Int,String,Date 等 Java 對象屬性類型的任意一個。示例如下:

<insert id="insertStudent" parameterType="Student">
   INSERT INTO STUDENTS(STUD_ID,NAME,EMAIL,DOB) 
   VALUES(#{studId},#{name},#{email},#{dob})
</insert>           

為執行這個語句,MyBatis 将采取以下一系列動作:

1. 建立一個有占位符的 PreparedStatement 接口,如下:

PreparedStatement pstmt = connection.prepareStatement

("INSERT INTO STUDENTS(STUD_ID,NAME,EMAIL,DOB) VALUES(?,?,?,?)");

2. 檢查 Student 對象的屬性 studId 的類型, 然後使用合适 setXXX 方法去設定參數值。 這裡 studId 是 integer類型,是以會使用 setInt()方法:

pstmt.setInt(1,student.getStudId());

3. 類似地,對于 name 和 email 屬性都是 String 類型,MyBatis 使用 setString()方法設定參數:

pstmt.setString(2, student.getName());

pstmt.setString(3, student.getEmail());

4. 至于 dob 屬性, MyBatis 會使用 setDate() 方法設定 dob 處占位符位置的值。

5. MyBaits 會将 java.util.Date 類型轉換為 into java.sql.Timestamp 并設值:

pstmt.setTimestamp(4, new Timestamp((student.getDob()).getTime()));

其原理就是通過使用類型處理器(type handlers)來決定這麼做的。

MyBatis 對于以下的類型使用内建的類型處理器:所有的基本資料類型、基本類型的包裹類型、byte[]、java.util.Date、java.sql.Date、java,sql.Time、java.sql.Timestamp、java 枚舉類型等。是以當 MyBatis 發現屬性的類型屬于上述類型,他會使用對應的類型處理器将值設定到 PreparedStatement 中,同樣地,當從 SQL 結果集建構 JavaBean 時,也有類似的過程。

可如果我們有一個自定義的對象類型,來存儲存儲到資料庫呢?

假設表 STUDENTS 有一個 PHONE 字段,類型為 VARCHAR(15),而 JavaBean Student 有一個 PhoneNumber 類定義類型的 phoneNumber 屬性。

<insert id="insertStudent" parameterType="Student">

insert into students(name,email,phone)

values(#{name},#{email},#{phone})

</insert>

這裡,phone 參數需要傳遞給#{phone};而 phone 對象是 PhoneNumber 類型。然而,MyBatis 并不知道該怎樣來處理這個類型的對象。

為了讓 MyBatis 明白怎樣處理這個自定義的 Java 對象類型,如 PhoneNumber,我們可以建立一個自定義的類型處理器,如下所示:

1. MyBatis 提供了抽象類 BaseTypeHandler<T> ,我們可以繼承此類建立自定義類型處理器。

public class PhoneTypeHandler extends BaseTypeHandler<PhoneNumber> { 
    @Override 
    public void setNonNullParameter(PreparedStatement ps, int i, 
                                    PhoneNumber parameter, JdbcType jdbcType) throws 
        SQLException { 
        ps.setString(i, parameter.getAsString()); 
    } 
    @Override 
    public PhoneNumber getNullableResult(ResultSet rs, String columnName) 
    throws SQLException { 
        return new PhoneNumber(rs.getString(columnName)); 
    } 
    @Override 
    public PhoneNumber getNullableResult(ResultSet rs, int columnIndex) 
    throws SQLException { 
        return new PhoneNumber(rs.getString(columnIndex));
} 
    @Override 
    public PhoneNumber getNullableResult(CallableStatement cs, int columnIndex) 
    throws SQLException { 
        return new PhoneNumber(cs.getString(columnIndex)); 
    } 
}            

2. 我們使用 ps.setString()和 rs.getString()方法是因為 phone 列是 VARCHAR 類型。

3. 一旦我們實作了自定義的類型處理器,我們需要在 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="application.properties" /> 
  <typeHandlers> 
    <typeHandler handler="com.neucloud.typehandlers. PhoneTypeHandler" /> 
  </typeHandlers> 
</configuration>            

注冊 PhoneTypeHandler 後, MyBatis 就能夠将 Phone 類型的對象值存儲到 VARCHAR 類型的列上。

全局參數設定 Settings

為滿足應用特定的需求,MyBatis 預設的全局參數設定可以被覆寫(overridden)掉,如下所示:

<settings> 
  <setting name="cacheEnabled" value="true" /> 
  <setting name="lazyLoadingEnabled" value="true" /> 
  <setting name="multipleResultSetsEnabled" value="true" /> 
  <setting name="useColumnLabel" value="true" /> 
  <setting name="useGeneratedKeys" value="false" /> 
  <setting name="autoMappingBehavior" value="PARTIAL" /> 
  <setting name="defaultExecutorType" value="SIMPLE" /> 
  <setting name="defaultStatementTimeout" value="25000" /> 
  <setting name="safeRowBoundsEnabled" value="false" /> 
  <setting name="mapUnderscoreToCamelCase" value="false" /> 
  <setting name="localCacheScope" value="SESSION" /> 
  <setting name="jdbcTypeForNull" value="OTHER" /> 
  <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode ,toString" /> 
</settings>            

SQL 映射定義 Mappers

Mapper XML 檔案中包含的 SQL 映射語句将會被應用通過使用其 statementid 來執行。我們需要在 mybatis-config.xml 檔案中配置 SQL Mapper 檔案的位置。

<mappers> 
  <mapper resource="com/neucloud/mappers/StudentMapper.xml"/>
  <mapper url="file:///D:/Intellij/MyBatisDemo/src/main/resources/com/neucloud/mappersStudentMapper.xml" /> 
  <mapper class="com.neucloud.mappers.StudentMapper" /> 
  <package name="com.neucloud.mappers" /> 
</mappers>            

以上每一個<mapper> 标簽的屬性有助于從不同類型的資源中加載映射 mapper:

● resource 屬性用來指定在 classpath 中的 mapper 檔案。

● url 屬性用來通過完全檔案系統路徑或者 web URL 位址來指向 mapper 檔案

● class 屬性用來指向一個 mapper 接口

● package 屬性用來指向可以找到 Mapper 接口的包名

使用 Java API 配置 MyBatis

我們已經讨論了各種 MyBatis 配置元素,如 envronments,typeAlias,和 typeHandlers,以及如何使用

XML 配置它們。即使你想使用基于 Java API 的 MyBatis 配置,經曆前面的學習是大有好處的,它可以幫你對這些配置元素有更好的了解。在本節中,我們會引用到前一節中描述的一些類。

MyBatis 的 SqlSessionFactory 接口除了使用基于 XML 的配置建立外也可以通過 Java API 程式設計式地被建立。每個在 XML 中配置的元素,都可以程式設計式的建立。

使用 Java API 建立 SqlSessionFactory,代碼如下:

public static SqlSessionFactory getSqlSessionFactoryUsingJavaAPI() {
    if (javaSqlSessionFactory == null) {
        try {
            DataSource dataSource = DataSourceFactory.getDataSource();
            TransactionFactory transactionFactory = new JdbcTransactionFactory();
            Environment environment = new Environment("development", transactionFactory, dataSource);
            Configuration configuration = new Configuration(environment);
            configuration.getTypeAliasRegistry().registerAlias("student", Student.class);
            configuration.getTypeHandlerRegistry().register(PhoneTypeHandler.class);
            configuration.addMapper(StudentMapper.class);
            javaSqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    return javaSqlSessionFactory;
}           

環境配置 Environment

我們需要為想使用 MaBatis 連接配接的每一個資料庫建立一個 Enviroment 對象。為了使用每一個環境,我們需要為每一個環境 environment 建立一個 SqlSessionFactory 對象。 而建立 Environment 對象, 我們需要 java.sql.DataSource和 TransactionFactory 執行個體。下面讓我們看看如何建立 DataSource 和 TransactionFactory 對象

MyBatis 支援三種内建的 DataSource 類型: UNPOOLED, POOLED和 JNDI,下面通過 MyBatis 的 PooledDataSource 獲得 DataSource 對象,如下:

public static DataSource getDataSource() {
    String driver = PROPERTIES.getProperty("jdbc.driverClassName");
    String url = PROPERTIES.getProperty("jdbc.url");
    String username = PROPERTIES.getProperty("jdbc.username");
    String password = PROPERTIES.getProperty("jdbc.password");
    PooledDataSource dataSource = new PooledDataSource(driver, url, username, password);
    return dataSource;
}           

一般在生産環境中,DataSource 會被應用伺服器配置,并通過 JNDI 擷取 DataSource 對象,如下所示:

public static DataSource getJNDIDataSource() {
    String dataSourceJNDIName = "java:comp/env/jdbc/MyBatisDemoDS";
    try {
        InitialContext ctx = new InitialContext();
        DataSource dataSource = (DataSource) ctx.lookup(dataSourceJNDIName);
        return dataSource;
    } catch (NamingException e) {
        throw new RuntimeException(e);
    }
}           

目前有一些流行的第三方類庫,如 commons-dbcp 和 c3p0 實作了 java.sql.DataSource,你可以使用它們來建立dataSource。

事務工廠 TransactionFactory

MyBatis 支援一下兩種 TransactionFactory 實作:

● JdbcTransactionFactory

● ManagedTransactionFactory

如果你的應用程式運作在未托管(non-managed)的環境中,你應該使用 JdbcTransactionFactory:

DataSource dataSource = DataSourceFactory.getDataSource();

TransactionFactory txnFactory = new JdbcTransactionFactory();

Environment environment = new Environment("development", txnFactory, dataSource);

如果你的應用程式運作在托管(managed)的環境中,并且使用容器支援的事務管理服務,你應該使用ManagedTransactionFactory:

TransactionFactory txnFactory = new ManagedTransactionFactory();

MyBatis 提供以下幾種通過 Configuration 對象注冊類型别名的方法:

1. 根據預設的别名規則,使用一個類的首字母小寫、非完全限定的類名作為别名注冊,可使用以下代碼:

configuration.getTypeAliasRegistry().registerAlias(Student.class);

2. 指定别名注冊,可使用以下代碼:

configuration.getTypeAliasRegistry().registerAlias("Student",Student.class);

3. 通過類的完全限定名注冊相應類别名,可使用一下代碼:

configuration.getTypeAliasRegistry().registerAlias("Student", "com.neucloud.domain.Student");

4. 為某一個包中的所有類注冊别名,可使用以下代碼:

configuration.getTypeAliasRegistry().registerAliases("com.neucloud.domain");

5. 為在 com.neucloud.domain package 包中所有的繼承自 Identifiable 類型的類注冊别名,可使用以下代碼:

configuration.getTypeAliasRegistry().registerAliases("com.neucloud.domain", Identifiable.class);

MyBatis 提供了一系列使用 Configuration 對象注冊類型處理器(type handler)的方法。我們可以通過以下方式注冊自定義的類處理器:

1. 為某個特定的類注冊類處理器:

configuration.getTypeHandlerRegistry().register(PhoneNumber. class, PhoneTypeHandler.class);

2. 注冊一個類處理器:

configuration.getTypeHandlerRegistry().register(PhoneTypeHandler.class);

3. 注冊 com.mybatis3.typehandlers 包中的所有類型處理器:

configuration.getTypeHandlerRegistry().register("com.neucloud.typehandlers");

MyBatis 提供了一組預設的,能夠很好地适用大部分的應用的全局參數設定。然而,你可以稍微調整這些參數,讓它更

好地滿足你應用的需要。你可以使用下列方法将全局參數設定成想要的值。

configuration.setCacheEnabled(true); 
configuration.setLazyLoadingEnabled(false); 
configuration.setMultipleResultSetsEnabled(true); 
configuration.setUseColumnLabel(true); 
configuration.setUseGeneratedKeys(false); 
configuration.setAutoMappingBehavior(AutoMappingBehavior.PARTIAL); 
configuration.setDefaultExecutorType(ExecutorType.SIMPLE); 
configuration.setDefaultStatementTimeout(25); 
configuration.setSafeRowBoundsEnabled(false); 
configuration.setMapUnderscoreToCamelCase(false); 
configuration.setLocalCacheScope(LocalCacheScope.SESSION); 
configuration.setAggressiveLazyLoading(true); 
configuration.setJdbcTypeForNull(JdbcType.OTHER); 
Set<String> lazyLoadTriggerMethods = new HashSet<String>(); 
lazyLoadTriggerMethods.add("equals"); 
lazyLoadTriggerMethods.add("clone"); 
lazyLoadTriggerMethods.add("hashCode"); 
lazyLoadTriggerMethods.add("toString"); 
configuration.setLazyLoadTriggerMethods(lazyLoadTriggerMethods );            

Mappers

MyBatis 提供了一些使用 Configuration 對象注冊 Mapper XML 檔案和 Mappe 接口的方法。

1. 添加一個 Mapper 接口,可使用以下代碼:

configuration.addMapper(StudentMapper.class);

2. 添加 com.neucloud.mappers 包中的所有 Mapper XML 檔案或者 Mapper 接口,可使用以下代碼:

configuration.addMappers("com.neucloud.mappers");

3. 添加所有 com.neucloud.mappers 包中的拓展了特定 Mapper 接口的 Maper 接口, 如 aseMapper,可使用如下代碼:

configuration.addMappers("com.neucloud.mappers", BaseMapper.class);