对象工厂
- MyBatis 每次创建结果对象的新的实例,它都会使用一个对象工厂(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, constructorArgTyps, constructorArgs); } public void setProperties(Properties properties) { super.steProperties(properties); } public <T> isCollection(Class<T> type) { return Collection.class.isAssignableFrom(type); } }
<!-- mybatis-config.xml --> <objectFactory type="org.mybatis.example.ExampleObjectFactory"> <property name="someProperty" value="100"/> </objectFactory>
- Object 接口很简单,它包含两个创建的方法,一个是处理默认构造的方法的,另外一个是处理带参数的构造方法。最后,setPropertes 方法可以用来
配置 ObjectFactory 实例后, objectFactory 元素提体中定义的属性会被传递给 setProperties 方法。
插件(Plugins)
- MyBatis 允许在已映射语句执行过程中某一个点进行拦截调用。默认情况下,MyBatis允许使用插件来拦截的方法包括:
- Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
- ParameterHandler (getParameterObject, setParameters)
- ResultSetHandler (handleResultSets, handleOutputParameters)
- StatementHandler (prepare, parameterize, batch, update, query)
- 这些类中方法的谢姐可听过查看每个方法的签名来发现,或者直接查看 MyBatis 发行包中的源代码,如果你想做的不仅仅是方法监控的调用,那么你最好相当了解要重写的方法的行为。因为如果在视图修改或重写已有方法的行为的时候,你可能在破坏 MyBaits 的核心模块。这些都是更底层的类和方法,所以使用插件的时候要特别当心。
- MyBatis 提供的强大机制,使用插件是非常简单的, 只需要实现 Interceptor 接口,并制定想要的方法签名即可。
@Intercepts({ @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})}) public class ExamplePlugin implements Interceptor { private Logger logger = LoggerFactory.getLogger(getClass()); private Properties properties = new Properties(); @Override public Object intercept(Invocation invocation) throws Throwable { // implement pre processing if need Object returnObject = invocation.proceed(); // implement post processing if need logger.info("post invocation: {}", invocation); logger.info("post returnObject: {}", returnObject); logger.info("post properties: {}", properties); return returnObject; } @Override public Object plugin(Object target) { return Plugin.wrap(target, this); } @Override public void setProperties(Properties properties) { this.properties = properties; } }
<plugins> <plugin interceptor="cn.edu.cqvie.plugin.ExamplePlugin"> <property name="someProperty" value="100"/> </plugin> </plugins>
- 上面的插件将会拦截 Executor 实例中所有的 "update" 方法调用,这里的 Executor 是负责执行底层映射语句的内部对象。
- 覆盖配置类, 除了用插件来修改 MyBatis 核心行为之外,还可以通过完全覆盖配置类来达到目的。只需继承后覆盖其中的每个方法,再把它传递到 SqlSessionFactoryBuilder.build(myConfig) 方法即可。再次重申,这可能会严重影响 MyBatis 的行为,务请慎之又慎。
环境配置(environments)
- 环境管理设置
- 事务管理器设置
- 数据源设置,
- dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC连接对象的资源
- 许多MyBatis 的应用程序会按照示例来配置数据源。虽然是可选的,单位了使用延迟加载,数据源是必须配置的。
- 有三种内置数据源类型(也就是 type = "[UNPOOLED| POOLED| JNDI]")
- UNPOOLED, 这个数据源的实现只是每次被请求时打开和关闭连接,虽然有点慢,但是对于数据库连接可用性方苗苗没有太高的程序来说
- 是一个很好的选择。不同的数据库在心梗方面的表现也是不一样的,对于某些数据库来说,使用连接池并不重要,这个配置很适合这种情形。UNPOOlED 数据源具有以下属性:
- driver – 这是 JDBC 驱动的 Java 类的完全限定名(并不是 JDBC 驱动中可能包含的数据源类)。
- url – 这是数据库的 JDBC URL 地址。
- username – 登录数据库的用户名。
- password – 登录数据库的密码。
- defaultTransactionIsolationLevel – 默认的连接事务隔离级别。
- POOLED, 这种数据源实现了 "池" 的概念将 JDBC 连接对象组织起来了,避免了创建新的连接实例时所必须的初始化和认证时间。这是一种使并发 WEB 应用快速响应请求的流行处理方式。
- poolMaximumActiveConnections – 在任意时间可以存在的活动(也就是正在使用)连接数量,默认值:10
- poolMaximumIdleConnections – 任意时间可能存在的空闲连接数。
- 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))。这是个可选属性,如果忽略,那么将会直接从 InitialContext 中寻找 data_source 属性。
- data_source – 这是引用数据源实例位置的上下文的路径。提供了 initial_context 配置时会在其返回的上下文中进行查找,没有提供时则直接在 InitialContext 中查找。
- 数据源配置示例:
<!-- 配置数据源(连接池) --> <dataSource type="POOLED"> <!-- 配置数据库的4个基本信息 --> <property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </dataSource>
数据库厂商标识 (databaseIdProvider)
- MyBatis 可以根据不同的数据库厂商执行不同的语句,这种多厂商的支持是基于映射语句中的 databaseId 属性。 MyBatis 会加载不带 databaseId 属性和带有匹配当前数据库 databaseId 属性的所有语句。 如果同时找到带有 databaseId 和不带 databaseId 的相同语句,则后者会被舍弃。 为支持多厂商特性只要像下面这样在 mybatis-config.xml 文件中加入 databaseIdProvider 即可:
<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 实现会将 databaseId 设置为第一个数据库产品名与属性中的名称相匹配的值,如果没有匹配的属性将会设置为 “null”。 在这个例子中,如果 getDatabaseProductName() 返回“Oracle (DataDirect)”,databaseId 将被设置为“oracle”。
- 你可以通过实现接口 org.apache.ibatis.mapping.DatabaseIdProvider 并在 mybatis-config.xml 中注册来构建自己的 DatabaseIdProvider:
public interface DatabaseIdProvider { default void setProperties(Properties p) { // Since 3.5.2, change to default method // NOP } String getDatabaseId(DataSource dataSource) throws SQLException; }
映射器(mappers) 配置
- 当我们配置完上述元素过后,我们现在需要定义SQL语句了, 首先我们需要告诉MyBatis 到哪里可以找到咱们的这些语句。 Java在自动查找这方面没有提供
一个比较好方法,所以最佳的方式是告诉mybatis到哪里去找到映射文件。你可以使用相对于类路径的引用,或者完全限定资源定位符(包括:file:// 的 URL),或类名包名等
<!-- 将包内的映射接口全部注册为映射器(实际开发中最常使用) --> <mappers> <package name="cn.edu.cqvie.example.mapper"/> </mappers>
<!-- 使用相对于类路径的资源引用 --> <mappers> <mapper resource="cn/edu/cqvie/example/mapper/BlogMapper.xml"/> <mapper resource="cn/edu/cqvie/example/mapper/AuthorMapper.xml"/> </mappers>
<!-- 使用完全限定资源定位符 --> <mappers> <mapper url="file:///var/mapper/mapper/BlogMapper.xml"/> <mapper url="file:///var/mapper/mapper/AuthorMapper.xml"/> </mappers>
<!-- 使用映射器接口实现类的完全限定名 --> <mappers> <mapper class="cn.edu.cqvie.example.mapper.BlogMapper"/> <mapper class="cn.edu.cqvie.example.mapper.AuthorMapper"/> </mappers>