MyBatis配置
目標:MyBatis官網 https://mybatis.org/mybatis-3/zh/configuration.html
掌握properties 元素的用法
掌握setting 元素的用法
掌握typeAliases 的用法
重點掌握typeHandler在Mybatis中的用法
了解ObjectFactory的作用
了解environments 的配置
了解databaseIdProvider 的用法
掌握如何有效引入映射器
概述
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="xml" cid="n22" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit;"><?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></properties>
<setting></setting>
<typeAliases>
<typeAlias alias="role" type="com.zw.pojo.Role"/>
</typeAliases>
<typeHandler></typeHandler>
<ObjectFactory></ObjectFactory>
<plugins></plugins>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/chapter3"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<databaseIdProvider></databaseIdProvider>
<mappers>
<mapper resource="com/zw/mapper/RoleMapper.xml"/>
</mappers>
</configuration>
</pre>
properties 屬性
properties 屬性可以給系統配置一些運行參數缰盏,可以放在xml文件或者properties文件中滑凉,而不是java代碼中。
優(yōu)點:方便參數修改昵济,而不引起代碼重新編譯
Mybatis提供3種方式使用properties:
propertie子元素
properties文件
程序代碼傳遞
propertie子元素
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="xml" cid="n35" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit;"><?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></properties>
<setting></setting>
<typeAliases>
<typeAlias alias="role" type="com.zw.pojo.Role"/>
</typeAliases>
<typeHandler></typeHandler>
<ObjectFactory></ObjectFactory>
<plugins></plugins>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/chapter3"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<databaseIdProvider></databaseIdProvider>
<mappers>
<mapper resource="com/zw/mapper/RoleMapper.xml"/>
</mappers>
</configuration>
</pre>
properti
es文件
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="xml" cid="n39" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit;"><?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="jdbc.properties">
</properties>
<typeAliases>
<package name="com.learn.ssm.chapter4.pojo" />
</typeAliases>
<typeHandlers>
<package name="com.learn.ssm.chapter4.typehandler" />
</typeHandlers>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource
type="com.learn.ssm.chapter4.datasource.DbcpDataSourceFactory">
<property name="driver" value="{database.url}" />
<property name="username" value="{database.password}" />
</dataSource>
</environment>
</environments>
<databaseIdProvider
type="com.learn.ssm.chapter4.databaseidprovider.MyDatabaseIdProvider">
<property name="msg" value="自定義DatabaseIdProvider" />
</databaseIdProvider>
<mappers>
<package name="com.learn.ssm.chapter4.mapper" />
</mappers>
</configuration></pre>
properties
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="properties" cid="n41" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit;">database.driver=com.mysql.jdbc.Driver
database.url=jdbc:mysql://localhost:3306/chapter4
database.username=root
database.password=123456</pre>
程序代碼傳遞
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n43" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit;">public static SqlSessionFactory getSqlSessionFactory() {
synchronized (LOCK) {
if (sqlSessionFactory != null) {
return sqlSessionFactory;
}
String resource = "mybatis-config.xml";
InputStream inputStream;
try {
inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new
SqlSessionFactoryBuilder().build(inputStream);
//采用程序傳遞加密參數,啟用它之前,修改用戶密碼為密文,可參考main方法......
// InputStream in = Resources.getResourceAsStream("jdbc.properties");
// Properties props = new Properties();
// props.load(in);
// String username = props.getProperty("database.username");
// String password = props.getProperty("database.password");
// // 解密用戶和密碼奇昙,并在屬性中重置
// props.put("database.username", CodeUtils.decode(username));
// props.put("database.password", CodeUtils.decode(password));
// inputStream = Resources.getResourceAsStream(resource);
// // 使用程序傳遞的方式覆蓋原有的properties屬性參數
// sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream, props);
} catch (IOException e) {
e.printStackTrace();
return null;
}
return sqlSessionFactory;
}
}</pre>
總結:Mybatis使用properties用36種方式,優(yōu)先級:properey--》 properties文件--》程式傳遞
setting 元素
setting是MyBatis中最復雜的配置才顿,它能深刻影響MyBatis底層運行恩商,但部分使用默認方式即可。
一般使用:自動映射贝搁,駝峰影視吗氏,級聯映射,是否啟動緩存雷逆,執(zhí)行器類型弦讽。
這是 MyBatis 中極為重要的調整設置,它們會改變 MyBatis 的運行時行為膀哲。 下表描述了設置中各項設置的含義坦袍、默認值等。
設置名 | 描述 | 有效值 | 默認值 | ||||||
---|---|---|---|---|---|---|---|---|---|
cacheEnabled | 全局性地開啟或關閉所有映射器配置文件中已配置的任何緩存等太。 | true | false | true | |||||
lazyLoadingEnabled | 延遲加載的全局開關捂齐。當開啟時,所有關聯對象都會延遲加載缩抡。 特定關聯關系中可通過設置 fetchType 屬性來覆蓋該項的開關狀態(tài)奠宜。 |
true | false | false | |||||
aggressiveLazyLoading | 開啟時,任一方法的調用都會加載該對象的所有延遲加載屬性瞻想。 否則压真,每個延遲加載屬性會按需加載(參考 lazyLoadTriggerMethods )。 |
true | false | false (在 3.4.1 及之前的版本中默認為 true) | |||||
multipleResultSetsEnabled | 是否允許單個語句返回多結果集(需要數據庫驅動支持)蘑险。 | true | false | true | |||||
useColumnLabel | 使用列標簽代替列名滴肿。實際表現依賴于數據庫驅動,具體可參考數據庫驅動的相關文檔佃迄,或通過對比測試來觀察泼差。 | true | false | true | |||||
useGeneratedKeys | 允許 JDBC 支持自動生成主鍵,需要數據庫驅動支持呵俏。如果設置為 true堆缘,將強制使用自動生成主鍵。盡管一些數據庫驅動不支持此特性普碎,但仍可正常工作(如 Derby)吼肥。 | true | false | False | |||||
autoMappingBehavior | 指定 MyBatis 應如何自動映射列到字段或屬性。 NONE 表示關閉自動映射;PARTIAL 只會自動映射沒有定義嵌套結果映射的字段缀皱。 FULL 會自動映射任何復雜的結果集(無論是否嵌套)斗这。 | NONE, PARTIAL, FULL | PARTIAL | ||||||
autoMappingUnknownColumnBehavior | 指定發(fā)現自動映射目標未知列(或未知屬性類型)的行為。NONE : 不做任何反應WARNING : 輸出警告日志('org.apache.ibatis.session.AutoMappingUnknownColumnBehavior' 的日志等級必須設置為 WARN )FAILING : 映射失敗 (拋出 SqlSessionException ) |
NONE, WARNING, FAILING | NONE | ||||||
defaultExecutorType | 配置默認的執(zhí)行器啤斗。SIMPLE 就是普通的執(zhí)行器表箭;REUSE 執(zhí)行器會重用預處理語句(PreparedStatement); BATCH 執(zhí)行器不僅重用語句還會執(zhí)行批量更新争占。 | SIMPLE REUSE BATCH | SIMPLE | ||||||
defaultStatementTimeout | 設置超時時間燃逻,它決定數據庫驅動等待數據庫響應的秒數。 | 任意正整數 | 未設置 (null) | ||||||
defaultFetchSize | 為驅動的結果集獲取數量(fetchSize)設置一個建議值臂痕。此參數只可以在查詢設置中被覆蓋伯襟。 | 任意正整數 | 未設置 (null) | ||||||
defaultResultSetType | 指定語句默認的滾動策略。(新增于 3.5.2) | FORWARD_ONLY | SCROLL_SENSITIVE | SCROLL_INSENSITIVE | DEFAULT(等同于未設置) | 未設置 (null) | |||
safeRowBoundsEnabled | 是否允許在嵌套語句中使用分頁(RowBounds)握童。如果允許使用則設置為 false姆怪。 | true | false | False | |||||
safeResultHandlerEnabled | 是否允許在嵌套語句中使用結果處理器(ResultHandler)。如果允許使用則設置為 false澡绩。 | true | false | True | |||||
mapUnderscoreToCamelCase | 是否開啟駝峰命名自動映射稽揭,即從經典數據庫列名 A_COLUMN 映射到經典 Java 屬性名 aColumn。 | true | false | False | |||||
localCacheScope | MyBatis 利用本地緩存機制(Local Cache)防止循環(huán)引用和加速重復的嵌套查詢肥卡。 默認值為 SESSION溪掀,會緩存一個會話中執(zhí)行的所有查詢。 若設置值為 STATEMENT步鉴,本地緩存將僅用于執(zhí)行語句揪胃,對相同 SqlSession 的不同查詢將不會進行緩存。 | SESSION | STATEMENT | SESSION | |||||
jdbcTypeForNull | 當沒有為參數指定特定的 JDBC 類型時氛琢,空值的默認 JDBC 類型喊递。 某些數據庫驅動需要指定列的 JDBC 類型,多數情況直接用一般類型即可阳似,比如 NULL骚勘、VARCHAR 或 OTHER。 | JdbcType 常量撮奏,常用值:NULL俏讹、VARCHAR 或 OTHER。 | OTHER | ||||||
lazyLoadTriggerMethods | 指定對象的哪些方法觸發(fā)一次延遲加載挽荡。 | 用逗號分隔的方法列表藐石。 | equals,clone,hashCode,toString | ||||||
defaultScriptingLanguage | 指定動態(tài) SQL 生成使用的默認腳本語言。 | 一個類型別名或全限定類名定拟。 | org.apache.ibatis.scripting.xmltags.XMLLanguageDriver | ||||||
defaultEnumTypeHandler | 指定 Enum 使用的默認 TypeHandler 。(新增于 3.4.5) |
一個類型別名或全限定類名。 | org.apache.ibatis.type.EnumTypeHandler | ||||||
callSettersOnNulls | 指定當結果集中值為 null 的時候是否調用映射對象的 setter(map 對象時為 put)方法青自,這在依賴于 Map.keySet() 或 null 值進行初始化時比較有用株依。注意基本類型(int、boolean 等)是不能設置成 null 的延窜。 | true | false | false | |||||
returnInstanceForEmptyRow | 當返回行的所有列都是空時恋腕,MyBatis默認返回 null 。 當開啟這個設置時逆瑞,MyBatis會返回一個空實例荠藤。 請注意,它也適用于嵌套的結果集(如集合或關聯)获高。(新增于 3.4.2) |
true | false | false | |||||
logPrefix | 指定 MyBatis 增加到日志名稱的前綴哈肖。 | 任何字符串 | 未設置 | ||||||
logImpl | 指定 MyBatis 所用日志的具體實現,未指定時將自動查找念秧。 | SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING | 未設置 |
proxyFactory | 指定 Mybatis 創(chuàng)建可延遲加載對象所用到的代理工具淤井。 | CGLIB | JAVASSIST | JAVASSIST (MyBatis 3.3 以上) | |||||
vfsImpl | 指定 VFS 的實現 | 自定義 VFS 的實現的類全限定名,以逗號分隔摊趾。 | 未設置 | ||||||
useActualParamName | 允許使用方法簽名中的名稱作為語句參數名稱币狠。 為了使用該特性,你的項目必須采用 Java 8 編譯砾层,并且加上 -parameters 選項漩绵。(新增于 3.4.1) |
true | false | true | |||||
configurationFactory | 指定一個提供 Configuration 實例的類。 這個被返回的 Configuration 實例用來加載被反序列化對象的延遲加載屬性值肛炮。 這個類必須包含一個簽名為static Configuration getConfiguration() 的方法止吐。(新增于 3.2.3) |
一個類型別名或完全限定類名。 | 未設置 | ||||||
shrinkWhitespacesInSql | 從SQL中刪除多余的空格字符铸董。請注意祟印,這也會影響SQL中的文字字符串。 (新增于 3.5.5) | true | false | false | |||||
defaultSqlProviderType | Specifies an sql provider class that holds provider method (Since 3.5.6). This class apply to the type (or value ) attribute on sql provider annotation(e.g. @SelectProvider ), when these attribute was omitted. |
A type alias or fully qualified class name | Not set |
一個配置完整的 settings 元素的示例如下:
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="xml" cid="n207" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit;"><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="autoMappingUnknownColumnBehavior" value="WARNING"/>
<setting name="defaultExecutorType" value="SIMPLE"/>
<setting name="defaultStatementTimeout" value="25"/>
<setting name="defaultFetchSize" value="100"/>
<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></pre>
類型別名(typeAliases)
類型別名可為 Java 類型設置一個縮寫名字粟害。 它僅用于 XML 配置蕴忆,意在降低冗余的全限定類名書寫。例如:
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="xml" cid="n211" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit;"><typeAliases>
<typeAlias alias="Author" type="domain.blog.Author"/>
<typeAlias alias="Blog" type="domain.blog.Blog"/>
<typeAlias alias="Comment" type="domain.blog.Comment"/>
<typeAlias alias="Post" type="domain.blog.Post"/>
<typeAlias alias="Section" type="domain.blog.Section"/>
<typeAlias alias="Tag" type="domain.blog.Tag"/>
</typeAliases></pre>
當這樣配置時悲幅,Blog
可以用在任何使用 domain.blog.Blog
的地方套鹅。
也可以指定一個包名,MyBatis 會在包名下面搜索需要的 Java Bean汰具,比如:
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="xml" cid="n214" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit;"><typeAliases>
<package name="domain.blog"/>
</typeAliases></pre>
每一個在包 domain.blog
中的 Java Bean卓鹿,在沒有注解的情況下,會使用 Bean 的首字母小寫的非限定類名來作為它的別名留荔。 比如 domain.blog.Author
的別名為 author
吟孙;若有注解,則別名為其注解值。見下面的例子:
<pre spellcheck="false" class="md-fences mock-cm md-end-block" lang="java" cid="n216" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit;">@Alias("author")
public class Author {
...
}</pre>
下面是一些為常見的 Java 類型內建的類型別名杰妓。它們都是不區(qū)分大小寫的藻治,注意,為了應對原始類型的命名重復巷挥,采取了特殊的命名風格桩卵。
別名 | 映射的類型 |
---|---|
_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 |
object | Object |
map | Map |
hashmap | HashMap |
list | List |
arraylist | ArrayList |
collection | Collection |
iterator | Iterator |
類型處理器(typeHandlers)
MyBatis 在設置預處理語句(PreparedStatement)中的參數或從結果集中取出一個值時, 都會用類型處理器將獲取到的值以合適的方式轉換成 Java 類型倍宾。下表描述了一些默認的類型處理器雏节。
提示 從 3.4.5 開始,MyBatis 默認支持 JSR-310(日期和時間 API) 高职。
類型處理器 | 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[] |
數據庫兼容的字節(jié)流類型 |
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
步驟1:實現TypeHandler接口
<pre spellcheck="false" class="md-fences mock-cm md-end-block" lang="java" cid="n463" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit;">import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;
import org.apache.ibatis.type.TypeHandler;
/**
@author
-
java中的boolean和jdbc中的char之間轉換;true-Y;false-N
*/
//方式一:
@MappedJdbcTypes(JdbcType.CHAR)
@MappedTypes(Boolean.class)
public class BooleanTypeHandler implements TypeHandler {/* (non-Javadoc)
- @see org.apache.ibatis.type.TypeHandler#getResult(java.sql.ResultSet, java.lang.String)
*/
@Override
public Object getResult(ResultSet resultSet, String columnLabel) throws SQLException {
String str = resultSet.getString(columnLabel);
Boolean rt = Boolean.FALSE;
if (str.equalsIgnoreCase("Y")){
rt = Boolean.TRUE;
}
return rt;
}
@Override
public Object getResult(ResultSet resultSet, int columnIndex) throws SQLException {
String str = resultSet.getString(columnIndex);
Boolean rt = Boolean.FALSE;
if (str.equalsIgnoreCase("Y")){
rt = Boolean.TRUE;
}
return rt;
}/* (non-Javadoc)
- @see org.apache.ibatis.type.TypeHandler#getResult(java.sql.CallableStatement, int)
*/
@Override
public Object getResult(CallableStatement arg0, int arg1)
throws SQLException {
Boolean b = arg0.getBoolean(arg1);
return b == true ? "Y" : "N";
}
/* (non-Javadoc)
- @see org.apache.ibatis.type.TypeHandler#setParameter(java.sql.PreparedStatement, int, java.lang.Object, org.apache.ibatis.type.JdbcType)
*/
@Override
public void setParameter(PreparedStatement arg0, int arg1, Object arg2,
JdbcType arg3) throws SQLException {
Boolean b = (Boolean) arg2;
String value = (Boolean) b == true ? "Y" : "N";
arg0.setString(arg1, value);
}
} </pre>
- @see org.apache.ibatis.type.TypeHandler#getResult(java.sql.ResultSet, java.lang.String)
步驟2:在Mybatis配置中注冊該TypeHandler
<pre spellcheck="false" class="md-fences mock-cm md-end-block" lang="xml" cid="n466" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit;"><bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="mapperLocations" value="classpath:dao/mapper/*.xml"></property>
<property name="typeHandlers" >
<array>
<bean class="com.sankuai.travel.csc.test.dao.typehandler.BooleanTypeHandler" />
</array>
</property>
<property name="plugins">
<array>
<bean class="com.sankuai.travel.csc.test.dao.interceptor.SqlMonitorInterceptor" />
</array>
</property>
</bean></pre>
步驟3:在映射配置文件中使用該TypeHander(如果第一步使用了注解件蚕,此處可以省略)
3.1在resultMap的定義中對對應列定義typeHandler
<pre spellcheck="false" class="md-fences mock-cm md-end-block" lang="xml" cid="n470" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit;"><resultMap id="BaseResultMap" type="com.sankuai.travel.csc.test.dao.domain.CategoryDO" >
<id column="id" property="id" jdbcType="INTEGER" />
<result column="category_type" property="categoryType" jdbcType="INTEGER" />
<result column="category_name" property="categoryName" jdbcType="VARCHAR" />
<result column="allocate_time" property="allocateTime" jdbcType="INTEGER" />
<result column="promise_time" property="promiseTime" jdbcType="INTEGER" />
<result column="last_operator" property="lastOperator" jdbcType="VARCHAR" />
<result column="update_time" property="updateTime" jdbcType="TIMESTAMP" />
<!--寫在這里,僅對select語句有效产禾,typeHandler="com.sankuai.travel.csc.test.dao.typehandler.BooleanTypeHandler" -->
<result column="is_cancel" property="isCancel" jdbcType="CHAR" typeHandler="com.sankuai.travel.csc.test.dao.typehandler.BooleanTypeHandler"/>
<result column="status1" property="status1" jdbcType="CHAR" />
<result column="status2" property="status2" jdbcType="CHAR" />
<result column="phone_list" property="phoneList" jdbcType="VARCHAR" />
<result column="create_time" property="createTime" jdbcType="TIMESTAMP" />
</resultMap></pre>
這里只能是在select的時候才會使用自定義的TypeHandler處理對應的映射關系排作,如果要在insert或者update時使用則需要在sql定義中添加相應的內容
3.2在resultMap的定義中對對應列定義typeHandler
<pre spellcheck="false" class="md-fences mock-cm md-end-block" lang="xml" cid="n474" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit;"><insert id="insert" parameterType="com.sankuai.travel.csc.test.dao.domain.CategoryDO" >
<selectKey resultType="java.lang.Integer" keyProperty="id" order="AFTER" >
SELECT LAST_INSERT_ID()
</selectKey>
insert into hotel_order_category (category_type, category_name, allocate_time,
promise_time, last_operator, update_time,
is_cancel, status1, status2,
phone_list, create_time)
values (#{categoryType,jdbcType=INTEGER}, #{categoryName,jdbcType=VARCHAR}, #{allocateTime,jdbcType=INTEGER},
#{promiseTime,jdbcType=INTEGER}, #{lastOperator,jdbcType=VARCHAR}, #{updateTime,jdbcType=TIMESTAMP},
#{isCancel,jdbcType=CHAR,typeHandler=com.sankuai.travel.csc.test.dao.typehandler.BooleanTypeHandler},
#{status1,jdbcType=CHAR}, #{status2,jdbcType=CHAR},
#{phoneList,jdbcType=VARCHAR}, #{createTime,jdbcType=TIMESTAMP})
</insert></pre>
#mybatis-enumtypehandler和enumordinaltypehandler的區(qū)別
mybatis對枚舉類型提供了兩種類型支持:EnumTypeHandler和EnumOrdinalTypeHandler。
EnumTypeHandler是mybatis默認的枚舉類型轉換器亚情,如果pojo類中使用了枚舉類型妄痪,而配置文件沒有指定類型轉換類,mybatis將使用EnumTypeHandler處理枚舉屬性楞件。EnumTypeHandler的將把枚舉類的name進行存儲衫生,枚舉類的name即枚舉類名。參考:http://mybatis.github.io/mybatis-3/zh/configuration.html
EnumOrdinalTypeHandler是mybatis提供的另一種轉換器土浸,顧名思義這個轉換類使用了枚舉類的ordinal屬性作為數據庫存儲信息罪针,由于ordinal屬性是int類型的,按照官網的說明數據庫中對應資源應該是int或double類型的黄伊,但是個人測試過程中MYSQL的varchar字段也可以存儲泪酱。
總結:EnumTypeHandler和EnumOrdinalTypeHandler的區(qū)別主要是數據庫中存儲字段的類型差別,由于EnumOrdinalTypeHandler使用枚舉類型的ordinal作為存儲还最,所以必須使用數字類型字段存儲墓阀。
<pre spellcheck="false" class="md-fences mock-cm md-end-block" lang="xml" cid="n486" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit;"><bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="mapperLocations" value="classpath:dao/mapper/*.xml"></property>
<property name="typeHandlers" >
<array>
<bean class="com.sankuai.travel.csc.test.dao.typehandler.BooleanTypeHandler" />
<bean class="com.sankuai.travel.csc.test.dao.typehandler.StringArrayTypeHandler" />
<bean class="org.apache.ibatis.type.EnumTypeHandler" >
<constructor-arg name="type" value="com.sankuai.travel.csc.test.enums.SimpleStatusEnum" />
</bean>
<bean class="org.apache.ibatis.type.EnumOrdinalTypeHandler" >
<constructor-arg name="type" value="com.sankuai.travel.csc.test.enums.SimpleStatusEnum" />
</bean>
</array>
</property>
<property name="plugins">
<array>
<bean class="com.sankuai.travel.csc.test.dao.interceptor.SqlMonitorInterceptor" />
</array>
</property>
</bean></pre>
<pre spellcheck="false" class="md-fences mock-cm md-end-block" lang="xml" cid="n488" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit;"><resultMap id="BaseResultMap" type="com.sankuai.travel.csc.test.dao.domain.CategoryDO" >
<id column="id" property="id" jdbcType="INTEGER" />
<result column="category_type" property="categoryType" jdbcType="INTEGER" />
<result column="category_name" property="categoryName" jdbcType="VARCHAR" />
<result column="allocate_time" property="allocateTime" jdbcType="INTEGER" />
<result column="promise_time" property="promiseTime" jdbcType="INTEGER" />
<result column="last_operator" property="lastOperator" jdbcType="VARCHAR" />
<result column="update_time" property="updateTime" jdbcType="TIMESTAMP" />
<!--方式二:寫在這里,僅對select語句有效拓轻,typeHandler="com.sankuai.travel.csc.test.dao.typehandler.BooleanTypeHandler" -->
<result column="is_cancel" property="isCancel" jdbcType="CHAR" />
<result column="status1" property="status1" jdbcType="CHAR" />
<result column="status2" property="status2" jdbcType="CHAR" typeHandler="org.apache.ibatis.type.EnumOrdinalTypeHandler" />
<result column="phone_list" property="phoneList" jdbcType="VARCHAR" />
<result column="create_time" property="createTime" jdbcType="TIMESTAMP" /></pre>
MyBatis中ObjectFactory簡介
MyBatis 每次創(chuàng)建結果對象實例時,它使用一個 ObjectFactory 實例來完成斯撮。默認的ObjectFactory僅會按照配置結果類型的默認構造方法或者指定構造方法來創(chuàng)建對象實例。如果想重寫默認的 ObjectFactory,你可以創(chuàng)建你自己的扶叉。比如:
<pre spellcheck="false" class="md-fences mock-cm md-end-block" lang="jsx" cid="n492" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit;">// ExampleObjectFactory.java
//自定義的ObjectFactory
public class ExampleObjectFactory extends DefaultObjectFactory {
//使用默認構造方法創(chuàng)建對象實例
public Object create(Class type) {
return super.create(type);
}
//有構造參數列表和構造參數值列表的創(chuàng)建對象實例的方式
public Object create(Class type, List<Class> constructorArgTypes, List<Object> constructorArgs) {
return super.create(type, constructorArgTypes, constructorArgs);
}
//為自定義ObjectFactory設置配置參數
public void setProperties(Properties properties) {
super.setProperties(properties);
}
}
<objectFactory type="org.mybatis.example.ExampleObjectFactory">
<property name="someProperty" value="100"/>
</objectFactory></pre>
ObjectFactory 接口很簡單勿锅。它包含兩個創(chuàng)建用的方法,一個是處理默認構造方法的,另外一個是處理帶參數構造方法的帕膜。最終,setProperties 方法可以被用來配置 ObjectFactory。在 初 始化 你 的 ObjectFactory 實例 后 , objectFactory 元素 體 中定 義的 屬 性會 被傳 遞 給setProperties 方法粱甫。
一個例子: 假設實體對象實現了自定義的InitialEntity接口泳叠,則在創(chuàng)建對象完成之后必須調用InitialEntity接口的init方法:
<pre spellcheck="false" class="md-fences mock-cm md-end-block" lang="java" cid="n496" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit;">package cd.itcast.mybatis.myobjectfactory;
public interface InitialEntity {
void init();
}</pre>
假設有一個實體StockOutcomeBillItem對象用來記錄銷售出庫單明細作瞄,該對象再設置完值后茶宵,需要調用count()方法來完成總金額的計算:
<pre spellcheck="false" class="md-fences mock-cm md-end-block" lang="kotlin" cid="n499" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit;">package cd.itcast.mybatis.myobjectfactory;
public class StockOutcomeBillItem {
private Long id;
private Product product;
private Integer number;
private BigDecimal price;
private BigDecimal totalAmount;
//getter & setter
public void count(){
this.totalAmount=this.number*this.price;
}
}</pre>
該對象在實例化完成后需要調用count()方法來完成totalAmount屬性的計算。要完成這個邏輯宗挥,只需要讓該類實現定義的InitialEntity接口即可:
<pre spellcheck="false" class="md-fences mock-cm md-end-block" lang="java" cid="n502" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit;">package cd.itcast.mybatis.myobjectfactory;
public class StockOutcomeBillItem implements InitialEntity{
private Long id;
//other properties;
//getter & setter
public void init() {
this.count();
}
private void count(){
this.totalAmount=this.number*this.price;
}
}</pre>
接下來乌庶,只需要完成能辨別InitialEntity接口的對象并調用其中的方法即可:
<pre spellcheck="false" class="md-fences mock-cm md-end-block" lang="java" cid="n505" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit;">package cd.itcast.mybatis.myobjectfactory;
public class InitialObjectFactory extends DefaultObjectFactory {
private static final long serialVersionUID = 1L;
@Override
public <T> T create(Class<T> type) {
return super.create(type);
}
@Override
//注意,在DefaultObjectFactory的create(Class type)方法中調用的是
//create(Class,List<Class> constructorArgTypes,List<Object> constructorArgs)方法契耿,
//所以瞒大,只需要在這個方法中完成自定義初始化邏輯即可。
public <T> T create(Class<T> type, List<Class<?>> constructorArgTypes,List<Object> constructorArgs){
T ret= super.create(type, constructorArgTypes, constructorArgs);
//判斷接口類型和執(zhí)行接口方法搪桂。
if(InitialEntity.class.isAssignableFrom(type)){
InitialEntity entity=(InitialEntity)ret; entity.init();
}
return ret;
}
}</pre>
接下來只需要注冊這個ObjectFactory即可:
<pre spellcheck="false" class="md-fences mock-cm md-end-block" lang="xml" cid="n508" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit;">
<objectFactory type="org.mybatis.example.ExampleObjectFactory"/> </pre>
以上就是mybatis中objectfactory的簡單應用透敌,關于objectfactory更多的實現細節(jié),可以通過閱讀mybatis代碼去研究踢械。
叩丁狼教育關注
MyBatis配置文件environments和子元素transactionManager酗电、dataSource解析
< MyBatis ObjectFactoryMyBatis與Spring的整合步驟 >
在 MyBatis 中,運行環(huán)境主要的作用是配置數據庫信息都许,它可以配置多個數據庫稻薇,一般而言只需要配置其中的一個就可以了。
它下面又分為兩個可配置的元素:事務管理器(transactionManager)胶征、數據源(dataSource)塞椎。
在實際的工作中,大部分情況下會采用 Spring 對數據源和數據庫的事務進行管理睛低,這些我們教程后面都會進行講解案狠。本節(jié)我們會探討 MyBatis 自身實現的類服傍。
運行環(huán)境配置,代碼如下所示骂铁。
<pre spellcheck="false" class="md-fences mock-cm md-end-block" lang="xml" cid="n519" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit;"><environments default="development"> <environment id="development"> <transactionManager type="JDBC" /> <dataSource type="POOLED"> <property name="driver" value="{database.url}" /> <property name="username" value="
{database.password}" /> </dataSource> </environment></environments></pre>
這里用到兩個元素:transactionManager 和 environment吹零。
transactionManager(事務管理器)
在 MyBatis 中,transactionManager 提供了兩個實現類拉庵,它需要實現接口 Transaction(org.apache.ibatis.transaction.Transaction)灿椅,它的定義代碼如下所示。
<pre spellcheck="false" class="md-fences mock-cm md-end-block" lang="" cid="n523" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit;">public interface Transaction { Connection getConnection() throws SQLException; void commit() throws SQLException; void rollback() throws SQLException; void close() throws SQLException; Integer getTimeout() throws SQLException;}</pre>
從方法可知钞支,它主要的工作就是提交(commit)茫蛹、回滾(rollback)和關閉(close)數據庫的事務。MyBatis 為 Transaction 提供了兩個實現類:JdbcTransaction 和 ManagedTransaction烁挟,如圖 1 所示婴洼。
圖 1 Transaction的實現類
于是它對應著兩種工廠:JdbcTransactionFactory 和 ManagedTransactionFactory,這個工廠需要實現 TransactionFactory 接口撼嗓,通過它們會生成對應的 Transaction 對象柬采。于是可以把事務管理器配置成為以下兩種方式:
<transactionManager type="JDBC"/> <transactionManager type="MANAGED"/>
這里做簡要的說明。
JDBC 使用 JdbcTransactionFactory 生成的 JdbcTransaction 對象實現且警。它是以 JDBC 的方式對數據庫的提交和回滾進行操作粉捻。
MANAGED 使用 ManagedTransactionFactory 生成的 ManagedTransaction 對象實現。它的提交和回滾方法不用任何操作振湾,而是把事務交給容器處理杀迹。在默認情況下,它會關閉連接押搪,然而一些容器并不希望這樣树酪,因此需要將 closeConnection 屬性設置為 false 來阻止它默認的關閉行為。
不想采用 MyBatis 的規(guī)則時大州,我們可以這樣配置:
<transactionManager type="com.mybatis.transaction.MyTransactionFactory"/>
實現一個自定義事務工廠续语,代碼如下所示。
<pre spellcheck="false" class="md-fences mock-cm md-end-block" lang="java" cid="n534" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit;">public class MyTransactionFactory implements TransactionFactory {
@Override public void setProperties(Properties props) { } @Override public Transaction newTransaction(Connection conn) {
return new MyTransaction(conn);
}
@Override public Transaction newTransaction(DataSource dataSource, TransactionlsolationLevel level, boolean autoCommit) {
return new MyTransaction(dataSource, level, autoCommit);
}}</pre>
這里就實現了 TransactionFactory 所定義的工廠方法厦画,這個時候還需要事務實現類 MyTransaction疮茄,它用于實現 Transaction 接口,代碼如下所示根暑。
<pre spellcheck="false" class="md-fences mock-cm md-end-block" lang="java" cid="n536" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit;">public class MyTransaction extends JdbcTransaction implements Transaction {
public MyTransaction(DataSource ds, TransactionIsolationLevel desiredLevel, boolean desiredAutoCommit) {
super(ds, desiredLevel, desiredAutoCommit);
}
public MyTransaction(Connection connection) {
super(connection);
}
public Connection getConnection() throws SQLException {
return super.getConnection();
}
public void commit() throws SQLException {
super.commit();
}
public void rollback() throws SQLException {
super.rollback();
}
public void close() throws SQLException {
super.close();
}
public Integer getTimeout() throws SQLException {
return super.getTimeout();
}}</pre>
這樣就能夠通過自定義事務規(guī)則力试,滿足特殊的需要了。
environment 數據源環(huán)境
environment 的主要作用是配置數據庫排嫌,在 MyBatis 中畸裳,數據庫通過 PooledDataSource Factory、UnpooledDataSourceFactory 和 JndiDataSourceFactory 三個工廠類來提供淳地,前兩者對應產生 PooledDataSource怖糊、UnpooledDataSource 類對象帅容,而 JndiDataSourceFactory 則會根據 JNDI 的信息拿到外部容器實現的數據庫連接對象。
無論如何這三個工廠類伍伤,最后生成的產品都會是一個實現了 DataSource 接口的數據庫連接對象并徘。
由于存在三種數據源,所以可以按照下面的形式配置它們扰魂。
<dataSource type="UNPOOLED"> <dataSource type="POOLED"> <dataSource type="JNDI">
論述一下這三種數據源及其屬性麦乞。
1. UNPOOLED
UNPOOLED 采用非數據庫池的管理方式,每次請求都會打開一個新的數據庫連接阅爽,所以創(chuàng)建會比較慢路幸。在一些對性能沒有很高要求的場合可以使用它。
對有些數據庫而言付翁,使用連接池并不重要,那么它也是一個比較理想的選擇晃听。UNPOOLED 類型的數據源可以配置以下幾種屬性:
driver 數據庫驅動名百侧,比如 MySQL 的 com.mysql.jdbc.Driver。
url 連接數據庫的 URL能扒。
username 用戶名佣渴。
password 密碼。
defaultTransactionIsolationLevel 默認的連接事務隔離級別初斑,關于隔離級別辛润,后面教程中會討論挠铲。
傳遞屬性給數據庫驅動也是一個可選項结耀,注意屬性的前綴為“driver.”,例如 driver.encoding=UTF8谭跨。它會通過 DriverManager.getConnection(url,driverProperties)方法傳遞值為 UTF8 的 encoding 屬性給數據庫驅動鹃答。
2. POOLED
數據源 POOLED 利用“池”的概念將 JDBC 的 Connection 對象組織起來乎澄,它開始會有一些空置,并且已經連接好的數據庫連接测摔,所以請求時置济,無須再建立和驗證,省去了創(chuàng)建新的連接實例時所必需的初始化和認證時間锋八。它還控制最大連接數浙于,避免過多的連接導致系統瓶頸。
除了 UNPOOLED 下的屬性外挟纱,會有更多屬性用來配置 POOLED 的數據源羞酗,如表 1 所示:
名稱 | 說明 |
---|---|
poolMaximumActiveConnections | 是在任意時間都存在的活動(也就是正在使用)連接數量,默認值為 10 |
poolMaximumIdleConnections | 是任意時間可能存在的空閑連接數 |
poolMaximumCheckoutTime | 在被強制返回之前樊销,池中連接被檢出(checked out)的時間整慎,默認值為 20 000 毫秒(即 20 秒) |
poolTimeToWait | 是一個底層設置脏款,如果獲取連接花費相當長的時間,它會給連接池打印狀態(tài)日志裤园,并重新嘗試獲取一個連接(避免在誤配置的情況下一直失敵肥Α),默認值為 20 000 毫秒(即 20 秒)拧揽。 |
poolPingQuery | 為發(fā)送到數據庫的偵測查詢剃盾,用來檢驗連接是否處在正常工作秩序中,并準備接受請求淤袜。默認是“NO PING QUERY SET”痒谴,這會導致多數數據庫驅動失敗時帶有一個恰當的錯誤消息。 |
poolPingEnabled | 為是否啟用偵測查詢铡羡。若開啟积蔚,也必須使用一個可執(zhí)行的 SQL 語句設置 poolPingQuery 屬性(最好是一個非常快的 SQL)烦周,默認值為 false尽爆。 |
poolPingConnectionsNotUsedFor | 為配置 poolPingQuery 的使用頻度。這可以被設置成匹配具體的數據庫連接超時時間读慎,來避免不必要的偵測漱贱,默認值為 0(即所有連接每一時刻都被偵測——僅當 poolPingEnabled 為 true 時適用)。 |
3. JNDI
數據源 JNDI 的實現是為了能在如 EJB 或應用服務器這類容器中使用夭委,容器可以集中或在外部配置數據源幅狮,然后放置一個 JNDI 上下文的引用。這種數據源配置只需要兩個屬性:
1)initial_context
用來在 InitialContext 中尋找上下文(即株灸,initialContext.lookup(initial_context))崇摄。initial_context 是個可選屬性,如果忽略蚂且,那么 data_source 屬性將會直接從 InitialContext 中尋找配猫。
2)data_source
是引用數據源實例位置上下文的路徑。當提供 initial_context 配置時杏死,data_source 會在其返回的上下文中進行查找泵肄;當沒有提供 initial_context 時,data_source 直接在 InitialContext 中查找淑翼。
與其他數據源配置類似腐巢,它可以通過添加前綴“env.”直接把屬性傳遞給初始上下文(InitialContext)。比如 env.encoding=UTF8玄括,就會在初始上下文實例化時往它的構造方法傳遞值為 UTF8 的 encoding 屬性冯丙。
MyBatis 也支持第三方數據源,例如使用 DBCP 數據源遭京,那么需要提供一個自定義的 DataSourceFactory胃惜,代碼如下所示泞莉。
<pre spellcheck="false" class="md-fences mock-cm md-end-block" lang="java" cid="n596" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit;">public class DbcpDataSourceFactory implements DataSourceFactory {
private Properties props = null;
public void setProperties(Properties props) {
this.props = props;
}
public DataSource getDataSource() {
DataSource dataSource = null;
dataSource = BasicDataSourceFactory.createDataSource(props);
return dataSource;
}}</pre>
然后進行如下配置:
<pre spellcheck="false" class="md-fences mock-cm md-end-block" lang="xml" cid="n598" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit;"><dataSource type="com.mybatis.dataSource.DbcpDataSourceFactory">
<property name="driver" value="{database.url}" />
<property name="username" value="{database.password}" />
</dataSource></pre>
這樣 MyBatis 就會采用配置的數據源工廠來生成數據源了。
databaseIdProvider 用法
databaseIdProvider 元素主要是支持多種不同廠商的數據庫
<databaseIdProvider
type="com.learn.ssm.chapter4.databaseidprovider.MyDatabaseIdProvider">
<property name="msg" value="自定義DatabaseIdProvider" />
</databaseIdProvider></pre>
<pre spellcheck="false" class="md-fences mock-cm md-end-block" lang="java" cid="n603" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit;">package com.learn.ssm.chapter4.databaseidprovider;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.ibatis.mapping.DatabaseIdProvider;
import org.apache.log4j.Logger;
public class MyDatabaseIdProvider implements DatabaseIdProvider {
private static final String DATEBASE_TYPE_DB2 = "DB2";
private static final String DATEBASE_TYPE_MYSQL = "MySQL";
private static final String DATEBASE_TYPE_ORACLE = "Oralce";
private Logger log = Logger.getLogger(MyDatabaseIdProvider.class);
@Override
public void setProperties(Properties props) {
log.info(props);
}
@Override
public String getDatabaseId(DataSource dataSource) throws SQLException {
Connection connection = dataSource.getConnection();
String dbProductName = connection.getMetaData().getDatabaseProductName();
if (MyDatabaseIdProvider.DATEBASE_TYPE_DB2.equals(dbProductName)) {
return "db2";
} else if (MyDatabaseIdProvider.DATEBASE_TYPE_MYSQL
.equals(dbProductName)) {
return "mysql";
} else if (MyDatabaseIdProvider.DATEBASE_TYPE_ORACLE
.equals(dbProductName)) {
return "oracle";
} else {
return null;
}
}
}
</pre>
有效引入映射器
首先定義接口
<pre spellcheck="false" class="md-fences mock-cm md-end-block" lang="java" cid="n606" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit;">package com.learn.ssm.chapter4.mapper;
import java.util.List;
import com.learn.ssm.chapter4.pojo.Role;
public interface RoleMapper {
public int insertRole(Role role);
public int deleteRole(Long id);
public int updateRole(Role role);
public Role getRole(Long id);
public List<Role> findRoles(String roleName);
}</pre>
其次船殉,給出xml
<pre spellcheck="false" class="md-fences mock-cm md-end-block" lang="xml" cid="n608" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit;"><?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.learn.ssm.chapter4.mapper.RoleMapper">
<resultMap id="roleMapper" type="role">
<result property="id" column="id" />
<result property="roleName" column="role_name" jdbcType="VARCHAR"
javaType="string" />
<result property="note" column="note"
typeHandler="com.learn.ssm.chapter4.typehandler.MyTypeHandler" />
</resultMap>
<select id="getRole" parameterType="long" resultMap="roleMapper">
select id, role_name, note from t_role where id = #{id}
</select>
<select id="findRoles" parameterType="string" resultMap="roleMapper">
select id, role_name, note from t_role
where role_name like concat('%', #{roleName, jdbcType=VARCHAR,
javaType=string}, '%')
</select>
<select id="findRoles2" parameterType="string" resultMap="roleMapper">
select id, role_name, note from t_role
where note like concat('%', #{note,
typeHandler=com.learn.ssm.chapter4.typehandler.MyTypeHandler}, '%')
</select>
</mapper></pre>
-
用文件路勁引入映射器
<pre spellcheck="false" class="md-fences mock-cm md-end-block" lang="xml" cid="n612" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit;"><mappers>
<mapper resource="com/learn/ssm/chapter4/mapper/RoleMapper"/>
</mappers></pre> -
用包名引入引射器
<pre spellcheck="false" class="md-fences mock-cm md-end-block" lang="xml" cid="n615" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit;"><mappers>
<package name="com.learn.ssm.chapter4.mapper" />
</mappers></pre>-
用類注冊引入映射器
<pre spellcheck="false" class="md-fences mock-cm md-end-block" lang="xml" cid="n619" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"><mappers>
<mapper class="com.learn.ssm.chapter4.mapper.RoleMapper"/>
</mappers></pre>4.用userMapperxml 引入映射器
<pre spellcheck="false" class="md-fences mock-cm md-end-block" lang="xml" cid="n621" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"><mappers>
<mapper url="file:///Chapter4/src/com/learn/ssm/chapter4/mapper/RoleMapper.xml"/>
</mappers></pre>
-