Mybatis简介和认识

mybatis是什么

MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生类型、接口和 Java 的 POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

为什么要用mybatis

1、最原始的方式是通过JDBC的API去操作数据库,这种方式存在很多重复性的工作(代码),每一次操作数据库都会进行一下操作:
1.注册驱动(前提是引入jar包)
2.通过 DriverManager 获取一个 Connection,参数里面填数据库地址,用户名和密码
3.我们通过 Connection 创建一个 Statement 对象
4.通过 Statement 的 execute()方法执行 SQL,当然 Statement 上面定义了非常多的方法,execute()方法返回一个 ResultSet 对象(结果集)
5.我们通过 ResultSet 获取数据,转换成一个 POJO 对象
6.我们要关闭数据库相关的资源,包括 ResultSet、Statement、Connection,它们的关闭顺序和打开的顺序正好是相反的

2、如果处理业务逻辑和处理数据的代码是耦合在一起的,业务流程复杂的话,跟数据库交互的次数会很多,会消耗太多的资源

3、DbUtils 和 Spring JDBC,这两个对 JDBC 做了轻量级封装的框架(工具),虽然帮我们解决了一些问题
3.1、无论是 QueryRunner 还是 JdbcTemplate,都可以传入一个数据源进行初始化,也就是资源管理这一部分的事情,可以交给专门的数据源组件去做,不用我们手动创建和关闭;
3.2、对操作数据的增删改查的方法进行了封装;
3.3、可以帮助我们映射结果集,无论是映射成 List、Map 还是实体类。

但是也存在缺点:
3.4、SQL 语句都是写死在代码里面的,依旧存在硬编码的问题;
3.5、参数只能按固定位置的顺序传入(数组),它是通过占位符去替换的,不能自动映射;
3.6、在方法里面,可以把结果集映射成实体类,但是不能直接把实体类映射成数据库的记录(没有自动生成 SQL 的功能);
3.7、查询没有缓存的功能。

ORM框架介绍

什么是ORM?
ORM 的全拼是 Object Relational Mapping,也就是对象与关系的映射,对象是程序里面的对象,关系是它与数据库里面的数据的关系。也就是说,ORM 框架帮助我们解决的问题是程序对象和关系型数据库的相互映射的问题。
O:对象(Object) R:关系型数据库(Relational) M:映射(Mapping)

Hibernate

Hibernate是一个全自动化的ORM框架,帮我们自动的生成sql语句(可以兼容各种流行的数据库),自动进行映射。

如果遇到复杂的业务的时候,Hibernate 的问题就显示出来了:
1、比如使用 get()、save() 、update()对象的这种方式,实际操作的是所有字段,没有办法指定部分字段,换句话说就是不够灵活

2、这种自动生成 SQL 的方式,如果我们要去做一些优化的话,是非常困难的,也就是说可能会出现性能比较差的问题。

3、不支持动态 SQL(比如分表中的表名变化,以及条件、参数)。

Mybatis

Mybatis是一个半自动化的ORM架构,“半自动化”相对于“全自动化”来说的话,封装程度没有 “全自动化” 那么高,不会自动生成全部的 SQL 语句,主要解决的是 SQL 和对象的映射问题。

学习成本低: MyBatis 里面,SQL 和代码是分离的,所以会写 SQL 基本上就会用 MyBatis

Hibernate和MyBatis跟 DbUtils、Spring JDBC 一样,都是对 JDBC 的一个封装

Mybatis的核心特性

1、使用连接池对连接进行管理
2、SQL 和代码分离,集中管理
3、结果集映射
4、参数映射和动态 SQL
5、重复 SQL 的提取
6、缓存管理
7、插件机制

关于技术选型问题:

1、在一些业务比较简单的项目中,我们可以使用 Hibernate;
2、如果需要更加灵活的 SQL,可以使用 MyBatis,
3、对于底层的编码,或者性能要求非常高的场合,可以用 JDBC。
4、当然,根据业务需要,也可以MyBatis 和 Spring JDBC 是可以混合使用的。

