详解mybatis-config.xml文件

<?xml version="1.0" encoding=UTF-8">
<configuration><!--配置-->
    <properties/><!--属性-->
    <settings/><!--设置-->
    <typeAliases><!--类型命名-->
    <typeHandler><!--类型处理器-->
    <objectFactory><!--对象工厂-->
    <plugins><!--插件-->
    <!-- 配置全局属性 -->
    <environments><!--配置环境-->
        <environment><!--环境变量-->
            <transactionManager/><!--事务管理器-->
            <dataSource/><!--数据源-->
        </environment>
    </environments>
    <databaseIdProvider/><!--数据库厂商标识-->
    <mappers/><!--映射器-->
</configuration>

properties元素

properties是一个配置属性的元素,让我们能在配置文件的上下文中使用它。
MyBatis提供3中配置方式:

  • property子元素
  • properties配置文件
  • 程序参数传递

property子元素

<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/study?useUnicode=true&characterEncoding=utf8" />
<property name="username" value="root" />
<property name="password" value="root" />

这样我们就可以在上下文中使用已经配置好的属性值了。我们配置数据库时就可以按照以下方式配置

<dataSource type="POOLED">
    <property name="driver" value="${driver}" />
    <property name="url" value="${url}" />
    <property name="username" value="${username}" />
    <property name="password" value="${password}" />
</dataSource>

properties
properties还可以加载配置文件,如jdbc.properties,并以比较简洁的方式进行数据库的配置

<properties resource="jdbc.properties" />
<dataSource type="POOLED">
    <property name="driver" value="${jdbc.Driver}" />
    <property name="url" value="${jdbc.url}" />
    <property name="username" value="${jdbc.userName}" />
    <property name="password" value="${jdbc.passWd}" />
</dataSource>

jdbc.properties配置文件内容如下:

jdbc.Driver=com.mysql.jdbc.Driver
jdbc.userName=root
jdbc.passWd=root
jdbc.url=jdbc:mysql://localhost:3306/study?useUnicode=true&characterEncoding=utf8

由于以上两种为常用的配置,所以只分析它们。
优先级
MyBatis支持的3中配置方式可能同时出现,并且属性还会重复配置,其实这三种方式是存在优先级的,MyBatis将按照下面的顺序来进行加载

  1. 在properties元素体内指定的属性首先被读取
  2. 根据properties元素中的resource属性读取类路径下的属性文件;或者根据url属性指定的路径读取属性文件,并覆盖已读取的同名属性
  3. 读取作为方法参数传递的属性,并覆盖已读取的同名属性

因此,通过方法参数传递的属性具有最高优先级,resource/url属性中指定的配置文件次之,最低优先级是properties属性中指定的属性
推荐使用properties文件的形式

Settings

settings在Mybatis中是最复杂的配置,同时也是最为重要的配置内容之一,它会改变MyBatis运行时的行为。即使不配置settings,MyBatis也可以正常工作。

typeAliases

别名是一个指点的名称,因为我们遇到的类全限定名过长,所以我们希望用一个简短的名称去指代它,这个名称可以在MyBatis上下文重视会用。别名可以分为系统定义别名自定义别名两类。在Mybatis中别名是不区分大小写的。一个typeAliases的实例是在解析配置文件时生成的,然后长期保存在Configuration对象中,当我们使用它时,再把它拿出来,这样就没有必要运行的时候再次生成它的实例了。
系统定义别名
MyBatis系统定义了一些经常使用的类型的别名,如数值,字符串,日期和集合等,我们可以在MyBatis中直接使用它们,在使用时不要重复定义把它们给覆盖了
其实我们可以在 org.apache.ibatis.type.TypeAliasRegistry这个类中查看别名信息。

 registerAlias("string", String.class);
 registerAlias("byte", Byte.class);
 registerAlias("long", Long.class);
 registerAlias("short", Short.class);
 registerAlias("int", Integer.class);
 registerAlias("integer", Integer.class);
 registerAlias("double", Double.class);
 registerAlias("float", Float.class);
 registerAlias("boolean", Boolean.class);
 ...

自定义别名
因为不同的应用有不同的需要,系统所定义的别名往往不够用,所以MyBatis允许自定义的别名。我们可以用typeAliases配置别名。也可以使用@Alias方法注册别名。如

<typeAliases>
        <typeAlias type="com.wojiushiwo.mybatis_demo.User" alias="user" />
</typeAliases>

这样就在MyBatis的上下文中使用”user”来代替其全路径,减少配置的复杂度

如果POJO类较多的话,以上面的方式配置也稍显麻烦。我们可以通过扫描包的方式。如下

<typeAliases>
        <package name="com.wojiushiwo.mybatis_demo" />
</typeAliases>

在实体类上添加上注解,定义别名

