mybatis全局文件的学习

挺多的反正我脑子记不过来,根据简介挑需要的看吧。
mybatis全局配置文件的几大标签:

  • properties,可以用来加载外部资源文档和定义属性key:value对
  • settings,MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。
  • typeAliases,类型别名是为 Java 类型设置一个短的名字(俗称起别名)。
  • typeHandlers,控制JAVA数据类型《——》JDBC数据类型的转换。
  • objectFactory,对象工厂(不是会话工厂),用来创建对象的。
  • plugins,插件。
  • environments,运行时环境,配置数据源(可多个)。
  • databaseIdProvider,当需要对多种多样数据库适配时和映射文件中的databaseId 属性配合使用。
  • mappers,加载映射文件。

properties

可以在其内部写property 子标签

<property name="username" value="dev_user"/>

也可以使用它的resource属性加载外部文件(.properties后缀)

<properties resource="org/mybatis/example/config.properties">
	<property name="username" value="dev_user"/>
</properties>

当子标签中和外部资源文件中同时定义一个属性时是怎么处理呢?
mybatis首先加载内部定义,在加载外部文件,然后加载会话工厂传人的(感觉不太常用,忽略了)。后加载的覆盖先加载的。所以也就是说同时定义一个属性,外部文件中的会覆盖内部定义的。

setting

<settings>
  //该配置影响的所有映射器中配置的缓存的全局开关。默认true
  <setting name="cacheEnabled" value="true"/>
  
  //延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置fetchType属性来覆盖该项的开关状态。默认为false
  <setting name="lazyLoadingEnabled" value="true"/>
  
  //当启用时,对任意延迟属性的调用会使带有延迟加载属性的对象完整加载;反之,每种属性将会按需加载。没有默认值
  aggressiveLazyLoading不写了

  //是否允许单一语句返回多结果集(需要兼容驱动)。默认true
  <setting name="multipleResultSetsEnabled" value="true"/>

  //使用列标签代替列名。不同的驱动在这方面会有不同的表现, 具体可参考相关驱动文档或通过测试这两种不同的模式来观察所用驱动的结果。默认ture
  <setting name="useColumnLabel" value="true"/>

  //允许 JDBC 支持自动生成主键,需要驱动兼容。 如果设置为 true 则这个设置强制使用自动生成主键,尽管一些驱动不能兼容但仍可正常工作(比如 Derby)。默认为false
  <setting name="useGeneratedKeys" value="false"/>

  //指定 MyBatis 应如何自动映射列到字段或属性。
  // NONE 表示取消自动映射;
  //PARTIAL 只会自动映射没有定义嵌套结果集映射的结果集。--默认
  // FULL 会自动映射任意复杂的结果集(无论是否嵌套)。
  <setting name="autoMappingBehavior" value="PARTIAL"/>
  
  //配置默认的执行器。
  //SIMPLE 就是普通的执行器;--默认
  //REUSE 执行器会重用预处理语句(prepared statements);
  // BATCH 执行器将重用语句并执行批量更新。
  <setting name="defaultExecutorType" value="SIMPLE"/>

  //设置超时时间,它决定驱动等待数据库响应的秒数。
  <setting name="defaultStatementTimeout" value="25"/>
  
  //允许在嵌套语句中使用分页,默认false
  <setting name="safeRowBoundsEnabled" value="false"/>

  //是否开启自动驼峰命名规则(camel case)映射
  //即从经典数据库列名 A_COLUMN 到经典 Java 属性名 aColumn 的类似映射。默认false
  <setting name="mapUnderscoreToCamelCase" value="false"/>

  //MyBatis 利用本地缓存机制(Local Cache)防止循环引用(circular references)和加速重复嵌套查询。 
  //默认值为 SESSION,这种情况下会缓存一个会话中执行的所有查询。 
  //若设置值为 STATEMENT,本地会话仅用在语句执行上,对相同 SqlSession 的不同调用将不会共享数据。
  <setting name="localCacheScope" value="SESSION"/>
  
  //当没有为参数提供特定的 JDBC 类型时,为空值指定 JDBC 类型。 某些驱动需要指定列的 JDBC 类型,多数情况直接用一般类型即可,比如 NULL、VARCHAR 或 OTHER。
  <setting name="jdbcTypeForNull" value="OTHER"/>
  
  //指定哪个对象的方法触发一次延迟加载。
  <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
