MyBatis

MyBatis

MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。

使用 Maven 来构建项目,则需将下面的 dependency 代码置于 pom.xml 文件中:

<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis</artifactId>
  <version>x.x.x</version>
</dependency>

1.1. 缓存介绍

什么是缓存:

缓存就是内存中的临时数据,当内存释放后,缓存消失。

缓存的作用:

提高查询效率,当查询数据时可以先从缓存中看看有没有,有的话直接用,没有再去数据库查询。缓存可以减少和数据库交互的次数。 

什么样的数据不适合用缓存:

经常修改的数据;对数据的准确性要求非常高的。

 

mybatis中缓存分为一级缓存和二级缓存

1.1.1 一级缓存

mybatis中,一级缓存指的是SqlSession级别的缓存,默认是开启的,并且无法关闭。

作用域:在同一个SqlSession范围内有效;执行同一个namespace中的同一个语句才能使用一级缓存中的数据。

调用SqlSessionclearCache方法或SqlSession关闭后,一级缓存失效:

执行insertdeleteupdate方法后,会清空一级缓存:

1.1.2 二级缓存

mybatis中,二级缓存是指SqlSessionFacotory级别的缓存,可以跨SqlSession存在。

作用域:跨SqlSession;执行同一个namespace中的同一个语句才能使用二级缓存中的数据。

 

怎么开启二级缓存:

mybatis-config.xml中把二级缓存的全局开关打开,默认是开启的:

在映射文件中,添加<cache>标签。UserMapper.xml:

<mapper namespace="cn.an.mapper.UserMapper">

  <!-- 开启二级缓存 -->

  <cache />

注意:

由于数据是在sqlSession调用close方法时,放入二级缓存中的,所以第一个sqlSession必先关闭;

二级缓存中的对象必须实现序列化接口,所以User类需要实现Serializable接口。

执行insertdeleteupdate后,也会清空二级缓存:

 

那么如何关闭二级缓存呢?

mybatis-config.xml中把cacheEnabled的值设置为false;

mapper映射文件中不要添加<cache />标签;

XML配置

MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。 配置文档的顶层结构如下:

XML 配置文件中包含了对 MyBatis 系统的核心设置,包含获取数据库连接实例的数据源(DataSource)和决定事务作用域和控制方式的事务管理器(TransactionManager)。

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

jdbc.properties

jdbc.driverClass:com.mysql.jdbc.Driver
jdbc.url:jdbc:mysql://localhost:3306/test
jdbc.username:root
jdbc.password:root

当然,还有很多可以在 XML 文件中进行配置,上面的示例指出的则是最关键的部分。 要注意 XML 头部的声明,它用来验证 XML 文档正确性。environment 元素体中包含了事务管理和连接池的配置。mappers 元素则是包含一组映射器(mapper),这些映射器的 XML 映射文件包含了 SQL 代码和映射定义信息。

XML 映射文件

<![CDATA[]]>和转义字符

被<![CDATA[]]>这个标记所包含的内容将表示为纯文本,比如<![CDATA[<]]>表示文本内容“<”。 
  此标记用于xml文档中,我们先来看看使用转义符的情况。我们知道,在xml中,”<”、”>”、”&”等字符是不能直接存入的,否则xml语法检查时会报错,如果想在xml中使用这些符号,必须将其转义为实体,如”&lt;”、”&gt;”、”&amp;”,这样才能保存进xml文档。 
  在使用程序读取的时候,解析器会自动将这些实体转换回”<”、”>”、”&”。举个例子: 
  <age> age < 30 </age> 
  上面这种写法会报错,应该这样写: 
  <age> age &lt; 30 </age> 
  值得注意的是: 
  (1)转义序列字符之间不能有空格; 
  (2) 转义序列必须以”;”结束; 
  (3) 单独出现的”&”不会被认为是转义的开始; 
  (4) 区分大小写。 
   
  在XML中,需要转义的字符有: 
  (1)&   &amp; 
  (2)<   &lt; 
  (3)>   &gt; 
  (4)"   &quot; 
  (5)'   &apos; 
  但是严格来说,在XML中只有”<”和”&”是非法的,其它三个都是可以合法存在的,但是,把它们都进行转义是一个好的习惯。 
  不管怎么样,转义前的字符也好,转义后的字符也好,都会被xml解析器解析,为了方便起见,使用<![CDATA[]]>来包含不被xml解析器解析的内容。但要注意的是: 
  (1) 此部分不能再包含”]]>”; 
  (2) 不允许嵌套使用; 
  (3)”]]>”这部分不能包含空格或者换行。 
  最后,说说<![CDATA[]]>和xml转移字符的关系,它们两个看起来是不是感觉功能重复了? 
  是的,它们的功能就是一样的,只是应用场景和需求有些不同: 
  (1)<![CDATA[]]>不能适用所有情况,转义字符可以; 
  (2) 对于短字符串<![CDATA[]]>写起来啰嗦,对于长字符串转义字符写起来可读性差; 
  (3) <![CDATA[]]>表示xml解析器忽略解析,所以更快。