Mybatis的使用

1.引入jar包
2.创建全局的配置文件,里面的配置是控制mybatis的核心行为,非常重要,并命名为mybatis-config.xml
3.创建映射器文件,一般是一个表对应一个Mapper.xml,在这个Mapper.xml中可以配置我们的CRUD的sql语句、参数和返回的结果集的映射关系

Mybatis核心对象的生命周期

SqlSessionFactoryBuilder(方法局部 method)

这个类用 来 构 建 SqlSessionFactory 的 , 而SqlSessionFactory 只需要一个,所以只要构建了这一个 SqlSessionFactory,它的使命就完成了,也就没有存在的意义了。所以它的生命周期只存在于方法的局部

SqlSessionFactory(单例的,应用级别 application)

SqlSessionFactory 是用来创建 SqlSession 的,每次应用程序访问数据库,都需要创建一个会话。因为我们一直有创建会话的需要,所以 SqlSessionFactory 应该存在于应用的整个生命周期中(作用域是应用作用域)。创建 SqlSession 只需要一个实例来做这件事就行了,否则会产生很多的混乱,和浪费资源,所以可以采用单例模式。

SqlSession(请求和操作 request / method)

SqlSession 是一个会话,因为它不是线程安全的,不能在线程间共享。所以我们在请求开始的时候创建一个 SqlSession 对象,在请求结束或者说方法执行完毕的时候要及时关闭它(作用域:一次请求或者操作中)。

Mapper(方法 method)

mapper实际上是一个代理的对象,从SqlSession中获取,他是用来发送sql来操作数据库的数据的,作用域是在一个SqlSession事务方法之内

核心配置

XML配置.png
Configuration

configuration 是整个配置文件的根标签,实际上也对应着 MyBatis 里面最重要的配置类 Configuration。它贯穿 MyBatis 执行流程的每一个环节。

MyBatis 全局配置文件顺序是固定的,不能随意更改配置的位置,否则启动的时候会报错。

properties

用来配置参数信息,比如最常见的数据库连接信息。

为了避免直接把参数写死在 xml 配置文件中,我们可以把这些参数单独放在properties 文件中,用 properties 标签引入进来,然后在 xml 配置文件中用${}引用就可以了。

可以用 resource 引用应用里面的相对路径,也可以用 url 指定本地服务器或者网络的绝对路径。

独立配置properties 文件的好处:
1、提取,利于多处引用,维护简单;
2、把配置文件放在外部,避免修改后重新编译打包,只需要重启应用;
3、程序和配置分离,提升数据的安全性。

settings
settings.png

setttings 里面是 MyBatis 的一些核心配置

typeAliases(别名)

TypeAlias 是类型的别名,跟 Linux 系统里面的 alias 一样,主要用来简化全路径类名的拼写。

它只和 XML 配置有关,存在的意义仅在于用来减少类完全限定名的冗余。
例如:

<typeAliases>
  <typeAlias alias="Author" type="domain.blog.Author"/>
  <typeAlias alias="Blog" type="domain.blog.Blog"/>
  <typeAlias alias="Comment" type="domain.blog.Comment"/>
  <typeAlias alias="Post" type="domain.blog.Post"/>
  <typeAlias alias="Section" type="domain.blog.Section"/>
  <typeAlias alias="Tag" type="domain.blog.Tag"/>
</typeAliases>

<typeAliases>
  <package name="domain.blog"/>
</typeAliases>
类型对比.png
typeHandlers

作用:由于 Java 类型和数据库的 JDBC 类型不是一一对应的(比如 String 与 varchar),利用typeHandlers把 Java 对象转换为数据库的值,和把数据库的值转换成 Java 对象,相互转换。

objectFactory