</settings>
---------------------------------------
以上是比较常用的,还有几种列在下面,有需要自己查:
属性名  作用   可选值  默认值
defaultScriptingLanguage 	指定动态 SQL 生成的默认语言。 	A type alias or fully qualified class name. 	org.apache.ibatis.scripting.xmltags.XMLDynamicLanguageDriver
callSettersOnNulls 	指定当结果集中值为 null 的时候是否调用映射对象的 setter(map 对象时为 put)方法,这对于有 Map.keySet() 依赖或 null 值初始化的时候是有用的。注意基本类型(int、boolean等)是不能设置成 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

typeAliases

作用给javaBean起别名
给单个类起别名

<typeAliases>
  <typeAlias alias="Author" type="domain.blog.Author"/>
</typeAliases>

给一个package起别名

<typeAliases>
//别名为javaBean的首字母小写的非限定类名
  <package name="domain.blog"/>
</typeAliases>

如果JavaBean类名上使用注解,那么以注解为准

  	@Alias("author")
    public class Author {
        ...
    }

typeHandlers(一般用不到,用默认的就行)

typeHandlers又叫类型处理器,就像在JDBC中,我们在PreparedStatement中设置预编译sql所需的参数或执行sql后根据结果集ResultSet对象获取得到的数据时,需要将数据库中的类型和java中字段的类型进行转换一样,在MyBatis中使用typeHandler来实现。所以说白了,typeHandlers就是用来完成javaType和jdbcType之间的转换。
使用实现方式:

  • 继承BaseTypeHandler类
  • 实现TypeHandler接口
package com.daily.handler;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.Date;

import org.apache.ibatis.type.DateTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeHandler;
import org.postgresql.jdbc2.optional.SimpleDataSource;

/**
 * 自定义一个TypeHandler用来将javatype的日期类型和jdbctype的VARCHAR进行转换
 */
public class MyDateHandler implements TypeHandler<Date> {
    @Override
    // 设置sql中指定索引的参数,即将javaType转化为jdbcType
    public void setParameter(PreparedStatement ps, int i, Date parameter, JdbcType jdbcType) throws SQLException {
        //设置数据存储到数据库中的格式
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        ps.setString(i, sdf.format(parameter));
    }

    @Override
    // 根据列名称从结果集获取值,并将jdbcType转换成javaType
    public Date getResult(ResultSet rs, String columnName) throws SQLException {
        String columnValue = rs.getString(columnName);
        if (null != columnValue) {
            return new Date(Long.valueOf(columnValue));
        }
        return null;
    }

    @Override
    // 根据列名称从结果集获取值,并将jdbcType转换成javaType
    public Date getResult(ResultSet rs, int columnIndex) throws SQLException {
        String columnValue = rs.getString(columnIndex);
        if (null != columnValue) {
            return new Date(Long.valueOf(columnValue));
        }
        return null;
    }

    @Override
    public Date getResult(CallableStatement cs, int columnIndex) throws SQLException {
        String columnValue = cs.getString(columnIndex);
        if (null != columnValue) {
            return new Date(Long.valueOf(columnValue));
        }
        return null;
    }

}

在全局文件中:

<!--类型处理器 -->
     <typeHandlers>
        <!-- 注册自定义handler,说明它作用的jdbcType和javaType -->
         <typeHandler jdbcType="VARCHAR" javaType="date" handler="com.daily.handler.MyDateHandler" />
     </typeHandlers>