View Code

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

SQL 映射文件只有很少的几个顶级元素(按照应被定义的顺序列出):

  • cache – 对给定命名空间的缓存配置。
  • cache-ref – 对其他命名空间缓存配置的引用。
  • resultMap – 是最复杂也是最强大的元素,用来描述如何从数据库结果集中来加载对象。
  • parameterMap – 已被废弃!老式风格的参数映射。更好的办法是使用内联参数,此元素可能在将来被移除。文档中不会介绍此元素。
  • sql – 可被其他语句引用的可重用语句块。
  • insert – 映射插入语句
  • update – 映射更新语句
  • delete – 映射删除语句
  • select – 映射查询语句

探究已映射的 SQL 语句

<mapper namespace="org.mybatis.example.BlogMapper">
  <select id="selectBlog" resultType="Blog">
    select * from Blog where id = #{id}
  </select>
</mapper>

<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.example.student.entity.Course">
<id column="id" property="id"/>
<result column="name" property="name"/>
</resultMap>

在命名空间 “org.mybatis.example.BlogMapper” 中定义了一个名为 “selectBlog” 的映射语句,允许你使用指定的完全限定名 “org.mybatis.example.BlogMapper.selectBlog” 来调用映射语句

namespace

命名空间(Namespaces)的作用有两个,一个是利用更长的完全限定名来将不同的语句隔离开来,同时也实现了你上面见到的接口绑定。

id需要与Mapper中的方法对应,用来引用这条语句。

 

select  映射查询语句

属性介绍:

  • id :唯一的标识符.
  • parameterType:传给此语句的参数的全路径名或别名 例:com.test.poso.User或user
  • resultType :语句返回值类型或别名。注意,如果是集合,那么这里填写的是集合的泛型,而不是集合本身(resultType 与resultMap 不能并用)
属性描述
id 在命名空间中唯一的标识符,可以被用来引用这条语句。
parameterType 将会传入这条语句的参数类的完全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过类型处理器(TypeHandler) 推断出具体传入语句的参数,默认值为未设置(unset)。
parameterMap 这是引用外部 parameterMap 的已经被废弃的方法。请使用内联参数映射和 parameterType 属性。
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

属性介绍:

  • id :唯一的标识符
  • parameterType:传给此语句的参数的全路径名或别名 例:com.test.poso.User
属性描述
id 命名空间中的唯一标识符,可被用来代表这条语句。
parameterType 将要传入语句的参数的完全限定类名或别名。这个属性是可选的,因为 MyBatis 可以通过类型处理器推断出具体传入语句的参数,默认值为未设置(unset)。
parameterMap 这是引用外部 parameterMap 的已经被废弃的方法。请使用内联参数映射和 parameterType 属性。
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 的语句;如果带或者不带的语句都有,则不带的会被忽略。

配置JAVA对象属性与查询结果集中列名对应关系

resultMap 标签的使用
基本作用:

  • 建立SQL查询结果字段与实体属性的映射关系信息
  • 查询的结果集转换为java对象,方便进一步操作。
  • 将结果集中的列与java对象中的属性对应起来并将值填充进去

!注意:与java对象对应的列不是数据库中表的列名,而是查询后结果集的列名

<resultMap id="BaseResultMap" type="com.online.charge.platform.student.model.Student">
        <id property="id" column="id" />
        <result column="NAME" property="name" />
        <result column="HOBBY" property="hobby" />
        <result column="MAJOR" property="major" />
        <result column="BIRTHDAY" property="birthday" />
        <result column="AGE" property="age" />

</resultMap>
  <!--查询时resultMap引用该resultMap -->  
<select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="Object">
        select id,name,hobby,major,birthday,age from student where id=#{id}
</select> 

标签说明:

主标签:

  • id:该resultMap的标志
  • type:返回值的类名,此例中返回Studnet类

子标签:

  • id:用于设置主键字段与领域模型属性的映射关系,此处主键为ID,对应id。
  • result:用于设置普通字段与领域模型属性的映射关系

动态sql拼接

if  foreach choose where set trim collection association sql 

if 标签