MyBatis 每次创建结果对象的新实例时,它都会使用一个对象工厂(ObjectFactory)实例来完成,由于不知道要处理什么类型和属性,
ObjectFactory接口定义了4个方法:

void setProperties(Properties properties);  //设置参数时调用
<T> T create(Class<T> type);//创建对象(调用无参构造函数)
<T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs);//创建对象(调用带参数构造函数)
<T> n boolean isCollection(Class<T> type);  // 判断是否集合

ObjectFactory 有一个默认的实现类 DefaultObjectFactory,创建对象的方法最终都调用了 instantiateClass(),是通过反射来实现的。

如果想要修改对象工厂在初始化实体类的时候的行为,就可以通过创建自己的对象工厂,继承 DefaultObjectFactory 来实现

问题

什么时候调用了 objectFactory.create()?
创建 DefaultResultSetHandler 的时候、创建对象的时候。

创建对象后,已有的属性为什么被覆盖了?
在 DefaultResultSetHandler 类的getRowValue()方法里面里面调用了applyPropertyMappings()。

返回结果的时候,ObjectFactory 和 TypeHandler 哪个先工作?
先是 ObjectFactory,再是 TypeHandler。肯定是先创建对象。

plugins

插件是 MyBatis 的一个很强大的机制,跟很多其他的框架一样,MyBatis 预留了插件的接口,让 MyBatis 更容易扩展。

MyBatis 允许你在已映射语句执行过程中的某一点进行拦截调用,默认情况下,MyBatis 允许使用插件来拦截的方法调用包括:

Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
ParameterHandler (getParameterObject, setParameters)
ResultSetHandler (handleResultSets, handleOutputParameters)
StatementHandler (prepare, parameterize, batch, update, query)
environments

environment
environments 标签用来管理数据库的环境,比如我们可以有开发环境、测试环境、生产环境的数据库。可以在不同的环境中使用不同的数据库地址或者类型。

尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。每个数据库对应一个 SqlSessionFactory 实例

<environments  default ="development">
    <environment  id ="development">
        <transactionManager  type ="JDBC"/>
        <dataSource  type ="POOLED">
            <property  name" ="driver"  value="com.mysql.jdbc.Driver"/>
            <property  name ="url" value="jdbc:mysql://127.0.0.1:3306/mybatis?useUnicode=true"/>
            <property  name" ="username"  value ="root"/>
            <property  name" ="password"  value ="root"/>
        </ dataSource>
     </ environment>
</ environments>

一个 environment 标签就是一个数据源,代表一个数据库。这里面有两个关键的标签,一个是事务管理器,一个是数据源

transactionManager
如果配置的是 JDBC,则会使用 Connection 对象的 commit()、rollback()、close()管理事务。

如果配置成 MANAGED,会把事务交给容器来管理,比如 JBOSS,Weblogic。因为我们跑的是本地程序,如果配置成 MANAGE 不会有任何事务。

如果你正在使用 Spring + MyBatis,则没有必要配置事务管理器, 因为 Spring 模块会使用自带的管理器来覆盖前面的配置。

dataSource
dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象的资源。
mybatis有三种默认的内建的数据源类型:UNPOOLED、POOLED、JNDI

UNPOOLED

这个数据源的实现只是每次被请求时打开和关闭连接。虽然有点慢,但对于在数据库连接可用性方面没有太高要求的简单应用程序来说,是一个很好的选择。 不同的数据库在性能方面的表现也是不一样的,对于某些数据库来说,使用连接池并不重要,这个配置就很适合这种情形。

具有的配置属性:

driver – 这是 JDBC 驱动的 Java 类的完全限定名(并不是 JDBC 驱动中可能包含的数据源类)。

url – 这是数据库的 JDBC URL 地址。

username – 登录数据库的用户名。

password – 登录数据库的密码。

defaultTransactionIsolationLevel – 默认的连接事务隔离级别。

defaultNetworkTimeout – The default network timeout value in milliseconds to wait for the database operation to complete. See the API documentation of java.sql.Connection#setNetworkTimeout() for details.
POOLED

