Mybatis 结构与动态SQL

 1.Mybatis结构

      

  (1)加载配置:配置来源于两个地方,一处是配置文件,一处是Java代码的注解,将SQL的配置信息加载成为一个
 个MappedStatement对象(包括了传入参数映射配置、执行的SQL语句、结果映射配置),存储在内存中。
 (2)SQL解析:当API接口层接收到调用请求时,会接收到传入SQL的ID和传入对象(可以是Map、JavaBean或者基本数据类型),Mybatis会根据SQL的ID找到对应的          MappedStatement,然后根据传入参数对象对MappedStatement进行解析,解析后可以得到最终要执行的SQL语句和参数。
(3)SQL执行:将最终得到的SQL和参数拿到数据库进行执行,得到操作数据库的结果。
(4)结果映射:将操作数据库的结果按照映射的配置进行转换,可以转换成HashMap、JavaBean或者基本数据类型,并将最终结果返回

2.Mybaits配置文件解析

configuration —— 根元素 
properties —— 定义配置属性文件
settings —— 一些全局性的配置
typeAliases —— 为一些类定义别名
typeHandlers —— 定义类型处理,也就是定义java类型与数据库中的数据类型之间的转换关系
objectFactory
plugins —— Mybatis的插件,插件可以修改Mybatis内部的运行规则
environments —— 配置Mybatis的环境 
environment 
transactionManager —— 事务管理器
dataSource —— 数据源

mappers —— 指定映射文件或映射类

   2.1 Mybatis主配置文件

      <?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="jdbc.properties"/>  
      
    <!-- 设置缓存和延迟加载等等重要的运行时的行为方式 -->  
    <settings>  
        <!-- 设置超时时间,它决定驱动等待一个数据库响应的时间  -->  
        <setting name="defaultStatementTimeout" value="25000"/>  
    </settings>  
      
    <!-- 别名 -->  
    <typeAliases>  
        <typeAlias alias="User" type="com.mybatis.model.User"/>  
    </typeAliases>  
      
    <environments default="development">  
        <!-- environment 元素体中包含对事务管理和连接池的环境配置 -->  
        <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>  
      
    <!-- ORM映射文件 -->  
    <mappers>  
        <mapper resource="com/mybatis/model/UserSqlMap.xml" />  
    </mappers>  
</configuration>   

jdbc.properties

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

 UserSqlMap.xml

<?xml version="1.0" encoding="UTF-8"?>  
<!DOCTYPE mapper       
PUBLIC "-//ibatis.apache.org//DTD Mapper 3.0//EN"       
"http://ibatis.apache.org/dtd/ibatis-3-mapper.dtd">       
     