if标签通常用于WHERE语句、UPDATE语句、INSERT语句中,通过判断参数值来决定是否使用某个查询条件、判断是否更新某一个字段、判断是否插入某个字段的值。

<if test="name != null and name != ''">
         and NAME = #{name}
</if>

foreach 标签

foreach标签主要用于构建in条件,可在sql中对集合进行迭代。也常用到批量删除、添加等操作中。

<!-- in查询所有,不分页 -->
    <select id="selectIn" resultMap="BaseResultMap">
        select name,hobby 
              from student where id in
        <foreach item="item" index="index" collection="list" open="(" separator="," close=")">
            #{item}
        </foreach>
    </select>

属性介绍:

  • collection:collection属性的值有三个分别是list、array、map三种,分别对应的参数类型为:List、数组、map集合。
  • item :表示在迭代过程中每一个元素的别名
  • index :表示在迭代过程中每次迭代到的位置(下标)
  • open :前缀
  • close :后缀
  • separator :分隔符,表示迭代时每个元素之间以什么分隔

choose标签

有时候我们并不想应用所有的条件,而只是想从多个选项中选择一个。MyBatis提供了choose 元素,按顺序判断when中的条件出否成立,如果有一个成立,则choose结束。当choose中所有when的条件都不满则时,则执行 otherwise中的sql。类似于Java 的switch 语句,choose为switch,when为case,otherwise则为default。

 if是与(and)的关系,而choose是或(or)的关系。