在Mapper映射文件中使用:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.daily.dao.BlogMapper">
    <resultMap id="BaseResultMap" type="com.daily.pojo.Blog">
        <id column="blog_id" jdbcType="INTEGER" property="blogId" />
        <result column="blog_title" jdbcType="VARCHAR" property="blogTitle" />
        <result column="blog_content" jdbcType="VARCHAR" property="blogContent" />
        <!-- 不使用MyDateHandler-->
        <result column="create_time" jdbcType="VARCHAR" property="createTime" />
        <!-- 使用MyDateHandler-->
        <result column="modify_time" typeHandler="com.daily.handler.MyDateHandler" property="modifyTime" />
    </resultMap>

    <insert id="insert" parameterType="com.daily.pojo.Blog">
        insert into blog (blog_id, blog_title, blog_content,
        create_time, modify_time)
        values (#{blogId,jdbcType=INTEGER}, #{blogTitle,jdbcType=VARCHAR},
        #{blogContent,jdbcType=VARCHAR},
        #{createTime,jdbcType=VARCHAR}, #{modifyTime,typeHandler=com.daily.handler.MyDateHandler})
    </insert>
</mapper>

MyBatis会根据结果自动选择合适的handler进行转换。

日常开发中,一般不需要定义,使用默认的就可以,除非是像枚举这种特殊类型就需要自己实现。
大佬网址:
https://www.cnblogs.com/hellowhy/p/9670635.html

objectFactory(一般用不到,用默认的就行)

关于在MyBatis中的ObjectFactory有什么用,在官方文档中有这样的描述(大多数网上的博客都是直接引用这一描述):MyBatis 每次创建结果对象的新实例时,它都会使用一个对象工厂(ObjectFactory)实例来完成。 默认的对象工厂需要做的仅仅是实例化目标类,要么通过默认构造方法,要么在参数映射存在的时候通过参数构造方法来实例化。 如果想覆盖对象工厂的默认行为,则可以通过创建自己的对象工厂来实现。对于像我这种水平的来说,完全就是一脸蒙逼,这到底有啥用?可以说这个对象工厂就是用来创建实体类的,MyBatis有一个DefaultObjectFactory默认对象工厂类,就像上面所说的默认的对象工厂需要做的仅仅是实例化目标类,要么通过默认构造方法,要么在参数映射存在的时候通过参数构造方法来实例化。它不做其他任何的处理。如果我们想在创建实例化一个目标类的时候做点啥其他的动作,可以继承DefaultObjectFactory,覆写父类方法,并在mybatis-config.xml中注册配置这个对象工厂类。
全局文件中配置:

 <objectFactory type="day_8_mybatis.util.ExampleObjectFactory">
         <property name="someProperty" value="100"/>
 </objectFactory>

自定义Demo:

package day_8_mybatis.util;

import java.util.Collection;
import java.util.Iterator;
import java.util.Properties;

import org.apache.ibatis.reflection.factory.DefaultObjectFactory;

import day_8_mybatis.pojo.People;

/**
 * @author turbo
 *
 * 2016年10月24日
 */
public class ExampleObjectFactory extends DefaultObjectFactory {
	//DefaultObjectFactory有俩个create方法,重写哪个都可以,我们想干什么都是在这进行的
    @Override
    public Object create(Class type) {
        if (type.equals(People.class)){
            People p = (People)super.create(type);
            p.setAge(22);
            p.setName("keven");
            return p;
        }
        return super.create(type);
    }
//全局配置文件中objectFactory标签配置的property会传到这
    @Override
    public void setProperties(Properties properties) {
        Iterator iterator = properties.keySet().iterator();
        while (iterator.hasNext()){
            String keyValue = String.valueOf(iterator.next());
            System.out.println(properties.getProperty(keyValue));
        }
        super.setProperties(properties);
    }

    @Override
    public <T> boolean isCollection(Class<T> type) {
        return Collection.class.isAssignableFrom(type);
    }

}

关于mybatis objectFactory的原理:

  • 在获取SQL session对象的过程中就已经调用了DefaultObjectFactory中的setProperties方法,其实这个不难理解,毕竟在获取SQL session之前就已经加载了mybatis的配置文件,首先当然要进行配置;
  • 然后会进入到DefaultObjectFactory中的isCollection方法,而传给它的参数类型就是我在映射器接口中定义的返回类型;
  • 不管查询出多少条数据,也不管返回类型是什么,首先都会调用create方法创建一个ArrayList对象;
  • 查询出多少条数据,就会调用多少次create方法,将一条数据封装成一个类并进行实例化;

创建结果集的过程大致为:

  • 先判断接口返回的类型是一个单独的类还是一个集合;
  • 创建一个ArrayList对象;
  • 将每个查询结果实例化成一个对象,然后设置到ArrayList对象中;
  • 如果在第一步中接口返回的是单独的类,此时查看第三步封装的结果,如果只有一条数据,则获取对象并返回;如果有多条,则报错;如果在第一步中接口返回的是一个集合,则直接返回第三步封装的结果;

感觉用不太到,大致理解了以下,没做深究提供俩个大佬网址自己看下:
https://www.cnblogs.com/yulinfeng/p/5995200.html
https://www.cnblogs.com/hellowhy/p/9672942.html

plugins(慎用)

插件使用的场景有:日志记录、权限控制、缓存控制等。使用 plugin 拦截和覆盖 MyBatis 的核心方法时,建议谨慎使用,否则会影响 MyBatis 的核心功能。
MyBatis 允许在已映射语句执行过程中的某一点进行拦截调用。默认情况下,MyBatis 允许使用插件来拦截的方法调用包括:

  • Executor (update, query, flushStatements, commit, rollback,
    getTransaction, close, isClosed) 执行器
public interface Executor {
    // 不需要 ResultHandler
    ResultHandler NO_RESULT_HANDLER = null;
    // 更新
    int update(MappedStatement ms, Object parameter) throws SQLException;
    // 查询(先查缓存),带分页,BoundSql
    <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) throws SQLException;
    // 查询,带分页
    <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException;
    // 查询游标
    <E> Cursor<E> queryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds) throws SQLException;
    // 刷新(Statement)批处理语句
    List<BatchResult> flushStatements() throws SQLException;
    // 提交事务,参数为是否要强制
    void commit(boolean required) throws SQLException;
    // 回滚事务,参数为是否要强制
    void rollback(boolean required) throws SQLException;
    // 创建 CacheKey
    CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql);
    // 判断是否缓存了,通过 CacheKey
    boolean isCached(MappedStatement ms, CacheKey key);
    // 清理 Session(本地一级) 缓存
    void clearLocalCache();
    // 延迟加载
    void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key, Class<?> targetType);
    // 获取事务
    Transaction getTransaction();
    // 关闭连接
    void close(boolean forceRollback);
    // 是否关闭
    boolean isClosed();
    // 设置 Executor
    void setExecutorWrapper(Executor executor);
}
  • ParameterHandler (getParameterObject, setParameters) 参数处理器
