【65】Mybatis详解

Mybatis介绍

MyBatis是一款一流的支持自定义SQL、存储过程和高级映射的持久化框架。MyBatis几乎消除了所有的JDBC代码,也基本不需要手工去设置参数和获取检索结果。MyBatis能够使用简单的XML格式或者注解进行来配置,能够映射基本数据元素、Map接口和POJOs(普通java对象)到数据库中的记录。

MyBatis工作流程

1)加载配置并初始化

触发条件:加载配置文件
配置来源于两个地方,一处是配置文件,一处是Java代码的注解,将SQL的配置信息加载成为一个个MappedStatement对象(包括了传入参数映射配置、执行的SQL语句、结果映射配置),存储在内存中。

(2)接收调用请求

触发条件:调用Mybatis提供的API
传入参数:为SQL的ID和传入参数对象
处理过程:将请求传递给下层的请求处理层进行处理。

(3)处理操作请求 触发条件:API接口层传递请求过来

传入参数:为SQL的ID和传入参数对象
处理过程:
(A)根据SQL的ID查找对应的MappedStatement对象。  
(B)根据传入参数对象解析MappedStatement对象,得到最终要执行的SQL和执行传入参数。  
(C)获取数据库连接,根据得到的最终SQL语句和执行传入参数到数据库执行,并得到执行结果。  
(D)根据MappedStatement对象中的结果映射配置对得到的执行结果进行转换处理,并得到最终的处理结果。  
(E)释放连接资源。

(4)返回处理结果将最终的处理结果返回。

orm工具的基本思想
无论是用过的hibernate,mybatis,你都可以法相他们有一个共同点:

从配置文件(通常是XML配置文件中)得到 sessionfactory.
由sessionfactory 产生 session
在session 中完成对数据的增删改查和事务提交等.
在用完之后关闭session 。
在java 对象和 数据库之间有做mapping 的配置文件,也通常是xml 文件。

Mybatis的功能架构

【65】Mybatis详解_第1张图片

Mybatis的功能架构分为三层:

API接口层:

提供给外部使用的接口API,开发人员通过这些本地API来操纵数据库。接口层一接收到调用请求就会调用数据处理层来完成具体的数据处理。

数据处理层:

负责具体的SQL查找、SQL解析、SQL执行和执行结果映射处理等。它主要的目的是根据调用的请求完成一次数据库操作。

基础支撑层:

负责最基础的功能支撑,包括连接管理、事务管理、配置加载和缓存处理,这些都是共用的东西,将他们抽取出来作为最基础的组件。为上层的数据处理层提供最基础的支撑。

mapper的增删改查语法:

查询数据

查询出列表,也就是返回 list, 在我们这个例子中也就是 List , 这种方式返回数据,需要在 User.xml 里面配置返回的类型 resultMap, 注意不是 resultType, 而这个 resultMap 所对应的应该是我们自己配置的

<!-- 为了返回list 类型而定义的returnMap -->
    <resultMap type="User" id="resultListUser">
        <id column="id" property="id" />
        <result column="userName" property="userName" />
        <result column="userAge" property="userAge" />
        <result column="userAddress" property="userAddress" />
    </resultMap>

查询列表的语句在 User.xml 中

<!-- 返回list 的select 语句,注意 resultMap 的值是指向前面定义好的 -->
    <select id="selectUsers" parameterType="string" resultMap="resultListUser">
        select * from user where userName like #{userName}
    </select>

在 IUserOperation 接口中增加方法:public List selectUsers(String userName);

现在在 Test 类中做测试

public void getUserList(String userName){
        SqlSession session = sqlSessionFactory.openSession();
        try {
            IUserOperation userOperation=session.getMapper(IUserOperation.class);           
            List<User> users = userOperation.selectUsers(userName);
            for(User user:users){
                System.out.println(user.getId()+":"+user.getUserName()+":"+user.getUserAddress());
            }

        } finally {
            session.close();
        }
    }
现在在 main 方法中可以测试:

public static void main(String[] args) {
        Test testUser=new Test();
        testUser.getUserList("%");
    }

用 mybatis 增加数据

在 IUserOperation 接口中增加方法:public void addUser(User user);

在 User.xml 中配置

