mybatis-config详解
5.1 属性、全局设置、别名
5.1.1 本章目标
学会使用XML配置文件配置Mybatis
5.1.2 本节目标
详细了解每个属性的作用
5.1.3 mybatis-config.xml介绍
以下是mybatis官网关于配置文件的说明
*注意:配置项的顺序不能颠倒,如果颠倒了它们的顺序,在MyBatis的自启动阶段会发生异常,导致程序无法运行。
报错信息为:元素类型为 "configuration" 的内容必须匹配 "(properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,objectWrapperFactory?,reflectorFactory?,plugins?,environments?,databaseIdProvider?,mappers?)"。
5.1.4 properties介绍
这些属性可以在外部进行配置,并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性,也可以在xml配置文件中使用 properties 元素的子元素property中设置
5.1.5 properties配置数据库参数
<properties >
<property name="driver" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/book_system"></property>
<property name="username" value="root"></property>
<property name="password" value="123456"></property>
</properties>
5.1.6 引用properties并设置默认值
新建db.properties文件,写入如下内容:
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/book_system
username=root
password=123456
<configuration>
<properties resource="db.properties"></properties>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
</configuration>
注意这里的关键点:
- 默认的环境 ID(比如:default="development")。
- 每个 environment 元素定义的环境 ID(比如:id="development")。
- 事务管理器的配置(比如:type="JDBC")。
- 数据源的配置(比如:type="POOLED")。
默认的环境和环境ID是自解释的,因此一目了然。你可以对环境随意命名,但一定要保证默认的环境 ID 要匹配其中一个环境 ID。
事务管理器(transactionManager)
在 MyBatis 中有两种类型的事务管理器(也就是 type=”[JDBC|MANAGED]”):
- JDBC – 这个配置就是直接使用了 JDBC 的提交和回滚设置,它依赖于从数据源得到的连接来管理事务作用域。
- MANAGED – 这个配置几乎没做什么。它从来不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如 JEE 应用服务器的上下文)。 默认情况下它会关闭连接,然而一些容器并不希望这样,因此需要将 closeConnection 属性设置为 false 来阻止它默认的关闭行为。例如:
<transactionManager type="MANAGED">
<property name="closeConnection" value="false"/>
</transactionManager>
数据源(dataSource)
dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象的资源。
- 许多 MyBatis 的应用程序会按示例中的例子来配置数据源。虽然这是可选的,但为了使用延迟加载,数据源是必须配置的。
有三种内建的数据源类型(也就是 type=”[UNPOOLED|POOLED|JNDI]”):
UNPOOLED– 这个数据源的实现只是每次被请求时打开和关闭连接。虽然有点慢,但对于在数据库连接可用性方面没有太高要求的简单应用程序来说,是一个很好的选择。 不同的数据库在性能方面的表现也是不一样的,对于某些数据库来说,使用连接池并不重要,这个配置就很适合这种情形。UNPOOLED 类型的数据源仅仅需要配置以下 5 种属性:
driver
– 这是 JDBC 驱动的 Java 类的完全限定名(并不是 JDBC 驱动中可能包含的数据源类)。url
– 这是数据库的 JDBC URL 地址。username
– 登录数据库的用户名。password
– 登录数据库的密码。defaultTransactionIsolationLevel
– 默认的连接事务隔离级别。
作为可选项,你也可以传递属性给数据库驱动。要这样做,属性的前缀为“driver.”,例如:
driver.encoding=UTF8
这将通过 DriverManager.getConnection(url,driverProperties) 方法传递值为 UTF8
的 encoding
属性给数据库驱动。
POOLED– 这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来,避免了创建新的连接实例时所必需的初始化和认证时间。 这是一种使得并发 Web 应用快速响应请求的流行处理方式。
除了上述提到 UNPOOLED 下的属性外,还有更多属性用来配置 POOLED 的数据源:
poolMaximumActiveConnections
– 在任意时间可以存在的活动(也就是正在使用)连接数量,默认值:10poolMaximumIdleConnections
– 任意时间可能存在的空闲连接数。poolMaximumCheckoutTime
– 在被强制返回之前,池中连接被检出(checked out)时间,默认值:20000 毫秒(即 20 秒)poolTimeToWait
– 这是一个底层设置,如果获取连接花费了相当长的时间,连接池会打印状态日志并重新尝试获取一个连接(避免在误配置的情况下一直安静的失败),默认值:20000 毫秒(即 20 秒)。poolMaximumLocalBadConnectionTolerance
– 这是一个关于坏连接容忍度的底层设置, 作用于每一个尝试从缓存池获取连接的线程. 如果这个线程获取到的是一个坏的连接,那么这个数据源允许这个线程尝试重新获取一个新的连接,但是这个重新尝试的次数不应该超过poolMaximumIdleConnections
与poolMaximumLocalBadConnectionTolerance
之和。 默认值:3 (新增于 3.4.5)poolPingQuery
– 发送到数据库的侦测查询,用来检验连接是否正常工作并准备接受请求。默认是“NO PING QUERY SET”,这会导致多数数据库驱动失败时带有一个恰当的错误消息。poolPingEnabled
– 是否启用侦测查询。若开启,需要设置poolPingQuery
属性为一个可执行的 SQL 语句(最好是一个速度非常快的 SQL 语句),默认值:false。poolPingConnectionsNotUsedFor
– 配置 poolPingQuery 的频率。可以被设置为和数据库连接超时时间一样,来避免不必要的侦测,默认值:0(即所有连接每一时刻都被侦测 — 当然仅当 poolPingEnabled 为 true 时适用)。
JNDI – 这个数据源的实现是为了能在如 EJB 或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个 JNDI 上下文的引用。这种数据源配置只需要两个属性:
initial_context
– 这个属性用来在 InitialContext 中寻找上下文(即,initialContext.lookup(initial_context))。这是个可选属性,如果忽略,那么 data_source 属性将会直接从 InitialContext 中寻找。data_source
– 这是引用数据源实例位置的上下文的路径。提供了 initial_context 配置时会在其返回的上下文中进行查找,没有提供时则直接在 InitialContext 中查找。
和其他数据源配置类似,可以通过添加前缀“env.”直接把属性传递给初始上下文。比如:
env.encoding=UTF8
这就会在初始上下文(InitialContext)实例化时往它的构造方法传递值为 UTF8
的 encoding
属性。
从 MyBatis 3.4.2 开始,你可以为占位符指定一个默认值。例如:
<property name="username" value="${username:root}"/> <!-- 如果属性 'username' 没有被配置,'username' 属性的值将为 'root' -->
这个特性默认是关闭的。要启用这个特性,需要添加一个特定的属性来开启这个特性。例如:
<property name="org.apache.ibatis.parsing.PropertyParser.enable-default-value" value="true"/> <!-- 启用默认值特性 -->
5.1.7 settings介绍及作用
这是 MyBatis 中极为重要的调整设置,它们的配置非常重要,因为它们会改变 MyBatis 的运行时行为。
5.1.8 settings中可配置的属性介绍(参照官网)
- cacheEnabled
- lazyLoadingEnabled
- aggressiveLazyLoading
- multipleResultSetsEnabled
- useColumnLabel
使用列标签代替列名。不同的驱动在这方面会有不同的表现,具体可参考相关驱动文档或通过测试这两种不同的模式来观察所用驱动的结果。 - useGeneratedKeys
允许 JDBC 支持自动生成主键,需要驱动兼容。如果设置为 true 则这个设置强制使用自动生成主键,尽管一些驱动不能兼容但仍可正常工作(比如 Derby)。 - autoMappingBehavior
指定 MyBatis 是否以及如何自动映射指定的列到字段或属性。NONE 表示取消自动映射;PARTIAL 只会自动映射没有定义嵌套结果集映射的结果集。FULL 会自动映射任意复杂的结果集(包括嵌套和其他情况)。 - autoMappingUnknownColumnBehavior
- defaultExecutorType
配置默认的执行器。SIMPLE 就是普通的执行器;REUSE 执行器会重用预处理语句(prepared statements);BATCH 执行器将重用语句并执行批量更新。 - defaultStatementTimeout
设置超时时间,它决定驱动等待数据库响应的秒数。 - defaultFetchSize
- safeRowBoundsEnabled
- safeResultHandlerEnabled
- mapUnderscoreToCamelCase
是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN 到经典 Java 属性名 aColumn 的类似映射。
开启:
<setting name="mapUnderscoreToCamelCase" value="true"/>
未开启:
- localCacheScope
- jdbcTypeForNull
- lazyLoadTriggerMethods
- defaultScriptingLanguage
- defaultEnumTypeHandler
- callSettersOnNulls
- returnInstanceForEmptyRow
- logPrefix
- logImpl
指定 MyBatis 所用日志的具体实现,未指定时将自动查找。
<setting name="logImpl" value="STDOUT_LOGGING" />
开启后效果
- proxyFactory
- useActualParamName
- configurationFactory
5.1.9 如何配置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="logImpl" value="STDOUT_LOGGING" />
<setting name="mapUnderscoreToCamelCase" value="true"/>
<setting name="localCacheScope" value="SESSION"/>
<setting name="jdbcTypeForNull" value="OTHER"/>
<setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
</settings>
5.1.10 设置别名
类型别名是为 Java 类型命名的一个短的名字。它只和 XML 配置有关,存在的意义仅在于用来减少类完全限定名的冗余。
Mybatis中已经定义好的别名
5.1.11 演示效果
<typeAliases>
<typeAlias type="com.study.pojo.Book" alias="book" />
</typeAliases>
<select id="getBookList" resultType="book">
SELECT * FROM book
</select>
5.2 类型转换器
5.2.1 本节目标
了解Mybatis内置的类型转换器,学会自定义Mybatis类型转换器
5.2.1 类型转换器介绍
mybatis作为一个ORM框架,要求java中的对象与数据库中的表记录应该对应 因此java类名-数据库表名,java类属性名-数据库表字段名,java类属性类型-数据库字段类型 前面两个都容易设置,但是第三点要求经常会出现java类型和数据库的存储类型不一样, 例如java类型是String,数据库中存储的是char、varchar、text
对于一般常见的类型对应,mybatis已经内部包含了类型转换器,使String类型的java属性可以直接插入到数据库中,也可以直接从数据库中取出直接赋值给对象的属性
5.2.2 Mybatis系统定义的TypeHandler
5.2.2.1 Mybatis系统定义的TypeHandler
5.2.2.2 mybatis支持的jdbcType转换为javaType对应关系
JDBC Type Java Type
- CHAR String
- VARCHAR String
- LONGVARCHAR String
- NUMERIC java.math.BigDecimal
- DECIMAL java.math.BigDecimal
- BIT boolean
- BOOLEAN boolean
- TINYINT byte
- SMALLINT short
- INTEGER int
- BIGINT long
- REAL float
- FLOAT double
- DOUBLE double
- BINARY byte[]
- VARBINARY byte[]
- LONGVARBINARY byte[]
- DATE java.sql.Date
- TIME java.sql.Time
- TIMESTAMP java.sql.Timestamp
- CLOB Clob
- BLOB Blob
- ARRAY Array
- DISTINCT mapping of underlying type
- STRUCT Struct
- REF Ref
- DATALINK java.net.URL[color=red][/color]
5.2.3 创建工程演示
5.2.4 查询不同类型的数据
<select id="getBookList_resultMap" resultMap="resultData">
SELECT * FROM book
</select>
<resultMap id="resultData" type="book" >
<result property="bookId" column="book_id" javaType="int" jdbcType="INTEGER"/>
<result property="bookName" column="book_name" javaType="string" jdbcType="VARCHAR"/>
<result property="publishDate" column="publish_date" javaType="java.sql.Date" jdbcType="DATE"/>
<result property="publishHouse" column="publish_house" javaType="string" jdbcType="VARCHAR"/>
<result property="author" column="author" javaType="string" jdbcType="VARCHAR"/>
<result property="price" column="price" javaType="double" jdbcType="DOUBLE"/>
</resultMap>
5.2.5 MyBatis自定义TypeHandler
创建我们自己的类型转换类MyTypeHandler需要
实现org.apache.ibatis.type.TypeHandler接口,或继承org.apache.ibatis.type.BaseTypeHandler类
5.2.6 如何将数据库类型转换为枚举类型?
Mybatis中默认提供了两种Enum类型的handler:EnumTypeHandler和EnumOrdinalTypeHandler。
- EnumTypeHandler:将enum按照String存入库,存储为varchar类型;
- EnumOrdinalTypeHandler:将enum按照Integer处理,存储为int(smallint、tinyint也可以)。
5.2.7 创建一个枚举类型
public enum GenderTypeEnum {
/**
* female
*/
FEMALE(0,"女"),
/**
* male
*/
MALE(1,"男"),
/**
* unknown
*/
UNKNOWN(2,"未知");
private int value;
private String desc;
GenderTypeEnum(int value, String desc) {
this.value = value;
this.desc = desc;
}
public int value(){
return this.value;
}
public String desc(){
return this.desc;
}
}
5.2.8 编写自定义类型转换器
public class MyTypeHandler implements TypeHandler {
/**
* 此方法是在插入是进行设置参数
* 参数: PreparedStatement
* int i 为Jdbc预编译时设置参数的索引值
* Object obj 要插入的参数值
* JdbcType jdbcType 要插入JDBC的类型
*/
@Override
public void setParameter(PreparedStatement preparedStatement, int i, Object o, JdbcType jdbcType) throws SQLException {
if( o == null){
preparedStatement.setInt(i,0);
}
Boolean par = (Boolean)o;
if(par){
preparedStatement.setInt(i, 1);
}else{
preparedStatement.setInt(i, 0);
}
}
@Override
public Object getResult(ResultSet resultSet, String s) throws SQLException {
int flag = resultSet.getInt(s);
Boolean b = Boolean.FALSE;
if(flag == 1){
b = Boolean.TRUE;
}
return b;
}
@Override
public Object getResult(ResultSet resultSet, int i) throws SQLException {
return null;
}
@Override
public Object getResult(CallableStatement callableStatement, int i) throws SQLException {
return null;
}
}
public class MyTypeHandler2 extends BaseTypeHandler {
@Override
public void setNonNullParameter(PreparedStatement preparedStatement, int i, Object o, JdbcType jdbcType) throws SQLException {
if( o == null){
preparedStatement.setInt(i,0);
}
Boolean par = (Boolean)o;
if(par){
preparedStatement.setInt(i, 1);
}else{
preparedStatement.setInt(i, 0);
}
}
@Override
public Object getNullableResult(ResultSet resultSet, String s) throws SQLException {
int flag = resultSet.getInt(s);
Boolean b = Boolean.FALSE;
if(flag == 1){
b = Boolean.TRUE;
}
return b;
}
@Override
public Object getNullableResult(ResultSet resultSet, int i) throws SQLException {
return null;
}
@Override
public Object getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
return null;
}
}
现在我们就需要最后一步,进行自定义类型转换器的注册(在面向接口编程中好多我们实现或者集成人家的接口或者是实现类都需要去注册,这样子程序在运行时才会知道运行的实现类是哪个)。
5.2.9 注册类型转换器
注册类型转换器的方式有两种: 1,进行全局的注册 在核心配置文件中添加:
<typeHandlers>
<typeHandler handler="com.study.typehandler.MyTypeHandler"
javaType="Boolean" jdbcType="BIGINT" />
</typeHandlers>
这种配置的作用域是全局的,也就是说所有的我们书写的Mapper中凡是满足Java类型是Boolean数据库类型是Number或者是int时(满足这个条件 javaType=“Boolean” jdbcType=“BIGINT” ),都会执行这个MyTypeHandler。
2,局部注册 在对应的Mapper文件中添加resultMap标签:
<select id="getBorrowInfoList" resultType="borrowInfo" resultMap="borrowInfoMap">
SELECT * FROM borrow_info
</select>
<resultMap id="borrowInfoMap" type="borrowInfo">
<result property="borrowState" column="borrow_state" typeHandler="com.study.typehandler.MyTypeHandler"/>
</resultMap>
如果你注册了TypeHandler。在Mapper.xml中只需要声明jdbcType和javaType,无需再声明具体的typeHandler。Mybatis会自动通过jdbcType、javaType来映射到具体注册的TypeHandler上去
<result property="borrowState" column="borrow_state" javaType="Boolean" jdbcType="BIGINT"/>