目錄:
- Mybatis的核心配置 :
- 一、MyBatis的 “核心對象”
- 1.1 SqlSessionFactory
- 1.2 SqlSession :
- SqlSession對象中的操作數據庫的方法 :
- \<T> T selectOne ( String statement )
- \<T> T selectOne( String statement , Object parameter )
- \<E> List\<E> selectList ( String statement )
- \<E> List\<E> selectList ( String statement , Object parameter )
- \<E> List\<E> selectList ( String statement , Object parameter , RowBounds rowBounds )
- void select ( String statement , Object parameter , ResultHandler handler )
- int insert ( String statement )
- int insert ( String statement , Object parameter )
- int update( String statement )
- int update( String statement , Object parameter)
- int delete( String statement )
- int delete( String statement , Object parameter)
- int commit( )
- void rollback( )
- void close( )
- \<T> T getMapper( Class\<T> type )
- Connection getConnection( )
- 使用工具類創建 “SqlSession” / SqlSession工具類
- 二、MyBatis的 “配置文件”
- “映射文件”中的 “主要元素”
- \<properties>元素
- \<settings>元素
- \<typeAliases>元素
- \<typeHandler>元素
- \<objectFactory>元素
- \<plugins>元素
- \<environments>元素
- \<mappers>元素
- 三、MyBatis的 “映射文件”
- “配置文件”中的 “主要元素”
- \<select>元素
- \<insert>元素
- \<update>元素和\<delete>元素
- \<sql>元素
- \<resultMap>元素 (可解決“屬性名” 和 “字段名”不一樣導致的數據無法映射成功的問題)
Mybatis的核心配置 :
一、MyBatis的 “核心對象”
- 在使用MyBatis框架時,主要涉及 兩個核心對象 : SqlSessionFactory 和 SqlSession,它們在MyBatis框架中起著至關重要的作用。
1.1 SqlSessionFactory
SqlSessionFactory是MyBatis 框架中十分重要的對象,它是單個數據庫映射關系經過編澤后的內存鏡像,其主要作用是 創建SqlSession。
SqlSessionFactory 對象的實例可以通過 SqlSessionFactoryBuilder對象 來構建,而SqlSessionFactoryBuilder對象 則可以通過 XML配置文件 或一個預先定義好的 Configuration實例 構建出SqlSessionFactory的實例。
以下內容講解的是 :就是 通過XML配置文件 構建出的SqlSessionFactory實例,其實現代碼如下:
InputStream inputStream = Resources.getResourceAsStream("配置文件的位置"); //通過SqlSessionFactoryBuilder的 build()方法 + 配置文件來創建 SqlSessionFactory SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSessionFactory對象 是 線程安全 的,它一旦被創建,在整個應用執行期間都會存在。如果我們多次地創建同一個數據庫的SqlSessionFactory,那么此數據庫的資源將很容易被耗盡。為了解決此問題,通常每一個數據庫都會只對應一個 SqlSessionFactory, 所以在 構建SqlSessionFactory實例時,建議使用單列模式。
1.2 SqlSession :
SqlSession 是MyBatis 框架中另一個重要的對象, 它是 應用程序 與 持久層之間執行與操作的一個單線程對象,其主要作用是 執行持久化操作。
SqlSession對象包含數據庫中所有執行SOL操作的方法 (SqlSession中有很多操作數據庫的方法),由于其底層封裝了JDBC連接,所以可以直接使用SqlSession實例來 執行已映射的SQL語句
(可用SqlSession來執行 “映射文件” 中的sql語句)。
每一個線程都應該有一個自己的SqlSession實例,并且該實例是不能被共享的。同時,SqlSession實例 是 線程不安全 的,因此 其使用范圍 最好在 一次請求或一個方法 中,絕不能將其放在一個類的靜態字段、實例字段 或 任何類型的管理范圍 (如Servlet的HttpSession)中使用。
使用完SqlSession對象之后,要及時地關閉它,通常可以將其放在fnally塊中關閉。
//通過 sqlSessionFactory對象獲得"SqlSession" SqlSession sqlSession = sqlSessionFactory.openSession(); try{//此處執行持久化操作 }finally{sqlSession.close(); }
SqlSession對象中的操作數據庫的方法 :
<T> T selectOne ( String statement )
<T> T selectOne ( String statement ) : 查詢方法 : 參數 statement 是在 “ 映射文件” 中定義的 <select>元素 的 id 。
目的是 : 獲得映射文件中的 “<select>元素下所代表的 sql語句 作為selectOne( )方法的參數 ”)。使用該方法后,會返回執行SQL語句查詢結果的 一條泛型對象。
<T> T selectOne( String statement , Object parameter )
<T> T selectOne ( String statement, Object parameter ) :查詢方法 : 參數 statement 是在 “ 映射文件” 中定義的 <select>元素 的 id 。 parameter是查詢所需的 參數。使用該方法后,會返回執行SQL語句查詢結果的 一條泛型對象。
<E> List<E> selectList ( String statement )
<E> List<E> selectList ( String statement ) : 查詢方法 : 參數 statement 是在 “映射文件” 中定義的 <select>元素 的 id 。使用該方法后,會返回執行SQL語句查詢結果的 泛型對象的集合。
<E> List<E> selectList ( String statement , Object parameter )
<E> List<E> selectList ( String statement , Object parameter ) : 查詢方法 : 參數 statement 是在 “ 映射文件” 中定義的 <select>元素 的 id , parameter 是查詢所需的參數。使用該方法后,會返回執行SQL語句查詢結果的 泛型對象的集合。
<E> List<E> selectList ( String statement , Object parameter , RowBounds rowBounds )
<E> List<E> selectList ( String statement , Object parameter ) : 查詢方法 : 參數==statement==是在 “ 映射文件” 中定義的 <select>元素 的 id , parameter 是查詢所需的參數,rowBounds是用于分頁的參數對象。使用該方法后會返回執行SQL語句查詢結果的 泛型對象的集合。
void select ( String statement , Object parameter , ResultHandler handler )
void select ( String statement, Object parameter,ResultHandler handler ) : 查詢方法 : 參數statement是在配置文件中定義的 <select>元素的id,parameter 是查詢所需的 參數, ResultHandler對象用于處理查詢返回的復雜結果集。 (通常用于多表查詢)
int insert ( String statement )
int insert ( String statement ) : 插入方法 : 參數 statement是在 “映射文件” 中定義的 <select>元素 的 id ,使用該方法后,會返回執行 SQL語句所影響的行數。
int insert ( String statement , Object parameter )
int insert ( String statement , Object parameter ) : 插入方法 : 參數 statement 是在 “ 映射文件” 中定義的 <select>元素 的 id ,parameter 是查詢所需的參數。使用該方法后,會返回執行 SQL語句所影響的行數。
int update( String statement )
int update ( String statement ) : 更新方法 : 參數 statement 是在 “ 映射文件” 中定義的 <update>元素 的 id ,使用該方法后,會返回執行 SQL語句所影響的行數。
int update( String statement , Object parameter)
int update ( String statement , Object parameter ) : 更新方法 : 參數 statement 是在 “ 映射文件” 中定義的 <update>元素 的 id ,parameter 是更新所需的參數。使用該方法后,會返回執行 SQL語句所影響的行數。
int delete( String statement )
int delete ( String statement ) : 刪除方法 : 參數 statement 是在 “映射文件” 中定義的 <delete>元素 的 id ,使用該方法后,會返回執行 SQL語句所影響的行數。
int delete( String statement , Object parameter)
int delete ( String statement , Object parameter ) : 刪除方法 : 參數 statement 是在 “ 映射文件” 中定義的 <delete>元素 的 id ,parameter 是刪除所需的參數使用該方法后,會返回執行 SQL語句所影響的行數。
int commit( )
int commit ( ) : 提交事務 的方法。
void rollback( )
int rollback ( ) : 回滾事務 的方法。
void close( )
int close ( ) : 關閉SqlSession 對象。
<T> T getMapper( Class<T> type )
- <T> T getMapper ( Class<T> type ) : 該方法會返回 Mapper接口 的 代理對象,該對象關聯了SqlSession對象,開發人員可以使用該對象直接調用方法操作數據庫。參數type是Mapper的接口類型。MyBatis官方推薦通過
Mapper對象訪問MyBatis。- 該方法 : getMapper( ) 的目的是根據傳入的 類類型 :
type
返回一個與該類型匹配的對象。具體實現可能涉及反射機制,用于 創建并返回一個與傳入類類型相匹配的實例。
Connection getConnection( )
Connection getConnection( ) : 獲取 JDBC數據庫連接對象 的方法。
使用工具類創建 “SqlSession” / SqlSession工具類
使用工具類創建 “SqlSession”對象 :
package com.myh.utils;import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder;import java.io.IOException; import java.io.InputStream;/*** 工具類*/ public class SqlSessionUtils { //獲得SqlSession的"工具類"private static SqlSessionFactory sqlSessionFactory = null;//初始化 SqlSessionFactory 對象static { //靜態代碼塊try {//使用Mybatis提供的Resources類加載mybatis-config.xml配置文件InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");//構建SqlSessionFactory工廠SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);} catch (IOException e) {e.printStackTrace();}}/*** 獲得SqlSession對象的靜態方法*/public static SqlSession getSession() {return sqlSessionFactory.openSession();} }
這樣,我們在使用時就 只創建了一個SqlSessionFactory 對象,并且可以通過工具類的 getSession( ) 方法, 來 獲取SqlSession對象。
二、MyBatis的 “配置文件”
MyBatis的核心配置文件中,包含了很多影響MyBatis行為的重要信息。這些信息通常在一個項目中只會在一個配置文件中編寫,并且編寫后也不會輕易改動。
“映射文件”中的 “主要元素”
在 MyBatis 框架的 核心配置文件 (即 mybatis-config.xml )中,<configuration> 元素 是配置文件的 根元素,其他元素都要在 <configuration> 元素內配置。
Mybatis配置文件中 主要元素圖 :(要熟悉 <configuration>元素各個子元素的配置。)
ps :
==<Cofgnaion>的子元素必須按照圖中由上到下==的順序進行配置,否則Mybatis在解新xml配置文件的時候會報錯。
<properties>元素
- <properties>是一個配置屬性的元素,該元素通常用于將內部的配置 “外在化”,即通過外部的配置來動態地替換內部定義的屬性
(直接的使用 : 將外部的 Xxx.properties文件中的屬性用于 mybatis配置文件中 )。
例如,數據庫的連接等屬性,就可以通過典型的 Java屬性文件 ( .properties文件 )中的配置來替換。ps :
當我們在mybatis配置文件中 使用 <properties>元素導入 .properties文件時,即可在mybatis配置文件中,即直接使用 .properties文件中的數據 。db.properties
jdbc.driver = com.mysql.jdbc.Driver jdbc.url = jdbc:mysql://localhost:3306/mybatis jdbc.username = root jdbc.password = root
mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration><!-- properties屬性 --><!-- 通過properties屬性引入 .properties配置文件, mybatis配置文件中則可直接使用 .properties中的數據,進行"動態替換" --><properties resource="db.properties"/><!-- environments屬性 --><environments default="mysql"><environment id="mysql"><transactionManager type="JDBC"/><dataSource type="POOLED"><!--通過“properties屬性”來將 以下的driver、url、username、password 和.properties配置文件 中的數據進行“動態替換”--><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></configuration>
完成上述配置后,dataSource中連接數據庫的4個屬性 ( driver、url、usermame和password值將會由db.properties文件中對應的值來動態替換。這樣就為配置提供了諸多靈活的選擇。
除了可以像上述通過外部配置文件來定義屬性值外,還可以通過配置 <properties>元素的子元素 <property>,以及通過方法參數傳遞的方式來獲取屬性值。由于使用properties配置文件來配置屬性值可以方便地在多個配置文件中使用這些屬性值,并且方便日后的維護和修改,所以在實際開發中,使用.properties文件來配置屬性值是最常用的方式。
<settings>元素
<settings>元素主要用于改變MyBatis運行時的行為,例如 開啟二級緩存、開啟延遲加載 等。
雖然不配置<settings>元素,也可以正常運行MyBatis, 但是熟悉<settings>的配置內容以及它們的作用還是十分必要的。常見的**<settings>屬性配置在 “配置文件” 中的使用** :
<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"/>.....</settings>
<typeAliases>元素
<typeAliases>元素 用于為配置文件中的Java類型設置一個簡短的名字,即 設置別名。別名的設置與XML配置相關,其使用的意義在于減少全限定類名的冗余。 如 : 可用 <typeAliases>元素 為POJO類設置一個 “別名”。
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration><!-- 定義別名 --><typeAliases><!-- typeAlias元素 為 typeAliases元素的 "子元素" --><typeAlias alias="user" type="com.myh.po.Customer"/></typeAliases></configuration>
上述示例中,<typeAliases> 元素的子元素 <typeAlias> 中的type屬性用于指定需要被定義別名的類的全限定名; alias屬性的屬性值user 就是自定義的別名,它可以代替com.myh.po.Customer使用在MyBatis文件的任何位置。如果省略alias屬性,MyBatis 會默認將類名首字母 小寫后的名稱作為別名。
當POJO類過多時,還可以通過自動掃描包 的 形式自定義別名 (此時以類名首字母小寫后的名稱為 “別名”),具體示例如下 :
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration><!-- 定義別名 --><typeAliases><!-- 使用自動掃描包來定義“別名” --><!-- Mybatis會將所用 com.myh.po包中POJO類以首字母小寫的名稱 作為“別名” --><!-- 如: Customer 的 默認設置的別名為: customer --><package name="com.myh.po"/></typeAliases></configuration>
需要注意的是,上述方式的別名只適用于沒有使用注解的情況。如果在程序中使用了注解,則別名為其注解的值, 具體如下 :
//使用注解來為該POJO類設置在 mybatis-config.xml配置文件中使用的 "別名" @Alias(value = "customer") public class Customer { ..... }
除了可以使用 <typeAliases>元素自定義別名外,MyBatis框架還默認為許多常見的Java類型(如數值、 字符串、日期和集合等 )提供了 相應的類型別名。(可使用時查詢常見的Java類型的別名是什么)
?
<typeHandler>元素
MyBatis在 預處理語句( PreparedStatement )中 設置一個參數或者從結果集 ( ResultSet )中取出一個值 時,都會用其框架內部注冊了的 typeHandler ( 類型處理器 ) 進行相關處理。
typeHandler的作用就是將預處理語句 中傳入的參數從 javaType ( Java類型) 轉換為 jdbcType
( JDBC類型),或者從數據庫取出結果時將 jdbcType 轉換為 javaType。為了方便轉換,Mybatis框架提供了一系列默認的類型處理器。
類型處理器 Java 類型 JDBC 類型 BooleanTypeHandler java.lang.Boolean, boolean 數據庫兼容的 BOOLEAN ByteTypeHandler java.lang.Byte, byte 數據庫兼容的 NUMERIC 或 BYTE ShortTypeHandler java.lang.Short, short 數據庫兼容的 NUMERIC 或 SMALLINT IntegerTypeHandler java.lang.Integer, int 數據庫兼容的 NUMERIC 或 INTEGER LongTypeHandler java.lang.Long, long 數據庫兼容的 NUMERIC 或 BIGINT FloatTypeHandler java.lang.Float, float 數據庫兼容的 NUMERIC 或 FLOAT DoubleTypeHandler java.lang.Double, double 數據庫兼容的 NUMERIC 或 DOUBLE BigDecimalTypeHandler java.math.BigDecimal 數據庫兼容的 NUMERIC 或 DECIMAL StringTypeHandler java.lang.String CHAR, VARCHAR ClobReaderTypeHandler java.io.Reader - ClobTypeHandler java.lang.String CLOB, LONGVARCHAR NStringTypeHandler java.lang.String NVARCHAR, NCHAR NClobTypeHandler java.lang.String NCLOB BlobInputStreamTypeHandler java.io.InputStream - ByteArrayTypeHandler byte[] 數據庫兼容的字節流類型 BlobTypeHandler byte[] BLOB, LONGVARBINARY DateTypeHandler java.util.Date TIMESTAMP DateOnlyTypeHandler java.util.Date DATE TimeOnlyTypeHandler java.util.Date TIME SqlTimestampTypeHandler java.sql.Timestamp TIMESTAMP SqlDateTypeHandler java.sql.Date DATE SqlTimeTypeHandler java.sql.Time TIME ObjectTypeHandler Any OTHER 或未指定類型 EnumTypeHandler Enumeration Type VARCHAR 或任何兼容的字符串類型,用來存儲枚舉的名稱(而不是索引序數值) EnumOrdinalTypeHandler Enumeration Type 任何兼容的 NUMERIC 或 DOUBLE 類型,用來存儲枚舉的序數值(而不是名稱)。 SqlxmlTypeHandler java.lang.String SQLXML InstantTypeHandler java.time.Instant TIMESTAMP LocalDateTimeTypeHandler java.time.LocalDateTime TIMESTAMP LocalDateTypeHandler java.time.LocalDate DATE LocalTimeTypeHandler java.time.LocalTime TIME OffsetDateTimeTypeHandler java.time.OffsetDateTime TIMESTAMP OffsetTimeTypeHandler java.time.OffsetTime TIME ZonedDateTimeTypeHandler java.time.ZonedDateTime TIMESTAMP YearTypeHandler java.time.Year INTEGER MonthTypeHandler java.time.Month INTEGER YearMonthTypeHandler java.time.YearMonth VARCHAR 或 LONGVARCHAR JapaneseDateTypeHandler java.time.chrono.JapaneseDate DATE 當MyBatis框架所提供的 這些類型處理器不能夠滿足需求時,還可以通過自定義的方式對類型處理器進行擴展 ( 自定義類型處理器可以通過實現TypeHandler 接口 或者 繼承 BaseTypeHandle類來定義)。
<typeHandler> 元素就是用于在配置文件中注冊自定義的類型處理器的。它的使用方式有兩種 :
① 注冊一個類的類型處理器
②注冊一個包中所有的類型處理器CustomertypeHandler.java
package com.myh.type;import org.apache.ibatis.type.JdbcType; import org.apache.ibatis.type.TypeHandler;import java.sql.CallableStatement; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; public class CustomertypeHandler implements TypeHandler {@Overridepublic void setParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException {} @Overridepublic Object getResult(ResultSet rs, String columnName) throws SQLException {return null;}@Overridepublic Object getResult(ResultSet rs, int columnIndex) throws SQLException {return null;}@Overridepublic Object getResult(CallableStatement cs, int columnIndex) throws SQLException {return null;} }
mybatis-config.xml
<!-- 注冊一個類的類型處理器 --><typeHandlers><!-- 以單個類的形式配置 --><typeHandler handler="com.myh.type.CustomertypeHandler"/></typeHandlers><!-- 注冊一個包中所有類的類型處理器 --><typeHandlers><!-- 注冊一個包中所有的typeHandler,系統在啟動時會自動掃描包下的所有文件 --><package name="com.myh.type"/></typeHandlers>
<objectFactory>元素
MyBatis框架每次創建 結果對象的新實例 時,都會使用一個對象工廠( ObjectFactory )的實例來完成。MyBatis中默認的 ObjectFactory的作用 就是 實例化目標類,它既可以通過默認構造方法實例化,也可以在參數映射存在的時候通過參數構造方法來實例化。
在通常情況下, 我們使用默認的ObjectFactory即可,MyBatis 中默認的ObjectFactory是由org.apache.ibatis rflection.factory.DefaultObjectFactory來提供服務的。大部分場景下都不用配置和修改,但如果想覆蓋ObjectFactory的默認行為,則可以通過自定義ObjectFactory來實現。
MyObjectFactory.java
package com.myh.objFactory;import org.apache.ibatis.reflection.factory.DefaultObjectFactory;import java.util.List; import java.util.Properties;//自定義工廠類 : 該類可以實現ObjectFactory接口 或 繼承 DefaultObjectFactory類 public class MyObjectFactory extends DefaultObjectFactory { //要繼承DefaultObjectFactory類private static final long serialVerSionUID = -4114845625429965832L;@Overridepublic <T> T create(Class<T> type) {return super.create(type);}@Overridepublic <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {return super.create(type, constructorArgTypes, constructorArgs);}@Overridepublic void setProperties(Properties properties) {super.setProperties(properties);}@Overridepublic <T> boolean isCollection(Class<T> type) {return super.isCollection(type);} }
mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration><objectFactory type="com.myh.objFactory.MyObjectFactory"><property name="name" value="MyObjectFactory"/></objectFactory></configuration>
<plugins>元素
- MyBatis允許在已映射語句執行過程中的某一點進行攔截調用,這種攔截調用是通過插件來實現的。<plugins> 元素的作用就是配置用戶所開發的插件。如果用戶想要進行插件開發,必須要先了解其內部運行原理,因為在試圖修改或重寫已有方法的行為時,很可能會破壞MyBatis原 有的核心模塊。
<environments>元素
在配置文件中,<environments>元素用于對環境進行配置。MyBatis的 環境配置 實際上就是 數據源的配置,我們可以通過 <environments>元素配置多種數據源,即配置多種數據庫。
<!-- environments屬性 --><environments default="mysql"><environment id="mysql"><transactionManager type="JDBC"/><dataSource type="POOLED"><!--通過“properties屬性”來將 以下的driver、url、username、password 和.properties配置文件 中的數據進行“動態替換”--><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>
在上述代碼中,<environments>元素是環境配置的 根元素,它包含個一default屬性,該屬性用于指定默認的環境ID。 是 <environments>元素的 “子元素”,它 : <environment> 可以定義多個,其記屬性用于表示所定義環境的ID值。在 environment元素內,包含事務管理 ( transactionManager ) 和 數據源 ( dataSource ) 的配置信息,其 <transactionManager>元素用于配置事務管理,它的type屬性用于指定事務管理的方式,即使用哪種事務管理器;<dalaSource>元素用于配置數據源,它的type屬性用于指定使用哪種數據源。
在MyBatis中,可以配置兩種類型的事務管理器,分別是 JDBC 和 MANAGED。JDBC : 此配置直接使用了JDBC的提交和回滾設置,它依賴于從數據源得到的連接來管理事務的作用域。
MANAGED : 此配置從來不提交或回滾一個連接 ,而是讓容器來管理事務的整個生命周期。
在默認情況下,它會關閉連接,但一些容器并不希望這樣,為此可以將closeConnection屬性設
置為false來阻止它默認的關閉行為。ps :
如果沒有必要中 使用的是 Spring+ MyBatis,則 沒有必要 在MyBatis ( mybatis-config.xml ) 中 配置事務管理器,因為實際開發中,會使用Spring自帶的管理器來實現事務管理。
<mappers>元素
在配置文件 ( mybatis-config.xml )中,<mappers>元素 用于 指定MyBatis 映射文件 (引入“映射文件”)(XxxMapper.xml )的 位置,一般可以使用以下 4種方法 引入映射文件。 ( 一個mybatis-config.xml 配置文件可以引入多個“映射文件”。)
① 使用 “類路徑” 引入
② 使用 “本地文件路徑” 引入
③ 使用 “接口類” 引入
④ 使用 “包名” 引入① 使用 “類路徑” 引入
<mappers><!-- 使用"類路徑"讀取"映射文件" --><mapper resource="com/myh/mapper/CustomerMapper.xml"/> </mappers>
② 使用 “本地文件路徑” 引入
<mappers><!-- 使用“本地文件路徑”引入“映射文件” --><mapper url="file:///D:/com/myh/mapper/CustomerMapper.xml"/></mappers>
③ 使用 “接口類” 引入
<mappers><!-- 使用“接口類”引入“映射文件” --><mapper class="com.myh.mapper.CustomerMapper"/> </mappers>
④ 使用 “包名” 引入
<mappers><!-- 使用“包名”引入“映射文件” --><package name="com.myh.mapper"/> </mappers>
三、MyBatis的 “映射文件”
- 映射文件 ( XxxMapper.xml )是Mybatis框架中十分重要的文件,可以說,Mybatis框架的強大之處就體現在“映射文件”的編寫上。
- 在映射文件中,<mapper>元素 是映射文件的根元素,其他元素都是它的子元素。
“配置文件”中的 “主要元素”
<select>元素
<select>元素 用于映射 “查詢語句”,它可以幫助我們從數據庫中讀出數據,并組裝數據給企業開發者。
<!-- “查詢數據”--><select id="findCustomerById" parameterType="Integer" resultType="com.myh.po.Customer">select * from t_customer where id = #{id}</select>
上述語句中的唯一標識為 findCustomerByld,它接收一個 Integer 類型的參數,并返回一個Customer類型的對象。
<select>元素中,除了上述代碼中的幾個屬性外,還有其他一些可以配置的屬性,如下所示 :
屬性 說明 id 表示命名空間中的唯一標識符, 常與命名空間組合起來使用。組合后如果不唯一, MyBatis會拋出異常。 parameterType 該屬性表示傳入SQL語句的參數類的全限定名或者別名。它是一個可選屬性, 因為MyBatis可以通過TypeHandler推斷出具體傳入語句的參數。其默認值是unset (依賴于驅動)。 resultType 從SQL語句中返回的類型的類的全限定名或者別名。如果是集合類型,那么返回的應該是集合可以包含的類型,而不是集合本身。返回時可以使用resultType或resultMap之一。 resultMap 表示外部resultMap的命名引用。返回時可以使用resultType或resultMap之一。 flushCache 表示在調用SQL語句之后,是否需要MyBatis清空之前查詢的本地緩存和二級緩存。其值為布爾類型( truelfalse),默認值為false。如果設置為true,則任何時候只要SQL語句被調用,都會清空本地緩存和二級緩存。 useCache 用于控制二級緩存的開啟和關閉。其值為布爾類型( truelfalse),默認值為true,表示將查詢結果存入二級緩存中。 timeout 用于設置超時參數,單位為秒。超時將拋出異常。 fetchSize 獲取記錄的總條數設定,其默認值是unset (依賴于驅動)。 statementType 用于設置MyBatis使用哪個JDBC的Statement工作,其值為STATEMENT、PREPARED(默認值) 或CALLABLE, 分別對應JDBC中的Statement 、PreparedStatement 和 CallableStatement。
屬性 說明 resultSetType 表示結果集的類型,其值可設置為FORWARD_ONLY、SCROLL_SENSITIVE 或SCROLL_INSENSITIVE, 它的默認值是unset (依賴于驅動)。
<insert>元素
- <insert>元素用于映射“插入語句”,在執行完元素中定義的SQL語句后,會返回一個表示插入記錄數的整數。
<!--useGeneratedKeys="true" : 獲得該insert語句插入數據庫時形成的“主鍵id” / 獲得數據庫內部產生的主鍵idkeyProperty="id" : 將插入或更新時的“返回值”賦值到PO類的對應的“屬性”上 : 即將剛獲得的“主鍵id”賦值到PO類對應的id屬性上--> <!-- 該insert語句的返回值 : ①返回插入成功的行數 ②插入行的主鍵id --> <insert id="addCustomer" parameterType="com.myh.po.Customer"flushCache="true" statementType="PREPARED"keyProperty="id" keyColumn="" useGeneratedKeys="true" timeout="20">insert into t_customer(username,jobs,phone)values(#{username},#{jobs},#{phone}) </insert>
以上的 insert語句的返回值 : ①返回插入成功的行數 ②插入行的主鍵id。
從上述代碼中可以看出,<insert>元素的屬性 與 <select>元素 的 屬性大部分相同,<insert>元素包含了 3個特有屬性。
- <insert>元素 中的三個特有 屬性 :
屬性 說明 keyProperty ( 僅對insert和update有用 )此屬性 ( keyProperty )的作用是將插入 或 更新操作時的返回值賦值給 PO類的某個屬性,通常會設置為“主鍵”對應的屬性。
(通常會設置該屬性的值為“id” (即將插入形成的“主鍵id”值賦值到PO類中 )。如果需要設置聯合主鍵,可以在多個值之間用逗號隔開。
例子如 :
keyProperty =“i‘d” ( 要結合useGeneratedKeys屬性使用 ) :
將useGeneratedKeys屬性獲得的 ( 插入形成的 ) “主鍵id” 賦值到PO類的對應的id屬性上,這樣就能獲得insert語句生成的數據對應的“主鍵id”了。keyColumn ( 僅對insert和update有用 ) 此屬性用于 設置第幾列是主鍵,當主鍵列不是表中的第一列時需要設置,在需要主鍵聯合時,值可以使用逗號隔開。 useGeneratedKeys ( 僅對insert和update有用 )此屬性會使 MyBatis 使用 JDBC 的 getGeneratedKeys( )方法來獲取由數據庫內部生產的 主鍵 (此時一般配合keyProperty屬性使用來將該“主鍵 賦值給PO類對應的屬性上。”), 如MySQL和SQL Server等自動遞增的字段,其 默認值為false。 執行插入操作后,很多時候我們會需要返回插入成功的數據生成的主鍵值 ( 表中主鍵id ),此時就可以通過
上面所講解的3個屬性來實現。
- 如果使用的數據庫支持主鍵自動增長 (如MySQL ),那么可以通過keyProperty屬性 指定PO類的某個屬性接收主鍵返回值 ( 通常會設置到id屬性上 : 將主鍵id賦值給PO類的 id屬性上 ),同時還要通過 useGeneratedKeys屬性才能實現目標功能。 例子如下 :
<insert>元素 中的三個特有 屬性 例子如 :
CustomerMapper.xml (映射文件) :
<!--useGeneratedKeys="true" : 獲得該insert語句插入數據庫時形成的“主鍵id” / 獲得數據庫內部產生的主鍵idkeyProperty="id" : 將插入或更新時的“返回值”賦值到PO類的對應的“屬性”上 : 即將剛獲得的“主鍵id”賦值到PO類對應的id屬性上--> <!-- 該insert語句的返回值 : ①返回插入成功的行數 ②插入行的主鍵id --> <insert id="addCustomer" parameterType="com.myh.po.Customer"keyProperty="id" useGeneratedKeys="true" >insert into t_customer(username,jobs,phone)values(#{username},#{jobs},#{phone}) </insert>
以上的 insert語句的返回值 : ①返回插入成功的行數 ②插入行的主鍵id。
CustomerTest.java (測試類) :
public class CustomerTest {@org.junit.Test //單元測試public void addCustomerTest() throws IOException {//1.讀取mybatis框架的配置文件String resource = "com/myh/映射文件的元素/mybatis-config.xml";//通過“輸入流”讀取mybatis配置文件/*在該mybatis-config.xml配置文件中,已配置了“數據源”信息 和配置了"映射文件 : XxxMapper.xml”的位置,可實施加載“映射文件”*/InputStream inputStream = Resources.getResourceAsStream(resource);//2.根據配置文件“構建會話工廠 : SqlSessionFactory ”SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);//3.通過SqlSessionFactory(會話工廠)創建SqlSession("會話"對象)SqlSession sqlSession = sqlSessionFactory.openSession();Customer customer = new Customer();customer.setUsername("小藍");customer.setJobs("學生");customer.setPhone("12345678");//將該Customer對象存入到數據庫中,同時目的是: 將存入到數據庫中的數據對應的“主鍵id”獲得且返回int insert = sqlSession.insert("CustomerMapper.addCustomer", customer);/*** 輸出"插入數據"形成的"主鍵id值" (從數據庫中獲得的主鍵id值是存儲在Customer這個PO類中的)*/System.out.println(customer.getId());if (insert > 0) {System.out.println("你成功插入了" + insert + "條數據!");} else {System.out.println("插入數據操作失敗! ");}//4.設置“事務管理”sqlSession.commit();//5.關閉SqlSessionsqlSession.close();} }
通過上述的<insert>元素的三個特有屬性,即可獲得插入數據的對應的 “ 主鍵id”。
如果使用的數據庫不支持主鍵自動增長 (如Oracle ), 或者支持增長的數據庫 取消了主鍵自增 的規則時,也可以使用MyBatis提供的另一種方式來自定義生成主鍵。 例子如下 :
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!--映射文件中,插入數據用 <insert>元素 --> <!-- #{} : 相當于"占位符" ${} : 相當于在sql語句后要拼接的"字符串" --> <mapper namespace="CustomerMapper"><insert id="insertCustomer" parameterType="com.myh.po.Customer"><selectKey keyProperty="id" resultType="Integer" order="BEFORE">select if(max(id) is null,1,max(id) + 1)as newId from t_customer</selectKey>insert into t_customer(username,jobs,phone)values(#{username},#{jobs},#{phone})</insert></mapper>
上述代碼中,<selectKey> 元素會首先運行,它會通過自定義的語句來設置數據中的主鍵 (如果
t_customer表中沒有記錄,則將id設置為1,否則就將id的最大值加1,來為新的主鍵),然后再調用插入語句。
<selectKey>元素在使用時可以設置以下幾種屬性 :<selectKeykeyProperty="id"resultType="Integer"order="BEFORE"statementType="PREPARED">
在上述 <selectKey>元素的幾個屬性中,keyProperty、 resultType 和statementType的作用與前面講解的相同,order 屬性可以被設置為BEFORE或AFTER。如果設置為BEFORE,那么它會首先執行 <selectKey>元素中的配置來設置主鍵,然后執行插入語句;如果設置為AFTER,那么它會先執行插入語句,然后執行 <selectKey>元素中的配置內容。
<update>元素和<delete>元素
- <update> 和 <delete>元素 的使用比較簡單,它們的屬性配置也基本相同 ,其常用屬性如下 :
<!-- 更新 --><update id="updateCustomer" parameterType="com.myh.po.Customer"flushCache="true" statementType="PREPARED" timeout="20"></update><!-- 刪除 --><delete id="deleteCustomer" parameterType="com.myh.po.Customer"flushCache="true" statementType="PREPARED" timeout="20"></delete>
從上述配置代碼中可以看出,<update>和<delete>元素的屬性基本與 <select>元素中的屬性一致。
與 <insert>元素一樣,<update> 和<delete>元素在執行完之后,也會返回一個表示影響記錄條數的整數,其使用示例如下 :<!-- 更新 --> <update id="updateCustomer" parameterType="com.myh.po.Customer">update t_customer set username = #{username},jobs=#{jobs},phone=#{phone}where id = #{id}</update><!-- 刪除 --><delete id="deleteCustomer" parameterType="Integer">delete from t_customer where id = #{id}</delete>
<sql>元素
在一個映射文件中,通常需要定義多條SQL語句,這些SQL語句的組成可能有一部分是相同的 ( 如多條select語句中都查詢相同的id、username、 jobs 字段),如果每一個SQL語句都重寫遍相同的部分, 勢必會增加代碼量,導致映射文件過于臃腫。
那么有沒有什么辦法將這些SQL語句中相同的組成部分抽取出來,然后在需要的地方引用呢 ?
答案是肯定的,我們可以在映射文件中使用MyBatis所提供的 <sql>元素來解決上述問題。<sql>元素的作用 : 就是定義可重用的SQL代碼片段,然后在其他語句中引用這一代碼片段。例子如 :
<sql id="customerColumns"> id,username,jobs,phone</sql><select id="findCustomerById" parameterType="Integer" resultType="com.myh.po.Customer">select <include refid="customerColumns"/>from t_customerwhere id = #{id}</select>
<resultMap>元素 (可解決“屬性名” 和 “字段名”不一樣導致的數據無法映射成功的問題)
<resultMap>元素表示結果映射集,是 MyBatis中最重要 也是 最強大 的元素。它的主要作用 : 是
定義映射規則、級聯的更新 以及 定義類型轉化器 等。ps :
<resultMap>元素 可解決“屬性名” 和 “字段名” 不一樣導致的數據無法映射成功的問題。<resutMap>元素中包含了屬性 / 子元素,如下所示 :
<!-- resultMap的元素結構 --><resultMap type="" id=""><constructor> <!-- 類在實例時,用來注入"結果"到"結構方法"中 --><idArg/> <!-- ID參數;標記結果為ID --><arg/> <!-- 注入到構造方法的一個普通結果 --></constructor><id/> <!-- 用于表示哪個"列"是"主鍵" --><result/> <!-- 注入到“字段”或“JavaBean屬性”的普通結果 --><association property=""/> <!-- 用于一對一關聯 --><collection property=""/> <!-- 用于一對多關聯 --><discriminator javaType=""> <!-- 使用"結果值"來決定哪個"結果映射"--><case value=""></case></discriminator></resultMap>
<resutMap>元素 的 屬性 關系如下表所示 :
屬性 描述 type 表示需要 映射 的POJO ( 普通Java對象 ) id 這個 resultMap 的 唯一標識。 <resutMap>元素 的 子元素 關系如下表所示 :
子元素 描述 <constructor> 用于配置構造方法 ( 當一個POJO中未定義無參的構造方法時,就可以使用 <constructor>元素 進行配置)。 <id> 分別標記 POJO中屬性中的“主鍵”和 標記數據庫表中字段的 “主鍵”,并 將二者進行關聯。
ps :
這意味著,通過 <resultMap> 中的 <id>元素的配置,POJO 中 “主鍵”屬性名 不用 和數據庫中 “主鍵”名相同。<result> 表示 POJO 中 “屬性”和 數據庫表中列 的 映射關系。(用于將 POJO中 “屬性”和 數據庫表中的 “列”進行關聯。 )
ps :
這意味著,通過 <resultMap> 中的 <result>元素的配置,數據庫中的 “字段” 以及 該“字段”相對應的 “屬性”名,不用一致。(在 <result>中設置各自的名稱即可)<association> 表示“一對一”關聯。用于處理“多表”時的關聯關系。 <collection> 表示“一對多”關聯。用于處理“多表”時的關聯關系。 <discriminator> 使用"結果值"來決定哪個"結果映射"。用于處理一個單獨的數據庫查詢 返回很多不同數據類型 結果集的情況。 在默認情況下,MyBatis程序在運行時會 自動地將查詢到的數據與需要返回的對象的屬性進行匹配賦值 ( 需要表中的 列名與對象的屬性名稱完全一致 )。 然而實際開發時,數據表中的列和需要返回的對象的屬性可能不會完全一致, 這種情況下MyBatis是不會自動賦值的。此時,就可以使用 <resultMap>元素進行處理。
實際開發中,如果當POJO中“屬性名” 和 數據庫中“字段名” 不一致,此時查詢數據庫,數據會無法映射到POJO類中,最后導致查詢到的內容為 : null。 此時用 <resultMap>元素即可解決這個問題。
例子如:
此時可使用“映射文件” 中的因屬性名 和 字段名不一致而導致的數據無法映射到POJO中的問題。如下所示 :
UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="UserMapper"><!-- select元素中使用resultType時,當數據庫中"字段名" 和POJO中"屬性名"不一致時,select的數據將則無法映射到POJO類中,即輸出內容為null --><!-- select元素中用resultMap時,數據庫中“字段名” 和 POJO中“屬性名”不用保持一致,此時也能完成將select到的數據映射到POJO類中--><select id="selectUser_resultType" resultType="com.myh.po.User" parameterType="Integer">select * from t_user where t_id = #{id}</select><!--上面這個select的查詢的數據是無法映射到POJO類中,即select的數據為null,因為數據庫中“字段名” 和 POJO中的“屬性名”,此時可用 <resultMap>元素來解決這個問題 --><resultMap id="resultMap" type="com.myh.po.User"><!-- 下面配置的目的 : "屬性名" 和 "字段名" 可以不用保持一致 --><id property="id" column="t_id"/><result property="name" column="t_name"/><result property="age" column="t_age"/></resultMap><!-- 因為此處用了resultMap(已經配置好了,完成各種內容的“映射了”,所以即使"屬性名" 和 “字段名”不一致,也能select到數據) --><select id="selectUser_resultMap" resultMap="resultMap" parameterType="Integer">select * from t_user where t_id = #{id}</select></mapper>
UserTest.java (測試類)
public class UserTest {@org.junit.Test //單元測試public void selectUser_resultType_resultMap_Test() throws IOException {//1.讀取mybatis框架的配置文件String resource = "com/myh/映射文件的元素/mybatis-config.xml";InputStream inputStream = Resources.getResourceAsStream(resource);//2.根據配置文件“構建會話工廠 : SqlSessionFactory ”SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);//3.通過SqlSessionFactory(會話工廠)創建SqlSession("會話"對象)SqlSession sqlSession = sqlSessionFactory.openSession();User user1 = (User)sqlSession.selectOne("UserMapper.selectUser_resultType", 2);/**此處輸出的內容為 : null ,因為字段名和屬性名 不一樣,數據無法映射成功,最后輸出的內容為 : null*/System.out.println("從數據庫中查詢到的數據為(通過resultType獲得): "+user1);/**此處輸出的內容為 : "查詢到的數據",即使“屬性名” 和 “字段名”沒有保持一致,但通過resultMap元素的配置,查詢到的數據依然能映射到POJO類中。*/User user2 = (User)sqlSession.selectOne("UserMapper.selectUser_resultMap", 2);System.out.println("從數據庫中查詢到的數據為(通過resultMap獲得): "+user2);//4.關閉SqlSessionsqlSession.close();} }
控制臺輸出結果為 :