组态
MyBatis配置包含对MyBatis的行为具有重大影响的设置和属性。文件的高层结构如下:
- 组态
- 性能
- 设置
- 类型别名
- 类型处理器
- objectFactory对象
- 插件
- 环境
- 环境
- transactionManager的
- 数据源
- 环境
- databaseIdProvider
- 映射器
性能
这些是可外部化的,可替换的属性,可以在典型的Java属性文件实例中配置,或者通过属性元素的子元素传入。例如:
<properties resource="org/mybatis/example/config.properties"> <property name="username" value="dev_user"/> <property name="password" value="F2Fa3!33TYyg"/> </properties>
然后可以在整个配置文件中使用这些属性来替代需要动态配置的值。例如:
<dataSource type="POOLED"> <property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </dataSource>
本例中的用户名和密码将被属性元素中设置的值替换。驱动程序和url属性将被替换为config.properties文件中包含的值。这为配置提供了很多选项。
属性也可以传递到SqlSessionFactoryBuilder.build()方法中。例如:
SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader, props); // ... or ... SqlSessionFactory factory = new SqlSessionFactoryBuilder.build(reader, environment, props);
如果一个属性存在于多个这样的地方,MyBatis会按以下顺序加载它们:
- 首先读取属性元素的主体中指定的属性,
- 从属性元素的类路径资源或url属性加载的属性被读取,并覆盖已指定的任何重复属性,
- 最后读取作为方法参数传递的属性,并覆盖可能已经从属性主体和资源/ url属性加载的任何重复属性。
因此,最高优先级属性是作为方法参数传递的属性,接着是资源/ URL属性,最后是属性元素的主体中指定的属性。
由于MyBatis 3.4.2,你可以指定一个默认值到占位符如下:
<dataSource type="POOLED"> <!-- ... --> <property name="username" value="${username:ut_user}"/> <!-- If 'username' property not present, username become 'ut_user' --> </dataSource>
此功能在默认情况下是禁用的。如果你指定一个默认值到占位符,你应该通过添加一个特殊的属性来启用这个功能,如下所示:
<properties resource="org/mybatis/example/config.properties"> <!-- ... --> <property name="org.apache.ibatis.parsing.PropertyParser.enable-default-value" value="true"/> <!-- Enable this feature --> </properties>
注意如果你已经使用了“:”作为属性键(例如db:username),或者你已经在你的sql 中使用了OGNL表达式的三元运算符(例如$ {tableName!= null?tableName:'global_constants'})定义,你应该通过添加一个特殊的属性来改变分隔键和默认值的字符,如下所示:
<properties resource="org/mybatis/example/config.properties"> <!-- ... --> <property name="org.apache.ibatis.parsing.PropertyParser.default-value-separator" value="?:"/> <!-- Change default value of separator --> </properties>
<dataSource type="POOLED"> <!-- ... --> <property name="username" value="${db:username?:ut_user}"/> </dataSource>
设置
这些是非常重要的调整,修改MyBatis在运行时的行为方式。下表介绍了设置,含义及其默认值。
设置 | 描述 | 有效值 | 默认 |
---|---|---|---|
cacheEnabled | 全局启用或禁用在此配置下的任何映射器中配置的任何缓存。 | true | 假 | 真正 |
lazyLoadingEnabled | 全局启用或禁用延迟加载。启用时,所有关系都将被延迟加载。通过在其上使用fetchType属性,该值可以被特定关系取代。 | true | 假 | 假 |
aggressiveLazyLoading | 启用时,任何方法调用都会加载对象的所有惰性属性。否则,每个属性都按需加载(另请参阅lazyLoadTriggerMethods)。 | true | 假 | 错误(≤3.4.1为真) |
multipleResultSetsEnabled | 允许或禁止从单个语句返回多个ResultSet(需要兼容的驱动程序)。 | true | 假 | 真正 |
useColumnLabel | 使用列标签而不是列名称。不同的司机在这方面的表现有所不同。请参阅驱动程序文档,或者测试两种模式以确定您的驱动程序的行为。 | true | 假 | 真正 |
useGeneratedKeys | 允许JDBC支持生成的密钥。兼容的驱动程序是必需的。如果设置为true,这个设置会强制使用生成的密钥,因为一些驱动程序拒绝兼容性,但仍然有效(例如Derby)。 | true | 假 | 假 |
autoMappingBehavior | 指定MyBatis是否以及如何自动将列映射到字段/属性。NONE禁用自动映射。PARTIAL只会自动映射结果,而不会在内部定义嵌套的结果映射。FULL将自动映射任何复杂的结果映射(包含嵌套或其他)。 | 无,部分,完整 | 局部 |
autoMappingUnknownColumnBehavior | 指定检测自动映射目标的未知列(或未知属性类型)时的行为。
| 无,警告,失败 | 没有 |
defaultExecutorType | 配置默认执行程序。简单的执行者没有什么特别的。REUSE执行程序重用预准备语句。BATCH执行程序重用语句并批量更新。 | 简单的重新使用BATCH | 简单 |
defaultStatementTimeout | 设置驱动程序等待数据库响应的秒数。 | 任何正整数 | 未设置(null) |
defaultFetchSize | 设置驱动程序提示,以控制返回结果的读取大小。这个参数值可以被查询设置覆盖。 | 任何正整数 | 未设置(null) |
safeRowBoundsEnabled | 允许在嵌套语句中使用RowBounds。如果允许,设置为false。 | true | 假 | 假 |
safeResultHandlerEnabled | 允许在嵌套语句中使用ResultHandler。如果允许,设置为false。 | true | 假 | 真正 |
mapUnderscoreToCamelCase | 使经典数据库列名称A_COLUMN自动映射到骆驼案例经典Java属性名称aColumn。 | true | 假 | 假 |
localCacheScope | MyBatis使用本地缓存来防止循环引用,并加速重复的嵌套查询。默认情况下(SESSION)会话中执行的所有查询都被缓存。如果localCacheScope = STATEMENT本地会话将仅用于语句执行,则不会在对同一个SqlSession的两个不同调用之间共享数据。 | 会话| 声明 | SESSION |
jdbcTypeForNull | 当没有为参数提供特定的JDBC类型时,指定空值的JDBC类型。某些驱动程序需要指定列的JDBC类型,但其他驱动程序则使用NULL,VARCHAR或OTHER等通用值。 | JdbcType枚举。最常见的是:NULL,VARCHAR和OTHER | 其他 |
lazyLoadTriggerMethods | 指定哪个对象的方法触发延迟加载 | 用逗号分隔的方法名称列表 | 等于,克隆,hashCode时的toString |
defaultScriptingLanguage | 指定动态SQL生成默认使用的语言。 | 类型别名或完全限定的类名称。 | org.apache.ibatis.scripting.xmltags.XMLLanguageDriver |
defaultEnumTypeHandler | 指定类型处理器默认为枚举使用。(自:3.4.5) | 类型别名或完全限定的类名称。 | org.apache.ibatis.type.EnumTypeHandler |
callSettersOnNulls | 指定当检索值为null时是否调用setter或map的put方法。当您依赖Map.keySet()或空值初始化时,它非常有用。注意诸如(int,boolean等)的原语不会被设置为null。 | true | 假 | 假 |
returnInstanceForEmptyRow | 默认情况下,MyBatis 在返回行的所有列都为NULL时返回null。启用此设置后,MyBatis将返回一个空实例。请注意,它也适用于嵌套结果(即收集和关联)。由于:3.4.2 | true | 假 | 假 |
logPrefix | 指定MyBatis将添加到记录器名称的前缀字符串。 | 任何字符串 | 没有设置 |
logImpl | 指定MyBatis应该使用哪个日志记录实现。如果这个设置不存在,日志实现将被自动发现。 | SLF4J | LOG4J |LOG4J2 |JDK_LOGGING |COMMONS_LOGGING | STDOUT_LOGGING |NO_LOGGING | 没有设置 |
ProxyFactory里 | 指定MyBatis将用于创建延迟加载对象的代理工具。 | CGLIB | 了Javassist | JAVASSIST(MyBatis 3.3或以上) |
vfsImpl | 指定VFS实现 | 自定义VFS实现的完全限定类名,用逗号分隔。 | 没有设置 |
useActualParamName | 允许通过在方法签名中声明的实际名称来引用语句参数。要使用此功能,必须使用-parameters选项在Java 8中编译项目。(自:3.4.1) | true | 假 | 真正 |
configurationFactory | 指定提供配置实例的类。返回的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>
类型别名只是Java类型的简称。它只与XML配置相关,并且简单地存在以减少完全限定的类名的多余类型。例如:
<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>
有了这个配置, Blog 现在可以在任何可以使用domain.blog.Blog的地方 使用。
您还可以指定一个包,其中MyBatis将搜索bean。例如:
<typeAliases> <package name = “domain.blog” /> </ typeAliases>
在domain.blog中找到的每个bean ,如果没有找到注释,将被注册为使用该bean的非资本化的非限定类名称的别名。这是 domain.blog.Author 将注册为 作者。如果 找到@Alias注释,它的值将被用作别名。看下面的例子:
@Alias("author") public class Author { ... }
常见Java类型有许多内置类型别名。它们都是大小写不敏感的,请注意由于重载名称的特殊处理。
_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 |
每当MyBatis在PreparedStatement上设置参数或从ResultSet中检索一个值时,就会使用TypeHandler以适合Java类型的方式检索值。下表介绍了默认的TypeHandlers。
注意 从版本3.4.5开始,MyBatis默认支持JSR-310(日期和时间API)。
Type Handler | Java Types | JDBC Types |
---|---|---|
BooleanTypeHandler | java.lang.Boolean, boolean | Any compatible BOOLEAN |
ByteTypeHandler | java.lang.Byte, byte | Any compatible NUMERIC or BYTE |
ShortTypeHandler | java.lang.Short, short | Any compatible NUMERIC or SHORT INTEGER |
IntegerTypeHandler | java.lang.Integer, int | Any compatible NUMERIC or INTEGER |
LongTypeHandler | java.lang.Long, long | Any compatible NUMERIC or LONG INTEGER |
FloatTypeHandler | java.lang.Float, float | Any compatible NUMERIC or FLOAT |
DoubleTypeHandler | java.lang.Double, double | Any compatible NUMERIC or DOUBLE |
BigDecimalTypeHandler | java.math.BigDecimal | Any compatible NUMERIC or 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[] | Any compatible byte stream type |
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, or unspecified |
EnumTypeHandler | Enumeration Type | VARCHAR any string compatible type, as the code is stored (not index). |
EnumOrdinalTypeHandler | Enumeration Type | Any compatible NUMERIC or DOUBLE, as the position is stored (not the code itself). |
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 or LONGVARCHAR |
JapaneseDateTypeHandler | java.time.chrono.JapaneseDate | DATE |
// ExampleTypeHandler.java @MappedJdbcTypes (的jdbcType 。VARCHAR )公共类ExampleTypeHandler 延伸BaseTypeHandler < 字符串> {您可以重写类型处理程序或创建自己的处理不支持的或非标准的类型。 为此,请实现 org.apache.ibatis.type.TypeHandler 接口 或扩展便捷类 org.apache.ibatis.type.BaseTypeHandler, 并可选择将其映射到JDBC类型。例如:
// ExampleTypeHandler.java @MappedJdbcTypes(JdbcType.VARCHAR) public class ExampleTypeHandler extends BaseTypeHandler<String> { @Override public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException { ps.setString(i, parameter); } @Override public String getNullableResult(ResultSet rs, String columnName) throws SQLException { return rs.getString(columnName); } @Override public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException { return rs.getString(columnIndex); } @Override public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { return cs.getString(columnIndex); } }
<!-- mybatis-config.xml --> <typeHandlers> <typeHandler handler="org.mybatis.example.ExampleTypeHandler"/> </typeHandlers>
使用这样的TypeHandler将覆盖Java String属性和VARCHAR参数和结果的现有类型处理程序。请注意,MyBatis不会检查数据库元数据以确定类型,因此您必须指定它是参数中的VARCHAR字段,并将结果映射到正确的类型处理程序中。这是由于MyBatis在语句执行之前不知道数据类型。
MyBatis会通过内省它的泛型来知道你想用这个TypeHandler处理的Java类型,但是你可以通过两种方式来覆盖这个行为:
- 将javaType属性添加到typeHandler元素(例如:javaType =“String”)
- 将@MappedTypes注释添加到TypeHandler类,指定要与之关联的Java类型列表。如果javaType属性也被指定,这个注解将被忽略。
关联的JDBC类型可以通过两种方式指定:
- 将jdbcType属性添加到typeHandler元素(例如:jdbcType =“VARCHAR”)。
- 将@MappedJdbcTypes注释添加到TypeHandler类中,以指定要与之关联的JDBC类型列表。如果还指定了jdbcType属性,则此注释将被忽略。
当决定在ResultMap中使用哪个TypeHandler时,Java类型是已知的(来自结果类型),但是JDBC类型是未知的。因此,MyBatis使用组合 javaType = [TheJavaType],jdbcType = null来选择一个TypeHandler。这意味着使用@MappedJdbcTypes注解将限制TypeHandler的作用域,并使其不可用于ResultMap,除非明确设置。为了使可用于在使用一个类型处理器的ResultMap,设置includeNullJdbcType =真正 的@MappedJdbcTypes注释。由于Mybatis 3.4.0然而,如果单一 类型处理器被注册为处理Java类型,它会被默认使用的ResultMap S使用该Java类型(即,即使没有includeNullJdbcType = TRUE)。
最后你可以让MyBatis搜索你的TypeHandlers:
<!-- mybatis-config.xml --> <typeHandlers> <package name="org.mybatis.example"/> </typeHandlers>
请注意,使用自动发现功能时,只能使用注释指定JDBC类型。
您可以创建一个能够处理多个类的泛型TypeHandler。为此,添加一个构造函数来接收这个类作为参数,MyBatis将在构造TypeHandler时传递实际的类。
//GenericTypeHandler.java public class GenericTypeHandler<E extends MyObject> extends BaseTypeHandler<E> { private Class<E> type; public GenericTypeHandler(Class<E> type) { if (type == null) throw new IllegalArgumentException("Type argument cannot be null"); this.type = type; } ...
EnumTypeHandler和EnumOrdinalTypeHandler是通用的TypeHandler。我们将在下面的章节中了解它们。
处理枚举
如果你想映射一个枚举,你将需要使用 EnumTypeHandler或EnumOrdinalTypeHandler。
例如,假设我们需要存储舍入模式,如果需要四舍五入,应该使用舍入模式。默认情况下,MyBatis使用EnumTypeHandler将Enum 值转换为它们的名字。
注意EnumTypeHandler与其他处理程序不同,它不能处理一个特定的类,而是任何扩展Enum的类但是,我们可能不想存储名称。我们的DBA可能会坚持使用整数代码。这很简单:将EnumOrdinalTypeHandler添加 到配置文件中的typeHandlers,现在每个RoundingMode将使用其序号值映射到一个整数。
<!-- mybatis-config.xml --> <typeHandlers> <typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler" javaType="java.math.RoundingMode"/> </typeHandlers>
但是如果你想在同一个地方将相同的Enum映射到一个字符串,而在另一个地方则是整数?
自动映射器将自动使用EnumOrdinalTypeHandler,所以如果我们想要回到使用普通的普通 EnumTypeHandler,我们必须明确地设置用于这些SQL语句的类型处理程序。
(Mapper文件只有在下一节才会介绍,所以如果这是您第一次阅读文档,那么您可能需要暂时跳过这个文档,稍后再回来。)
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="org.apache.ibatis.submitted.rounding.Mapper"> <resultMap type="org.apache.ibatis.submitted.rounding.User" id="usermap"> <id column="id" property="id"/> <result column="name" property="name"/> <result column="funkyNumber" property="funkyNumber"/> <result column="roundingMode" property="roundingMode"/> </resultMap> <select id="getUser" resultMap="usermap"> select * from users </select> <insert id="insert"> insert into users (id, name, funkyNumber, roundingMode) values ( #{id}, #{name}, #{funkyNumber}, #{roundingMode} ) </insert> <resultMap type="org.apache.ibatis.submitted.rounding.User" id="usermap2"> <id column="id" property="id"/> <result column="name" property="name"/> <result column="funkyNumber" property="funkyNumber"/> <result column="roundingMode" property="roundingMode" typeHandler="org.apache.ibatis.type.EnumTypeHandler"/> </resultMap> <select id="getUser2" resultMap="usermap2"> select * from users2 </select> <insert id="insert2"> insert into users2 (id, name, funkyNumber, roundingMode) values ( #{id}, #{name}, #{funkyNumber}, #{roundingMode, typeHandler=org.apache.ibatis.type.EnumTypeHandler} ) </insert> </mapper>
请注意,这迫使我们在select语句中使用resultMap 而不是resultType。
objectFactory对象
每次MyBatis创建一个结果对象的新实例时,它都会使用一个ObjectFactory实例来执行此操作。默认的ObjectFactory只是用默认的构造函数实例化目标类,或者如果存在参数映射,则实例化参数化的构造函数。如果你想重写ObjectFactory的默认行为,你可以创建自己的。例如:
// ExampleObjectFactory.java public class ExampleObjectFactory extends DefaultObjectFactory { public Object create(Class type) { return super.create(type); } public Object create(Class type, List<Class> constructorArgTypes, List<Object> constructorArgs) { return super.create(type, constructorArgTypes, constructorArgs); } public void setProperties(Properties properties) { super.setProperties(properties); } public <T> boolean isCollection(Class<T> type) { return Collection.class.isAssignableFrom(type); }}
<!-- mybatis-config.xml --> <objectFactory type="org.mybatis.example.ExampleObjectFactory"> <property name="someProperty" value="100"/> </objectFactory>
ObjectFactory接口非常简单。它包含两个创建方法,一个处理默认的构造函数,另一个处理参数化的构造函数。最后,可以使用setProperties方法来配置ObjectFactory。在ObjectFactory实例初始化之后,在objectFactory元素体内定义的属性将被传递给setProperties方法。
插件
MyBatis允许您在执行映射语句的某些点上拦截调用。默认情况下,MyBatis允许插件拦截以下方法调用:
- 执行器(更新,查询,flushStatements,提交,回滚,getTransaction,关闭,isClosed)
- ParameterHandler(getParameterObject,setParameters)
- ResultSetHandler(handleResultSets,handleOutputParameters)
- StatementHandler(准备,参数化,批处理,更新,查询)
这些类方法的细节可以通过查看每个方法的完整方法签名以及每个MyBatis发行版可用的源代码来发现。你应该理解你重写的方法的行为,假设你正在做的不仅仅是监视调用。如果您尝试修改或重写给定方法的行为,您可能会打破MyBatis的核心。这些是低级别的类和方法,所以请谨慎使用插件。
考虑到它们提供的功能,使用插件非常简单。只需实现Interceptor接口,确保指定要截取的特征。
// ExamplePlugin.java @Intercepts({@Signature( type= Executor.class, method = "update", args = {MappedStatement.class,Object.class})}) public class ExamplePlugin implements Interceptor { public Object intercept(Invocation invocation) throws Throwable { return invocation.proceed(); } public Object plugin(Object target) { return Plugin.wrap(target, this); } public void setProperties(Properties properties) { } }
<!-- mybatis-config.xml --> <plugins> <plugin interceptor="org.mybatis.example.ExamplePlugin"> <property name="someProperty" value="100"/> </plugin> </plugins>
上面的插件将拦截对Executor实例上的“update”方法的所有调用,该实例是负责映射语句的低级执行的内部对象。
注 覆盖配置类
除了使用插件修改核心MyBatis行为外,您还可以完全覆盖Configuration类。简单地扩展它,并覆盖里面的任何方法,并将其传递给SqlSessionFactoryBuilder.build(myConfig)方法的调用。虽然如此,这可能会对MyBatis的行为产生严重的影响,所以请谨慎使用。
环境
MyBatis可以配置多个环境。这有助于将SQL地图应用于多个数据库,原因很多。例如,您的开发,测试和生产环境可能有不同的配置。或者,您可能有多个共享相同模式的生产数据库,并且您希望为这两个数据库使用相同的SQL映射。有很多用例。
但要记住一件重要的事情:虽然可以配置多个环境,但每个SqlSessionFactory实例只能选择一个。
所以如果你想连接两个数据库,你需要创建两个SqlSessionFactory实例,每个实例一个。对于三个数据库,您需要三个实例,依此类推。这很容易记住:
- 每个数据库一个SqlSessionFactory实例
要指定要构建的环境,只需将其作为可选参数传递给SqlSessionFactoryBuilder即可。接受环境的两个签名是:
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment); SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment, properties);
如果省略了环境,则加载默认环境,如下所示:
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader); SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, properties);
environments元素定义了环境的配置方式。
<environments default="development"> <environment id="development"> <transactionManager type="JDBC"> <property name="..." value="..."/> </transactionManager> <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>
- 默认的环境ID(例如default =“development”)。
- 定义的每个环境的环境ID(例如id =“development”)。
- TransactionManager配置(例如type =“JDBC”)
- 数据源配置(例如type =“POOLED”)
默认环境和环境ID是自我解释的。把它们命名为任何你喜欢的,只要确保默认匹配其中的一个。
transactionManager的
MyBatis包含两个TransactionManager类型(即type =“[JDBC | MANAGED]”):
- JDBC - 该配置直接使用JDBC提交和回滚工具。它依赖于从dataSource中获取的连接来管理事务的范围。
- MANAGED - 这种配置几乎没有任何作用。它从不提交或回滚连接。相反,它允许容器管理事务的整个生命周期(例如JEE应用服务器上下文)。默认情况下它会关闭连接。但是,有些容器并不期望这样做,因此如果您需要停止关闭连接,请将“closeConnection”属性设置为false。例如:
-
<transactionManager type="MANAGED"> <property name="closeConnection" value="false"/> </transactionManager>
注意 如果打算在Spring中使用MyBatis,则不需要配置任何TransactionManager,因为Spring模块将自行设置覆盖之前设置的配置。
这些TransactionManager类型都不需要任何属性。但是,它们都是类型别名,所以换句话说,不要使用它们,而是可以将自己的完全限定类名称或类型别名引用到您自己实现的TransactionFactory接口。
public interface TransactionFactory { void setProperties(Properties props); Transaction newTransaction(Connection conn); Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit); }
在XML中配置的任何属性将在实例化后传递给setProperties()方法。您的实现也需要创建一个事务实现,这也是一个非常简单的接口:
public interface Transaction { Connection getConnection() throws SQLException; void commit() throws SQLException; void rollback() throws SQLException; void close() throws SQLException; Integer getTimeout() throws SQLException; }
使用这两个接口,您可以完全自定义MyBatis如何处理事务。
数据源
dataSource元素使用标准JDBC DataSource接口配置JDBC Connection对象的源。
- 大多数MyBatis应用程序将像例子一样配置一个数据源。但是,这不是必需的。实现,虽然,为了方便延迟加载,这个数据源是必需的。
有三种内置的dataSource类型(即type =“[UNPOOLED | POOLED | JNDI]”):
UNPOOLED - 这个DataSource的实现只是在每次请求时打开和关闭一个连接。虽然速度稍慢,但对于不要求立即可用连接性能的简单应用来说,这是一个不错的选择。不同的数据库在这个性能领域也不同,所以对于一些数据库来说可能不那么重要,这个配置将是理想的。UNPOOLED数据源仅配置了五个属性:
- 驱动程序 - 这是JDBC驱动程序的完全限定Java类(如果您的驱动程序包含一个,则不是DataSource类的)。
- url - 这是数据库实例的JDBC URL。
- 用户名 - 用于登录的数据库用户名。
- 密码 - 用于登录的数据库密码。
- defaultTransactionIsolationLevel - 连接的默认事务隔离级别。
或者,您也可以将属性传递给数据库驱动程序。为此,请使用驱动程序将属性前缀。, 例如:
- driver.encoding = UTF8
这将通过DriverManager.getConnection(url,driverProperties)方法将属性编码(通过值UTF8)传递给数据库驱动程序。
POOLED - DataSource的这种实现将JDBC Connection对象池,以避免创建新的Connection实例所需的初始连接和身份验证时间。这是并行Web应用程序实现最快响应的流行方法。
除了上面的(UNPOOLED)属性之外,还有更多可用于配置POOLED数据源的属性:
- poolMaximumActiveConnections - 这是在任何给定时间可以存在的活动(即正在使用)连接的数量。默认:10
- poolMaximumIdleConnections - 在任何给定时间可以存在的空闲连接数。
- poolMaximumCheckoutTime - 这是在强制返回连接之前可以“检出”连接的时间量。默认值:20000ms(即20秒)
- poolTimeToWait - 这是一个低级别的设置,使池有机会打印日志状态,并重新尝试获取连接的情况下,它需要非常长的时间(以避免如果池配置错误永远沉默失败)。默认值:20000ms(即20秒)
- poolMaximumLocalBadConnectionTolerance - 这是一个关于任何线程的不良连接公差的低级设置。如果一个线程连接不好,可能还有另一个机会重新尝试获得另一个有效的连接。但重试次数不应超过poolMaximumIdleConnections 和poolMaximumLocalBadConnectionTolerance之和。默认:3(自:3.4.5)
- poolPingQuery - 将Ping查询发送到数据库以验证连接是否处于良好工作状态并准备好接受请求。缺省值是“NO PING QUERY SET”,这将导致大多数数据库驱动程序失败,并显示正常的错误消息。
- poolPingEnabled - 启用或禁用ping查询。如果启用,您还必须使用有效的SQL语句(最好是非常快的)来设置poolPingQuery属性。默认:false。
- poolPingConnectionsNotUsedFor - 这将配置poolPingQuery的使用频率。这可以设置为匹配数据库连接的典型超时,以避免不必要的ping。默认值:0(即所有的连接每次ping - 但只有当poolPingEnabled是真的当然)。
JNDI - DataSource的这个实现是为了与EJB或Application Server这样的容器一起使用的,这些容器可以集中或者外部地配置DataSource,并且在JNDI上下文中引用它。这个DataSource配置只需要两个属性:
- initial_context - 该属性用于InitialContext的上下文查找(即initialContext.lookup(initial_context))。该属性是可选的,如果省略,那么data_source属性将直接在InitialContext上查找。
- data_source - 这是可以找到对DataSource实例的引用的上下文路径。它将根据initial_context查找返回的上下文进行查找,如果没有提供initial_context,则直接对InitialContext进行查找。
与其他DataSource配置类似,可以通过在env前面添加属性,直接将属性发送到InitialContext 。, 例如:
- env.encoding = UTF8
这将 在实例化时将带有UTF8值的属性编码发送到InitialContext的构造函数。
您可以通过实现org.apache.ibatis.datasource.DataSourceFactory接口来插入任何第三方数据源:
public interface DataSourceFactory { void setProperties(Properties props); DataSource getDataSource(); }
org.apache.ibatis.datasource.unpooled.UnpooledDataSourceFactory可以用作超类来构建新的数据源适配器。例如,这是插入C3P0所需的代码:
import org.apache.ibatis.datasource.unpooled.UnpooledDataSourceFactory; import com.mchange.v2.c3p0.ComboPooledDataSource; public class C3P0DataSourceFactory extends UnpooledDataSourceFactory { public C3P0DataSourceFactory() { this.dataSource = new ComboPooledDataSource(); } }
要设置它,请为每个希望MyBatis调用的setter方法添加一个属性。下面是一个连接到PostgreSQL数据库的示例配置:
<dataSource type="org.myproject.C3P0DataSourceFactory"> <property name="driver" value="org.postgresql.Driver"/> <property name="url" value="jdbc:postgresql:mydb"/> <property name="username" value="postgres"/> <property name="password" value="root"/> </dataSource>
MyBatis能够根据您的数据库供应商执行不同的语句。多数据库供应商支持基于映射语句databaseId属性。MyBatis将加载所有没有databaseId属性或与当前匹配的databaseId的语句。如果在使用和不使用databaseId的情况下发现相同的语句,则后者将被丢弃。要启用多供应商支持,请 按如下方式将databaseIdProvider添加到mybatis-config.xml文件中:
<databaseIdProvider type = “DB_VENDOR” />
DB_VENDOR实现databaseIdProvider设置为databaseId由DatabaseMetaData#getDatabaseProductName()返回的字符串 。假设通常该字符串太长,并且同一产品的不同版本可能会返回不同的值,则可以通过添加如下属性将其转换为较短的值:
<databaseIdProvider type="DB_VENDOR"> <property name="SQL Server" value="sqlserver"/> <property name="DB2" value="db2"/> <property name="Oracle" value="oracle" /> </databaseIdProvider>
当提供属性时,DB_VENDOR databaseIdProvider将搜索与返回的数据库产品名称中找到的第一个键相对应的属性值,如果没有匹配的属性,则搜索“null”。在这种情况下,如果getDatabaseProductName()返回“Oracle(DataDirect)”,那么databaseId将被设置为“oracle”。
您可以通过实现org.apache.ibatis.mapping.DatabaseIdProvider接口来构建自己的DatabaseIdProvider, 并将其注册到mybatis-config.xml中:
public interface DatabaseIdProvider { void setProperties(Properties p); String getDatabaseId(DataSource dataSource) throws SQLException; }
映射器
现在MyBatis的行为已经配置了上面的配置元素,我们准备好定义映射的SQL语句。但首先,我们需要告诉MyBatis在哪里找到它们。Java在这方面并没有提供任何好的自动发现方法,所以最好的办法就是告诉MyBatis在哪里找到映射文件。您可以使用classpath相对资源引用,完全限定的url引用(包括file:/// URLs),类名称或包名称。例如:
<!-- Using classpath relative resources --> <mappers> <mapper resource="org/mybatis/builder/AuthorMapper.xml"/> <mapper resource="org/mybatis/builder/BlogMapper.xml"/> <mapper resource="org/mybatis/builder/PostMapper.xml"/> </mappers>
<!-- 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>
<!-- Using mapper interface classes --> <mappers> <mapper class="org.mybatis.builder.AuthorMapper"/> <mapper class="org.mybatis.builder.BlogMapper"/> <mapper class="org.mybatis.builder.PostMapper"/> </mappers>
<!-- Register all interfaces in a package as mappers --> <mappers> <package name="org.mybatis.builder"/> </mappers>