Mybatis | Mybatis的核心配置

目录:

Mybatis的核心配置 :

一、MyBatis的 “核心对象”

  • 在使用MyBatis框架时,主要涉及 两个核心对象 : SqlSessionFactorySqlSession,它们在MyBatis框架中起着至关重要作用

1.1 SqlSessionFactory

  • SqlSessionFactory是MyBatis 框架中十分重要对象,它是单个数据库映射关系经过编泽后内存镜像,其主要作用创建SqlSession

  • SqlSessionFactory 对象的实例可以通过 SqlSessionFactoryBuilder对象 来构建,而SqlSessionFactoryBuilder对象 则可以通过 XML配置文件 或一个预先定义好Configuration实例 构建出SqlSessionFactory实例

  • 以下内容讲解的是 :就是 通过XML配置文件 构建出的SqlSessionFactory实例,其实现代码如下:

    InputStream inputStream = Resources.getResourceAsStream("配置文件的位置");
    //通过SqlSessionFactoryBuilder的 build()方法 + 配置文件来创建 SqlSessionFactory
    SqlSessionFactory sqlSessionFactory = 
        new SqlSessionFactoryBuilder().build(inputStream);
    
  • SqlSessionFactory对象线程安全 的,它一旦被创建,在整个应用执行期间都会存在。如果我们多次地创建同一个数据库的SqlSessionFactory,那么此数据库的资源将很容易被耗尽。为了解决此问题,通常每一个数据库都会只对应一个 SqlSessionFactory, 所以在 构建SqlSessionFactory实例时,建议使用单列模式

1.2 SqlSession :

  • SqlSession 是MyBatis 框架中另一个重要对象, 它是 应用程序持久层之间执行与操作的一个单线程对象,其主要作用执行持久化操作

  • SqlSession对象包含数据库中所有执行SOL操作方法SqlSession中有很多操作数据库方法),由于其底层封装JDBC连接,所以可以直接使用SqlSession实例来 执行已映射SQL语句

    (可用SqlSession来执行 “映射文件” 中的sql语句)。

  • 每一个线程都应该有一个自己的SqlSession实例,并且该实例不能被共享的。同时,SqlSession实例线程不安全 的,因此 使用范围 最好在 一次请求一个方法 中,绝不能将其放在一个静态字段实例字段任何类型的管理范围 (如Servlet的HttpSession)中使用。

  • 使用完SqlSession对象之后,要及时地关闭它,通常可以将其放在fnally块中关闭

//通过 sqlSessionFactory对象获得"SqlSession"
SqlSession sqlSession = sqlSessionFactory.openSession();
try{
   //此处执行持久化操作
}finally{
   sqlSession.close();
}
SqlSession对象中的操作数据库的方法 :
<T> T selectOne ( String statement )

<T> T selectOne ( String statement ) : 查询方法 : 参数 statement 是在 “ 映射文件 中定义的 <select>元素id
目的是 : 获得映射文件中的 “<select>元素下所代表的 sql语句 作为selectOne( )方法的参数 ”)。使用该方法后,会返回执行SQL语句查询结果一条泛型对象

<T> T selectOne( String statement , Object parameter )

<T> T selectOne ( String statementObject parameter ) :查询方法 : 参数 statement 是在 “ 映射文件 中定义的 <select>元素idparameter查询所需参数。使用该方法后,会返回执行SQL语句查询结果一条泛型对象

<E> List<E> selectList ( String statement )

<E> List<E> selectList ( String statement ) : 查询方法 : 参数 statement 是在 “映射文件” 中定义的 <select>元素id 。使用该方法后,会返回执行SQL语句查询结果泛型对象集合

<E> List<E> selectList ( String statement , Object parameter )

<E> List<E> selectList ( String statement , Object parameter ) : 查询方法 : 参数 statement 是在 “ 映射文件” 中定义的 <select>元素id , parameter 是查询所需的参数。使用该方法后,会返回执行SQL语句查询结果的 泛型对象集合

<E> List<E> selectList ( String statement , Object parameter , RowBounds rowBounds )

<E> List<E> selectList ( String statement , Object parameter ) : 查询方法 : 参数==statement==是在 “ 映射文件” 中定义的 <select>元素id , parameter 是查询所需的参数,rowBounds是用于分页参数对象。使用该方法后会返回执行SQL语句查询结果的 泛型对象集合

void select ( String statement , Object parameter , ResultHandler handler )