@Alias(value="user")
public class User implements Serializable {
private static final long serialVersionUID = 1L;

这样,MyBatis就能够扫描到POJO类,并且指定其别名
如果配置了包扫描,而POJO类没有注解@alias,它也会被装载,只是它会把类的第一个字母变为小写,然后把改变后的类名作为MyBatis的别名。
定义别名时要特别注意,别名不要重复

typeHandler

Mybatis在预处理语句中设置一个参数时。或者从结果集中取出一个值时,都会使用到typeHandler。typeHandler允许根据项目的需要自定义设置Java传递到数据库的参数中,或者从数据库读出数据,这些都可以在自定义的typeHandler中处理。

typeHandler也分为系统定义和用户自定义两种。

typeHandler常用的配置为Java类型(javaType)、JDBC类型(jdbcType).typeHandler的作用就是将参数从JavaType转化为jdbcType;或者从数据库取出结果时把jdbcType转换为javaType

系统定义的typeHandler,可以通过org.apache.ibatis.type.TypeHandlerRegistry查看,如下

 ...
 register(Boolean.class, new BooleanTypeHandler());
 register(boolean.class, new BooleanTypeHandler());
 register(JdbcType.BOOLEAN, new BooleanTypeHandler());
 register(JdbcType.BIT, new BooleanTypeHandler());

 register(Byte.class, new ByteTypeHandler());
 register(byte.class, new ByteTypeHandler());
 register(JdbcType.TINYINT, new ByteTypeHandler());
 ...

自定义TypeHandler
当我们需要特殊的处理Java的那些类型和对应处理数据库的那些类型时,系统定义的typeHandler已经应付不了的时候,我们考虑自定义typeHandler。

自定义typeHandler需要实现TypeHandler接口

@MappedTypes(value = { String.class })
@MappedJdbcTypes(value = { JdbcType.VARCHAR })
public class MyStringTypeHandler implements TypeHandler<String> {
    private Logger log = Logger.getLogger(MyStringTypeHandler.class);

    @Override
    public void setParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
        log.info("使用我的typeHandler");
        ps.setString(i, parameter);

    }

    @Override
    public String getResult(ResultSet rs, String columnName) throws SQLException {
        log.info("使用我的typeHandler,ResultSet列名获取字符串");
        return rs.getString(columnName);
    }

    @Override
    public String getResult(ResultSet rs, int columnIndex) throws SQLException {
        log.info("使用我的typeHandler,ResultSet下标获取字符串");
        return rs.getString(columnIndex);
    }

    @Override
    public String getResult(CallableStatement cs, int columnIndex) throws SQLException {
        log.info("使用我的typeHandler,CallableStatement下标获取字符串");
        return cs.getString(columnIndex);
    }

}

重写TypeHandler的方法,方法大概有:为预编译语句设置参数、根据列名从结果集中获取数据、根据列索引从结构集中获取数据、从存储过程中获取数据

自定义typeHandler里用注解配置JdbcType和JavaType,这两个注解是:

  • @MappedTypes定义的是JavaType类型,可以指定哪些Java类型被拦截
  • @MappedJdbcTypes定义的是JdbcType类型,它需要满足枚举类org.apache.ibatis.type.JdbcType所列的枚举类型

    自定义typeHandler在mybatis-config.xml中的使用:

<typeHandlers>
        <typeHandler javaType="String" jdbcType="VARCHAR"
            handler="com.example.demo.handler.MyStringTypeHandler" />
</typeHandlers>
<!--也可以使用包扫描的方式-->
<!--<typeHandlers>
    <package name="com.example.demo.handler.MyStringTypeHandler"/>
</typeHandlers>
-->

常见的使用自定义typeHandler的方式:

<resultMap type="com.example.demo.entity.User" id="User">
    <!-- 方式一 使用自定义的typeHandler -->
    <!-- <result column="name" property="name" javaType="string" jdbcType="VARCHAR" 
        /> -->
    <!-- 方式二使用自定义的typeHandler -->
    <result column="name" property="name"
        typeHandler="com.example.demo.handler.MyStringTypeHandler" />
    </resultMap>

枚举类型处理器
先定义一个枚举类:

public enum Sex {
    MALE(1, "男"), FEMALE(2, "女");
    private int id;
    private String name;

    private Sex(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public static Sex getSex(int id) {
        if (id == 1) {
            return Sex.MALE;
        } else if (id == 2) {
            return Sex.FEMALE;
        }
        return null;

    }
}

EnumTypeHandler、EnumOrdinalTypeHandler均可作为枚举类型处理器,但两者存在区别:

EnumOrdinalTypeHandler获取的是枚举定义的下标,如1,2;EnumTypeHandler获取的是枚举定义的name,如男,女

截取一部分源码说明问题:

EnumTypeHandler
 @Override
  public void setNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType) throws SQLException {
    if (jdbcType == null) {
      ps.setString(i, parameter.name());
    } else {
      ps.setObject(i, parameter.name(), jdbcType.TYPE_CODE); // see r3589
    }
  }