public interface ParameterHandler {
    // 获取参数
    Object getParameterObject();
    // 设置参数
    void setParameters(PreparedStatement ps) throws SQLException;
}
  • ResultSetHandler (handleResultSets, handleOutputParameters) 结果集处理器
public interface ResultSetHandler {
    // 将结果集转化成 List
    <E> List<E> handleResultSets(Statement stmt) throws SQLException;
    // 将结果集转化成 Cursor
    <E> Cursor<E> handleCursorResultSets(Statement stmt) throws SQLException;
    // 处理存储过程的 OUT(输出) 参数
    void handleOutputParameters(CallableStatement cs) throws SQLException;
}
  • StatementHandler (prepare, parameterize, batch, update, query) SQL语句处理器
public interface StatementHandler {
    // 准备语句
    Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException;
    // 参数处理
    void parameterize(Statement statement) throws SQLException;
    // 批量处理
    void batch(Statement statement) throws SQLException;
    // 更新处理
    int update(Statement statement) throws SQLException;
    // 查询处理,结果给 ResultHandler
    <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException;
    <E> Cursor<E> queryCursor(Statement statement) throws SQLException;
    // 获取绑定 SQL 语句
    BoundSql getBoundSql();
    // 获取参数处理器
    ParameterHandler getParameterHandler();
}