<!--执行增加操作的SQL语句。id和parameterType 分别与IUserOperation接口中的addUser方法的名字和 参数类型一致。以#{name}的形式引用Student参数 的name属性,MyBatis将使用反射读取Student参数 的此属性。#{name}中name大小写敏感。引用其他 的gender等属性与此一致。seGeneratedKeys设置 为"true"表明要MyBatis获取由数据库自动生成的主 键;keyProperty="id"指定把获取到的主键值注入 到Student的id属性--> 
    <insert id="addUser" parameterType="User" useGeneratedKeys="true" keyProperty="id"> 
        insert into user(userName,userAge,userAddress)  
             values(#{userName},#{userAge},#{userAddress})  
    </insert>

然后在 Test 中写测试方法:

/** * 测试增加,增加后,必须提交事务,否则不会写入到数据库. */
    public void addUser(){
        User user=new User();
        user.setUserAddress("人民广场");
        user.setUserName("飞鸟");
        user.setUserAge(80);
        SqlSession session = sqlSessionFactory.openSession();
        try {
            IUserOperation userOperation=session.getMapper(IUserOperation.class);
            userOperation.addUser(user);
            session.commit();
            System.out.println("当前增加的用户 id为:"+user.getId());
        } finally {
            session.close();
        }
    }

用 mybatis 更新数据

方法类似,先在 IUserOperation 中增加方法:public void addUser(User user);

然后配置 User.xml

<update id="updateUser" parameterType="User" >
        update user set userName=#{userName},userAge=#{userAge},userAddress=#{userAddress} where id=#{id}
    </update>

Test 类总的测试方法如下:

public void updateUser(){
        //先得到用户,然后修改,提交。
        SqlSession session = sqlSessionFactory.openSession();
        try {
            IUserOperation userOperation=session.getMapper(IUserOperation.class);
            User user = userOperation.selectUserByID(4); 
            user.setUserAddress("原来是魔都的浦东创新园区");
            userOperation.updateUser(user);
            session.commit();

        } finally {
            session.close();
        }
    }

用 mybatis 删除数据

同理,IUserOperation 增加方法:public void deleteUser(int id);

配置 User.xml

<delete id="deleteUser" parameterType="int">
        delete from user where id=#{id}
    </delete>
然后在 Test 类中写测试方法:

 /** * 删除数据,删除一定要 commit. * @param id */
    public void deleteUser(int id){
        SqlSession session = sqlSessionFactory.openSession();
        try {
            IUserOperation userOperation=session.getMapper(IUserOperation.class);           
            userOperation.deleteUser(id);
            session.commit();            
        } finally {
            session.close();
        }
    }

这样,所有增删改查都完成了,注意在增加,更改,删除的时候要调用 session.commit(),这样才会真正对数据库进行操作,否则是没有提交的。

Mybatis 动态 SQL 语句基础

mybaits if 语句处理

<select id="dynamicIfTest" parameterType="Blog" resultType="Blog">
        select * from t_blog where 1 = 1
        <if test="title != null">
            and title = #{title}
        </if>
        <if test="content != null">
            and content = #{content}
        </if>
        <if test="owner != null">
            and owner = #{owner}
        </if>
    </select>

这条语句的意思非常简单,如果你提供了 title 参数,那么就要满足 title=#{title},同样如果你提供了 Content 和 Owner 的时候,它们也需要满足相应的条件,之后就是返回满足这些条件的所有 Blog,这是非常有用的一个功能,以往我们使用其他类型框架或者直接使用 JDBC 的时候, 如果我们要达到同样的选择效果的时候,我们就需要拼 SQL 语句,这是极其麻烦的,比起来,上述的动态 SQL 就要简单多了。

choose

(when,otherwize) ,相当于 Java 语言中的 switch ,与 jstl 中的choose 很类似

<select id="dynamicChooseTest" parameterType="Blog" resultType="Blog">
        select * from t_blog where 1 = 1 
        <choose>
            <when test="title != null">
                and title = #{title}
            </when>
            <when test="content != null">
                and content = #{content}
            </when>
            <otherwise>
                and owner = "owner1"
            </otherwise>
        </choose>
    </select>

when 元素表示当 when 中的条件满足的时候就输出其中的内容,跟 Java 中的 switch 效果差不多的是按照条件的顺序,当 when 中有条件满足的时候,就会跳出 choose,即所有的 when 和 otherwise 条件中,只有一个会输出,当所有的我很条件都不满足的时候就输出 otherwise 中的内容。所以上述语句的意思非常简单, 当 title!=null 的时候就输出 and titlte = #{title},不再往下判断条件,当 title 为空且 content!=null 的时候就输出 and content = #{content},当所有条件都不满足的时候就输出 otherwise 中的内容。

trim

对包含的内容加上 prefix,或者 suffix 等,前缀,后缀

<select id="dynamicTrimTest" parameterType="Blog" resultType="Blog">
        select * from t_blog 
        <trim prefix="where" prefixOverrides="and |or">
            <if test="title != null">
                title = #{title}
            </if>
            <if test="content != null">
                and content = #{content}
            </if>
            <if test="owner != null">
                or owner = #{owner}
            </if>
        </trim>
    </select>

trim 元素的主要功能是可以在自己包含的内容前加上某些前缀,也可以在其后加上某些后缀,与之对应的属性是 prefix 和 suffix;可以把包含内容的首部某些内容覆盖,即忽略,也可以把尾部的某些内容覆盖,对应的属性是 prefixOverrides 和 suffixOverrides;正因为 trim 有这样的功能,所以我们也可以非常简单的利用 trim 来代替 where 元素的功能。

where

主要是用来简化 SQL 语句中 where 条件判断的,能智能的处理 and or 条件

<select id="dynamicWhereTest" parameterType="Blog" resultType="Blog">
        select * from t_blog 
        <where>
            <if test="title != null">
                title = #{title}
            </if>
            <if test="content != null">
                and content = #{content}
            </if>
            <if test="owner != null">
                and owner = #{owner}
            </if>
        </where>
    </select>

where 元素的作用是会在写入 where 元素的地方输出一个 where,另外一个好处是你不需要考虑 where 元素里面的条件输出是什么样子的,MyBatis 会智能的帮你处理,如果所有的条件都不满足那么 MyBatis 就会查出所有的记录,如果输出后是 and 开头的,MyBatis 会把第一个 and 忽略,当然如果是 or 开头的,MyBatis 也会把它忽略;此外,在 where 元素中你不需要考虑空格的问题,MyBatis 会智能的帮你加上。像上述例子中,如果 title=null, 而 content != null,那么输出的整个语句会是 select * from t_blog where content = #{content},而不是select * from t_blog where and content = #{content},因为 MyBatis 会智能的把首个 and 或 or 给忽略。

set

主要用于更新时

<update id="dynamicSetTest" parameterType="Blog">
        update t_blog
        <set>
            <if test="title != null">
                title = #{title},
            </if>
            <if test="content != null">
                content = #{content},
            </if>
            <if test="owner != null">
                owner = #{owner}
            </if>
        </set>
        where id = #{id}
    </update>

set 元素主要是用在更新操作的时候,它的主要功能和 where 元素其实是差不多的,主要是在包含的语句前输出一个set,然后如果包含的语句是以逗号结束的话将会把该逗号忽略,如果 set 包含的内容为空的话则会出错。有了 set 元素我们就可以动态的更新那些修改了的字段。

foreach

在实现 mybatis in 语句查询时特别有用

foreach 的主要用在构建 in 条件中,它可以在 SQL 语句中进行迭代一个集合。foreach 元素的属性主要有 item,index,collection,open,separator,close。item 表示集合中每一个元素进行迭代时的别名,index指定一个名字,用于表示在迭代过程中,每次迭代到的位置,open 表示该语句以什么开始,separator表示在每次进行迭代之间以什么符号作为分隔符,close 表示以什么结束,在使用 foreach 的时候最关键的也是最容易出错的就是 collection 属性,该属性是必须指定的,但是在不同情况下,该属性的值是不一样的,

主要有一下 3 种情况:

如果传入的是单参数且参数类型是一个 List 的时候,collection 属性值为 list
如果传入的是单参数且参数类型是一个 array 数组的时候,collection 的属性值为 array
如果传入的参数是多个的时候,我们就需要把它们封装成一个 Map 了,当然单参数也可以封装成 map,实际上如果你在传入参数的时候,在 MyBatis 里面也是会把它封装成一个 Map 的,map 的 key 就是参数名,所以这个时候 collection 属性值就是传入的 List 或 array 对象在自己封装的 map 里面的 key
单参数 List 的类型

<select id="dynamicForeachTest" resultType="Blog">
        select * from t_blog where id in
        <foreach collection="list" index="index" item="item" open="(" separator="," close=")">
            #{item}
        </foreach>
    </select>
上述 collection 的

值为 list,对应的 Mapper 是这样的

public List<Blog> dynamicForeachTest(List<Integer> ids); 
测试代码

@Test
    public void dynamicForeachTest() {
        SqlSession session = Util.getSqlSessionFactory().openSession();
        BlogMapper blogMapper = session.getMapper(BlogMapper.class);
        List<Integer> ids = new ArrayList<Integer>();
        ids.add(1);
        ids.add(3);
        ids.add(6);
        List<Blog> blogs = blogMapper.dynamicForeachTest(ids);
        for (Blog blog : blogs)
            System.out.println(blog);
        session.close();
    }

数组类型的参数

<select id="dynamicForeach2Test" resultType="Blog">
        select * from t_blog where id in
        <foreach collection="array" index="index" item="item" open="(" separator="," close=")">
            #{item}
        </foreach>
    </select>

对应 mapper

public List<Blog> dynamicForeach2Test(int[] ids);  
Map 类型的参数
    <select id="dynamicForeach3Test" resultType="Blog">
        select * from t_blog where title like "%"#{title}"%" and id in
        <foreach collection="ids" index="index" item="item" open="(" separator="," close=")">
            #{item}
        </foreach>
    </select>

mapper 应该是这样的接口:

public List dynamicForeach3Test(Map

我的微信二维码如下,欢迎交流讨论

【65】Mybatis详解_第2张图片

欢迎关注《IT面试题汇总》微信订阅号。每天推送经典面试题和面试心得技巧,都是干货!

微信订阅号二维码如下:

【65】Mybatis详解_第3张图片

参考:
http://wiki.jikexueyuan.com/project/mybatis-in-action/mybatis-sql.html
http://www.jianshu.com/p/3f507c7ec3da

你可能感兴趣的:(java,数据库,mybatis,J2EE)