Mybatis基本用法–上

Mybatis基本用法–上

本文只是吧团结查漏补缺。系数的要看官方文档,扶助中英文
原理参考:http://blog.csdn.net/luanlouis/article/details/40422941

第一有的 基本概念

1.1 什么是MyBatis

  MyBatis 是援助定制化
SQL、存储过程及高档映射的优之持久层框架。MyBatis 避免了几乎所有的
JDBC 代码和手动设置参数与拿到结果集。MyBatis
可以对配备以及原生Map使用简便的 XML 或注明,将接口和 Java 的 POJOs(Plain
Old Java Objects,普通的 Java对象)映射成数据库中的记录。

1.2 经典安排

从 XML 中构建 SqlSessionFactory

  每个基于 MyBatis 的动都是盖一个 SqlSessionFactory 的实例为基本的。
而 SqlSessionFactory 本 身 是 由 SqlSessionFactoryBuilder
创设的,它好起 XML 配置,注脚或手动配置 Java 来创造SqlSessionFactory。可是当Mybatis与有依赖注入框架(如Spring或者Guice)同时使时,SqlSessions将受依注入框架所创,所以若切莫需用SqlSessionFactoryBuilder或者SqlSessionFactory

  从 XML 文件中构建 SqlSessionFactory
的实例相当简单,指出下类似路径下之资源文件举行安排。MyBatis 包含一个叫做
Resources 的工具类,它含有实用方法,可假若由 classpath
或另岗位加载资源文件越来越容易。

String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

首屈一指配置文件:

<?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>
  <environments default="development">
    <environment id="development">
      <transactionManager type="JDBC"/>
      <dataSource type="POOLED">
        <property name="driver" value="${driver}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
      </dataSource>
    </environment>
  </environments>
  <mappers>
    <mapper resource="org/mybatis/example/BlogMapper.xml"/>
  </mappers>
</configuration>

  要留意 XML 头部的表明,用来验证 XML 文档正确性。environment
元素体中蕴藏了事务管理和连接池的布置。mappers 元素则是含一组 mapper
映射器(这个 mapper 的 XML 文件包含了 SQL 代码和照耀定义音讯)

从 SqlSessionFactory 中获取 SqlSession

  既然生了 SqlSessionFactory ,顾名思义,我们不怕好从中得到 SqlSession
的实例了。SqlSession 完全含了面向数据库执行 SQL
命令所要的享有术。你可经过 SqlSession 实例来一向实施业已映射的 SQL
语句。

SqlSession session = sqlSessionFactory.openSession();

通过 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="org.mybatis.example.BlogMapper">
  <select id="selectBlog" resultType="Blog">
    select * from Blog where id = #{id}
  </select>
</mapper>

这就是说下点的SqlSession

try {
  Blog blog = (Blog) session.selectOne("org.mybatis.example.BlogMapper.selectBlog", 101);
} finally {
  session.close();
}

通过阐明定义

@Select({"select * from Blog where id=#{id}"})
Blog selectBlog(int id);

这就是说下方面的SqlSession

try {
  BlogMapper mapper = session.getMapper(BlogMapper.class);
  Blog blog = mapper.selectBlog(101);
} finally {
  session.close();
}

  可以观望:利用接口(基于申明),不但可推行还分明与类安全的代码,而且还未用担心易错的字符串字面值以及强制类型转换。
  其实可以组合使用,接口中:简单的形式以注明,复杂的方法应用xml配置。毕竟,对于简易语句来说,注脚使代码显得更为从简,但是Java 注脚对于有些复杂的口舌就碰面不能并且会展现更加混乱
  要求:

  1. mapper命名空间org.mybatis.example.BlogMapper应该本着应类路径,即接口应该以org.mybatis.example.BlogMapper类路径下;
  2. 富有同样的文本称,比如BlogMapper.java的布置也BlogMapper.xml(**
    看不清请Ctrl+鼠标滚轮拓宽页面 **);
  3. xml配置好放在resources对承诺目录下,且路径也为org.mybatis.example.BlogMapper。
      下边让有例子,但为NewsDAO的部署
    图片 1

  即下边的xml配置文件未更换,删去注脚@Select({"select * from Blog where id=#{id}"})

Blog selectBlog(int id);

1.3 效率域(Scope)和生命周期

对因注入框架Spring
  倚重注入框架可以创制线程安全之、基于事务的 SqlSession
和映射器(mapper)并以它们一向注入及您的 bean
中,由此可以平素忽略她的生命周期。假设对怎么通过依赖注入框架来运
MyBatis 感兴趣可以探究一下 MyBatis-Spring 或 MyBatis-Guice 两单子项目。

其他:

  SqlSessionFactoryBuilder:一旦创设了
SqlSessionFactory,就不再需要它了。因而 SqlSessionFactoryBuilder
实例的优良佳功能域是方功用域(也尽管是有的方法变量)。
  SqlSessionFactory:一旦让成立就应有当采纳的运作中一直有,由此SqlSessionFactory 的极致佳成效域是应用效率域
  SqlSession:每个线程都应该出她好之 SqlSession
实例。所以她的特级的效率域是告或情势效用域。每一次接到的 HTTP
请求,就足以打开一个
SqlSession,重临一个应,就关闭它。你当把这一个闭馆操作放到 finally
块中因保每一回都可以执行关闭。
  映射器实例(Mapper Instances):最好拿映射器放在方法功效域(method
scope)内。即下边的BlogMapper mapper = session.getMapper(BlogMapper.class);