void select ( String statement, Object parameter,ResultHandler handler ) : 查询方法 : 参数statement是在配置文件中定义的 <select>元素idparameter 是查询所需的 参数ResultHandler对象用于处理查询返回复杂结果集。 (通常用于多表查询

int insert ( String statement )

int insert ( String statement ) : 插入方法 : 参数 statement是在 “映射文件” 中定义的 <select>元素id ,使用该方法后,会返回执行 SQL语句所影响行数

int insert ( String statement , Object parameter )

int insert ( String statement , Object parameter ) : 插入方法 : 参数 statement 是在 “ 映射文件” 中定义的 <select>元素idparameter 是查询所需的参数。使用该方法后,会返回执行 SQL语句所影响行数

int update( String statement )

int update ( String statement ) : 更新方法 : 参数 statement 是在 “ 映射文件” 中定义的 <update>元素id ,使用该方法后,会返回执行 SQL语句所影响行数

int update( String statement , Object parameter)

int update ( String statement , Object parameter ) : 更新方法 : 参数 statement 是在 “ 映射文件” 中定义的 <update>元素idparameter更新所需的参数。使用该方法后,会返回执行 SQL语句所影响行数

int delete( String statement )

int delete ( String statement ) : 删除方法 : 参数 statement 是在 “映射文件” 中定义的 <delete>元素id ,使用该方法后,会返回执行 SQL语句所影响行数

int delete( String statement , Object parameter)

int delete ( String statement , Object parameter ) : 删除方法 : 参数 statement 是在 “ 映射文件” 中定义的 <delete>元素idparameter删除所需的参数使用该方法后,会返回执行 SQL语句所影响行数

int commit( )

int commit ( ) : 提交事务方法

void rollback( )

int rollback ( ) : 回滚事务方法

void close( )

int close ( ) : 关闭SqlSession 对象。

<T> T getMapper( Class<T> type )
  • <T> T getMapper ( Class<T> type ) : 该方法会返回 Mapper接口代理对象,该对象关联了SqlSession对象,开发人员可以使用对象直接调用方法操作数据库。参数type是Mapper的接口类型。MyBatis官方推荐通过
    Mapper对象访问MyBatis
  • 该方法 : getMapper( ) 的目的是根据传入的 类类型type 返回一个与该类型匹配的对象。具体实现可能涉及反射机制,用于 创建并返回一个与传入类类型相匹配实例
Connection getConnection( )

Connection getConnection( ) : 获取 JDBC数据库连接对象 的方法。

使用工具类创建 “SqlSession” / SqlSession工具类
  • 使用工具类创建 SqlSession对象 :

    package com.myh.utils;
    
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    
    import java.io.IOException;
    import java.io.InputStream;
    
    
    /**
     * 工具类
     */
    public class SqlSessionUtils {  //获得SqlSession的"工具类"
    
        private static SqlSessionFactory sqlSessionFactory = null;
        //初始化 SqlSessionFactory 对象
        static { //静态代码块
            try {
                //使用Mybatis提供的Resources类加载mybatis-config.xml配置文件
                InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
                //构建SqlSessionFactory工厂
                SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        /**
         * 获得SqlSession对象的静态方法
         */
        public static SqlSession getSession() {
            return sqlSessionFactory.openSession();
        }
    }
    

    这样,我们在使用时就 只创建了一个SqlSessionFactory 对象,并且可以通过工具类getSession( ) 方法, 来 获取SqlSession对象

二、MyBatis的 “配置文件”

MyBatis的核心配置文件中,包含了很多影响MyBatis行为的重要信息。这些信息通常在一个项目中只会在一个配置文件中编写,并且编写后也不会轻易改动。

“映射文件”中的 “主要元素”

  • MyBatis 框架的 核心配置文件 (即 mybatis-config.xml )中,<configuration> 元素 是配置文件的 根元素其他元素都要在 <configuration> 元素内配置。

  • Mybatis配置文件主要元素图 :(要熟悉 <configuration>元素各个子元素配置。)

    在这里插入图片描述

    ps :
    ==<Cofgnaion>子元素必须按照图中由上到下==的顺序进行配置,否则Mybatis在解新xml配置文件的时候会报错。

<properties>元素
  • <properties>是一个配置属性元素,该元素通常用于内部配置 “外在化”,即通过外部的配置来动态地替换内部定义的属性

(直接的使用 : 将外部的 Xxx.properties文件中的属性用于 mybatis配置文件中 )。
例如,数据库的连接等属性,就可以通过典型的 Java属性文件 ( .properties文件 )中的配置替换

ps :
当我们在mybatis配置文件中 使用 <properties>元素导入 .properties文件时,即可在mybatis配置文件中,即直接使用 .properties文件中的数据

db.properties

jdbc.driver = com.mysql.jdbc.Driver
jdbc.url = jdbc:mysql://localhost:3306/mybatis
jdbc.username = root
jdbc.password = root

mybatis-config.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属性引入 .properties配置文件, mybatis配置文件中则可直接使用 .properties中的数据,进行"动态替换"  -->
   <properties resource="db.properties"/>

   <!-- environments属性 -->
   <environments default="mysql">
       <environment id="mysql">
           <transactionManager type="JDBC"/>
           <dataSource type="POOLED">
               <!--
               通过“properties属性”来将 以下的driver、url、username、password 和
               .properties配置文件 中的数据进行“动态替换”
               -->
               <property name="driver" value="${jdbc.driver}"/>
               <property name="url" value="${jdbc.url}"/>
               <property name="username" value="${jdbc.username}"/>
               <property name="password" value="${jdbc.password}"/>
           </dataSource>
       </environment>
   </environments>

</configuration>

完成上述配置后,dataSource中连接数据库的4个属性 ( driverurlusermamepassword值将会由db.properties文件对应的值动态替换。这样就为配置提供了诸多灵活的选择。
除了可以像上述通过外部配置文件定义属性值外,还可以通过配置 <properties>元素的子元素 <property>,以及通过方法参数传递的方式来获取属性值。由于使用properties配置文件来配置属性值可以方便地多个配置文件使用这些属性值,并且方便日后的维护和修改,所以在实际开发中,使用.properties文件来配置属性值最常用的方式

<settings>元素
  • <settings>元素主要用于改变MyBatis运行时行为,例如 开启二级缓存开启延迟加载 等。
    虽然不配置<settings>元素,也可以正常运行MyBatis, 但是熟悉<settings>的配置内容以及它们的作用还是十分必要的。

  • 常见的 <settings>属性配置在 “配置文件 中的使用

   <settings>
       <!--  开启“二级缓存” -->
       <setting name="cacheEnabled" value="true" />

       <!--  开启“延迟加载” -->
       <!--  打开"延迟加载"的开关 -->
       <setting name="lazyLoadingEnabled" value="true" />
       <!--  将“积极加载”改为“延迟加载”,即按需加载   -->
       <setting name="aggressiveLazyLoading" value="false"/>
       
       <setting name="multipleResultSetsEnabled" value="true"/>
       <setting name="useColumnLabel" value="true"/>
      <setting name="useGeneratedKeys" value="false" />
       <setting name="autoMappingBehavior" value="PARTIAL"/>
       .....
   </settings>
<typeAliases>元素
  • <typeAliases>元素 用于为配置文件中的Java类型设置一个简短的名字,即 设置别名别名的设置与XML配置相关,其使用的意义在于减少全限定类名冗余。 如 : 可用 <typeAliases>元素POJO类设置一个 “别名

    <?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>
    
        <!--  定义别名  -->
        <typeAliases>
    		<!-- typeAlias元素 为 typeAliases元素的 "子元素"  -->
            <typeAlias alias="user" type="com.myh.po.Customer"/>
        </typeAliases>
    
    </configuration>
    

    上述示例中,<typeAliases> 元素子元素 <typeAlias> 中的type属性用于指定需要被定义别名的类的全限定名alias属性的属性值user 就是自定义的别名,它可以代替com.myh.po.Customer使用在MyBatis文件任何位置如果省略alias属性,MyBatis 会默认将类名首字母 小写后的名称作为别名

  • POJO类过多,还可以通过自动扫描包形式自定义别名 (此时以类名首字母小写后的名称为 “别名”),具体示例如下 :

    <?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>
    
        <!--  定义别名  -->
        <typeAliases>
            <!--   使用自动扫描包来定义“别名”  -->
            <!--   Mybatis会将所用 com.myh.po包中POJO类以首字母小写的名称 作为“别名” -->
            <!--   如: Customer 的 默认设置的别名为: customer  -->
            <package name="com.myh.po"/>
        </typeAliases>
    
    </configuration>
    
  • 需要注意的是,上述方式的别名只适用于没有使用注解的情况。如果在程序中使用了注解,则别名其注解的值, 具体如下 :

    //使用注解来为该POJO类设置在 mybatis-config.xml配置文件中使用的 "别名"
    @Alias(value = "customer")
    public class Customer {  
          .....
    }
    
  • 除了可以使用 <typeAliases>元素自定义别名外,MyBatis框架还默认为许多常见的Java类型(如数值字符串日期集合等 )提供了 相应的类型别名。(可使用时查询常见的Java类型别名是什么

<typeHandler>元素
  • MyBatis预处理语句( PreparedStatement )中 设置一个参数或者从结果集 ( ResultSet )中取出一个值 时,都会用其框架内部注册了的 typeHandler ( 类型处理器 ) 进行相关处理

  • typeHandler作用就是将预处理语句 中传入的参数从 javaType ( Java类型) 转换为 jdbcType
    ( JDBC类型),或者从数据库取出结果时将 jdbcType 转换为 javaType

  • 为了方便转换,Mybatis框架提供了一系列默认的类型处理器

    类型处理器Java 类型JDBC 类型
    BooleanTypeHandlerjava.lang.Boolean, boolean数据库兼容的 BOOLEAN
    ByteTypeHandlerjava.lang.Byte, byte数据库兼容的 NUMERIC 或 BYTE
    ShortTypeHandlerjava.lang.Short, short数据库兼容的 NUMERIC 或 SMALLINT
    IntegerTypeHandlerjava.lang.Integer, int数据库兼容的 NUMERIC 或 INTEGER
    LongTypeHandlerjava.lang.Long, long数据库兼容的 NUMERIC 或 BIGINT
    FloatTypeHandlerjava.lang.Float, float数据库兼容的 NUMERIC 或 FLOAT
    DoubleTypeHandlerjava.lang.Double, double数据库兼容的 NUMERIC 或 DOUBLE
    BigDecimalTypeHandlerjava.math.BigDecimal数据库兼容的 NUMERIC 或 DECIMAL
    StringTypeHandlerjava.lang.StringCHAR, VARCHAR
    ClobReaderTypeHandlerjava.io.Reader-
    ClobTypeHandlerjava.lang.StringCLOB, LONGVARCHAR
    NStringTypeHandlerjava.lang.StringNVARCHAR, NCHAR
    NClobTypeHandlerjava.lang.StringNCLOB
    BlobInputStreamTypeHandlerjava.io.InputStream-
    ByteArrayTypeHandlerbyte[]数据库兼容的字节流类型
    BlobTypeHandlerbyte[]BLOB, LONGVARBINARY
    DateTypeHandlerjava.util.DateTIMESTAMP
    DateOnlyTypeHandlerjava.util.DateDATE
    TimeOnlyTypeHandlerjava.util.DateTIME
    SqlTimestampTypeHandlerjava.sql.TimestampTIMESTAMP
    SqlDateTypeHandlerjava.sql.DateDATE
    SqlTimeTypeHandlerjava.sql.TimeTIME
    ObjectTypeHandlerAnyOTHER 或未指定类型
    EnumTypeHandlerEnumeration TypeVARCHAR 或任何兼容的字符串类型,用来存储枚举的名称(而不是索引序数值)
    EnumOrdinalTypeHandlerEnumeration Type任何兼容的 NUMERIC 或 DOUBLE 类型,用来存储枚举的序数值(而不是名称)。
    SqlxmlTypeHandlerjava.lang.StringSQLXML
    InstantTypeHandlerjava.time.InstantTIMESTAMP
    LocalDateTimeTypeHandlerjava.time.LocalDateTimeTIMESTAMP
    LocalDateTypeHandlerjava.time.LocalDateDATE
    LocalTimeTypeHandlerjava.time.LocalTimeTIME
    OffsetDateTimeTypeHandlerjava.time.OffsetDateTimeTIMESTAMP
    OffsetTimeTypeHandlerjava.time.OffsetTimeTIME
    ZonedDateTimeTypeHandlerjava.time.ZonedDateTimeTIMESTAMP
    YearTypeHandlerjava.time.YearINTEGER
    MonthTypeHandlerjava.time.MonthINTEGER
    YearMonthTypeHandlerjava.time.YearMonthVARCHAR 或 LONGVARCHAR
    JapaneseDateTypeHandlerjava.time.chrono.JapaneseDateDATE
  • MyBatis框架所提供的 这些类型处理器不能够满足需求时,还可以通过自定义的方式对类型处理器进行扩展 ( 自定义类型处理器可以通过实现TypeHandler 接口 或者 继承 BaseTypeHandle类来定义)。

    <typeHandler> 元素就是用于在配置文件注册自定义类型处理器的。它的使用方式有两种
    注册一个类类型处理器
    注册一个包所有类型处理器

    CustomertypeHandler.java

    package com.myh.type;
    
    import org.apache.ibatis.type.JdbcType;
    import org.apache.ibatis.type.TypeHandler;
    
    import java.sql.CallableStatement;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    public class CustomertypeHandler implements TypeHandler {
        @Override
        public void setParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException {
        } 
    
        @Override
        public Object getResult(ResultSet rs, String columnName) throws SQLException {
            return null;
        }
    
        @Override
        public Object getResult(ResultSet rs, int columnIndex) throws SQLException {
            return null;
        }
    
        @Override
        public Object getResult(CallableStatement cs, int columnIndex) throws SQLException {
            return null;
        }
    }
    

    mybatis-config.xml

         <!-- 注册一个类的类型处理器 -->
        <typeHandlers>
            <!--  以单个类的形式配置   -->
            <typeHandler handler="com.myh.type.CustomertypeHandler"/>
        </typeHandlers>
    
        <!-- 注册一个包中所有类的类型处理器 -->
         <typeHandlers>
             <!--  注册一个包中所有的typeHandler,系统在启动时会自动扫描包下的所有文件  -->
            <package name="com.myh.type"/>
        </typeHandlers>
    
<objectFactory>元素
  • MyBatis框架每次创建 结果对象新实例 时,都会使用一个对象工厂( ObjectFactory )的实例来完成。MyBatis中默认的 ObjectFactory的作用 就是 实例化目标类,它既可以通过默认构造方法实例化,也可以在参数映射存在的时候通过参数构造方法来实例化

  • 在通常情况下, 我们使用默认的ObjectFactory即可,MyBatis 中默认ObjectFactory是由org.apache.ibatis rflection.factory.DefaultObjectFactory来提供服务的。大部分场景下都不用配置和修改,但如果想覆盖ObjectFactory的默认行为,则可以通过自定义ObjectFactory来实现。

    MyObjectFactory.java

    package com.myh.objFactory;
    
    import org.apache.ibatis.reflection.factory.DefaultObjectFactory;
    
    import java.util.List;
    import java.util.Properties;
    
    //自定义工厂类 : 该类可以实现ObjectFactory接口 或 继承 DefaultObjectFactory类
    public class MyObjectFactory extends DefaultObjectFactory { //要继承DefaultObjectFactory类
    
        private static final long serialVerSionUID = -4114845625429965832L;
    
    
        @Override
        public <T> T create(Class<T> type) {
            return super.create(type);
        }
    
        @Override
        public <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
            return super.create(type, constructorArgTypes, constructorArgs);
        }
    
        @Override
        public void setProperties(Properties properties) {
            super.setProperties(properties);
        }
    
        @Override
        public <T> boolean isCollection(Class<T> type) {
            return super.isCollection(type);
        }
    }
    

    mybatis-config.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>
    
        <objectFactory type="com.myh.objFactory.MyObjectFactory">
            <property name="name" value="MyObjectFactory"/>
        </objectFactory>
    
    </configuration>
    
<plugins>元素
  • MyBatis允许在已映射语句执行过程中某一点进行拦截调用,这种拦截调用是通过插件来实现的。<plugins> 元素作用就是配置用户所开发插件。如果用户想要进行插件开发,必须要先了解其内部运行原理,因为在试图修改或重写已有方法的行为时,很可能会破坏MyBatis原 有的核心模块。
<environments>元素
  • 配置文件中,<environments>元素用于对环境进行配置MyBatis环境配置 实际上就是 数据源的配置,我们可以通过 <environments>元素配置多种数据源,即配置多种数据库

       <!-- environments属性 -->
        <environments default="mysql">
            <environment id="mysql">
                <transactionManager type="JDBC"/>
                <dataSource type="POOLED">
                    <!--
                    通过“properties属性”来将 以下的driver、url、username、password 和
                    .properties配置文件 中的数据进行“动态替换”
                    -->
                    <property name="driver" value="${jdbc.driver}"/>
                    <property name="url" value="${jdbc.url}"/>
                    <property name="username" value="${jdbc.username}"/>
                    <property name="password" value="${jdbc.password}"/>
                </dataSource>
            </environment>
        </environments>
    

    在上述代码中,<environments>元素环境配置根元素,它包含个一default属性,该属性用于指定默认环境ID。 是 <environments>元素的 “子元素”, : <environment> 可以定义多个,其记属性用于表示所定义环境ID值。在 environment元素内,包含事务管理 ( transactionManager ) 和 数据源 ( dataSource ) 的配置信息,其 <transactionManager>元素用于配置事务管理,它的type属性用于指定事务管理的方式,即使用哪种事务管理器<dalaSource>元素用于配置数据源,它的type属性用于指定使用哪种数据源

    在MyBatis中,可以配置两种类型的事务管理器,分别是 JDBCMANAGEDJDBC : 此配置直接使用了JDBC提交回滚设置,它依赖于从数据源得到的连接来管理事务作用域
    MANAGED : 此配置从来不提交回滚一个连接 ,而是让容器来管理事务整个生命周期
    默认情况下,它会关闭连接,但一些容器并不希望这样,为此可以将closeConnection属性
    置为false阻止它默认关闭行为

    ps :
    如果没有必要中 使用的是 Spring+ MyBatis,则 没有必要 在MyBatis ( mybatis-config.xml ) 中 配置事务管理器,因为实际开发中,会使用Spring自带的管理器实现事务管理

<mappers>元素
  • 配置文件 ( mybatis-config.xml )中,<mappers>元素 用于 指定MyBatis 映射文件 (引入“映射文件”)(XxxMapper.xml )的 位置,一般可以使用以下 4种方法 引入映射文件。 ( 一个mybatis-config.xml 配置文件可以引入多个“映射文件”。)

    使用 “类路径” 引入
    使用 “本地文件路径” 引入
    使用 “接口类” 引入
    使用 “包名” 引入

  • 使用 “类路径” 引入

    <mappers>
            <!-- 使用"类路径"读取"映射文件" -->
            <mapper resource="com/myh/mapper/CustomerMapper.xml"/>
    </mappers>
    
  • 使用 “本地文件路径” 引入

     <mappers>
            <!--  使用“本地文件路径”引入“映射文件”  -->
            <mapper url="file:///D:/com/myh/mapper/CustomerMapper.xml"/>
     </mappers>
    
  • 使用 “接口类” 引入

    <mappers>
            <!--  使用“接口类”引入“映射文件”  -->
            <mapper class="com.myh.mapper.CustomerMapper"/>
    </mappers>
    
  • 使用 “包名” 引入

    <mappers>
            <!-- 使用“包名”引入“映射文件” -->
          <package name="com.myh.mapper"/>
    </mappers>
    

三、MyBatis的 “映射文件”

  • 映射文件 ( XxxMapper.xml )是Mybatis框架中十分重要的文件,可以说,Mybatis框架的强大之处就体现在“映射文件”的编写上
  • 映射文件中,<mapper>元素映射文件根元素,其他元素都是它的子元素
    在这里插入图片描述

“配置文件”中的 “主要元素”

<select>元素
  • <select>元素 用于映射 “查询语句”,它可以帮助我们从数据库中读出数据,并组装数据给企业开发者。

        <!-- “查询数据”-->
    	<select id="findCustomerById" parameterType="Integer" resultType="com.myh.po.Customer">
             select * from t_customer where id = #{id}
        </select>
    

    上述语句中的唯一标识为 findCustomerByld,它接收一个 Integer 类型参数,并返回一个Customer类型对象

  • <select>元素中,除了上述代码中的几个属性还有其他一些可以配置属性如下所示

    属性说明
    id表示命名空间中唯一标识符, 常与命名空间组合起来使用组合后如果不唯一, MyBatis会抛出异常。
    parameterType该属性表示传入SQL语句参数类全限定名或者别名。它是一个可选属性, 因为MyBatis可以通过TypeHandler推断出具体传入语句参数。其默认值是unset (依赖于驱动)
    resultType从SQL语句中返回的类型全限定名或者别名。如果是集合类型,那么返回的应该是集合可以包含类型,而不是集合本身。返回时可以使用resultTyperesultMap之一。
    resultMap表示外部resultMap命名引用。返回时可以使用resultTyperesultMap之一。
    flushCache表示在调用SQL语句之后,是否需要MyBatis清空之前查询本地缓存二级缓存。其值为布尔类型( truelfalse),默认值为false。如果设置为true,则任何时候只要SQL语句被调用,都会清空本地缓存二级缓存。
    useCache用于控制二级缓存开启关闭。其值为布尔类型( truelfalse),默认值为true,表示将查询结果存入二级缓存中。
    timeout用于设置超时参数,单位为超时将抛出异常
    fetchSize获取记录总条数设定,其默认值是unset (依赖于驱动)。
    statementType用于设置MyBatis使用哪个JDBCStatement工作,其值为STATEMENTPREPARED(默认值)CALLABLE, 分别对应JDBC中的StatementPreparedStatementCallableStatement
    属性说明
    resultSetType表示结果集类型,其值可设置为FORWARD_ONLY、SCROLL_SENSITIVE 或SCROLL_INSENSITIVE, 它的默认值是unset (依赖于驱动)
<insert>元素
  • <insert>元素用于映射“插入语句,在执行完元素中定义的SQL语句后,返回一个表示插入记录数整数
<!--
   useGeneratedKeys="true" : 获得该insert语句插入数据库时形成的“主键id” / 获得数据库内部产生的主键id
   keyProperty="id" : 将插入或更新时的“返回值”赋值到PO类的对应的“属性”上 : 即将刚获得的“主键id”赋值到PO类对应的id属性上
   -->
<!--  该insert语句的返回值 : ①返回插入成功的行数 ②插入行的主键id  -->
<insert id="addCustomer" parameterType="com.myh.po.Customer"
        flushCache="true" statementType="PREPARED"
        keyProperty="id" keyColumn="" useGeneratedKeys="true" timeout="20">
    insert into t_customer(username,jobs,phone)
    values(#{username},#{jobs},#{phone})
</insert>

以上的 insert语句返回值 : ①返回插入成功的行数 ②插入行的主键id
上述代码中可以看出,<insert>元素属性<select>元素属性大部分相同<insert>元素包含了 3个特有属性

  • <insert>元素 中的三个特有 属性 :
属性说明
keyProperty( 仅对insert和update有用 )此属性 ( keyProperty )的作用插入 或 更新操作时返回值赋值给 PO类某个属性通常会设置为“主键”对应的属性
(通常会设置该属性的值为“id” (即将插入形成的“主键id”值赋值到PO类中 )。如果需要设置联合主键,可以在多个值之间用逗号隔开
例子如 :
keyProperty =“i‘d” ( 要结合useGeneratedKeys属性使用 ) :
useGeneratedKeys属性获得的 ( 插入形成的 ) “主键id” 赋值到PO类的对应的id属性上,这样就能获得insert语句生成的数据对应的“主键id”了。
keyColumn( 仅对insertupdate有用 ) 此属性用于 设置第几列主键主键列不是表中第一列时需要设置,在需要主键联合时,值可以使用逗号隔开。
useGeneratedKeys( 仅对insertupdate有用 )此属性会使 MyBatis 使用 JDBCgetGeneratedKeys( )方法来获取由数据库内部生产主键 (此时一般配合keyProperty属性使用来将该“主键 赋值给PO类对应的属性上。”), 如MySQLSQL Server自动递增字段,其 默认值false

执行插入操作后,很多时候我们会需要返回插入成功数据生成主键值 ( 表中主键id ),此时就可以通过
上面所讲解的3个属性来实现。


  • 如果使用的数据库支持主键自动增长 (如MySQL ),那么可以通过keyProperty属性 指定PO类某个属性接收主键返回值 ( 通常会设置到id属性上 : 将主键id赋值给PO类id属性上 ),同时还要通过 useGeneratedKeys属性才能实现目标功能。 例子如下 :

<insert>元素 中的三个特有 属性 例子如 :

CustomerMapper.xml (映射文件) :

<!--
   useGeneratedKeys="true" : 获得该insert语句插入数据库时形成的“主键id” / 获得数据库内部产生的主键id
   keyProperty="id" : 将插入或更新时的“返回值”赋值到PO类的对应的“属性”上 : 即将刚获得的“主键id”赋值到PO类对应的id属性上
   -->
<!--  该insert语句的返回值 : ①返回插入成功的行数 ②插入行的主键id  -->
<insert id="addCustomer" parameterType="com.myh.po.Customer"
        keyProperty="id"  useGeneratedKeys="true" >
    insert into t_customer(username,jobs,phone)
    values(#{username},#{jobs},#{phone})
</insert>

以上的 insert语句返回值 : ①返回插入成功的行数 ②插入行的主键id

CustomerTest.java (测试类) :

public class CustomerTest {

 @org.junit.Test //单元测试
 public void addCustomerTest() throws IOException {
     //1.读取mybatis框架的配置文件
     String resource = "com/myh/映射文件的元素/mybatis-config.xml";
     //通过“输入流”读取mybatis配置文件
     /*
        在该mybatis-config.xml配置文件中,已配置了“数据源”信息 和配置了"映射文件 : XxxMapper.xml”的位置,
        可实施加载“映射文件”
      */
     InputStream inputStream = Resources.getResourceAsStream(resource);

     //2.根据配置文件“构建会话工厂 : SqlSessionFactory ”
     SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
     //3.通过SqlSessionFactory(会话工厂)创建SqlSession("会话"对象)
     SqlSession sqlSession = sqlSessionFactory.openSession();

     Customer customer = new Customer();
     customer.setUsername("小蓝");
     customer.setJobs("学生");
     customer.setPhone("12345678");
     //将该Customer对象存入到数据库中,同时目的是: 将存入到数据库中的数据对应的“主键id”获得且返回
     int insert = sqlSession.insert("CustomerMapper.addCustomer", customer);
     /**
         * 输出"插入数据"形成的"主键id值"  (从数据库中获得的主键id值是存储在Customer这个PO类中的)
      */
     System.out.println(customer.getId());
     if (insert > 0) {
         System.out.println("你成功插入了" + insert + "条数据!");
     } else {
         System.out.println("插入数据操作失败! ");
     }
     //4.设置“事务管理”
     sqlSession.commit();
     //5.关闭SqlSession
     sqlSession.close();
 }
}

通过上述的<insert>元素三个特有属性,即可获得插入数据对应“ 主键id”

在这里插入图片描述


  • 如果使用的数据库不支持主键自动增长 (如Oracle ), 或者支持增长的数据库 取消了主键自增 的规则时,也可以使用MyBatis提供的另一种方式自定义生成主键例子如下

    <?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">
    <!--
       映射文件中,插入数据用 <insert>元素
    -->
    <!-- #{} : 相当于"占位符"  ${} : 相当于在sql语句后要拼接的"字符串" -->
    <mapper namespace="CustomerMapper">
    
        <insert id="insertCustomer" parameterType="com.myh.po.Customer">
             <selectKey keyProperty="id" resultType="Integer" order="BEFORE">
           select if(max(id) is null,1,max(id) + 1)as newId from t_customer
             </selectKey>
            insert into t_customer(username,jobs,phone)
            values(#{username},#{jobs},#{phone})
        </insert>
      
    </mapper>
    

    上述代码中,<selectKey> 元素会首先运行,它会通过自定义的语句来设置数据中的主键 (如果
    t_customer表中没有记录,则将id设置为1,否则就将id的最大值加1,来为新的主键),然后再调用插入语句
    <selectKey>元素在使用时可以设置以下几种属性

    <selectKey
       keyProperty="id"
       resultType="Integer"
       order="BEFORE"
       statementType="PREPARED">
    

    在上述 <selectKey>元素的几个属性中,keyPropertyresultTypestatementType的作用与前面讲解的相同,order 属性可以被设置为BEFOREAFTER如果设置BEFORE,那么它会首先执行 <selectKey>元素中的配置设置主键,然后执行插入语句;如果设置为AFTER,那么它会先执行插入语句,然后执行 <selectKey>元素中的配置内容。

<update>元素和<delete>元素
  • <update><delete>元素 的使用比较简单,它们的属性配置也基本相同 ,其常用属性如下 :
  <!-- 更新 -->
   <update id="updateCustomer" parameterType="com.myh.po.Customer"
           flushCache="true" statementType="PREPARED" timeout="20">
   </update>

   <!-- 删除 -->
   <delete id="deleteCustomer" parameterType="com.myh.po.Customer"
           flushCache="true" statementType="PREPARED" timeout="20">
   </delete>

从上述配置代码中可以看出,<update><delete>元素属性基本与 <select>元素中属性一致
<insert>元素一样,<update> 和<delete>元素在执行完之后,也会返回一个表示影响记录条数整数,其使用示例如下 :

<!-- 更新 -->
<update id="updateCustomer" parameterType="com.myh.po.Customer">
       update t_customer set username = #{username},jobs=#{jobs},phone=#{phone}
       where id = #{id}
   </update>

 <!-- 删除 -->
 <delete id="deleteCustomer" parameterType="Integer">
      delete from t_customer where id = #{id}
   </delete>
<sql>元素
  • 一个映射文件中,通常需要定义多条SQL语句,这些SQL语句的组成可能有一部分是相同的 ( 如多条select语句中都查询相同的idusernamejobs 字段),如果每一个SQL语句都重写遍相同的部分, 势必会增加代码量,导致映射文件过于臃肿

  • 那么有没有什么办法将这些SQL语句相同组成部分抽取出来,然后在需要的地方引用呢 ?
    答案是肯定的,我们可以在映射文件中使用MyBatis所提供的 <sql>元素来解决上述问题。<sql>元素的作用 : 就是定义可重用SQL代码片段,然后在其他语句中引用这一代码片段

    例子如

     <sql id="customerColumns"> id,username,jobs,phone</sql>
    
     <select id="findCustomerById" parameterType="Integer" resultType="com.myh.po.Customer">
            select <include refid="customerColumns"/>
            from t_customer
            where id = #{id}
     </select>
    
<resultMap>元素 (①可解决“属性名” 和 “字段名”不一样导致的数据无法映射成功的问题、 ②完成“一对一”关联关系、 ③完成“一对多”关联关系等)
  • <resultMap>元素表示结果映射集,是 MyBatis最重要 也是 最强大元素。它的主要作用 : 是
    定义映射规则级联的更新 以及 定义类型转化器 等。

    ps :
    <resultMap>元素 可解决“属性名” 和 “字段名不一样导致的数据无法映射成功问题

  • <resutMap>元素中包含了属性 / 子元素,如下所示 :

       <!--  resultMap的元素结构  -->
       <resultMap type="" id="">
    
           <constructor>  <!-- 类在实例时,用来注入"结果"到"结构方法"中 -->
              <idArg/>    <!-- ID参数;标记结果为ID -->
               <arg/>     <!-- 注入到构造方法的一个普通结果 -->
           </constructor>
    
           <id/>          <!-- 用于表示哪个"列"是"主键" -->
           <result/>      <!-- 注入到“字段”或“JavaBean属性”的普通结果 -->
           <association property=""/>  <!-- 用于一对一关联 -->
           <collection property=""/>   <!-- 用于一对多关联 -->
    
           <discriminator javaType="">   <!-- 使用"结果值"来决定哪个"结果映射"-->
               <case value=""></case>
           </discriminator>
    
       </resultMap>
    
  • <resutMap>元素属性 关系如下表所示 :

    属性描述
    type表示需要 映射 POJO ( 普通Java对象 )
    id这个 resultMap唯一标识
  • <resutMap>元素子元素 关系如下表所示 :

    子元素描述
    <constructor>用于配置构造方法 ( 当一个POJO未定义无参构造方法时,就可以使用 <constructor>元素 进行配置)。
    <id>分别标记 POJO中属性中的“主键和 标记数据库表中字段的 “主键,并 将二者进行关联
    ps :
    这意味着,通过 <resultMap> 中的 <id>元素的配置,POJO“主键”属性名 不用 和数据库中 “主键”名相同。
    <result>表示 POJO属性数据库表映射关系。(用于POJO中 “属性数据库表中的 “进行关联。 )
    ps :
    这意味着
    ,通过 <resultMap> 中的 <result>元素的配置,数据库中的 “字段” 以及 该“字段”相对应的 “属性”名,不用一致。(在 <result>中设置各自的名称即可)
    <association>表示“一对一”关联。用于处理“多表”时的关联关系
    <collection>表示“一对多”关联。用于处理“多表”时的关联关系
    <discriminator>使用"结果值"来决定哪个"结果映射"用于处理一个单独的数据库查询 返回很多不同数据类型 结果集情况
  • 在默认情况下,MyBatis程序在运行时会 自动地将查询到数据与需要返回的对象属性进行匹配赋值 ( 需要表中的 列名与对象的属性名称完全一致 )。 然而实际开发时,数据表中的和需要返回的对象的属性可能不会完全一致, 这种情况下MyBatis是不会自动赋值。此时,就可以使用 <resultMap>元素进行处理

  • 实际开发中,如果当POJO中“属性名” 和 数据库中“字段名不一致,此时查询数据库,数据会无法映射到POJO类中,最后导致查询到的内容为null。 此时<resultMap>元素即可解决这个问题

    例子如:
    在这里插入图片描述

    在这里插入图片描述


    此时可使用“映射文件” 中的因属性名 和 字段名不一致导致的数据无法映射POJO中的问题。如下所示 :

    UserMapper.xml

    <?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="UserMapper">
    
        <!--  select元素中使用resultType时,当数据库中"字段名" 和POJO中"属性名"不一致时,select的数据将则无法映射到POJO类中,即输出内容为null -->
        <!--  select元素中用resultMap时,数据库中“字段名” 和 POJO中“属性名”不用保持一致,此时也能完成将select到的数据映射到POJO类中-->
       <select id="selectUser_resultType" resultType="com.myh.po.User" parameterType="Integer">
           select * from t_user where t_id = #{id}
       </select>
    
    
        <!--
        上面这个select的查询的数据是无法映射到POJO类中,即select的数据为null,因为数据库中“字段名” 和 POJO中的“属性名”,
        此时可用 <resultMap>元素来解决这个问题 -->
        <resultMap id="resultMap" type="com.myh.po.User">
            <!--   下面配置的目的 : "属性名" 和 "字段名" 可以不用保持一致   -->
            <id property="id" column="t_id"/>
            <result property="name" column="t_name"/>
            <result property="age" column="t_age"/>
        </resultMap>
    
        <!--  因为此处用了resultMap(已经配置好了,完成各种内容的“映射了”,所以即使"属性名" 和 “字段名”不一致,也能select到数据)  -->
        <select id="selectUser_resultMap" resultMap="resultMap" parameterType="Integer">
            select * from t_user where t_id = #{id}
        </select>
    
    </mapper>
    

    UserTest.java (测试类)

    public class UserTest {
    
        @org.junit.Test //单元测试
        public void selectUser_resultType_resultMap_Test() throws IOException {
            //1.读取mybatis框架的配置文件
            String resource = "com/myh/映射文件的元素/mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            //2.根据配置文件“构建会话工厂 : SqlSessionFactory ”
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            //3.通过SqlSessionFactory(会话工厂)创建SqlSession("会话"对象)
            SqlSession sqlSession = sqlSessionFactory.openSession();
             User user1 = (User)sqlSession.selectOne("UserMapper.selectUser_resultType", 2);
            /**
               此处输出的内容为 : null ,因为字段名和属性名 不一样,数据无法映射成功,最后输出的内容为 : null
             */
            System.out.println("从数据库中查询到的数据为(通过resultType获得): "+user1);
    
            /**
             此处输出的内容为 : "查询到的数据",即使“属性名” 和 “字段名”没有保持一致,但通过resultMap元素的配置,查询到的数据依然能
              映射到POJO类中。
             */
            User user2 = (User)sqlSession.selectOne("UserMapper.selectUser_resultMap", 2);
            System.out.println("从数据库中查询到的数据为(通过resultMap获得): "+user2);
    
            //4.关闭SqlSession
            sqlSession.close();
        }
    }
    

    控制台输出结果为
    在这里插入图片描述

  • 25
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值