<!-- namespace用于java代码调用时识别指定xml的mapper文件 -->  
<mapper namespace="com.mybatis.model.User">  
    <!-- 配置ORM映射 -->  
    <resultMap type="User" id="user_orm">  
        <id property="id" column="id"/>  
        <result property="userName" column="userName"/>  
        <result property="password" column="password"/>  
    </resultMap>  
      
    <!-- 用来定义可重用的SQL代码段 -->  
    <sql id="demo_sql">  
       userName,password  
    </sql>  
      
    <insert id="inser_user" parameterType="User">  
        <!-- include 引用可重用的SQL代码段 -->  
        INSERT INTO USER(<include refid="demo_sql"/>) VALUES(#{userName},#{password})  
    </insert>  
      
    <update id="update_user" parameterType="User">  
        UPDATE USER SET userName=#{userName} ,password=#{password}  WHERE id=#{id}  
    </update>  
      
    <update id="delete_user" parameterType="int">  
        DELETE FROM USER WHERE id=#{id}  
    </update>  
    
    <select id="selectAll_user" useCache="false" flushCache="true" resultMap="user_orm">  
        SELECT * FROM USER  
    </select>  
      
    <!-- 使用map传人多个参数 -->  
    <select id="selectList_user" useCache="false" flushCache="true" parameterType="map" resultMap="user_orm">  
        SELECT * FROM USER LIMIT #{pageNow},#{pageSize}   
    </select>  
      
    <select id="selectById_user" parameterType="int" resultType="User">  
        SELECT * FROM USER WHERE id= #{id}  
    </select>  
      
    <select id="selectCount_user"  resultType="int">  
        SELECT count(*) FROM USER   
    </select>  
      
    <select id="selectByName_user" parameterType="String" resultType="User">  
        SELECT * FROM USER WHERE userName= #{userName}  
    </select>  
  
    <!--模糊 MyIbatis 3.2.0-->  
    <select id="selectUserByName" parameterType="String" resultMap="user_orm">  
         SELECT * FROM USER WHERE userName like "%"#{userName}"%"  
    </select>  
</mapper>  

SqlSessionFactoryUtil.java  MyBatis工具类,用于创建SqlSessionFactory


import java.io.IOException;  
import java.io.Reader;  
  
import org.apache.ibatis.io.Resources;  
import org.apache.ibatis.session.SqlSession;  
import org.apache.ibatis.session.SqlSessionFactory;  
import org.apache.ibatis.session.SqlSessionFactoryBuilder;  
  
public class SqlSessionFactoryUtil{  
      
    private static final String RESOURCE = "Configuration.xml";  
    private static SqlSessionFactory sqlSessionFactory = null;  
    private static ThreadLocal<SqlSession> threadLocal = new ThreadLocal<SqlSession>();  
  
    static {  
        Reader reader = null;  
        try {  
            reader = Resources.getResourceAsReader(RESOURCE);  
        } catch (IOException e) {  
            throw new RuntimeException("Get resource error:"+RESOURCE, e);  
        }  
  
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);  
    }  
      
    /** 
     *  获得SqlSessionFactory 
     */  
    public static SqlSessionFactory getSqlSessionFactory(){     
        return sqlSessionFactory;     
    }  
      
    /** 
     * : 重新创建SqlSessionFactory 
     */  
    public static void rebuildSqlSessionFactory(){  
        Reader reader = null;  
        try {  
            reader = Resources.getResourceAsReader(RESOURCE);  
        } catch (IOException e) {  
            throw new RuntimeException("Get resource error:"+RESOURCE, e);  
        }  
  
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);  
    }  
      
    /** 
     * 获取sqlSession 
     */  
    public static SqlSession getSession(){  
        SqlSession session = threadLocal.get();  
          
        if(session!=null){  
            if(sqlSessionFactory == null){  
                getSqlSessionFactory();  
            }  
            //如果sqlSessionFactory不为空则获取sqlSession,否则返回null  
            session = (sqlSessionFactory!=null) ? sqlSessionFactory.openSession(): null;  
        }  
          
        return session;  
    }  
      
    /** 
     *  关闭sqlSession 
     */  
    public static void closeSession(){  
        SqlSession session = threadLocal.get();  
        threadLocal.set(null);  
        if(session!=null){  
            session.close();  
        }  
    }  
}  

3.动态SQL配置

 MyBatis 的一个强大的特性之一通常是它的动态 SQL 能力。 如果你有使用 JDBC 或其他 相似框架的经验,你就明白条件地串联 SQL 字符串在一起是多么的痛苦,确保不能忘了空 格或在列表的最后省略逗号。动态 SQL 可以彻底处理这种痛苦

通常使用动态 SQL 不可能是独立的一部分,MyBatis 当然使用一种强大的动态 SQL 语 言来改进这种情形,这种语言可以被用在任意映射的 SQL 语句中。
动态 SQL 元素和使用 JSTL 或其他相似的基于 XML 的文本处理器相似。在 MyBatis 之 前的版本中,有很多的元素需要来了解。MyBatis 3 大大提升了它们,现在用不到原先一半 的元素就能工作了。MyBatis 采用功能强大的基于 OGNL 的表达式来消除其他元素。
if
choose (when, otherwise)
trim (where, set)
foreach
if
在动态 SQL 中所做的最通用的事情是包含部分 where 字句的条件。比如:

<select id="findActiveBlogWithTitleLike" 
     resultType="Blog">
  SELECT * FROM BLOG 
  WHERE state = ‘ACTIVE’ 
  <if test="title != null">
    AND title like #{title}
  </if>
</select>
这条语句会提供一个可选的文本查找功能。如果你没有传递 title,那么所有激活的博客 都会被返回。但是如果你传递了 title,那么就会查找相近的 title(对于敏锐的检索,这中情 况下你的参数值需要包含任意的遮掩或通配符)的博客。

假若我们想可选地搜索 title 和 author 呢?首先,要改变语句的名称让它有意义。然后 简单加入另外的一个条件。

<select id="findActiveBlogLike" 
     resultType="Blog">
  SELECT * FROM BLOG WHERE state = ‘ACTIVE’ 
  <if test="title != null">
    AND title like #{title}
  </if>
  <if test="author != null and author.name != null">
    AND author_name like #{author.name}
  </if>