除了用插件来修改 MyBatis 核心行为之外,还可以通过完全覆盖配置类来达到目的。只需继承后覆盖其中的每个方法,再把它传递到 SqlSessionFactoryBuilder.build(myConfig) 方法即可。
自定义一个插件,需要实现 Interceptor 接口

/**
 * @Intercepts 拦截器注解,包括一个或多个 @Signature
 * @Signature 拦截的目标类信息,包括 type、method、args
 * * type 要拦截的接口类型
 * * method 接口中的方法名
 * * args 方法的所有入参类型
 */
@Intercepts({
        @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})
})
public class ExamplePlugin implements Interceptor {
    /**
     * 拦截目标对象的目标方法的执行,将自定义逻辑写在该方法中
     */
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        System.out.println("ExamplePlugin...intercept:" + invocation.getMethod());

        // MetaObject 是 Mybatis 提供的一个用于访问对象属性的对象
        MetaObject metaObject = SystemMetaObject.forObject(invocation);

        System.out.println("当前拦截到的对象:" + metaObject.getValue("target"));
        System.out.println("SQL语句:" + metaObject.getValue("target.delegate.boundSql.sql"));
        System.out.println("SQL语句入参:" + metaObject.getValue("target.delegate.parameterHandler.parameterObject"));
        System.out.println("SQL语句类型:" + metaObject.getValue("target.delegate.parameterHandler.mappedStatement.sqlCommandType"));
        System.out.println("Mapper方法全路径名:" + metaObject.getValue("target.delegate.parameterHandler.mappedStatement.id"));

        // 修改 SQL 语句
        String newSQL = metaObject.getValue("target.delegate.boundSql.sql") + " limit 2";
        metaObject.setValue("target.delegate.boundSql.sql", newSQL);
        System.out.println("修改后SQL语句:" + newSQL);

        // 返回执行结果
        return invocation.proceed();
    }

    /**
     * 为目标对象创建一个代理对象,使用 Plugin.wrap(target,this) 即可
     * @param target 上次包装的代理对象
     * @return 本次包装过的代理对象
     */
    @Override
    public Object plugin(Object target) {
        System.out.println("ExamplePlugin...plugin:" + target);
        return Plugin.wrap(target, this);
    }

    /**
     * 获取自定义配置参数
     * @param properties
     */
    @Override
    public void setProperties(Properties properties) {
        System.out.println("插件配置信息:" + properties);
        System.out.println("someProperty:" + properties.get("someProperty"));
    }
}

同时全局配置文件中:

 <plugins>
        <plugin interceptor="com.plugins.ExamplePlugin">
        //这个property会被传入setProperties方法中去
            <property name="someProperty" value="100"/>
        </plugin>
</plugins>

environments

原则:
尽管可以配置多个环境,每个 SqlSessionFactory 实例只能选择其一
如果你想连接两个数据库,就需要创建两个 SqlSessionFactory 实例,每个数据库对应一个。而如果是三个数据库,就需要三个实例,依此类推。

environments的作用是用来配置数据库信息,可以配置多个,其有两个可配的子元素,分别是:事务管理器transactionManager和数据源dataSource。
配置代码如下:

<!-- 环境模式:development开发模式 work工作模式 -->
    <environments default="development">
        <!--环境变量 -->
        <environment id="development">
            <!--事务管理器 -->
            <transactionManager type="JDBC" />
            <!--数据源 -->
            <dataSource type="POOLED">
                <property name="driver" value="${db.driver}" />
                <property name="url" value="${db.url}" />
                <property name="username" value="${db.username}" />
                <property name="password" value="${db.pwd}" />
            </dataSource>
        </environment>
    </environments>
  • environments-default:该属性指定当前的环境,有development和work两种选择,默认是development开发模式;
  • environment-id:该属性是每个environment定义的环境,也有development和work两种选择,默认是development开发模式;
  • transactionManager-type:该属性是配置事务管理器的类型,mybatis中有JDBC和MANAGED两种
  • dataSource-type:该属性用来配置数据源类型,有UNPOOLED、POOLED和JNDI三种
  • dataSource中的property元素就是数据库相关的信息

如果在environments中配置了多个environment的环境且都是开发模式,那mybatis会采用配置的最后一个。
下边俩个章节是该章节的继续

transactionManager 事务管理器配置

MyBatis中为Transaction接口提供了两个实现类,分别是JdbcTransaction和ManagedTransaction,并且分别对应着JdbcTransactionFactory和ManagedTransactionFactory两个工厂,这两个工厂实现了TransactionFactory这个接口,当我们在配置文件中通过transactionManager的type属性配置事务管理器类型的时候,mybatis就会自动从对应的工厂获取实例。下面说一下这两者的区别:

  1. JDBC使用JdbcTransactionFactory工厂生成的JdbcTransaction对象实现,以JDBC的方式进行数据库的提交、回滚等操作;
  2. MANAGED使用ManagedTransactionFactory工厂生成的ManagedTransaction对象实现,它的提交和回滚不需要任何操作,而是把事务交给容器进行处理,默认情况下会关闭连接,如果不希望默认关闭,只要将其中的closeConnection属性设置为false即可。

最明显的区别就是,如果我使用JDBC的事务处理方式,当我向数据库中插入一条数据时,在调用完插入接口执行SQL之后,必须 执行sqlSession.commit();进行提交,否则虽然插入成功但是数据库中还是看不到刚才插入的数据;而使用MANAGED方式就不一样了,只需调用接口即可,无需手动提交。

如果有需要可以自定义创建事务:

//第一步:创建一个事务管理类,继承ManagedTransaction或JdbcTransaction类或实现Transaction接口;
/**
 * 定义自己的事务管理器
 */
public class MyTransaction extends JdbcTransaction implements Transaction {

    // 重写父类方法
    public MyTransaction(Connection connection) {
        super(connection);
    }

    public MyTransaction(DataSource ds, TransactionIsolationLevel desiredLevel, boolean desiredAutoCommit) {
        super(ds, desiredLevel, desiredAutoCommit);
    }
}
-----------------------------------------------------------------
第二步:创建一个事务管理工厂类,实现TransactionFactory接口,提供生产事务处理相关接口;
/**
 * 定义自己的事务管理器,实现获取连接、提交、回滚、关闭数据库连接等操作
 */
public class MyTransaction extends JdbcTransaction implements Transaction {

    public MyTransaction(Connection connection) {
        super(connection);
    }

    public MyTransaction(DataSource ds, TransactionIsolationLevel desiredLevel, boolean desiredAutoCommit) {
        super(ds, desiredLevel, desiredAutoCommit);
    }

    @Override
    public Connection getConnection() throws SQLException {
        return super.getConnection();
    }

    @Override
    public void commit() throws SQLException {
        super.commit();
    }

    @Override
    public void rollback() throws SQLException {
        super.rollback();
    }

    @Override
    public void close() throws SQLException {
        super.close();
    }

    @Override
    public Integer getTimeout() throws SQLException {
        return super.getTimeout();
    }
}
------------------------------------------------------------------------------------------
第三步:配置自定义事务管理器
在全局配置文件中
//可以使用typeAliases起别名
<transactionManager type="com.daily.objectfactory.MyTransactionFactory" />

dataSource 数据源配置