EnumOrdinalTypeHandler
 @Override
  public void setNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType) throws SQLException {
    ps.setInt(i, parameter.ordinal());
  }

使用方式:

<typeHandlers>
        <typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler"
            javaType="com.example.demo.entity.Sex" />
    </typeHandlers>
<!--user类中定义了该Sex枚举属性-->
<resultMap type="com.example.demo.entity.User" id="User">
        ...
        <result column="sex" property="sex"
            typeHandler="org.apache.ibatis.type.EnumOrdinalTypeHandler" />
        ...
    </resultMap>

ObjectFactory

当MyBatis从数据库取得数据返回的时候,都会使用ObjectFactory去构建POJO;在MyBatis中可以定制自己的对象工厂。一般来说我么们使用默认的ObjectFactory(org.apache.ibatis.reflection.factory.DefaultObjectFactory)即可。当然我们也可以自己自定义。

public class MyObjectFactory extends DefaultObjectFactory {
    private static final long serialVersionUID = 6016076182957642243L;
    private Logger log = Logger.getLogger(MyObjectFactory.class);

    @Override
    public <T> T create(Class<T> type) {
        log.info("使用定制对象工厂 创建单个对象");
        return super.create(type);
    }

    @Override
    public <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
        log.info("使用定制对象工厂 创建列表对象");
        return super.create(type, constructorArgTypes, constructorArgs);
    }

    @Override
    public void setProperties(Properties properties) {
        log.info("定制属性:" + properties);
        super.setProperties(properties);
    }


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

}

我们可以通过实现ObjectFactory接口来构建ObjectFactory。但是由于DefaultObjectFactory已经实现了ObjectFactory的接口,我们可以通过继承DefaultObjectFactory来简化编程。一般我们不需要使用自己配置的ObjectFactory,使用系统默认即可

代码中setProperties方法可以使我们如何去处理设置进去的属性,而create方法可以分别处理单个对象和列表对象。

在mybatis-config.xml中使用
<objectFactory type="com.example.demo.factory.MyObjectFactory">
        <property name="name" value="MyObjectFactory" />
</objectFactory>

environments

<!-- 配置全局属性 -->
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC" />
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.Driver}" />
                <property name="url" value="${jdbc.url}" />
                <property name="username" value="${jdbc.userName}" />
                <property name="password" value="${jdbc.passWd}" />
            </dataSource>
        </environment>
    </environments>

配置环境可以注册多个数据源,每个数据源可以分为两大部分:一个是数据源的配置,一个是数据库事务的配置。

  • environments中的属性default,表明在缺省的情况下,我们将启动哪个数据源配置
  • environment元素是配置一个数据源的开始;属性id是设置这个数据源的标识,以便MyBatis上下文使用它
  • transactionManager配置的是数据库事务,其中type属性有3种配置方式:
    JDBC:采用JDBC方式管理事务,在独立编码中经常使用
    MANAGED:采用容器方式管理事务,在JNDI数据源中常用
    自定义,由使用者自定义数据库事务管理办法,适用于特殊应用

  • property元素则可以配置数据源的各类属性,autoCommit=false则表示数据源不自动提交

  • dataSource:配置数据源连接的信息,type属性是提供我们对数据库连接方式的配置:
    UNPOOLED 非连接池数据库
    POOLED 连接池数据库
    JNDI JNDI数据源
    自定义数据源

数据源

  • UNPOOLED 非连接池 使用 org.apache.ibatis.datasource.unpooled.UnpooledDataSource实现
  • POOLED 连接池 使用org.apache.ibatis.datasource.pooled.PooledDataSource实现
  • JNDI 使用org.apache.ibatis.datasource.jndi.JndiDataSourceFactory来获取数据源

如果我们需要自定义数据源,必须实现org.apache.ibatis.datasource.DataSourceFactory接口

Mapper

引入mapper的方式:

<mappers>   
        <!--使用文件路径引入-->
        <mapper resource="com.wojiushiwo/UserMapper.xml"/>
        <mapper resource="com.wojiushiwo/ArticleMapper.xml"/>
    </mappers>
<mappers>
        <!--使用类注册引入-->
        <mapper class="com.wojiushiwo.mybatis_demo.UserMapper"/>
</<mappers>
<mappers>
        <!--使用包名引入-->
        <package name="com.wojiushiwo.mybatis_demo"/>
</<mappers>

参考文献:
深入浅出MyBatis技术原理与实战

猜你喜欢

转载自blog.csdn.net/zyxwvuuvwxyz/article/details/79647240