</select>
choose, when, otherwise
有时我们不想应用所有的条件, 相反我们想选择很多情况下的一种。 Java 中的 switch 和 语句相似,MyBatis 提供 choose 元素。

我们使用上面的示例,但是现在我们来搜索当 title 提供时仅有 title 条件,当 author 提 供时仅有 author 条件。如果二者都没提供,只返回 featured blogs(也许是由管理员策略地选 择的结果列表,而不是返回大量没有意义的随机博客结果列表)。

<select id="findActiveBlogLike" 
     resultType="Blog">
  SELECT * FROM BLOG WHERE state = ‘ACTIVE’
  <choose>
    <when test="title != null">
      AND title like #{title}
    </when>
    <when test="author != null and author.name != null">
      AND author_name like #{author.name}
    </when>
    <otherwise>
      AND featured = 1
    </otherwise>
  </choose>
</select>
trim, where, set
前面的例子已经方便地处理了一个臭名昭著的动态 SQL 问题。要考虑我们回到“if”示 例后会发生什么,但是这次我们将“ACTIVE = 1”也设置成动态的条件。

<select id="findActiveBlogLike" 
     resultType="Blog">
  SELECT * FROM BLOG 
  WHERE 
  <if test="state != null">
    state = #{state}
  </if> 
  <if test="title != null">
    AND title like #{title}
  </if>
  <if test="author != null and author.name != null">
    AND author_name like #{author.name}
  </if>
</select>
如果这些条件都没有匹配上将会发生什么?这条 SQL 结束时就会成这样:

SELECT * FROM BLOG 
WHERE
这会导致查询失败。如果仅仅第二个条件匹配是什么样的?这条 SQL 结束时就会是这 样:

SELECT * FROM BLOG 
WHERE 
AND title like ‘someTitle’
这个查询也会失败。这个问题不能简单的用条件来解决,如果你从来没有这样写过,那 么你以后也不会这样来写。

MyBatis 有一个简单的处理,这在 90%的情况下都会有用。而在不能使用的地方,你可 以自定义处理方式。加上一个简单的改变,所有事情都会顺利进行:
<select id="findActiveBlogLike" 
     resultType="Blog">
  SELECT * FROM BLOG 
  <where> 
    <if test="state != null">
         state = #{state}
    </if> 
    <if test="title != null">
        AND title like #{title}
    </if>
    <if test="author != null and author.name != null">
        AND author_name like #{author.name}
    </if>
  </where>
</select>
where 元素知道如果由被包含的标记返回任意内容,就仅仅插入“WHERE” 。而且,如 果以“AND”或“OR”开头的内容,那么就会跳过 WHERE 不插入。


如果 where 元素没有做出你想要的,你可以使用 trim 元素来自定义。比如,和 where 元素相等的 trim 元素是:

<trim prefix="WHERE" prefixOverrides="AND |OR ">
  ... 
</trim>

和动态更新语句相似的解决方案是 set。set 元素可以被用于动态包含更新的列,而不包 含不需更新的。比如:

<update id="updateAuthorIfNecessary">
  update Author
    <set>
      <if test="username != null">username=#{username},</if>
      <if test="password != null">password=#{password},</if>
      <if test="email != null">email=#{email},</if>
      <if test="bio != null">bio=#{bio}</if>
    </set>
  where id=#{id}
</update>
这里,set 元素会动态前置 SET 关键字,而且也会消除任意无关的逗号,那也许在应用 条件之后来跟踪定义的值。
如果你对和这相等的 trim 元素好奇,它看起来就是这样的:
<trim prefix="SET" suffixOverrides=",">
  ...
</trim>
注意这种情况下我们覆盖一个后缀,而同时也附加前缀。
foreach
另外一个动态 SQL 通用的必要操作是迭代一个集合, 通常是构建在 IN 条件中的。 比如:
<select id="selectPostIn" resultType="domain.blog.Post">
  SELECT *
  FROM POST P
  WHERE ID in
  <foreach item="item" index="index" collection="list"
      open="(" separator="," close=")">
        #{item}
  </foreach>
</select>
foreach 元素是非常强大的,它允许你指定一个集合,声明集合项和索引变量,它们可 以用在元素体内。它也允许你指定开放和关闭的字符串,在迭代之间放置分隔符。这个元素 是很智能的,它不会偶然地附加多余的分隔符。

注意 你可以传递一个 List 实例或者数组作为参数对象传给 MyBatis。当你这么做的时 候,MyBatis 会自动将它包装在一个 Map 中,用名称在作为键。List 实例将会以“list” 作为键,而数组实例将会以“array”作为键。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值