这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来,避免了创建新的连接实例时所必需的初始化和认证时间。 这是一种使得并发 Web 应用快速响应请求的流行处理方式。

配置的属性:

driver – 这是 JDBC 驱动的 Java 类的完全限定名(并不是 JDBC 驱动中可能包含的数据源类)。

url – 这是数据库的 JDBC URL 地址。

username – 登录数据库的用户名。

password – 登录数据库的密码。

defaultTransactionIsolationLevel – 默认的连接事务隔离级别。

defaultNetworkTimeout – The default network timeout value in milliseconds to wait for the database operation to complete. See the API documentation of java.sql.Connection#setNetworkTimeout() for details.

<!--另外的配置-->
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 中查找。
mappers

<mappers>标签配置的是我们的映射器,也就是 Mapper.xml 的路径。这里配置的目的是让 MyBatis 在启动的时候去扫描这些映射器,创建映射关系。

<!-- 使用相对于类路径的资源引用(resource) -->
<mappers>
  <mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
  <mapper resource="org/mybatis/builder/BlogMapper.xml"/>
  <mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>
<!-- 使用完全限定资源定位符(绝对路径)(URL) -->
<mappers>
  <mapper url="file:///var/mappers/AuthorMapper.xml"/>
  <mapper url="file:///var/mappers/BlogMapper.xml"/>
  <mapper url="file:///var/mappers/PostMapper.xml"/>
</mappers>
<!-- 使用映射器接口实现类的完全限定类名 -->
<mappers>
  <mapper class="org.mybatis.builder.AuthorMapper"/>
  <mapper class="org.mybatis.builder.BlogMapper"/>
  <mapper class="org.mybatis.builder.PostMapper"/>
</mappers>
<!-- 将包内的映射器接口实现全部注册为映射器(最常用) -->
<mappers>
  <package name="org.mybatis.builder"/>
</mappers>

Mapper.xml映射配置文件

MyBatis 的真正强大在于它的映射语句。由于它的异常强大,映射器的 XML 文件就显得相对简单。如果拿它跟具有相同功能的 JDBC 代码进行对比,你会立即发现省掉了将近 95% 的代码。MyBatis 为聚焦于 SQL 而构建,以尽可能地为你减少麻烦。

映射器里面主要是配置了sql语句,解决了我们的参数映射和结果集映射的问题,主要有8个标签:
cache – 对给定命名空间的缓存配置。(是否开启二级缓存)

cache-ref – 对其他命名空间缓存配置的引用。

resultMap – 是最复杂也是最强大的元素,用来描述如何从数据库结果集中来加载对象。

<resultMap id="userResultMap" type="User">
  <id property="id" column="user_id" />
  <result property="username" column="user_name"/>
  <result property="password" column="hashed_password"/>
</resultMap>

sql – 可被其他语句引用的可重用语句块。

<sql id="someinclude">
  from
    <include refid="${include_target}"/>
</sql>

insert – 映射插入语句
update – 映射更新语句
delete – 映射删除语句
select – 映射查询语句

select

select 元素允许你配置很多属性来配置每条语句的作用细节。

属性  描述
id  在命名空间中唯一的标识符,可以被用来引用这条语句。

parameterType   将会传入这条语句的参数类的完全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过类型处理器(TypeHandler) 推断出具体传入语句的参数,默认值为未设置(unset)。

resultType  从这条语句中返回的期望类型的类的完全限定名或别名。 注意如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身。可以使用 resultType 或 resultMap,但不能同时使用。

resultMap   外部 resultMap 的命名引用。结果集的映射是 MyBatis 最强大的特性,如果你对其理解透彻,许多复杂映射的情形都能迎刃而解。可以使用 resultMap 或 resultType,但不能同时使用。

flushCache  将其设置为 true 后,只要语句被调用,都会导致本地缓存和二级缓存被清空,默认值:false。