次有些 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 resource="org/mybatis/example/config.properties">
        <property name="username" value="dev_user"/>
        <property name="password" value="F2Fa3!33TYyg"/>
    </properties>

    <settings>
        <setting name="cacheEnabled" value="true"/>
        ...
    </settings>

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

    <plugins>
        <plugin interceptor="org.mybatis.example.ExamplePlugin">
            <property name="someProperty" value="100"/>
        </plugin>
    </plugins>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC">
                <property name="..." value="..."/>
            </transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>

    <!-- 数据库提供厂家 -->
    <databaseIdProvider type="DB_VENDOR">
        <property name="SQL Server" value="sqlserver"/>
        <property name="DB2" value="db2"/>
        <property name="Oracle" value="oracle" />
    </databaseIdProvider>

    <mappers>
        <mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
        ...
    </mappers>
</configuration>

2.1 properties 属性

  这一个性都是只是外部配置都可动态替换的,既可在一级的 Java
属性文件中配备,亦可通过 properties 元素的子元从来传递。例如:

<properties resource="org/mybatis/example/config.properties">
  <property name="username" value="dev_user"/>
  <property name="password" value="F2Fa3!33TYyg"/>
</properties>

  其中的习性就得于周配置文件被使来替换需要动态配置的属性值。比如:

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

  那些事例中之 username 和 password 将会面由 properties
元素中安装的相应值来替换。 driver 和 url 属性将会合由于 config.properties
文件中对应的价来替换。

2.2 settings 设置

设置参数 描述 有效值 默认值
cacheEnabled 所有映射器中配置的缓存全局开关。 true | false true
lazyLoadingEnabled 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 true |false false
aggressiveLazyLoading 开启时,任何方法的调用都会加载该对象的所有属性,否则每个属性会按需加载. true | false false (true in ≤3.4.1)
multipleResultSetsEnabled 对于未知的SQL查询,允许单一语句返回不同的结果集以达到通用的效果。 true | false true
useColumnLabel 允许使用列标签代替列名 true | false true
useGeneratedKeys (仅对 insert 和 update 有用)这会令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键(比如:像 MySQL 和 SQL Server 这样的关系数据库管理系统的自动递增字段) true | false false
autoMappingBehavior 指定 MyBatis 应如何自动映射列到字段或属性。 NONE 表示取消自动映射;PARTIAL 只会自动映射没有定义嵌套结果集映射的结果集。 FULL 会自动映射任意复杂的结果集(无论是否嵌套)。 NONE, PARTIAL, FULL PARTIAL
defaultExecutorType 配置默认的执行器。SIMPLE 就是普通的执行器;REUSE 执行器会重复用预处理语句(prepared statements); BATCH 执行器将重复用语句(即多次执行以批量操作)并执行批量更新。 SIMPLE,REUSE,BATCH SIMPLE
defaultStatementTimeout 设置超时时间,它决定驱动等待数据库响应的秒数。 任意正整数 Not Set (null)
mapUnderscoreToCamelCase 是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN 到经典 Java 属性名 aColumn 的类似映射。 true|false false
callSettersOnNulls 指定当结果集中值为 null 的时候是否调用映射对象的 setter(map 对象时为 put)方法,这对于有 Map.keySet() 依赖或 null 值初始化的时候是有用的。注意基本类型(int、boolean等)是不能设置成 null 的。 true | false false
logImpl 指定 MyBatis 所用日志的具体实现,未指定时将自动查找。 SLF4J,LOG4J,LOG4J2,JDK_LOGGING,COMMONS_LOGGING,STDOUT_LOGGING,NO_LOGGING Not set

  延期加载:延迟加载(lazy
load)是(也号称懒加载)Hibernate3关联关系对象默认的加载模式,所谓延迟加载就是当调用load方法加载对象时,重返代理对象,等到真正用到对象的情节日常才出sql语句,这些目标及之所有属性都是默认值。
发生如下程序代码:

User user=(User)session.load(class, id);//直接返回的是代理对象
System.out.println(user.getId());//没有发送sql语句到数据库加载,因为id不用查就知道
user.getName();//创建真实的User实例,并发送sql语句到数据库中

2.3 typeAliases 类型别名

  类型别名是吗 Java 类型设置一个差的名字。它只有与 XML
配置有关,存在的意义就在于用来裁减类似完全限定名的冗余。例如:

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

  当这样安排时,Blog可以据此当其余利用domain.blog.Blog的地点。
  当然也得用阐明指定,看下的例证:

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

2.4 typeHandlers 类型处理器

  无论是 MyBatis
在先期处理语句(PreparedStatement)中设置一个参数时,如故打结果集中取出一个值时,
都会师由此型处理器将收获之价为适宜的措施易成为 Java 类型。
  要注意 MyBatis
不会师窥探数据库处女信息来决定采取啊系列型,所以若必在参数与结果映射中指明这是哪个种类档次的字段,
以要其可以绑定到正确的档次处理器上。 那是以:MyBatis
直到讲话为实践才清楚数据类型。可以以此间设定:

<typeHandlers>
  <typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler" javaType="java.math.RoundingMode"/>
</typeHandlers>

啊可以当映射器文件被设定:

<mapper namespace="org.apache.ibatis.submitted.rounding.Mapper">
    <resultMap type="org.apache.ibatis.submitted.rounding.User" id="usermap">
        <id column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="funkyNumber" property="funkyNumber"/>
        <result column="roundingMode" property="roundingMode typeHandler="org.apache.ibatis.type.EnumTypeHandler""/>
    </resultMap>

    <select id="getUser" resultMap="usermap">
        select * from users
    </select>
    <insert id="insert">
        insert into users (id, name, funkyNumber, roundingMode) values (
            #{id}, #{name}, #{funkyNumber}, #{roundingMode, typeHandler=org.apache.ibatis.type.EnumTypeHandler}
        )
    </insert>
</mapper>

2.5 plugins 插件

  MyBatis
允许而于曾经映射语句执行进程中的某部平等沾开展拦阻调用。默认状况下,MyBatis
允许用插件来阻拦的点子调用包括:

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

  那些类似中艺术的底细可以经过查看每个方法的签署来发现,或者直接翻
MyBatis 的批发包中的源代码。
假一经你想做的不仅仅是监督措施的调用,那么你应当好好之刺探在重写的办法的表现。
因为假如在试图修改或者再写就起主意的所作所为之时光,你非凡可能于破坏 MyBatis
的要旨模块。 这一个都是重新低层的近乎和道,所以拔取插件的时段要专门警惕。

  通过 MyBatis 提供的强硬机制,使用插件是相当简单的,只需要兑现
Interceptor 接口,并指定了回想只要堵住的法子签名即可。

// ExamplePlugin.java
  @Intercepts({@Signature(
  type= Executor.class,
  method = "update",
  args = {MappedStatement.class,Object.class})})
  public class ExamplePlugin implements Interceptor {
    public Object intercept(Invocation invocation) throws Throwable {
      return invocation.proceed();
    }
    public Object plugin(Object target) {
      return Plugin.wrap(target, this);
    }
    public void setProperties(Properties properties) {
    }
  }

<!-- mybatis-config.xml -->
<plugins>
  <plugin interceptor="org.mybatis.example.ExamplePlugin">
    <property name="someProperty" value="100"/>
  </plugin>
</plugins>

  下面的插件将相会堵住在 Executor 实例中享有的 “update” 方法调用,
这里的 Executor 是承受执行低层映射语词的里边对象。

2.6 environments 环境

  没必要配置 ,Spring +
MyBatis完全可拿不同环境的安排放到application-dev.yml,application-prod.yml,application.yml等配置文件中包括dataSource
数据源的配备

图片 2

2.7 dataSource 数据源

  发出三栽内建的数源类型(也便是
type=”[UNPOOLED|POOLED|JNDI]”):

UNPOOLED
  这些数据源的贯彻只是每一趟吃呼吁时打开和关闭连接。即便发生少数迟迟,它对以即时可用连接方面没性能要求的简要应用程序是一个大好之选用。UNPOOLED
类型的数据源仅仅需要配置以下 5 种属性:

属性 描述
driver 这是 JDBC 驱动的 Java 类的完全限定名。
url 这是数据库的 JDBC URL 地址。
username 登录数据库的用户名。
password 登录数据库的密码。
defaultTransactionIsolationLevel 默认的连接事务隔离级别。
driver.encoding UTF8(可选项)

POOLED
  这种数据源的兑现以“池”的定义将 JDBC
连接对象协会起,避了成立新的连日实例时所不可或缺的起先化和表达时间
使得并发 Web 应用可快响应请求。

  除了上述提到 UNPOOLED 下的性质外,会时有暴发还多属性用来布局 POOLED
的数据源:

属性 描述
poolMaximumActiveConnections 在任意时间可以同时使用的最大连接数量,默认值:10
poolMaximumIdleConnections 任意时间可能存在的空闲连接数,经验值建议设置与poolMaximumActiveConnections相同即可
poolMaximumCheckoutTime 获取链接时如果没有idleConnection同时activeConnection达到最大值,则从activeConnections列表第一个链接开始(即最先开始的链接,也最可能快速结束),检查是否超过该设置的时间,如果超过,则被强制失效,返回链接。默认值为20000毫秒(即 20 秒),建议设置在预期最大的SQL执行时间。
poolTimeToWait 这是一个底层设置,如果获取连接花费相当长的时间,它会给连接池打印状态日志并重新尝试获取一个连接(避免在误配置的情况下一直安静的失败),默认值:20000 毫秒(即 20 秒)。
poolPingQuery 发送到数据库的侦测查询,用来检验连接是否处在正常工作秩序中并准备接受请求。默认是“NO PING QUERY SET”,建议使用select 1,开销小
poolPingEnabled 是否启用侦测查询。若开启,也必须使用一个可执行的 SQL 语句设置 poolPingQuery 属性(最好是一个非常快的 SQL),默认值:false,建议启用,防止服务器端异常关闭,导致客户端错误。
poolPingConnectionsNotUsedFor 用来配置poolPingQuery多长时间被调用一次。可以被设置匹配标准的数据库链接超时时间,来避免不必要的侦测。默认值0(也就是所有链接每一时刻都被侦测到,但仅仅当poolPingEnabled为true时适用)。建议小于服务器端超时时间,MySQL默认超时是8小时。

JNDI
  这么些数据源是为了采用要Spring或应用服务器这仿佛的器皿,容器可以集中或当外部配置数据源,然后设置JNDI上下文的援。
斯数据源只待配置有限独特性:

属性 描述
initial_context 这个属性用来在 InitialContext 中寻找上下文(即,initialContext.lookup(initial_context))。这是个可选属性,如果忽略,那么 data_source 属性将会直接从 InitialContext 中寻找。
data_source 这是引用数据源实例位置的上下文的路径。提供了 initial_context 配置时会在其返回的上下文中进行查找,没有提供时则直接在 InitialContext 中查找。

  和此外数据源配置类似,可以透过长前缀“env.”直接拿性能传递让起上下文。比如:
env.encoding=UTF8

2.8 mappers 映射器

  告诉 MyBatis 到哪儿去找映射文件。
比如:

<mappers>
  <!-- Using classpath relative resources -->
  <mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
  <!-- Using url fully qualified paths -->
  <mapper class="org.mybatis.builder.AuthorMapper"/>
  <!-- Register all interfaces in a package as mappers -->
  <package name="org.mybatis.builder"/>
</mappers>

老三片段 Mapper XML 文件

3.1 SQL 映射文件的头等元素

cache – 给定命名空间的缓存配置。
cache-ref – 其他命名空间缓存配置的引用。
resultMap – 是最复杂也是最强大的元素,用来描述如何从数据库结果集中来加载对象。
sql – 可被其他语句引用的可重用语句块。
insert – 映射插入语句
update – 映射更新语句
delete – 映射删除语句
select – 映射查询语句

  下面分别介绍:

3.2 select

  比如一个简单易行的Mapper 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="com.nowcoder.dao.NewsDAO">
    <sql id="table">news</sql>
    <sql id="selectFields">id,title, link, image, like_count, comment_count,created_date,user_id
    </sql>
    <select id="selectByUserIdAndOffset" resultType="com.nowcoder.model.News">
        SELECT
        <include refid="selectFields"/>
        FROM
        <include refid="table"/>

        <if test="userId != 0">
            WHERE user_id = #{userId}
        </if>
        ORDER BY id DESC
        LIMIT #{offset},#{limit}
    </select>
</mapper>

  这得过多独立的 JDBC
的代码来提取结果并以它映射到对象实例中,这便是 MyBatis
节省你时之地点。

select元素属性

<select
  id="selectPerson"
  parameterType="int"
  resultType="hashmap"
  resultMap="personResultMap"
  flushCache="false"
  useCache="true"
  timeout="10000"
  fetchSize="256"
  statementType="PREPARED"
  resultSetType="FORWARD_ONLY">
属性 描述
id 在命名空间中唯一的标识符,可以被用来引用这条语句。
parameterType 传入这条语句的参数类的完全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过 TypeHandler 推断出具体传入语句的参数,默认值为 unset。
resultType 返回的期望类型的类的完全限定名或别名。注意如果是集合情形,那应该是集合可以包含的类型,而不能是集合本身。使用 resultType 或 resultMap,但不能同时使用。
resultMap 外部 resultMap 的命名引用。结果集的映射是 MyBatis 最强大的特性,对其有一个很好的理解的话,许多复杂映射的情形都能迎刃而解。
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 中的一个,默认值为 unset (依赖驱动)。
databaseId 如果配置了 databaseIdProvider,MyBatis 会加载所有的不带 databaseId 或匹配当前 databaseId 的语句;如果带或者不带的语句都有,则不带的会被忽略。
resultSets 这个设置仅对多结果集的情况适用,它将列出语句执行后返回的结果集并每个结果集给一个名称,名称是逗号分隔的。

resultSetType

FORWORD_ONLY 结果集的游标只好往下滚动。
SCROLL_INSENSITIVE
结果集的游标能够上下移动,当数据库变化时,当前结果集不变换。
SCROLL_SENSITIVE
再次来到可滚动的结果集,当数据库变化时,当前结果集一起转移。

3.3 insert, update 和 delete

Insert, Update, Delete ‘s Attributes

属性 描述
id 同select
parameterType 同select
flushCache 同select,默认值:true(对应插入、更新和删除语句)。
timeout 同select
statementType 同select,默认值:PREPARED。
useGeneratedKeys (仅对 insert 和 update 有用)这会令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键(比如:像 MySQL 和 SQL Server 这样的关系数据库管理系统的自动递增字段),默认值:false。
keyProperty (仅对 insert 和 update 有用)唯一标记一个属性,MyBatis 会通过 getGeneratedKeys 的返回值或者通过 insert 语句的 selectKey 子元素设置它的键值,默认:unset。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。
keyColumn (仅对 insert 和 update 有用)通过生成的键值设置表中的列名,这个设置仅在某些数据库(像 PostgreSQL)是必须的,当主键列不是表中的第一列的时候需要设置。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。
databaseId 同select

例如:

<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>

  假如 id 使用了自动生成的列类型:

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

  倘使您的数据库尚补助多行插入,
你呢得以传一个Authors数组或集合,并再次来到自动生成的主键。

<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>

3.4 sql

  这么些因素得以让用来定义可采取的 SQL
代码段,可以蕴涵在其余语句中。比如:

<sql id="userColumns"> ${alias}.id,${alias}.username,${alias}.password </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
    inner join some_table t2
</select>

3.5 参数(Parameters)

  这不是一个五星级元素,但非凡重点。
  默认情形下,使用#{}格式的语法会导致 MyBatis
成立预处理语句属性并安全地设置值(比如?)。这样做还安全,更敏捷,平日也是首选做法。
比如:

<insert id="insertUser" parameterType="User">
  insert into users (id, username, password)
  values (#{id}, #{username}, #{password})
</insert>

  假若 User 类型的参数对象传递到了晓句被,id、username 和 password
属性将会师为摸,然后将它的价值传入预处理语句的参数中。你呢得以

#{age,javaType=int,jdbcType=NUMERIC,typeHandler=MyTypeHandler}

  但其实你一味待简单指定属性名,其他的政工 MyBatis
会自己失去臆想,最多而待也可能为空的列名指定 jdbcType。

#{firstName}
#{middleInitial,jdbcType=VARCHAR}

字符串替换
  可是有时你只是思念一直当 SQL 语句被插一个无改变的字符串。比如,像
ORDER BY,你能够这样来用:

ORDER BY ${columnName}

  这里 MyBatis 不会晤修改或者转义字符串。
  **注意:这种办法是勿安全之,会招私的 SQL
注入攻击,由此要不允用户输入这么些字段,要么自行转义并检查(即将输入被之特殊字符转义处理,比如”&”→
“&”, “<“→”<“,” “→”  “。

3.6 Result Maps

  resultMap 元素是 MyBatis 中最关键最强大的要素。它就是吃你远离
90%底得打结果 集中取出数据的 JDBC 代码的杀东西。 ResultMap
的宏图虽简语句不需精晓的结果映射,而多繁杂语句只待描述其的关系。
  当应用程序使用 JavaBeans 或 POJOs(Plain Old Java Objects,普通 Java
对象)来作世界模型,大部分足概括 resultMap,MyBatis
会在骨子里自动创制一个 ResultMap,基于性名来映射列到 JavaBean
的性上。
  要铭记类型别名是您的同伙。使用其而得无用输入类的全路径。

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

<!-- In SQL Mapping XML file -->
<select id="selectUsers" resultType="User">
  select id, username, hashedPassword
  from some_table
  where id = #{id}
</select>

解决列名不般配的有限种办法

第一种:

<select id="selectUsers" resultType="User">
  select
    user_id             as "id",
    user_name           as "userName",
    hashed_password     as "hashedPassword"
  from some_table
  where id = #{id}
</select>

第二种:

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

  引用它的说话以 resultMap 属性就尽了(注意大家错过丢了 resultType
属性)。比如:

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

ResultMap Attributes

属性 描述
id 当前命名空间中的一个唯一标识,用于标识一个result map.
type 类的全限定名, 或者一个类型别名
autoMapping 如果设置这个属性,MyBatis将会为这个ResultMap开启或者关闭自动映射。这个属性会覆盖全局的属性autoMappingBehavior。默认值为:unset。

id & result

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

  那么些是结果映射最主旨内容。id 和 result
都映射一个单身列的价到概括数据类型(字符
串,整型,双精度浮点数,日期等)的单独属性或字段。

  唯一不同是 id
表示的结果用凡当于对象实例时用到的标识性,类似于主键。这拉来改进全部表现,特别是缓存和搭结果映射(也即是一头映射)

Id and Result Attributes

属性 描述
property 映射到列结果的字段或属性。比如,你可以这样映射一些东西: “username” ,或者映射到一些复杂的东西: “address.street.number” 。
column 从数据库中得到的列名,或者是列名的重命名标签。
javaType 一个 Java 类的完全限定名,或一个类型别名。如果你映射到一个JavaBean,MyBatis 通常可以断定类型。然而,如果你映射到的是 HashMap,那么你应该明确地指定 javaType 来保证所需的行为。
jdbcType JDBC 类型仅仅需要对插入,更新和删除操作可能为空的列进行设置
typeHandler 使用这个属性,你可以覆盖默认的类型处理器。这个属性值是类的完全限定名或者是一个类型处理器的实现,或者是类型别名。

3.7 Result Maps高级用法

1.率先,我们先行瞧一个周边的博客页面的构成,如下:
  a.页面上可以显示的片段:正文,标题,日期,作者,评论正文,评论时,评论人等等
  b.页面之外的组成部分:用户称,用户id,用户密码,用户大旨音信(电话,邮箱,地址,兴趣,特长,等等)
2.用大家页面上的音信于数据库中查出来的SQL语句转化为Mapper文件中之语,可能是之类内容:

<!-- Very Complex Statement -->
<select id="selectBlogDetails" resultMap="detailedBlogResultMap">
  select
       B.id as blog_id,
       B.title as blog_title,
       B.author_id as blog_author_id,
       A.id as author_id,
       A.username as author_username,
       A.password as author_password,
       A.email as author_email,
       A.bio as author_bio,
       A.favourite_section as author_favourite_section,
       P.id as post_id,
       P.blog_id as post_blog_id,
       P.author_id as post_author_id,
       P.created_on as post_created_on,
       P.section as post_section,
       P.subject as post_subject,
       P.draft as draft,
       P.body as post_body,
       C.id as comment_id,
       C.post_id as comment_post_id,
       C.name as comment_name,
       C.comment as comment_text,
       T.id as tag_id,
       T.name as tag_name
  from Blog B
       left outer join Author A on B.author_id = A.id
       left outer join Post P on B.id = P.blog_id
       left outer join Comment C on P.id = C.post_id
       left outer join Post_Tag PT on PT.post_id = P.id
       left outer join Tag T on PT.tag_id = T.id
  where B.id = #{id}
</select>

该针对性诺在万分复杂的结果集合,Mapper文件可能增长之样子,(注意当我们于select语句被使B.title as blog_title,在resultMap的<result property="title" column="blog_title"/>
能够免使,系统会自动映射生成<result property="title" column="blog_title"/>,不过加上再度清楚,也无会见加系统负责)如下:

<!-- Very Complex Result Map -->  
<resultMap id="detailedBlogResultMap" type="Blog">  
  <constructor>  
    <idArg column="blog_id" javaType="int"/>  
  </constructor>  
  <result property="title" column="blog_title"/>  
  <association property="author" javaType="Author">  
    <id property="id" column="author_id"/>  
    <result property="username" column="author_username"/>  
    <result property="password" column="author_password"/>  
    <result property="email" column="author_email"/>  
    <result property="bio" column="author_bio"/>  
    <result property="favouriteSection" column="author_favourite_section"/>  
  </association>  
  <collection property="posts" ofType="Post">  
    <id property="id" column="post_id"/>  
    <result property="subject" column="post_subject"/> 
    <!-- 由于自动映射等级为:PARTIAL,自动的映射author_id;同时注意上面对Author类已经映射过了, -->  
    <association property="author" javaType="Author"/>  
    <collection property="comments" ofType="Comment">  
      <id property="id" column="comment_id"/>  
    </collection>  
    <collection property="tags" ofType="Tag" >  
      <id property="id" column="tag_id"/>  
    </collection>  
    <discriminator javaType="int" column="draft">  
      <case value="1" resultType="DraftPost"/>  
    </discriminator>  
  </collection>  
</resultMap>  

  注意点是以Blog为主题,来索对应的作者,对应的章,对应之评说和标签。下边,起初详细表明每一个素,请读者必定论单元测试的措施推动,千万不要一遍性安排大量属性,以免影响上兴趣。

3.7.1 构造方法

<constructor>  
   <idArg column="id" javaType="int"/>  
   <arg column="username" javaType="String"/> 
   <arg column="age" javaType="_int"/> 
</constructor>  

  即使对绝大多数底数额传对象(DTO)对象,以及我们的domain模型,属性值都是会打至相应的意,但是,在某些情况下而我辈怀念接纳部分稳定的近乎。比如:表格中概括有单纯供浏览的数目要很少改变之数码。Mybatis的构造函数注入力量允许我们在类初步化时便装某些价值,而休露内的public方法。
例如,程序中咱们是这么一个实体类,如下:

public class User {
   //...
   public User(Integer id, String username, int age) {
     //...
  }
//...
}

  于Mybatis中,为了为这构造方法中流入结果,Mybatis需要经其的参数来代表构造方法。java中,没有反射参数名称的计,因而,当创设一个构造方法的要素时,必须管参数是准顺序排列的,而且,数据类型也必须配合!

3.7.2 关联

<association property="author" column="blog_author_id" javaType="Author">
  <id property="id" column="author_id"/>
  <result property="username" column="author_username"/>
</association>

  关联元素用来处理数据模型中之“has-one”关系。比如一个博客账号只可以属于一个用户。关联映射大部分凡冲这种以场景。关联中不同的凡若要告诉
MyBatis 如何加载关联。MyBatis 于这面会发生少栽不同之法:

  • 嵌套查询:通过履行其余一个 SQL 映射语句来回到预期的错综复杂类型。
  • 嵌套结果:使用嵌套结果映射来拍卖又的同步结果的子集。

关系的嵌套查询:即分别执行sql语句,一个sql语句之实施因让另外一长达告词的结果,比如:

<resultMap id="blogResult" type="Blog">
  <association property="author" column="author_id" javaType="Author" select="selectAuthor"/>
</resultMap>

<select id="selectBlog" resultMap="blogResult">
  SELECT * FROM BLOG WHERE ID = #{id}
</select>

<select id="selectAuthor" resultType="Author">
  SELECT * FROM AUTHOR WHERE ID = #{id}
</select>

  大家发出星星点点个查询语句:一个来加载博客,其它一个来加载作者,而且博客的结果映射描
述了“selectAuthor”语句子应该让用来加载它的 author
属性。其他有的属性将会师吃自动加载,假诺它们的排列和总体性名相匹配。
  这种办法要命简单, 不过对于大型数据集合和列表将无会面彰显不行好。
问题不怕是我们熟练的 “N+1
查询问题”。比如大家要得到4只作者对应的博客列表,遵照嵌套查询的措施:

select * from BLOG; 
select * from BLOG where Author_ID=1;
select * from BLOG where Author_ID=2;
select * from BLOG where Author_ID=3;
select * from BLOG where Author_ID=4;

  select告诉句之数额最为多,需要数的走访数据库,会潜移默化检索性能。如若用查询n个作者,那么要尽n+1不良select查询语句。那虽是藏的n+1不善select查询问题。
那种检索策略没有以SQL的连续查询效用,例如以上5漫漫select语句完全可以由此以下1条select语句来完成:

select * from BLOG left outer join Author on BLOG.Author_ID=AUTHOR.Author_ID 

关系的嵌套结果
采纳嵌套结果来一同查询,比如左连接,右连接,内连续等。比如:

<select id="selectBlog" resultMap="blogResult">
  select
    B.id            as blog_id,
    B.title         as blog_title,
    B.author_id     as blog_author_id,
    A.id            as author_id,
    A.username      as author_username,
    A.password      as author_password,
    A.email         as author_email,
    A.bio           as author_bio
  from Blog B left outer join Author A on B.author_id = A.id
  where B.id = #{id}
</select>

<resultMap id="blogResult" type="Blog">
  <id property="id" column="blog_id" />
  <result property="title" column="blog_title"/>
  <association property="author" column="blog_author_id" javaType="Author" resultMap="authorResult"/>
</resultMap>

<resultMap id="authorResult" type="Author">
  <id property="id" column="author_id"/>
  <result property="username" column="author_username"/>
  <result property="password" column="author_password"/>
  <result property="email" column="author_email"/>
  <result property="bio" column="author_bio"/>
</resultMap>

  万分首要:
id元素在嵌套结果映射中饰演着挺紧要之角色。你应有总是指定一个要多独好唯一标识结果的习性。实际上要你无点名它吧,
MyBatis仍旧可干活,不过会时有暴发严重的性能问题。在可唯一标识结果的景色下,
尽可能少的接纳属性。主键是一个显明的抉择(尽管是复合主键)。
  现在,下面的以身作则用了表的结果映射元从来映射关联。这令 Author
结果映射可以拔取。然则,如若你免需要选定它的言语。你可以嵌套结果映射:

<resultMap id="blogResult" type="Blog">
  <id property="id" column="blog_id" />
  <result property="title" column="blog_title"/>
  <association property="author" javaType="Author">
    <id property="id" column="author_id"/>
    <result property="username" column="author_username"/>
    <result property="password" column="author_password"/>
    <result property="email" column="author_email"/>
    <result property="bio" column="author_bio"/>
  </association>
</resultMap>

  倘若blog有一个co-author怎么惩罚? select语句以关押起是法:

<select id="selectBlog" resultMap="blogResult">
  select
    B.id            as blog_id,
    B.title         as blog_title,
    A.id            as author_id,
    A.username      as author_username,
    A.password      as author_password,
    A.email         as author_email,
    A.bio           as author_bio,
    CA.id           as co_author_id,
    CA.username     as co_author_username,
    CA.password     as co_author_password,
    CA.email        as co_author_email,
    CA.bio          as co_author_bio
  from Blog B
  left outer join Author A on B.author_id = A.id
  left outer join Author CA on B.co_author_id = CA.id
  where B.id = #{id}
</select>

  再一次调用Author的resultMap将定义如下:

<resultMap id="authorResult" type="Author">
  <id property="id" column="author_id"/>
  <result property="username" column="author_username"/>
  <result property="password" column="author_password"/>
  <result property="email" column="author_email"/>
  <result property="bio" column="author_bio"/>
</resultMap>

  当连接多表时,你以只可以动用列别名来避免ResultSet中的重列名。指定columnPrefix允许而照列名到一个标的结果集中。你需要指定columnPrefix去用映射resultMap。

<resultMap id="blogResult" type="Blog">
  <id property="id" column="blog_id" />
  <result property="title" column="blog_title"/>
  <association property="author"
    resultMap="authorResult" />
  <association property="coAuthor"
    resultMap="authorResult"
    columnPrefix="co_" />
</resultMap>

  下边就见到了如何处理“has-one”类型涉及。可是“has-many”是哪的,比如一个作者就出一个博客账号,可是却爆发多首作品?下边这片就是来谈谈是大旨的。

3.7.3 集合

<collection property="posts" ofType="domain.blog.Post">
  <id property="id" column="post_id"/>
  <result property="subject" column="post_subject"/>
  <result property="body" column="post_body"/>
</collection>

  一个作者有多稿子,那么结果回到的接口写法如下:

private List<Post> posts;

  集合也爆发嵌套查询及嵌套结果,大家了解后者:

<select id="selectBlog" resultMap="blogResult">
  select
  B.id as blog_id,
  B.title as blog_title,
  B.author_id as blog_author_id,
  P.id as post_id,
  P.subject as post_subject,
  P.body as post_body,
  from Blog B
  left outer join Post P on B.id = P.blog_id
  where B.id = #{id}
</select>

咱一齐了博客表和著作申明,每个博客账号发差不多首随笔,和association相比唯一不同点在ofType="Post":

<resultMap id="blogResult" type="Blog">
  <id property="id" column="blog_id" />
  <result property="title" column="blog_title"/>
  <collection property="posts" ofType="Post">
    <id property="id" column="post_id"/>
    <result property="subject" column="post_subject"/>
    <result property="body" column="post_body"/>
  </collection>
</resultMap>

脚的写法方便用:

<resultMap id="blogResult" type="Blog">
  <id property="id" column="blog_id" />
  <result property="title" column="blog_title"/>
  <collection property="posts" ofType="Post" resultMap="blogPostResult" columnPrefix="post_"/>
</resultMap>

<resultMap id="blogPostResult" type="Post">
  <id property="id" column="id"/>
  <result property="subject" column="subject"/>
  <result property="body" column="body"/>
</resultMap>

3.7.4 鉴别器

<resultMap id="vehicleResult" type="Vehicle">
  <id property="id" column="id" />
  <result property="vin" column="vin"/>
  <result property="year" column="year"/>
  <result property="make" column="make"/>
  <result property="model" column="model"/>
  <result property="color" column="color"/>
  <discriminator javaType="int" column="vehicle_type">
    <case value="1" resultType="carResult">
      <result property="doorCount" column="door_count" />
    </case>
    <case value="2" resultType="truckResult">
      <result property="boxSize" column="box_size" />
      <result property="extendedCab" column="extended_cab" />
    </case>
    <case value="3" resultType="vanResult">
      <result property="powerSlidingDoor" column="power_sliding_door" />
    </case>
    <case value="4" resultType="suvResult">
      <result property="allWheelDrive" column="all_wheel_drive" />
    </case>
  </discriminator>
</resultMap>

  有时一个独自的数据库查询也许回很多见仁见智 (不过希望多少关系)
数据类型的结果集。鉴别器元素就是是被设计来拍卖是情的,
还有包括类的存续层次结构。 鉴别器相当容易理 解,因为它的显现相当像 Java
语言中的 switch 语词。

3.7.5 自动映射

  以简短的情景下,MyBatis可以给而活动映射查询结果。
倘使遇上复杂的场地,你要构建一个result
map。当自动映射查询结果平时,MyBatis会获取sql重返的列名并于java类中寻觅相同名字的特性(忽略大小写)。
那意味如若Mybatis发现了ID列和id属性,Mybatis会将ID的值赋给id。
  日常数据库列使用大写单词命名,单词里用生划线分隔;而java属性一般照驼峰命名法。
为了当及时简单栽命名模式中启用自动映射,需要以
mapUnderscoreToCamelCase设置也true。
  自动映射的效率吗会在非常的resultMap下继续做事。在这种状态下,对于各级一个结出映射的集结,所有出现于结果集当中的排列,假若没有给手动的安装映射,那么它们都晤面被自动的照射。
在连片下的例子中, id 和 userName列将于机关映射, hashed_password
列将按照配置映射。

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

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

发二种植电动映射等级

NONE – 禁用电动映射。仅装手动映射属性。
PARTIAL –
会自动的映射结果,除了那一个定义在里面的都存在嵌套的照耀(默认)
FULL – 自动映射所有(但当不同表有相同之列名时好出错,别用)。
因此添加autoMapping属性可以忽略自动映射等级配置,你得启用或剥夺自动映射指定的ResultMap。

<resultMap id="userResultMap" type="User" autoMapping="false">
  <result property="password" column="hashed_password"/>
</resultMap>

3.8 缓存

  mybaits提供一流缓存,和二级缓存。
图片 3
  一流缓存是SqlSession级此外休息存。在操作数据库时欲社团sqlSession对象,在对象吃有一个(内存区域)数据结构(HashMap)用于存储缓存数据。不同之sqlSession之间的缓存数据区域(HashMap)是并行不影响之。在同一个sqlSession中有数蹩脚举行同样的sql语句,第一涂鸦执行了会以数据库被查询的数额勾勒及缓存(内存),第二不成会师由缓存中获取数据将不再由数据库查询,从而增强查询功用。当一个sqlSession截至后该sqlSession中之一流缓存也就是非有了。Mybatis默认开启一流缓存。但要打开了二级缓存,那么当关sqlsession后,会拿该sqlsession顶尖缓存中之数量增长到namespace的二级缓存中。
  对sqlsession执行commit操作,也便象征用户执行了update、delete等操作,那么数据库中之数据势必会发生变化,假使用户要数据还以在此之前内存中的数量,那么以读到污染数据。所以于履行sqlsession操作后,会消除保存数据的HashMap,用户以提倡查询请求时即使会晤还读取数据并放入一流缓存中了。
怎被二级缓存:

1、 在mybatis总配置文件中加入一行设置
<settings>
   <!--开启二级缓存-->
    <setting name="cacheEnabled" value="true"/>
</settings>

2、在需要开启二级缓存的mapper.xml中加入caceh标签
<cache/>

  二级缓存是mapper级其它缓存,按namespace分,假设namespace相同则运用和一个相同之二级缓存区,两只SqlSession去操作数据库得到数码会存在二级缓存区域。注意:即便被了二级缓存,不同之sqlsession之间的缓存数据也不是怀恋互访就能互访的,必须顶及sqlsession关闭了后来,才谋面拿该一级缓存中之数码写入二级缓存。

不过大家连无行使mybaits提供的二级缓存,理由如下:

  1. 缓存是盖namespace为单位的,不同namespace下的操作互不影响。例如UserMapper.xml包含一个命名空间,所有对user表的insert,update,delete操作皆以斯命名空间下。假若其它一个XXXMapper.xml对user表的内容开展select查询,并将查询结果二级缓存。然后我们针对user表举办insert,update或者delete操作,insert,update,delete操作会清空所在namespace下的全缓存,可是XXXMapper.xml命名空间下的缓存却没有变,导致XXXMapper.xml再一次询问错误。
  2. 多表操作不可能拔取缓存。比如自己而查询某一个作者的全部文章,作者也同摆设表,作品为同样张表。首先,对不同表的增删改一般坐不同之namespace,原因是:假如我将多表的凡事操作放到一个namespace,那么我本着自由一张表的增删改都晤面接触清空这几个namespace的漫天缓存,导致缓存一直以换,这我哪怕倘若平昔查表,这如若缓存也远非意义了。然后,假而将查询某一个作者的全部文章立刻同一操作放到作者所当的酷namespace,那么小说表的增删改由和查询某一个作者的全部文章旋即同操作不以同一namespace,导致那同样操作的二级缓存不转换,查询错误。
      所以抛弃Mybatis二级缓存,在业务层使用可控制的二级缓存代替更好,即服务器上的缓存。推荐下redis或者ehcache做分布式二级缓存
网站地图xml地图