<select id="getStudentListChoose" parameterType="Student" resultMap="BaseResultMap">     
    SELECT * from STUDENT WHERE 1=1    
    <where>     
        <choose>     
            <when test="Name!=null and student!='' ">     
                   AND name LIKE CONCAT(CONCAT('%', #{student}),'%')      
            </when>     
            <when test="hobby!= null and hobby!= '' ">     
                    AND hobby = #{hobby}      
            </when>                   
            <otherwise>     
                    AND AGE = 15  
            </otherwise>     
        </choose>     
    </where>     
</select>   

格式化输出

where标签

当if标签较多时,这样的组合可能会导致错误。 如下:

<select id="getStudentListWhere" parameterType="Object" resultMap="BaseResultMap">     
    SELECT * from STUDENT      
        WHERE      
        <if test="name!=null and name!='' ">     
            NAME LIKE CONCAT(CONCAT('%', #{name}),'%')      
        </if>     
        <if test="hobby!= null and hobby!= '' ">     
            AND hobby = #{hobby}      
        </if>     
</select> 

当name值为null时,查询语句会出现 “WHERE AND” 的情况,解决该情况除了将"WHERE"改为“WHERE 1=1”之外,还可以利用where标签。这个“where”标签会知道如果它包含的标签中有返回值的话,它就插入一个‘where’。此外,如果标签返回的内容是以AND 或OR 开头的,则它会剔除掉。

<select id="getStudentListWhere" parameterType="Object" resultMap="BaseResultMap">     
    SELECT * from STUDENT      
       <where>   
         <if test="name!=null and name!='' ">     
            NAME LIKE CONCAT(CONCAT('%', #{name}),'%')      
         </if>     
         <if test="hobby!= null and hobby!= '' ">     
            AND hobby = #{hobby}      
         </if>  
       </where>        
</select>    

set 标签

没有使用if标签时,如果有一个参数为null,都会导致错误。当在update语句中使用if标签时,如果最后的if没有执行,则或导致逗号多余错误。使用set标签可以将动态的配置set关键字,和剔除追加到条件末尾的任何不相关的逗号。

<update id="updateStudent" parameterType="Object">     
    UPDATE STUDENT   
       SET NAME = #{name},   
           MAJOR = #{major},
           HOBBY = #{hobby}
     WHERE ID = #{id};      
</update>  
<update id="updateStudent" parameterType="Object">     
    UPDATE STUDENT SET    
        <if test="name!=null and name!='' ">     
            NAME = #{name},      
        </if>     
        <if test="hobby!=null and hobby!='' ">     
            MAJOR = #{major},      
        </if> 
        <if test="hobby!=null and hobby!='' ">     
            HOBBY = #{hobby}    
        </if>          
    WHERE ID = #{id};      
</update>  

使用set+if标签修改后,如果某项为null则不进行更新,而是保持数据库原值。

<update id="updateStudent" parameterType="Object">     
    UPDATE STUDENT      
    <set>     
        <if test="name!=null and name!='' ">     
            NAME = #{name},      
        </if>     
        <if test="hobby!=null and hobby!='' ">     
            MAJOR = #{major},      
        </if> 
        <if test="hobby!=null and hobby!='' ">     
            HOBBY = #{hobby}    
        </if>     
    </set>     
    WHERE ID = #{id};      
</update>  

 trim标签

格式化输出,也可以通过trim标签设定或忽略前后缀来实现,

trim标记是一个格式化的标记,主要用于拼接sql的条件语句(前缀或后缀的添加或忽略),可以完成set或者是where标记的功能。

trim属性主要有以下四个

  •  prefix:前缀覆盖并增加其内容
  •  suffix:后缀覆盖并增加其内容
  •  prefixOverrides:前缀判断的条件
  •  suffixOverrides:后缀判断的条件

配置关联关系

关联映射最主要的是能够用好如下两个标签:

  • *  对多关联映射:collection
  • *  对一关联映射:association 

此外注意:一对多使用的都是lazy(懒加载)。

定义常量及引用

sql标签

当多种类型的查询语句的查询字段或者查询条件相同时,可以将其定义为常量,方便调用。为求<select>结构清晰也可将sql语句分解。

include标签

用于引用定义的常量

(http://www.mybatis.org/mybatis-3/zh/sqlmap-xml.html)

$和#的区别

#是预编译的方式,防止sql注入;Mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值;

#不需要关注数据类型,mybatis实现自动数据类型转换;如果只有一个参数,默认情况下,#{}中可以写任意的名字;

$是直接拼接字符串替换,不能防止sql注入;Mybatis在处理${}时,就是把${}替换成变量的值;

$不做数据类型转换,需要自行判断数据类型;${}中只能用value来接收。在order by 中就需要使用 $.

#{} 传入值时,sql解析时,参数是带引号的,而的区别最大在于:#{} 传入值时,sql解析时,参数是带引号的,而{}穿入值,sql解析时,参数是不带引号的。

#{}: 解析为一个 JDBC 预编译语句(prepared statement)的参数标记符,一个 #{ } 被解析为一个参数占位符 。

${}: 仅仅为一个纯碎的 string 替换,在动态 SQL 解析阶段将会进行变量替换。

 #是将传入的值当做字符串的形式,eg:select id,name,age from student where id =#{id},当前端把id值1,传入到后台的时候,就相当于 select id,name,age from student where id ='1'.

 $是将传入的数据直接显示生成sql语句,eg:select id,name,age from student where id =${id},当前端把id值1,传入到后台的时候,就相当于 select id,name,age from student where id = 1.

 

   

模糊查询like语句该怎么写?

第1种:在Java代码中添加sql通配符。

string wildcardname = “%smi%”;
    list<name> names = mapper.selectlike(wildcardname);
 
    <select id=”selectlike”>
     select * from foo where bar like #{value}
    </select>

第2种:在sql语句中拼接通配符,会引起sql注入

string wildcardname = “smi”;
    list<name> names = mapper.selectlike(wildcardname);
 
    <select id=”selectlike”>
         select * from foo where bar like "%"#{value}"%"
    </select>

 

1、mybatis-config.xml
(1)Environments
①transactionManager
②dataSource
(2)引入外部的属性资源文件:jdbc.properties
(3)settings:开启驼峰匹配
(4)配置别名
(5)引入映射
2、mapper文件
(1)select:id resultType parameterType
(2)insert:id   主键回写
(3)update:id
(4)delete:id
5、parameterType:基本类型  POJO   hashmap
6、resultMap
(1)解决属性名和列名不一致的问题
(2)高级查询
7、sql片段

1、动态代理Mapper接口
(1)映射文件的namespace一定要与接口的全路径名一致
(2)映射文件语句的id一定要与接口中方法名一致
(3)映射文件中的resultType一定要与接口中方法的返回值类型一致
(4)映射文件中的parameterType一定要与接口中方法的形参类型一致(不一定)
2、动态sql
(1)If
(2)Choose when otherwise
(3)Where
(4)Set
(5)Foreach
3、高级查询(多表查询)
(1)一对一
(2)一对多
(3)多对多
View Code

 

https://blog.csdn.net/liyang_com/article/details/83756273#6.%24%E5%92%8C%23%E7%9A%84%E5%8C%BA%E5%88%AB

https://blog.csdn.net/a745233700/article/details/80977133

https://www.cnblogs.com/huajiezh/p/6415388.html

https://www.cnblogs.com/huajiezh/p/6415388.html

https://blog.csdn.net/eaphyy/article/details/71190441

https://www.jianshu.com/p/b7c591494fe8

MyBatis 详解(一对一,一对多,多对多)

 

posted @ 2019-04-24 22:18  andy_mz  阅读(53)  评论(0)    收藏  举报