useCache    将其设置为 true 后,将会导致本条语句的结果被二级缓存缓存起来,默认值:对 select 元素为 true。

timeout 这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为未设置(unset)(依赖驱动)。

fetchSize   这是一个给驱动的提示,尝试让驱动程序每次批量返回的结果行数和这个设置值相等。 默认值为未设置(unset)(依赖驱动)。

statementType   STATEMENT,PREPARED 或 CALLABLE 中的一个。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。

resultSetType   FORWARD_ONLY,SCROLL_SENSITIVE, SCROLL_INSENSITIVE 或 DEFAULT(等价于 unset) 中的一个,默认值为 unset (依赖驱动)。

databaseId  如果配置了数据库厂商标识(databaseIdProvider),MyBatis 会加载所有的不带 databaseId 或匹配当前 databaseId 的语句;如果带或者不带的语句都有,则不带的会被忽略。

resultOrdered   这个设置仅针对嵌套结果 select 语句适用:如果为 true,就是假设包含了嵌套结果集或是分组,这样的话当返回一个主结果行的时候,就不会发生有对前面结果集的引用的情况。 这就使得在获取嵌套的结果集的时候不至于导致内存不够用。默认值:false。

resultSets  这个设置仅对多结果集的情况适用。它将列出语句执行后返回的结果集并给每个结果集一个名称,名称是逗号分隔的。
insert, update 和 delete
<insert
  id="insertAuthor"
  parameterType="domain.blog.Author"
  flushCache="true"
  statementType="PREPARED"
  keyProperty=""
  keyColumn=""
  useGeneratedKeys=""
  timeout="20">

<update
  id="updateAuthor"
  parameterType="domain.blog.Author"
  flushCache="true"
  statementType="PREPARED"
  timeout="20">

<delete
  id="deleteAuthor"
  parameterType="domain.blog.Author"
  flushCache="true"
  statementType="PREPARED"
  timeout="20">

元素属性

id  命名空间中的唯一标识符,可被用来代表这条语句。

parameterType   将要传入语句的参数的完全限定类名或别名。这个属性是可选的,因为 MyBatis 可以通过类型处理器推断出具体传入语句的参数,默认值为未设置(unset)。

flushCache  将其设置为 true 后,只要语句被调用,都会导致本地缓存和二级缓存被清空,默认值:true(对于 insert、update 和 delete 语句)。

timeout 这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为未设置(unset)(依赖驱动)。

statementType   STATEMENT,PREPARED 或 CALLABLE 的一个。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。

useGeneratedKeys    (仅对 insert 和 update 有用)这会令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键(比如:像 MySQL 和 SQL Server 这样的关系数据库管理系统的自动递增字段),默认值:false。

keyProperty (仅对 insert 和 update 有用)唯一标记一个属性,MyBatis 会通过 getGeneratedKeys 的返回值或者通过 insert 语句的 selectKey 子元素设置它的键值,默认值:未设置(unset)。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。

keyColumn   (仅对 insert 和 update 有用)通过生成的键值设置表中的列名,这个设置仅在某些数据库(像 PostgreSQL)是必须的,当主键列不是表中的第一列的时候需要设置。如果希望使用多个生成的列,也可以设置为逗号分隔的属性名称列表。

databaseId  如果配置了数据库厂商标识(databaseIdProvider),MyBatis 会加载所有的不带 databaseId 或匹配当前 databaseId 的语句;如果带或者不带的语句都有,则不带的会被忽略。

示例:

<insert id="insertAuthor">
  insert into Author (id,username,password,email,bio)
  values (#{id},#{username},#{password},#{email},#{bio})
</insert>

<update id="updateAuthor">
  update Author set
    username = #{username},
    password = #{password},
    email = #{email},
    bio = #{bio}
  where id = #{id}
</update>

<delete id="deleteAuthor">
  delete from Author where id = #{id}
</delete>

selectKey

<insert id="insertAuthor" useGeneratedKeys="true"
    keyProperty="id">
  insert into Author (username,password,email,bio)
  values (#{username},#{password},#{email},#{bio})
</insert>

<insert id="insertAuthor" useGeneratedKeys="true"
    keyProperty="id">
  insert into Author (username, password, email, bio) values
  <foreach item="item" collection="list" separator=",">
    (#{item.username}, #{item.password}, #{item.email}, #{item.bio})
  </foreach>
</insert>

selectKey 元素中的语句将会首先运行,Author 的 id 会被设置,然后插入语句会被调用。这可以提供给你一个与数据库中自动生成主键类似的行为,同时保持了 Java 代码的简洁。

元素属性

keyProperty selectKey 语句结果应该被设置的目标属性。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。

keyColumn   匹配属性的返回结果集中的列名称。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。

resultType  结果的类型。MyBatis 通常可以推断出来,但是为了更加精确,写上也不会有什么问题。MyBatis 允许将任何简单类型用作主键的类型,包括字符串。如果希望作用于多个生成的列,则可以使用一个包含期望属性的 Object 或一个 Map。

order   这可以被设置为 BEFORE 或 AFTER。如果设置为 BEFORE,那么它会首先生成主键,设置 keyProperty 然后执行插入语句。如果设置为 AFTER,那么先执行插入语句,然后是 selectKey 中的语句 - 这和 Oracle 数据库的行为相似,在插入语句内部可能有嵌入索引调用。

statementType   与前面相同,MyBatis 支持 STATEMENT,PREPARED 和 CALLABLE 语句的映射类型,分别代表 PreparedStatement 和 CallableStatement 类型。
sql

用来定义可重用的 SQL 代码段,这些 SQL 代码可以被包含在其他语句中。它可以(在加载的时候)被静态地设置参数。 在不同的包含语句中可以设置不同的值到参数占位符上。

示例

<sql id="userColumns"> ${alias}.id,${alias}.username,${alias}.password </sql>

<!--SQL 片段可以被包含在其他语句中-->
<select id="selectUsers" resultType="map">
  select
    <include refid="userColumns"><property name="alias" value="t1"/></include>,
    <include refid="userColumns"><property name="alias" value="t2"/></include>
  from some_table t1
    cross join some_table t2
</select>

<!--属性值也可以被用在 include 元素的 refid 属性里或 include 元素的内部语句中-->
<sql id="sometable">
  ${prefix}Table
</sql>

<sql id="someinclude">
  from
    <include refid="${include_target}"/>
</sql>

<select id="select" resultType="map">
  select
    field1, field2, field3
  <include refid="someinclude">
    <property name="prefix" value="Some"/>
    <property name="include_target" value="sometable"/>
  </include>
</select>
resultMap(结果映射)

resultMap 元素是 MyBatis 中最重要最强大的元素。它可以让你从 90% 的 JDBC ResultSets 数据提取代码中解放出来,并在一些情形下允许你进行一些 JDBC 不支持的操作。实际上,在为一些比如连接的复杂语句编写映射代码的时候,一份 resultMap 能够代替实现同等功能的长达数千行的代码。ResultMap 的设计思想是,对于简单的语句根本不需要配置显式的结果映射,而对于复杂一点的语句只需要描述它们的关系就行了。

示例

<!--resultType-->
<select id="selectUsers" resultType="com.someapp.model.User">
  select id, username, hashedPassword
  from some_table
  where id = #{id}
</select>

<!-- mybatis-config.xml 中 -->
<typeAlias type="com.someapp.model.User" alias="User"/>

<!-- SQL 映射 XML 中 -->
<select id="selectUsers" resultType="User">
  select id, username, hashedPassword
  from some_table
  where id = #{id}
</select>


<!--resultMap-->
<resultMap id="userResultMap" type="User">
  <id property="id" column="user_id" />
  <result property="username" column="user_name"/>
  <result property="password" column="hashed_password"/>
</resultMap>

<select id="selectUsers" resultMap="userResultMap">
  select user_id, user_name, hashed_password
  from some_table
  where id = #{id}
</select>

元素

id  当前命名空间中的一个唯一标识,用于标识一个结果映射。

type    类的完全限定名, 或者一个类型别名(关于内置的类型别名,可以参考上面的表格)。

autoMapping 如果设置这个属性,MyBatis将会为本结果映射开启或者关闭自动映射。 这个属性会覆盖全局的属性 autoMappingBehavior。默认值:未设置(unset)。
id & result

这些是结果映射最基本的内容。id 和 result 元素都将一个列的值映射到一个简单数据类型(String, int, double, Date 等)的属性或字段。

这两者之间的唯一不同是,id 元素表示的结果将是对象的标识属性,这会在比较对象实例时用到。 这样可以提高整体的性能,尤其是进行缓存和嵌套结果映射(也就是连接映射)的时候。

<id property="id" column="post_id"/>
<result property="subject" column="post_subject"/>

property    映射到列结果的字段或属性。如果用来匹配的 JavaBean 存在给定名字的属性,那么它将会被使用。否则 MyBatis 将会寻找给定名称的字段。 无论是哪一种情形,你都可以使用通常的点式分隔形式进行复杂属性导航。 比如,你可以这样映射一些简单的东西:“username”,或者映射到一些复杂的东西上:“address.street.number”。

column  数据库中的列名,或者是列的别名。一般情况下,这和传递给 resultSet.getString(columnName) 方法的参数一样。

javaType    一个 Java 类的完全限定名,或一个类型别名(关于内置的类型别名,可以参考上面的表格)。 如果你映射到一个 JavaBean,MyBatis 通常可以推断类型。然而,如果你映射到的是 HashMap,那么你应该明确地指定 javaType 来保证行为与期望的相一致。

jdbcType    JDBC 类型, 只需要在可能执行插入、更新和删除的且允许空值的列上指定 JDBC 类型。这是 JDBC 的要求而非 MyBatis 的要求。如果你直接面向 JDBC 编程,你需要对可能存在空值的列指定这个类型。

typeHandler 我们在前面讨论过默认的类型处理器。使用这个属性,你可以覆盖默认的类型处理器。 这个属性值是一个类型处理器实现类的完全限定名,或者是类型别名。

更多配置详见

配置总结

配置名称 配置含义 配置简介
configuration 包裹所有配置标签 整个配置文件的顶级标签
properties 属性 该标签可以引入外部配置的属性,也可以自己配置。该配置标签所在的同一个配置文件的其他配置均可以引用此配置中的属性
setting 全局配置参数 用来配置一些改变运行时行为的信息,例如是否使用缓存机制,是否使用延迟加载,是否使用错误处理机制等。
typeAliases 类型别名 用来设置一些别名来代替 Java 的长类型声明(如 java.lang.int变为 int),减少配置编码的冗余
typeHandlers 类型处理器 将数据库获取的值以合适的方式转换为 Java 类型,或者将 Java类型的参数转换为数据库对应的类型
objectFactory 对象工厂 实例化目标类的工厂类配置
plugins 插件 可以通过插件修改 MyBatis 的核心行为,例如对语句执行的某一点进行拦截调用
environments 环境集合属性对象 数据库环境信息的集合。在一个配置文件中,可以有多种数据库环境集合,这样可以使 MyBatis 将 SQL 同时映射至多个数据库
environment 环境子属性对象 数据库环境配置的详细配置
transactionManager 事务管理 指定 MyBatis 的事务管理器
dataSource 数据源 使用其中的 type 指定数据源的连接类型,在标签对中可以使用property 属性指定数据库连接池的其他信息
mappers 映射器 配置 SQL 映射文件的位置,告知 MyBatis 去哪里加载 SQL 映射文件
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容