在mybatis中,数据库是通过PooledDataSourceFactory、UnpooledDataSourceFactory和JndiDataSourceFactory三个工厂类来提供,前两者分别产生PooledDataSource和UnpooledDataSource类对象,第三个则会根据JNDI的信息拿到外部容器实现的数据库连接对象,但是不管怎样,它们最后都会生成一个实现了DataSource接口的数据库连接对象。

  • UNPOOLED,非线程池
    采用非数据库池的管理方式,每次请求都会新建一个连接,所以性能不是很高,使用这种数据源的时候,我们可以配置以下属性:driver、url、username、password、defaultTransactionIsolationLevel(不太了解)

  • POOLED,线程池
    采用连接池的概念将数据库链接对象Connection组织起来,可以在初始化时创建多个连接,使用时直接从连接池获取,避免了重复创建连接所需的初始化和认证时间,从而提升了效率,所以这种方式比较适合对性能要求高的应用中。
    除了非线程池中需要的5个属性之外,还需要配置poolMaximumActiveConnections(任意时间都会存在的连接数,默认值为10)、poolMaxmumIdleConnections(可以空闲存在的连接数)、poolMaxmumCheckoutTime(在被强制返回之前,检查出存在空闲连接的等待时间。即如果有20个连接,只有一个空闲,在这个空闲连接被找到之前的等待时间就用这个属性配置,默认值:20000 毫秒(即 20 秒)。)、poolTimeToWait(等待一个数据库连接成功所需的时间,如果超出这个时间则尝试重新连接,默认值:20000 毫秒(即 20 秒)。)等。

  • JNDI
    数据源JNDI的实现是为了能在如EJB或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个JNDI上下文的引用。这种数据源只需配置两个属性:
    initial_context:用来在InitialContext中寻找上下文。可选,如果忽略,data_source属性将会直接从InitialContext中寻找;
    data_source:引用数据源实例位置上下文的路径。当提供initial_context配置时,data_source会在其返回的上下文进行查找,否则直接从InitialContext中查找。

databaseIdProvider

根据不同的数据库厂商执行不同的语句,这种多厂商的支持是基于映射语句中的 databaseId 属性。
因为不同的数据库对于SQL的标准可能不同,所以有了databaseIdProvider,说白了就是全局配置文件中的databaseIdProvider+mapper映射文件中执行语句的databaseid属性可以做到,根据数据库不同,执行相应的语句。
全局文件配置代码;

<!--数据库厂商标示 -->
     <databaseIdProvider type="DB_VENDOR">
         <property name="Oracle" value="oracle"/>
         <property name="MySQL" value="mysql"/>
         <property name="DB2" value="d2"/>
</databaseIdProvider>

property子元素是配置一个数据库,其中的name属性是数据库名称,value是我们自定义的别名,通过别名我们可以在SQL语句中标识适用于哪种数据库运行。

mapper文件的使用:
设置多个id相同的DDL语句并配置不同的databaseid,mybatis会根据databaseIdProvider中的配置找到相应的databaseid,如果没有匹配的那么就使用没有设置databaseid的语句。
面对未知名称的数据库我们可以使用如下代码获取它的名称和版本:

/**
     * 获取数据库名称
     */
    public static void getDbInformation() {
        SqlSession sqlSession = null;
        Connection connection = null;
        try {
            sqlSession = getSqlSession();
            connection = sqlSession.getConnection();
            String dbName = connection.getMetaData().getDatabaseProductName();
            String dbVersion = connection.getMetaData().getDatabaseProductVersion();
            System.out.println("数据库名称是:" + dbName + ";版本是:" + dbVersion);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

同理我们对这个也可以自定义,不在介绍,有需要自己找。

mappers

四种方式:

<mappers>
  //类名
  <mapper class="org.mybatis.builder.AuthorMapper"/>
  //类路径的资源引用
  <mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
  //url引用
  <mapper url="file:///var/mappers/AuthorMapper.xml"/>
  //包名
  <package name="org.mybatis.builder"/>
</mappers>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值