Properties (属性)
这些是外部化的, 可替代的属性, 这些属性也可以配置在典型的 Java 属性配置文件中, 或者通过 properties 元素的子元素来传递。例如:
<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>
这个例子中的 username 和 password 将会由 properties 元素中设置的值来替换。driver 和 url 属性将会从包含进来的 config.properties 文件中的值来替换。这里提供很多配置的选项。
属性也可以被传递到 SqlSessionBuilder.build()方法中。例如:
SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader, props); // ... or ... SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader, environment, props);
如果在这些地方,属性多于一个的话,MyBatis 按照如下的顺序加载它们:
因此, 最高优先级的属性是那些作为方法参数的, 然后是资源/url 属性, 最后是 properties 元素中指定的属性。
Settings(设置)
这些是极其重要的调整, 它们会修改 MyBatis 在运行时的行为方式。 下面这个表格描述 了设置信息,它们的含义和默认值。
设置参数 |
描述 |
有效值 |
默认值 |
cacheEnabled |
在全局范围内启用或禁用缓存配置任何 映射器在此配置下。 |
true | false |
true |
lazyLoadingEnabled |
在全局范围内启用或禁用延迟加载。禁用时,所有协会将热加载。 |
true | false |
true |
aggressiveLazyLoading |
启用时,有延迟加载属性的对象将被完全加载后调用懒惰的任何属性。否则,每一个属性是按需加载。 |
true | false |
true |
multipleResultSetsEnabled |
允许或不允许从一个单独的语句(需要兼容的驱动程序)要返回多个结果集。 |
true | false |
true |
useColumnLabel |
使用列标签,而不是列名。在这方面,不同的驱动有不同的行为。参考驱动文档或测试两种方法来决定你的驱动程序的行为如何。 |
true | false |
true |
useGeneratedKeys |
允许JDBC支持生成的密钥。兼容的驱动程序是必需的。此设置强制生成的键被使用,如果设置为true,一些驱动会不兼容性,但仍然可以工作。 |
true | false |
false |
autoMappingBehavior |
指定MyBatis的应如何自动映射列到字段/属性。NONE自动映射。 PARTIAL只会自动映射结果没有嵌套结果映射定义里面。 FULL会自动映射的结果映射任何复杂的(包含嵌套或其他)。 |
NONE, PARTIAL, FULL |
PARTIAL |
defaultExecutorType |
配置默认执行人。SIMPLE执行人确实没有什么特别的。 REUSE执行器重用准备好的语句。 BATCH执行器重用语句和批处理更新。 |
SIMPLE REUSE BATCH |
SIMPLE |
defaultStatementTimeout |
设置驱动程序等待一个数据库响应的秒数。 |
Any positive integer |
Not Set (null) |
safeRowBoundsEnabled |
允许使用嵌套的语句RowBounds。 |
true | false |
false |
mapUnderscoreToCamelCase |
从经典的数据库列名A_COLUMN启用自动映射到骆驼标识的经典的Java属性名aColumn。 |
true | false |
false |
localCacheScope |
MyBatis的使用本地缓存,以防止循环引用,并加快反复嵌套查询。默认情况下(SESSION)会话期间执行的所有查询缓存。如果localCacheScope=STATMENT本地会话将被用于语句的执行,只是没有将数据共享之间的两个不同的调用相同的SqlSession。 |
SESSION | STATEMENT |
SESSION |
jdbcTypeForNull |
指定为空值时,没有特定的JDBC类型的参数的JDBC类型。有些驱动需要指定列的JDBC类型,但其他像NULL,VARCHAR或OTHER的工作与通用值。 |
JdbcType enumeration. Most common are: NULL, VARCHAR and OTHER |
OTHER |
lazyLoadTriggerMethods |
指定触发延迟加载的对象的方法。 |
A method name list separated by commas |
equals,clone,hashCode,toString |
defaultScriptingLanguage |
指定所使用的语言默认为动态SQL生成。 |
A type alias or fully qualified class name. |
org.apache.ibatis.scripting.xmltags.XMLDynamicLanguageDriver |
callSettersOnNulls |
指定如果setter方法或地图的put方法时,将调用检索到的值是null。它是有用的,当你依靠Map.keySet()或null初始化。注意原语(如整型,布尔等)不会被设置为null。 |
true | false |
false |
logPrefix |
指定的前缀字串,MyBatis将会增加记录器的名称。 |
Any String |
Not set |
logImpl |
指定MyBatis的日志实现使用。如果此设置是不存在的记录的实施将自动查找。 |
SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING |
Not set |
proxyFactory |
指定代理工具,MyBatis将会使用创建懒加载能力的对象。 |
CGLIB | JAVASSIST |
CGLIB |
下面是一个完整的setting元素的设置示例:
<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="defaultExecutorType" value="SIMPLE"/> <setting name="defaultStatementTimeout" value="25"/> <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>
<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>
每个bean都可以在domain.blog被发现,如果没有找到注解,将注册使用小写开头的非限定类的bean的名称作为别名。临屋区将为domain.blog.Author被登记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 |
类型处理器 |
Java类型 |
JDBC类型 |
BooleanTypeHandler |
java.lang.Boolean, boolean |
任何兼容的布尔值 |
ByteTypeHandler |
java.lang.Byte, byte |
任何兼容的数字或字节类型 |
ShortTypeHandler |
java.lang.Short, short |
任何兼容的数字或短整型 |
IntegerTypeHandler |
java.lang.Integer, int |
任何兼容的数字和整型 |
LongTypeHandler |
java.lang.Long, long |
任何兼容的数字或长整型 |
FloatTypeHandler |
java.lang.Float, float |
任何兼容的数字或单精度浮点型 |
DoubleTypeHandler |
java.lang.Double, double |
任何兼容的数字或双精度浮点型 |
BigDecimalTypeHandler |
java.math.BigDecimal |
任何兼容的数字或十进制小数类型 |
StringTypeHandler |
java.lang.String |
CHAR 和 VARCHAR 类型 |
ClobTypeHandler |
java.lang.String |
CLOB 和 LONGVARCHAR 类型 |
NStringTypeHandler |
java.lang.String |
NVARCHAR 和 NCHAR 类型 |
NClobTypeHandler |
java.lang.String |
NCLOB 类型 |
ByteArrayTypeHandler |
byte[] |
任何兼容的字节流类型 |
BlobTypeHandler |
byte[] |
BLOB 和 LONGVARBINARY 类型 |
DateTypeHandler |
java.util.Date |
TIMESTAMP 类型 |
DateOnlyTypeHandler |
java.util.Date |
DATE 类型 |
TimeOnlyTypeHandler |
java.util.Date |
TIME 类型 |
SqlTimestampTypeHandler |
java.sql.Timestamp |
TIMESTAMP 类型 |
SqlDateTypeHandler |
java.sql.Date |
DATE 类型 |
SqlTimeTypeHandler |
java.sql.Time |
TIME 类型 |
ObjectTypeHandler |
Any |
其他或未指定类型 |
EnumTypeHandler |
Enumeration Type |
VARCHAR-任何兼容的字符串类型, 作为代码存储(而不是索引) |
EnumOrdinalTypeHandler |
Enumeration Type |
Any compatible NUMERIC or DOUBLE, as the position is stored (not the code itself). |
// 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>使用这样的类型处理器将会覆盖已经存在的Java的String类型属性和VARCHAR参数及结果的类型处理器。注意MyBatis不会审视数据库元数据的类型来确定的,所以你必须指定,这是一个VARCHAR字段的参数和结果映射到正确的类型处理。由于这样事实是MyBatis直到执行该语句,它不知道的数据类型。
(1)添加javaType属性类型处理器的元素(例如:javaType=“String”)
(2)添加注释类型处理器类指定Java类型的列表,将它与一个@ MappedTypes。此注释将被忽略,如果javaType属性也被指定。
通过下列两种方式可以指定相关联的JDBC类型:
(1)添加jdbcType属性到类型处理器的元素(例如:jdbcType为VARCHAR)。
(2)添加注释联想到指定的JDBC类型列表类型处理器类的一个@MappedJdbcTypes。此注释将被忽略,而jdbcType属性将被指定。
最后你可以让MyBatis搜索你的类型处理器:
<!-- mybatis-config.xml --> <typeHandlers> <package name="org.mybatis.example"/> </typeHandlers>注意当使用JDBC类型自动发现功能时只能被指定的注解。
//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; } ...
然而,我们可能不希望存储姓名。我们的DBA可能整数代码,而不是坚持。这是一样容易:添加EnumOrdinalTypeHandler到你的配置文件的类型处理器,现在每个与RoundingMode将被映射到一个整数,使用其序数值。
<typeHandlers> <typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler" javaType="java.math.RoundingMode"/> </typeHandlers>但是如果你想相同的枚举映射到一个字符串在一个地方和另一个整数?自动映射器会自动使用EnumOrdinalTypeHandler的,所以如果我们想回去使用简单陈旧的普通EnumTypeHandler的,我们必须告诉它,明确设置类型处理程序使用这些SQL语句。(映射文件没有涉及到下一节,因此,如果这是你第一次通过阅读文档,你可能现在想跳过这些但以后会回来了解它的。
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!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>请注意,这迫使我们使用一个resultMap代替resultType在select语句中。
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的。body内的objectFactory元素中定义的属性将被传递给setProperties方法的ObjectFactory实例在初始化之后。
plugins(插件)
使用插件是非常简单的,通过他们所提供的力量。简单实现拦截器接口,确保你想拦截的指定签名。
// 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>该插件在上面会拦截所有叫做“update”的方法在Executor实例,这是一个内部负责低层次映射语句的执行对象。
MyBatis的可以配置多个environment。这是有助于您应用到多个数据库的SQL映射为任意数量的原因。例如:你可能会为您的开发,测试和生产环境中有不同的配置。或者,你可能有多个生产数据库,共享相同的架构,你想使用相同的SQL映射。有许多用例。
一个重要的事情要记住,虽然:虽然您可以配置多种environment,但你只能选择一个SqlSessionFactory对应的实例。
所以,如果你想连接两个数据库,你需要SqlSessionFactory的创建两个实例。三个数据库,你需要三个实例,并依此类推。这真的很容易,要记住:
1. 每个数据库对应一个SqlSessionFactory
要指定创建哪种环境,你只需把它传递到SqlSessionFactoryBuilder作为一个可选的参数。接受环境中的两个签名是:
SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader, environment); SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader, environment,properties);如果环境被忽略,那么默认环境将会被加载,如下进行:
SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader); SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader,properties);
environment元素定义了如何配置环境:
<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>请注意这里的关键部分:
<transactionManager type="MANAGED"> <property name="closeConnection" value="false"/> </transactionManager>注意:如果你打算使用MyBatis与Spring是无需配置任何的TransactionManager,因为Spring模块将覆盖任何先前设置的配置设置自己的。
TransactionManager的类型都不需要任何属性。但是,它们都是类型别名,所以换句话说,你可以把你自己的完全合格的类名或类型别名,是指你自己的实施的TransacFactory接口,而不是使用它们。
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; }使用这两个接口,你可以完全自定义MyBatis对事务的处理。
<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搜索发现在返回的数据库产品名称或“空”的第一个关键,如果没有匹配的属性对应的属性值。在这种情况下,如果getDatabaseProductName()返回“甲骨文公司(DataDirect产品)”的的databaseID将被设置为“oracle”。
public interface DatabaseIdProvider { void setProperties(Properties p); String getDatabaseId(DataSource dataSource) throws SQLException; }
<!-- 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>这些语句简单告诉了 MyBatis 去哪里找映射文件。其余的细节就是在每个 SQL 映射文 件中了,下面的部分我们来讨论 SQL 映射文件。