MyBatis配置xml層次結(jié)構(gòu),而且必須注意其順序。
<!ELEMENT configuration (properties?, settings?, typeAliases?, typeHandlers?, objectFactory?, objectWrapperFactory?, reflectorFactory?, plugins?, environments?, databaseIdProvider?, mappers?)>
<?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>
<!--設(shè)置-->
<settings>
<setting name="" value=""/>
</settings>
<!--類型命名-->
<typeAliases></typeAliases>
<!--類型處理器-->
<typeHandlers></typeHandlers>
<!--對象工廠-->
<objectFactory type=""/>
<!--插件-->
<plugins>
<plugin interceptor=""></plugin>
</plugins>
<!--配置環(huán)境-->
<environments default="">
<!--環(huán)境變量-->
<environment id="">
<!--事務(wù)管理器-->
<transactionManager type=""></transactionManager>
<!--數(shù)據(jù)源-->
<dataSource type="">
</dataSource>
</environment>
</environments>
<!--數(shù)據(jù)庫廠商標(biāo)識-->
<databaseIdProvider type=""/>
<!--映射器-->
<mappers></mappers>
</configuration>
1.properties屬性
properties是一個配置屬性的元素,讓我們能在配置文件的上下文中使用它。
如果屬性在不止一個地方進(jìn)行了配置,那么MyBatis按照下面的順序來加載
1.在properties元素體內(nèi)指定的屬性首先被讀取
2.然后根據(jù)properties元素中的resource屬性讀取類路徑下屬性文件或者根據(jù)url屬性指定的路徑讀取屬性文件,并覆蓋已讀取的同名模塊
3.最后讀取作為方法參數(shù)傳遞的屬性,并覆蓋已讀取的同名屬性。
因此優(yōu)先級順序:方法參數(shù)傳遞的屬性 > resource/url 屬性中指定的配置文件 > properties 屬性中指定的屬性
1.1 property子元素
在MyBatis.xml的配置里面配置如下的編碼
<dataSource type="pooled">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/springdatastudy?serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
1.2 properties配置文件
使用properties來配置屬性,可以方便我們在多個配置文件重復(fù)使用,也可以隨時修改及日后維護(hù)
- 1.在resources文件夾下面創(chuàng)建datasource.properties
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/springdatastudy?serverTimezone=UTC
username=root
password=root
- 2.在MyBatis.xml配置文件的properties節(jié)點(diǎn)下引入properties文件
<properties resource="datasource.properties"/>
<!--數(shù)據(jù)源-->
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
1.3 程序參數(shù)傳值
實(shí)際工作中,數(shù)據(jù)庫的用戶名及密碼可能是加密后的字符串。所以在SqlSessionFactoryBuilder處,需要將加密的字符串進(jìn)行解密。
/**
* 模擬字符串解密
*
* @param str
* @return
*/
public static String decode(String str) {
return str;
}
public static void main(String[] args) throws IOException {
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
Properties properties = new Properties();
properties.load(Resources.getResourceAsStream("datasource.properties"));
properties.setProperty("username",decode(properties.getProperty("username")));
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream,properties);
SqlSession sqlSession = sqlSessionFactory.openSession();
UserDao userDao = sqlSession.getMapper(UserDao.class);
List<User> users = userDao.getUser();
for (User u : users) {
System.out.println(u.toString());
}
}
不要使用混合的方式進(jìn)行屬性配置。優(yōu)先推薦使用properties文件。
2.settings屬性
這是 MyBatis 中極為重要的調(diào)整設(shè)置,它們會改變 MyBatis 的運(yùn)行時行為。下表描述了設(shè)置中各項的意圖、默認(rèn)值等。
- 1.cacheEnabled
boolean屬性,默認(rèn)是true。該配置影響的所有映射器中配置的緩存的全局開關(guān)。
- 2.lazyLoadingEnabled
boolean屬性,默認(rèn)值是false。延遲加載的全局開關(guān)。當(dāng)開啟時,所有關(guān)聯(lián)對象都會延遲加載。 特定關(guān)聯(lián)關(guān)系中可通過設(shè)置fetchType屬性來覆蓋該項的開關(guān)狀態(tài)。
- 3.aggressiveLazyLoading
boolean屬性,jar版本3.4.1以下是true。3.4.1以上是false。當(dāng)啟用時,任何方法的調(diào)用都會加載該對象的所有屬性。不開啟,按需加載。
- 4.multipleResultSetsEnabled
boolean屬性,默認(rèn)值是true。是否允許單一語句返回多結(jié)果集合。(需要兼容驅(qū)動)
- 5.useColumnLabel
boolean屬性,默認(rèn)值為true。使用列標(biāo)簽代替列名。
- 6.useGeneratedKeys
boolean屬性,默認(rèn)值為false。允許JDBC支持自動生成主鍵。如果設(shè)置為true,則這個設(shè)置強(qiáng)制使用自動生成主鍵。(需要驅(qū)動兼容)
- 7.autoMappingBehavior
枚舉屬性,三個可選值:None(表示取消自動映射)、Partial(表示只會自動映射沒有定義嵌套結(jié)果集映射的結(jié)果集)、Full(表示會自動映射任意復(fù)雜的結(jié)果集),默認(rèn)值為:Partial。
- 8.autoMappingUnknownColumnBehavior
枚舉屬性,三個可選值:None(不做任何反應(yīng))、WARNING(輸出提醒日志,org.apache.ibatis.session.AutoMappingUnknownColumnBehavior日志等級必須設(shè)置為Warn)、FAILING(映射失敗,拋出SqlSessionException)。默認(rèn)值為None。
- 9.defaultExecutorType
枚舉屬性,三個可選值:SIMPLE(普通執(zhí)行器)、REUSE(會重用預(yù)處理語句(prepared statements))、BATCH(重用語句并執(zhí)行批量更新)
- 10.重用語句并執(zhí)行批量更新
任意正整數(shù),默認(rèn)值沒有設(shè)置。設(shè)置超時時間,它決定驅(qū)動等待數(shù)據(jù)庫響應(yīng)的秒數(shù)。
- 11.defaultFetchSize
任意正整數(shù),默認(rèn)值沒有設(shè)置。為驅(qū)動的結(jié)果集獲取數(shù)量(fetchSize)設(shè)置一個提示值。此參數(shù)只可以在查詢設(shè)置中被覆蓋。
- 12.safeRowBoundsEnabled
boolean屬性,默認(rèn)值為false。允許在嵌套語句中使用分頁(RowBounds)。如果允許使用則設(shè)置為false。
- 13.safeResultHandlerEnabled
boolean屬性,默認(rèn)值為true。允許在嵌套語句中使用分頁(ResultHandler)。如果允許使用則設(shè)置為false。
- 14.mapUnderscoreToCamelCase
boolean屬性,默認(rèn)為false。是否開啟自動駝峰命名規(guī)則(camelcase)映射,即從經(jīng)典數(shù)據(jù)庫列名 A_COLUMN 到經(jīng)典 Java 屬性名 aColumn 的類似映射。
- 15.localCacheScope
枚舉屬性,兩個枚舉屬性:SESSION(會緩存一個會話中執(zhí)行的所有查詢)、STATEMENT(本地會話僅用在語句執(zhí)行上,對相同SqlSession的不同調(diào)用將不會共享數(shù)據(jù)。)。默認(rèn)值為SESSION。
- 16.jdbcTypeForNull
JDBCType屬性,常用的屬性有:Null、Varchar、Other。當(dāng)沒有為參數(shù)提供特定的 JDBC 類型時,為空值指定 JDBC 類型。
- 17.lazyLoadTriggerMethods
指定哪個對象的方法觸發(fā)一次延遲加載。
- 18.defaultScriptingLanguage
指定動態(tài)SQL生成的默認(rèn)語言。
- 19.defaultEnumTypeHandler
Specifies the TypeHandler used by default for Enum. (Since: 3.4.5)
- 20.callSettersOnNulls
boolean屬性,默認(rèn)值為false。。指定當(dāng)結(jié)果集中值為null的時候是否調(diào)用映射對象的 setter(map 對象時為put)方法,這對于有Map.keySet()依賴或null值初始化的時候是有用的。注意基本類型(int、boolean等)是不能設(shè)置成 null 的。
- 21.returnInstanceForEmptyRow
boolean屬性,默認(rèn)值為false。當(dāng)返回行的所有列都是空時,MyBatis默認(rèn)返回null。
- 22.logPrefix
String類型,指定 MyBatis 增加到日志名稱的前綴。
- 23.logImpl
枚舉值,指定 MyBatis 所用日志的具體實(shí)現(xiàn),未指定時將自動查找。SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING
- 24.proxyFactory
枚舉值,指定 Mybatis 創(chuàng)建具有延遲加載能力的對象所用到的代理工具。CGLIB | JAVASSIST。默認(rèn)值:JAVASSIST (MyBatis 3.3 or above)
- 25.vfsImpl
指定VFS的實(shí)現(xiàn)。自定義VFS的實(shí)現(xiàn)的類全限定名,以逗號分隔。
- 26.useActualParamName
boolean屬性,默認(rèn)值為true。允許使用方法簽名中的名稱作為語句參數(shù)名稱。為了使用該特性,你的工程必須采用Java8編譯,并且加上-parameters選項。(從3.4.1開始)
- 27.configurationFactory
指定一個提供Configuration實(shí)例的類.這個被返回的Configuration實(shí)例是用來加載被反序列化對象的懶加載屬性值. 這個類必須包含一個簽名方法static Configuration getConfiguration(). (從 3.2.3 版本開始)
一個配置完整的 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"/>
<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>
3.typeAliases(類型別名)
類型別名是為 Java 類型設(shè)置一個短的名字。它只和 XML 配置有關(guān),存在的意義僅在于用來減少類完全限定名的冗余。例如:
- MyBatis.xml里面設(shè)置別名
<typeAliases>
<typeAlias type="model.User" alias="yuser"></typeAlias>
</typeAliases>
- Mapper.xml文件里面使用
<select id="getUser" resultType="yuser">
select * FROM user;
</select>
3.1 自動掃描包自定義別名
如果POJO過多的時候,配置也非常多。這時候,我們可以使用自動掃描包自定義別名的方式。
- MyBatis.xml里面的設(shè)置掃描包的名稱
<typeAliases>
<package name="model"/>
</typeAliases>
- POJO上設(shè)置別名
@Alias("sasUser")
public class User {
}
- Mapper.xml使用方法
<select id="getUser" resultType="sasUser">
select * FROM user;
</select>
3.2系統(tǒng)定義別名
| 別名 | 映射的類型 |
|---|---|
| _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 |
4.typeHandlers(類型處理器)
無論是 MyBatis 在預(yù)處理語句(PreparedStatement)中設(shè)置一個參數(shù)時,還是從結(jié)果集中取出一個值時, 都會用類型處理器將獲取的值以合適的方式轉(zhuǎn)換成 Java 類型。
也就是將參數(shù)從Java類型(javaType)轉(zhuǎn)換為jdbcType;或者從數(shù)據(jù)庫取出結(jié)果把jdbcType轉(zhuǎn)化為javaType。
typeHandler和typeAliases(類型別名)一樣,分為系統(tǒng)定義及用戶自定義。
4.1 系統(tǒng)定義的typeHandler
| 類型處理器 | Java 類型 | JDBC 類型 |
|---|---|---|
| BooleanTypeHandler | java.lang.Boolean, boolean | 數(shù)據(jù)庫兼容的 BOOLEAN |
| ByteTypeHandler | java.lang.Byte, byte | 數(shù)據(jù)庫兼容的 NUMERIC 或 BYTE |
| ShortTypeHandler | java.lang.Short, short | 數(shù)據(jù)庫兼容的 NUMERIC 或 SHORT INTEGER |
| IntegerTypeHandler | java.lang.Integer, int | 數(shù)據(jù)庫兼容的 NUMERIC 或 INTEGER |
| LongTypeHandler | java.lang.Long, long | 數(shù)據(jù)庫兼容的 NUMERIC 或 LONG INTEGER |
| FloatTypeHandler | java.lang.Float, float | 數(shù)據(jù)庫兼容的 NUMERIC 或 FLOAT |
| DoubleTypeHandler | java.lang.Double, double | 數(shù)據(jù)庫兼容的 NUMERIC 或 DOUBLE |
| BigDecimalTypeHandler | java.math.BigDecimal | 數(shù)據(jù)庫兼容的 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[] | 數(shù)據(jù)庫兼容的字節(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 類型,存儲枚舉的索引(而不是名稱)。 |
注意點(diǎn):
- 1.時間精度,數(shù)據(jù)精確到天的使用DateOnlyTypeHandler即可,需要精確到秒的用SqlTimestampHandler。也就是Java類型使用java.sql.Timestamp。數(shù)據(jù)庫類型設(shè)置為Timestamp或者datetime。
DateTime與Timestamp區(qū)別
時間范圍不一樣。DateTime時間范圍:''1000-01-01 00:00:00''到''9999-12-31 23:59:59''。而Timestamp時間范圍:在1970~2037年之間。
timestamp與時區(qū)有關(guān),而datetime與時區(qū)無關(guān)。
timestamp存儲是4個字節(jié)存儲的,而datetime存儲是8個字節(jié)存儲的。
4.2 自定義TypeHanlder
一般情況下,MyBatis系統(tǒng)定義的typeHandler已經(jīng)應(yīng)付了大部分場景,但是有時候我們需要特殊處理一些Java類型與JDBC對應(yīng)的類型,該如何定義。
- 1.實(shí)現(xiàn)接口TypeHandler或者繼承BaseTypeHandler
@MappedTypes(String.class)
@MappedJdbcTypes(JdbcType.VARCHAR)
public class ExampleTypeHandler extends BaseTypeHandler<String> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
System.out.println("example setNonNullParameter");
ps.setString(i,parameter);
}
@Override
public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
System.out.println("example getNullableResult");
return rs.getString(columnName);
}
@Override
public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
System.out.println("example getNullableResult");
return rs.getString(columnIndex);
}
@Override
public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
System.out.println("example getNullableResult");
return cs.getString(columnIndex);
}
}
注釋:
使用@MappedTypes注釋,來指定與其關(guān)聯(lián)的Java類型列表。
使用@MappedJdbcTypes注釋,來指定與其關(guān)聯(lián)的JDBC類型列表
- 2.在MyBatis-config.xml里面配置typeHandler(類型處理器)
<!--類型處理器-->
<typeHandlers>
<typeHandler javaType="string" jdbcType="VARCHAR" handler="utils.ExampleTypeHandler"/>
</typeHandlers>
- 3.在mapper.xml文件中指定typeHandler進(jìn)行轉(zhuǎn)換。
盡管上面我們自定義了類型處理器類,并在MyBatis全局xml里面配置了類型處理器。但是MyBatis還是不會自動啟用你定義的typeHandler進(jìn)行轉(zhuǎn)換結(jié)果。需要人為的去指定哪些參數(shù)哪些結(jié)果類型去用自定義類型處理器。
需要人為配置jdbcType和javaType?;蛘咧苯佑胻ypeHandler屬性指定。
定義jdbcType和javaType
<resultMap id="AllColumnMap" type="model.DateDemo">
<result column="name" property="name" javaType="string" jdbcType="VARCHAR"/>
<result column="createdOn" property="createOn"/>
</resultMap>
直接使用typeHandler
<resultMap id="AllColumnMap" type="model.DateDemo">
<result column="name" property="name" javaType="string" jdbcType="VARCHAR" typeHandler="utils.ExampleTypeHandler"/>
<result column="createdOn" property="createOn"/>
</resultMap>
select語句
<select id="getUser" resultType="model.DateDemo" resultMap="AllColumnMap">
select * from datedemo;
</select>
4.3 枚舉類型的typeHandler
雖然MyBatis提供了兩個轉(zhuǎn)化枚舉的typeHandler給我們使用,但是對應(yīng)枚舉卻有自己的特殊轉(zhuǎn)換要求
org.apache.ibatis.type.EnumTypeHandler
org.apache.ibatis.type.EnumOrdinalTypeHandler
定義一個枚舉類型類
public enum Sex {
MALE(1, "男"),
FEMALE(2, "女");
private int id;
private String name;
private Sex(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
當(dāng)只有類用到字段屬性Sex時候,才用到枚舉類型處理器。一般實(shí)際項目中,都是使用int作為枚舉類型。這邊就跳過介紹。
5. ObjectFactory對象工廠
當(dāng)MyBatis在構(gòu)建一個結(jié)果返回的時候,都會使用ObjectFactory去構(gòu)建POJO,在MyBatis中可以定制自己的對象工廠。一般而言使用默認(rèn)的DefaultObjectFactory。這里不在贅述。
6.environments配置環(huán)境
配置環(huán)境可以注冊多個數(shù)據(jù)源(dataSource),每一個數(shù)據(jù)源分為兩大部分,一個是數(shù)據(jù)庫源的配置,另一個是數(shù)據(jù)庫事務(wù)(transactionManager)的配置。
<!--配置環(huán)境-->
<environments default="default">
<!--環(huán)境變量-->
<environment id="default">
<!--事務(wù)管理器-->
<transactionManager type="JDBC"></transactionManager>
<!--數(shù)據(jù)源-->
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
transactionManager配置的是數(shù)據(jù)庫事務(wù)。其中type屬性有三種配置方式。
- JDBC,采用JDBC方式管理事務(wù)
- Managed,采用容器方式管理事務(wù),在JNDI數(shù)據(jù)源中常用
- 自定義。
dataSource,是配置數(shù)據(jù)源連接的信息。type屬性有4種。
- Unpooled,非連接池數(shù)據(jù)庫
- pooled,連接池數(shù)據(jù)庫
- jndi,jndi數(shù)據(jù)源
- 自定義。
6.1 數(shù)據(jù)庫事務(wù)
數(shù)據(jù)庫事務(wù)是由SqlSession去控制的,可以通過SqlSession提交(commit)或者回滾(rollback)。如果成功就提交,如果失敗就回滾。
try {
sqlSession.commit();
} catch (Exception ex) {
ex.printStackTrace();
sqlSession.rollback();
}
7.mappers(映射器)
上述的一些是MyBatis的一些行為屬性配置。那么我們現(xiàn)在要定義SQL映射語句了。但是首先我們需要告訴MyBatis到哪里去找到這些語句。
可以使用類路徑的資源引用,或者完全限定的資源定位符(包括:file:///的URL),或者類名和包名。
- 1.文件路徑引入(推薦)
<mappers>
<mapper resource="mapper/DateDemoDao.xml"></mapper>
</mappers>
- 2.包名引入
<!-- Register all interfaces in a package as mappers -->
<mappers>
<package name="org.mybatis.builder"/>
</mappers>
- 3.使用類注冊
<!-- Using mapper interface classes -->
<mappers>
<mapper class="org.mybatis.builder.AuthorMapper"/>
<mapper class="org.mybatis.builder.BlogMapper"/>
<mapper class="org.mybatis.builder.PostMapper"/>
</mappers>
- 4.使用url注冊
<!-- Using url fully qualified paths -->
<mappers>
<mapper url="file:///var/mappers/AuthorMapper.xml"/>
<mapper url="file:///var/mappers/BlogMapper.xml"/>
<mapper url="file:///var/mappers/PostMapper.xml"/>
</mappers>