zoukankan      html  css  js  c++  java
  • 配置文件

    MyBatis的XML配置文件是有层次结构的,因为存在约束嘛,这些层次是有顺序的,如果颠倒顺序,MyBatis就会解析出错。来看一看这个XML文件的层次结构。

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration
     PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
     "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>  <!-- 配置 -->
    
        <properties></properties><!-- 属性 -->
        <settings></settings><!-- 设置 -->
        <typeAliases></typeAliases><!--别名 -->
        <typeHandlers></typeHandlers><!-- 类型处理器 -->
        <objectFactory type=""></objectFactory><!-- 对象工厂 -->
        <plugins></plugins><!-- 插件 -->
        <environments default=""><!-- 配置环境 -->
           <environment id=""><!-- 环境变量 -->
              <transactionManager type=""></transactionManager><!-- 事务管理器 -->
              <dataSource type=""></dataSource> <!-- 数据源 -->
           </environment>
        </environments>
        
        <databaseIdProvider type=""></databaseIdProvider><!-- 数据库厂商标识 -->
        <mappers></mappers> <!-- 映射器 -->
    
    </configuration>

    ProPerties元素

    properties是一个配置属性元素,让我们在配置文件上下文中使用它。

    MyBatis提供了3种配置方式

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

    property子元素

    配置如下:

        <properties>
          <property name="driver" value="com.mysql.jdbc.Driver"/>
          <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
          <property name="username" value="root"/>
          <property name="password" value="root"/>
        </properties>

    这样我们就可以在DataSource标签中配置:

              <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文件中,需要在MyBatis配置文件中导入:

    <properties resource="jdbc.properties"></properties>

    将这个外部的数据库信息配置在一个单独的文件中

    程序参数配置

    如果为了安全,数据库的用户名和密码都是加密的,我们无法使用这个加密的字符串来连接数据库,这个时候可以使用编码的方式来满足这种场景。

    修改一下获得SqlSessionFactory的initSqlSessionFactory方法:

        public static SqlSessionFactory initSqlSessionFactory() {
            InputStream cfgStream=null;
            Reader cfgReader=null;
            InputStream proInputStream=null;
            Reader proReader=null;
            try {
                //读入配置文件
                cfgStream=Resources.getResourceAsStream("mybatis-config.xml");
                cfgReader=new InputStreamReader(cfgStream);
                //读入属性文件
                proInputStream=Resources.getResourceAsStream("jdbc.properties");
                proReader=new InputStreamReader(proInputStream);
                Properties properties=new Properties();
                properties.load(proReader);
                //解密为明文  decode为解密方法
                properties.setProperty("username", decode(properties.getProperty("username")));
                properties.setProperty("password", decode(properties.getProperty("password")));
                
                synchronized (CLASS_LOCK) {
                    if(sqlSessionFactory==null) {
                        sqlSessionFactory=new SqlSessionFactoryBuilder().build(cfgReader,properties);
                    }
                }
                
            }catch (Exception e) {
                e.printStackTrace();
            }
        }

    主要是我们调用SqlSessionFactoryBuilder类的一个重载build(Reader,Properties)

    优先级问题

    通过方法参数传递的方式优先级最高;外部配置文件的方式次之;properties元素的方式最先被加载,但是会被比它优先级高的覆盖,所以优先级最低

    (优先级:参数传递>外部配置文件>properties元素,反之,就是它们加载的先后顺序)。

    注意:

    1.不要混用这些方式

    2.首选外部配置的方式

    3.如果有对于用户名或密码加密的场景,就是用方法参数的方式。

    其是在这里配置的properties标签在与spring整合之后,就会消失了,我们都将其配置在applicationContext.xml文件中。

    设置

    设置(settings)在MyBatis总是最为复杂的配置,同时也是最为重要的配置,它会改变MyBatis运行时的行为。即使不配置setting,MyBatis也会工作,因为其属性都有默认值的存在,在这里不显示其配置了,配置不需要修改太多,一般来说我们只会的修改一小部分就可以了。

    别名

    别名(typeAliases)是一个指代的名称,因为我们遇到的全限定名都太长了,所以希望使用一个简短的名称代替, 这个名称可以再MyBatis的整个上下文中使用。在MyBatis中分为系统定义别名和自定义别名两类,注意:在MyBatis中别名是不分大小写的。一个typeAliases实例在解析配置文件的时候生成,然后长期保存在Configuration对象中,但我们使用时,再把它拿出来,这样就没必要运行时再生成它的实例了。

    系统别名

    MyBatis中默认了一些经常使用的类型别名,例如:数值,字符串,日期和集合等,我们在MyBatis中直接使用即可,在使用的时候不要重复定义把它给覆盖了。基本上都是将类型的首字母小写了,如:

    别名 映射的类型 支持数组
    string String
    short Short
    integer Integer
    float Float
    boolean Boolean
    date Date
    list List
    arraylist ArrayList
    map Map
    hashmap HashMap
    object Object

    我们还可以在 MyBatis的源码 org.apache.ibatis.type.TypeAliasRegistry 可以看到更为详细的信息

    自定义别名

    系统定义的别名往往是不够的,因为不同的应用存在各种不同的需求,所以MyBatis可以自定义别名。我们使用typeAliases配置别名:

      <!-- 配置别名 -->
      <typeAliases>
        <typeAlias alias="user" type="cn.lynu.model.User"/>
      </typeAliases>

    alias属性就是在取别名,type指定其全限定名。如果我们没有使用ailas属性来设置别名,会有默认别名:类名首字母小写

    如果我们懂得POJO类比较多,MyBatis可以允许我们通过自动扫描的形式自定义别名:

      <!-- 扫描别名 -->
      <typeAliases>
        <package name="cn.lynu.model"/>
      </typeAliases>

    这样就可以自动扫描 cn.lynu.model 包下的POJO了,默认每个POJO的别名是将类名的首字母小写,当然我们也可以自己指定别名,使用@Alias注解标识在POJO类上:

    类型处理器

    类型处理器(typeHandler)是MyBatis在于预处理语句(PreparedStatement)中设置一个参数,或者从结果集中(result)中取出值时,都会用注册了的typeHandler进行处理。typeHandler常用的配置为java类型(javaType),JDBC类型(jdbcType)。所以说,typeHandler的作用就是将参数从javaType转换为javaType,或者是从数据库取结果的时候把jdbcType转换为javaType。

    由于数据库厂商的不同,不同的厂商之间的设置的参数也可能会有所不同,所以MyBatis允许我们自定义typeHandler,我们往往需要对数据进行特殊的处理,这些都需要使用到自定义的typeHandler,例如:在使用枚举的时候常常需要使用自定义的typeHandler进行数据的转换。

    同别名一样,类型处理器也有系统定义和用户定义两种

    系统定义的typeHandler

    来看几个系统定义的typeHandler:

    类型处理器 Java类型 JDBC类型
    BooleanTypeHandler java.lang.Boolean.boolean 数据库兼容的BOOLEAN
    IntegerTypeHandler java.lang.Integer.integer 数据库兼容的INTEGER
    LongTypeHandler java.lang.Long.long 数据库兼容的Long
    StringTypeHandler java.lang.String CHAR,  VARCHAR
    ClobTypeHandler java.lang.String CLOB,LONGVARCHAR
    ByteArrayTypeHandler byte[] 数据库兼容的字节流类型
    BlobTypeHandler byte[] BLOB,LONGVARBINARY
    DateOnlyTypeHandler java.util.Date DATE
    TimeOnlyTypeHandler java.util.Date TIME
    SqlTimestampTypeHandler java.sql.Timestamp TIMESTAMP
    SqlDateTypeHandler java.sql.Date Date
    SqlTimeTypeHandler java.sql.Tome TIME
    EnumTypeHandler Enum VARCHAR或任何兼容的的字符串类型,存储的是枚举的名称(而不是索引)默认的枚举处理类
    EnumOrdinalTypeHandler Enum 任何兼容的数值类型,存储的是枚举的索引(而不是名称)

    需要注意:

    • 数值类型的精度,数据库的int,double这些类型和java的精度,长度都是不一样的。
    • 时间精度,取数据到日用 DateOnlyTypeHandler 即可,用到精度到秒的用 SqlTimestampTypeHandler 。

    自定义typeHandler

    一般而言,Mybatis系统定义的typeHandler已经能应付大部分的场景了,但不排除不够用的时候,我们自定义的typeHandler需要明确要解决什么样的问题?现有的typeHandler是否够我们使用?

    接下来我们模仿StringTypeHandler来编写一个我们自己的处理String类型的

    步骤1:首先配置XML文件

    <typeHandlers>
        <typeHandler handler="cn.lynu.typeHandler.MyStringTypeHandler" javaType="string" jdbcType="VARCHAR"/>
    </typeHandlers>

    handler指定我们自定义typeHandler的全限定名,并指明 javaType 是String,JDBCType是VARCHAR

    步骤2:编写自定义TypeHandler

    自定义TypeHandler的要求就是必须实现接口:org.apache.ibatis.type.TypeHandler,也可以继承BaseTypeHandler ,因为BaseTypeHandler实现了这个接口,这里我们先使用继承接口的方式吧

    package cn.lynu.typeHandler;
    
    import java.sql.CallableStatement;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    
    import org.apache.ibatis.type.JdbcType;
    import org.apache.ibatis.type.MappedJdbcTypes;
    import org.apache.ibatis.type.MappedTypes;
    import org.apache.ibatis.type.TypeHandler;
    
    @MappedTypes({String.class})
    @MappedJdbcTypes({JdbcType.VARCHAR})
    public class MyStringTypeHandler implements TypeHandler<String>{
    
        @Override
        public String getResult(ResultSet rs, String value) throws SQLException {
            System.out.println("使用的是result和value");
            return rs.getString(value);
        }
    
        @Override
        public String getResult(ResultSet rs, int index) throws SQLException {
            System.out.println("使用的是result和index");
            return rs.getString(index);
        }
    
        @Override
        public String getResult(CallableStatement cs, int index) throws SQLException {
            return cs.getString(index);
        }
    
        @Override
        public void setParameter(PreparedStatement ps, int index, String value, JdbcType jt) throws SQLException {
            ps.setString(index, value);
        }
    
    }

    可以看到代码中有三个重载的getResult方法,分别根据Result和value,Result和index,存储过程callableStatement来获得值,setParameter方法使用预编译PreparedStatement来设置值。

    @MappedTypes 定义的是JavaType类型,可以指定哪些Java类型可以被处理

    @MappedJdbcTypes 定义的JdbcType类型,其值可以从org.apache.ibatis.type.JdbcType 的枚举值中获得

    步骤3:在Mapper的映射XML文件使用

    <resultMap type="user" id="userMap">
       <!-- 定义结果集 -->
       <id column="id" jdbcType="INTEGER" javaType="int" property="id" />
       <result column="username" property="userName" typeHandler="cn.lynu.typeHandler.MyStringTypeHandler"  />
    </resultMap>

    这里处理username就是使用的我们自定义的TypeHandler

    public User findUserById2(int id)throws Exception; 
     <select id="findUserById2" resultMap="userMap" parameterType="int">
         select id,username from user where id = #{id}
     </select>

    经测试可以正常运行

    枚举类型typeHandler

    MyBatis有两个用于枚举类型的类型处理器,分别为EnumTypeHandler(将枚举的值存入数据库)和EnumOrdinalTypeHandler(将枚举的下标存入数据库)

    我们来创建一个性别枚举类:

    package cn.lynu.model;
    
    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;
        }
    
    }
    EnumOrdinalTypeHandler虽然是系统自带的,还是需要在MyBatis的配置文件中配置,如果不配置Mybatis默认使用 EnumTypeHandler 作为枚举类型处理器
        <typeHandlers>
          <typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler" javaType="cn.lynu.model.Sex"/>
        </typeHandlers>

    然后我们在mapper的映射xml中使用:

    <resultMap type="user" id="userMap">
       <!-- 定义结果集 -->
       <id column="id" jdbcType="INTEGER" javaType="int" property="id" />
       <result column="username" property="userName" typeHandler="cn.lynu.typeHandler.MyStringTypeHandler"  />
       <result column="sex" property="sex" typeHandler="org.apache.ibatis.type.EnumOrdinalTypeHandler"/>
    </resultMap>

    添加了一个sex字段,并指明TypeHandler为   org.apache.ibatis.type.EnumOrdinalTypeHandler

     <insert id="insertUser" parameterType="user">
       insert into user(username,sex) values(#{userName},#{sex})
     </insert>

    这是一个添加的操作,测试可以正确的先数据库中添加数据,性别字段使用的下标,而使用EnumTypeHandler就是使用枚举的值,就不复述了。

    自定义枚举TypeHandler和之前我们自定义的 MyStringTypeHandler  一样的创建和使用方法

    对象工厂

    当MyBatis在构建一个结果返回的时候,都会使用ObjectFactory(对象工厂)来封装POJO,大部分情况下,我们不需要自己去配置ObjectFactory,使用默认即可。

    插件

    插件较为复杂,使用是要小心,因为插件会覆盖一些MyBatis内部对象的行为,我们在后面讨论。

    environments配置环境

    先来看一个环境配置:

    <!-- 和spring整合之后会废除environments -->
        <environments default="development">
            <environment id="development">
                <!-- 使用JDBC事务,事务控制有Mybatis控制 -->
                <transactionManager type="JDBC" />
                <!--数据库连接池,由Mybatis创建 -->
                <dataSource type="POOLED">
    
                    <!--这里使用前面我们说的外部jdbc属性文件的方式-->
                    <property name="driver" value="${jdbc.driverClass}" />
                    <property name="url" value="${jdbc.jdbcUrl}" />
                    <property name="username" value="${jdbc.user}" />
                    <property name="password" value="${jdbc.password}" />
    
                </dataSource>
            </environment>
        </environments>

    environments有一个defaule属性,标明在默认情况下,我们使用哪个数据源配置。

    environment标签是配置一个数据源的开始,属性id是设置这个数据源的标志,environments的default使用的就是个值

    transactionManager 配置的是事务,其实type的值可以为:

    1.JDBC,采用JDBC方式管理事务

    2.MANAGED,采用容器的方式管理事务,JNDI数据源中使用

    3.自定义,可以由使用者自定义数据库事务的管理

    dataSource标签是配置数据源的各项属性,type属性是提供我们对数据库的连接方式,可选择值为:

    1.UNPOOLED,非连接池的方式,由 org.apache.ibatis.datasource.unpooled.UnpooledDataSource.class实现

    2.POOLED,连接池的方式,由 org.apache.ibatis.datasource.pooled.PooledDataSource 实现

    3.JNDI,JNDI数据源

    4.自定义数据源

    其中,配置property元素,就是在定义数据库的各项参数(四大参数等等)

     大部分这些配置我们都与Spring 框架来控制,这以后再说。

    databaseIdProvider数据库厂商标识

    在相同的数据库中使用这个毫无意义,在实际中使用很少,因为很少有项目使用不同的数据库系统。MyBatis可以设置一个数据库厂商标识,用于将指定的SQL到对应的数据库中使用。

    默认的系统规则

        <databaseIdProvider type="DB_VENDOR">
        <!-- 配置数据库标识的时候注意name值的大小写 -->
          <property name="SQL Server" value="sqlserver"/>
          <property name="MySQL" value="mysql"/>
          <property name="DB2" value="db2"/>
          <property name="Oracle" value="oracle"/>
        </databaseIdProvider>

    type="DB_VENDOR" 就是使用默认的数据库厂商标识,但是需要注意property的name属性值,是区分大小写的

    我们可以使用:

    System.out.println(sqlSessionFactory.getConfiguration().getDatabaseId());

    将现在使用的数据库打印出来,输出的就是value值,没有配置databaseId或没有根据name值匹配上,就会返回null。

    将Mapper的XML文件修改一下,说明该SQL由哪个数据库执行:

      <select id="findUserById2" resultType="user" parameterType="int" databaseId="mysql">
         select id,username,birthday from user where id = #{id}
     </select>

    就是添加一个databaseId属性,其值就是property的value值。这条SQL就会在MySQL数据库中使用。如果有两条相同的SQL,一条使用databaseID数据库标识,一条不使用,后者就会舍弃。

    引入映射器方法

    映射器是MyBatis最复杂,最核心的东西,我们之后再来研究,这里只是说明如何引入映射器。引入映射器的方法有很多,一般有以下几种:

    1.使用文件路径(这种方式可以让映射文件放在其他包下)

        <mappers>
            <mapper resource="cn/lynu/mapper/userMapper.xml"/>
        </mappers>

    2.用包名引入映射器(这样可以一次导入一个包下的mapper的XML,但是需要将sql映射文件和接口发在同一个包下。建议写法:在config或Maven的resource下建立一个与接口同名的包,将sql映射文件放入其中)

        <mappers>
            <package name="cn.lynu.mapper" />
        </mappers>

    3.用类注册引入映射器(如果在接口中使用注解的方式来映射接口,推荐使用这种引入方法;如果还是使用xml映射文件则要求映射文件和接口放在同一个的包下)

        <mappers>
            <mapper class="cn.lynu.mapper.UserMapper"/>
        </mappers>

    我们需要根据实际情况恰当的选择合适的引入方法

  • 相关阅读:
    Android Api 检查參数状态Api
    【Jquery】prop与attr的差别
    【CODEFORCES】 A. Dreamoon and Sums
    使用&lt;jsp:include&gt;,不想写死URL,动态生成URL的解决的方法
    android.app.Activity 的介绍
    字符变换
    android之获取屏幕的宽度和高度
    2015跑过的路
    hdu5418--Victor and World(floyd+状压dp)
    解决PL/SQL Developer 连接oracle 11g 64位中的问题
  • 原文地址:https://www.cnblogs.com/lz2017/p/7819535.html
Copyright © 2011-2022 走看看