MyBatis( 二 )

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/QuietHRH/article/details/82345339

参数为java bean 或多个参数时 Mybatis是怎样封装数据的?

接口方法是多个参数时,推荐使用注解

MyBatis封装这些参数为Map时,键应该是什么??

MyBatis底层肯定是用反射来进行的这些操作,那么反射可以获取到方法,但是是否能获取的方法的参数名称呢?

答案是不行,方法的参数名称是形参,是可变的。反射类Method中,并没有提供获取方法名称的功能。所以MyBatis并不知道我们传递的参数名称,只知道这些参数的值!

再次回到上面的问题,只有值,那么MyBatis封装Map的时候,应该以什么做键呢?

答案是这样的:默认情况下MyBatis会设置两种键:

A:以从0开始的递增数字作为键,第一个参数是0,第2个参数就是1,以此类推

B:以”param” + i 作为键,i是从1递增的数字,第一个参数键就是param1,第2个就是param2,以此类推

所以我们可以通过#{0} 或 #{param1} 来取到第一个参数,以此类推

 #{ } 和 ${ }的用法

两者都支持@param注解, 指定参数名称, 获取参数值. 推荐这种方式

          #是占位符, 会对SQL进行预编译,相当于?; $是做sql拼接, 有SQL注入的隐患

          #不需要关注数据类型, MyBatis自动实现数据类型转换; ${} 必须自己判断数据类型

一般做参数传递,都会使用#{}

如果不是做预编译,而是做拼接sql, 会使用${}, 例如表名称的变化

 

ResultMap的高级映射

解决属性名和列名不一致的问题

<settings>
        <!--是否开启驼峰标识-->
        <setting name="mapUnderscoreToCamelCase" value="false"/>
</settings>



<resultMap id="userResultMap" type="User">
	<!--
		property: javabean对应的属性
		column : 数据库对应的列名
	-->
	<id property="id" column="id"></id>
	<result property="userName" column="user_name"/>
</resultMap>
	
<select id="queryUserById" resultMap="userResultMap">
    select * from tb_user where id=${id}
</select>

autoMapping自动映射

刚才的配置中,只配置了id和userName字段,其它字段没有配置,映射也没有问题,为什么呢?

这是因为,在resultMap中,有一个属性叫做:autoMapping,如果值为true,并且列名称和字段名一致,是可以完成自动映射的。

默认情况下,这个autoMapping的值就是为true的。

因此,一般我们配置resultMap,只要字段符合规则,我们只需要把ID配置出来就OK了。其它字段可以自动映射!

自动映射策略

       Mybatis的自动映射策略默认是开启的,而且默认是只对非嵌套的resultMap进行自动映射。这是通过Mybatis的全局配置autoMappingBehavior参数配置的。它一共有三种取值,分别是NONE、PARTIAL和FULL。

l  NONE表示不启用自动映射

l  PARTIAL表示只对非嵌套的resultMap进行自动映射

l  FULL表示对所有的resultMap都进行自动映射

     全局配置文件

     <setting name="autoMappingBehavior" value="PARTIAL"/>

       除了全局的是否启用自动映射的配置外,还可以对特定的resultMap设置是否启用自动映射。这是通过resultMap的autoMapping属性配置的,可选值是true和false。定义在resultMap上的autoMapping的优先级比全局配置的优先级更高。

SQL片段

<!--
	定义sql片段
	id: sql片段的唯一标识
-->
<sql id="userColumns">
	id, user_name, password, name, age, sex, birthday, created, updated
</sql>


<select id="queryUserById" resultMap="userResultMap">
     select <include refid="userColumns"/>
     from tb_user where id=${id}
</select>

<select id="queryUserList" resultType="User">
     select <include refid="userColumns"/>
     from tb_user
</select>

动态sql

需求1:查询所有男性用户,如果输入了姓名,则按照姓名模糊查找;如果没有输入则不管姓名

需求2:查询所有用户,传递参数orderType,如果值为0,按照年龄升序排序,如果为1则按照年龄降序排序,否则按照ID排序

需求3:查询所有用户,如果有姓名不为空,则按照姓名模糊查找;如果年龄也不为空,则还要满足年龄条件。

需求4:修改用户信息,如果某字段为null,则不修改这个字段

需求5:根据多个ID查询用户

<?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.hrh.mapper.UserMapper">

    <sql id="*">
        id,user_name,password,name,age,sex,birthday,created,updated
    </sql>
    <!--Id回填-->
    <insert id="insertUser" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
        insert into tb_user (<include refid="*"/>)
        VALUES (null,#{userName},#{password},#{name},#{age},#{sex},#{birthday},now(),now());
    </insert>

    <select id="queryByUP" resultType="User">
        select * from tb_user where user_name=#{username} and password=#{password};
    </select>

    <select id="queryById" resultType="User">
        select * from tb_user where id=${id};
    </select>

    <resultMap id="userResultMap" type="User">
        <id property="id" column="id"></id>
        <result property="userName" column="user_name"/>
    </resultMap>
    <select id="queryUserById" resultMap="userResultMap">
        select * from tb_user where id=#{id}
    </select>



    <!--查询所有男性用户,如果输入了姓名,则按照姓名模糊查找;如果没有输入则不管姓名-->
    <select id="query1" resultMap="userResultMap">
        select * from tb_user where sex=1
        <if test="name!=null and name.trim()!=''">
            and name like '%${name}%'
        </if>
    </select>

    <!--查询所有用户,传递参数orderType,如果值为0,按照年龄升序排序,
    如果为1则按照年龄降序排序,否则按照ID排序-->
    <select id="query2" resultMap="userResultMap">
        select * from tb_user
        <choose>
            <when test="orderType==0">order by age ASC </when>
            <when test="orderType==1">order by age desc </when>
            <otherwise>order by id asc</otherwise>
        </choose>
    </select>


    <!--查询所有用户,如果有姓名不为空,则按照姓名模糊查找;
    如果年龄也不为空,则还要满足年龄小于指定年龄。-->
    <select id="query3" resultMap="userResultMap">
        select * from tb_user
        <where>
            <if test="name!=null and name.trim()!=''">
                and name like '%${name}%'
            </if>
            <if test="age!=null">
                and age &lt; ${age}
            </if>
        </where>
    </select>

    <!--修改用户信息,如果某字段为null,则不修改这个字段-->
    <update id="update1">
        update tb_user
        <set>
            <if test="userName!=null and userName.trim()!=''">
                user_name = #{userName},
            </if>
            <if test="password!=null and password.trim()!=''">
                password = #{password},
            </if>
            <if test="name!=null and name.trim()!=''">
                name = #{name},
            </if>
            <if test="age!=null">
                age = #{age},
            </if>
            <if test="sex!=null">
                sex = #{sex},
            </if>
            <if test="birthday!=null">
                birthday = #{birthday},
            </if>
            updated = now()
        </set>
        where id=#{id}
    </update>

    <select id="query4" resultMap="userResultMap">
        select * from tb_user
        <where>
            <if test="ids!=null and ids.size()!=0">
                and id IN
                <foreach collection="ids" item="id" open="(" close=")" separator=",">
                    #{id}
                </foreach>

            </if>
        </where>
    </select>




</mapper>
package com.hrh.mapper;

import com.hrh.domain.User;
import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface UserMapper {

    //Id回显
    public void insertUser(User user);

    //用户名和密码查找用户
    public User queryByUP(@Param("username") String username,@Param("password") String password);

    //${}
    public User queryById(@Param("id") Long id);

    //resultMap 解决字段名不一致
    public User queryUserById(@Param("id")Long id);

    //动态sql if
    public List<User> query1(@Param("name") String name);

    //动态sql choose when otherwise
    public List<User> query2(@Param("orderType") Integer orderType);

    //动态sql where
    public List<User> query3(@Param("name") String name, @Param("age") Integer age);

    //动态sql set
    public void update1(User user);

    //动态sql foreach
    public List<User> query4(@Param("ids") List<Long> ids);


}
package com.hrh.mapper;

import com.hrh.domain.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;
import org.omg.PortableInterceptor.LOCATION_FORWARD;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import static org.junit.Assert.*;

public class UserMapperTest {
    UserMapper mapper;

    @Before
    public void setUp() throws Exception {
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        mapper=sqlSession.getMapper(UserMapper.class);
    }

    @Test
    public void insertUser() throws Exception {
        User user=new User();
        user.setName("嘻嘻嘻");

        mapper.insertUser(user);

        System.out.println(user.getId());
    }

    @Test
    public void queryByUP() throws Exception {
        User user = mapper.queryByUP("zhangsan", "123456");

        System.out.println(user);
    }

    @Test
    public void queryById() throws Exception {
        User user = mapper.queryById(1L);

        System.out.println(user);
    }

    @Test
    public void queryUserById() throws Exception {
        User user = mapper.queryUserById(2L);

        System.out.println(user);
    }

    @Test
    public void query1() throws Exception {
        List<User> users = mapper.query1(null);
        for (User user : users) {
            System.out.println(user);
        }
    }

    @Test
    public void query2() throws Exception {
        List<User> users = mapper.query2(1);
        for (User user : users) {
            System.out.println(user);
        }
    }

    @Test
    public void query3() throws Exception {
        List<User> users = mapper.query3("张",56);
        for (User user : users) {
            System.out.println(user);
        }
    }

    @Test
    public void update1() throws Exception {
        User user = mapper.queryById(1L);
        user.setAge(888);

        mapper.update1(user);

    }

    @Test
    public void query4() throws Exception {
        ArrayList<Long> list = new ArrayList<>();
        Collections.addAll(list,new Long[]{1L,2L,3L,4L});
        List<User> users = mapper.query4(list);
        for (User user : users) {
            System.out.println(user);
        }

    }


}

 

缓存

为数据库的查询进行缓存,是减少数据库压力的主要途径。分为一级缓存和二级缓存

一级缓存:session级别缓存,作用于当前会话。

二级缓存:SessionFactory级别缓存,作用于整个SessionFactory,多个会话之间可以共享缓存

一级缓存

  • 特点:

    • mybatis的一级缓存默认就是开启的,并且无法关闭。

    • mybatis的一级缓存作用域是当前session,一次openSession()后,如果相同的statement和相同参数,则不进行查询而是从缓存命中并且返回,如果没有命中则查询数据库。

    • 任何的增删改操作都会导致缓存被清空

    • 缓存会使用 Least Recently Used(LRU,最近最少使用的)算法来收回

二级缓存

  • 特点:

    • 二级缓存需要手动开启,开启的方式是在Mapper.xml中添加标签:<cache/>

    • mybatis-config.xml全局配置文件中,有一个配置,是二级缓存的全局开关,如果关闭,所有Mapper的二级缓存都会失效,默认是打开的。

    • 二级缓存的作用域是整个SessionFactory,并且是同一个Mapper中,如果namespace、statement和SQL参数一致,则缓存命中

    • 开启二级缓存后, 查询的对象需要实现序列化接口.

二级缓存的其他配置

所有的这些属性都可以通过缓存元素的属性来修改。比如:

<cache
  eviction="FIFO"
  flushInterval="60000"
  size="512"
  readOnly="true"/>

这个更高级的配置创建了一个 FIFO 缓存,并每隔 60 秒刷新,存数结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此在不同线程中的调用者之间修改它们会 导致冲突。

可用的收回策略有:

  • LRU – 最近最少使用的:移除最长时间不被使用的对象。

  • FIFO – 先进先出:按对象进入缓存的顺序来移除它们。

  • SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。

  • WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。

默认的是 LRU。

flushInterval(刷新间隔)可以被设置为任意的正整数,而且它们代表一个合理的毫秒 形式的时间段。默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新。

size(引用数目)可以被设置为任意正整数,要记住你缓存的对象数目和你运行环境的 可用内存资源数目。默认值是 1024。

readOnly(只读)属性可以被设置为 true 或 false。只读的缓存会给所有调用者返回缓 存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。可读写的缓存 会返回缓存对象的拷贝(通过序列化) 。这会慢一些,但是安全,因此默认是 false。

高级查询

一对一查询:一个订单只属于一个用户

    需求1:根据订单号 查询订单的同时,查询出订单所属用户

一对多查询:一个订单可以有多个订单详情

    需求2:根据订单号 查询订单,并且查询出所有订单详情及所属用户

多对多查询:订单中可以有多个商品,商品也可以属于多个订单

    需求3:根据订单号 查询订单,查询出所属用户,并且查询出订单的详情,及订单详情中的对应的商品信息

OrderMapper接口

package com.hrh.mapper;

import com.hrh.domain.Order;
import org.apache.ibatis.annotations.Param;

public interface OrderMapper {

    //需求1 两表查询
    public Order queryTwo(@Param("orderId")String orderId);
    //需求2 三表查询
    public Order queryThree(@Param("orderId")String orderId);
    //需求3 四表查询
    public Order queryFour(@Param("orderId")String orderId);


}

 OrderMapper.xml 配置文件 ( SQL语句 )

<?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.hrh.mapper.OrderMapper">
    <resultMap id="queryTwoResultMap" type="Order" autoMapping="true">
        <id property="oid" column="oid"/>
        <association property="user" javaType="User" autoMapping="true">
            <id property="id" column="user_id"/>
        </association>
    </resultMap>
    <resultMap id="queryThreeResultMap" type="Order" autoMapping="true" extends="queryTwoResultMap">
        <collection property="orderitemList" javaType="list" ofType="Orderitem" autoMapping="true">
            <id column="item_id" property="itemId"/>
        </collection>
    </resultMap>
    <resultMap id="queryFourResultMap" type="Order" autoMapping="true">
        <id property="oid" column="oid"/>
        <association property="user" javaType="User" autoMapping="true">
            <id column="id" property="id" />
        </association>
        <collection property="orderitemList" javaType="list" ofType="Orderitem" autoMapping="true">
            <id property="itemId" column="item_id"/>
            <association property="product" javaType="Product" autoMapping="true">
                <id property="pid" column="pid"/>
            </association>
        </collection>

    </resultMap>

    <!--根据订单号 查询订单的同时,查询出订单所属用户-->
    <select id="queryTwo" resultMap="queryTwoResultMap">
        SELECT * FROM tb_order o
        LEFT JOIN tb_user u ON o.user_id=u.id
        where o.order_number=#{orderId}
    </select>

    <!--根据订单号 查询订单,并且查询出所有订单详情及所属用户-->
    <select id="queryThree" resultMap="queryThreeResultMap">
        SELECT * FROM tb_order o
        LEFT JOIN tb_user u ON o.user_id=u.id
        LEFT JOIN tb_orderitem oi ON oi.order_id=o.oid
        WHERE o.order_number=#{orderId}
    </select>

    <!--根据订单号 查询订单,查询出所属用户,并且查询出订单的详情,及订单详情中的对应的商品信息-->
    <select id="queryFour" resultMap="queryFourResultMap">
        SELECT * FROM tb_order o
        LEFT JOIN tb_user u ON o.user_id=u.id
        LEFT JOIN tb_orderitem oi ON oi.order_id=o.oid
        LEFT JOIN tb_product p ON p.pid=oi.product_id
        WHERE o.order_number='20140921001'
    </select>




</mapper>

接口测试类

package com.hrh.mapper;

import com.hrh.domain.Order;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;

import java.io.InputStream;

import static org.junit.Assert.*;

public class OrderMapperTest {

    OrderMapper orderMapper;
    @Before
    public void setUp() throws Exception {
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        orderMapper=sqlSession.getMapper(OrderMapper.class);
    }

    @Test
    public void queryTwo() throws Exception {
        Order order = orderMapper.queryTwo("20140921003");
        System.out.println(order);
    }

    @Test
    public void queryThree() throws Exception {
        Order order = orderMapper.queryThree("20140921001");
        System.out.println(order);
    }

    @Test
    public void queryFour() throws Exception {
        Order order = orderMapper.queryFour("20140921001");
        System.out.println(order);
    }

}

猜你喜欢

转载自blog.csdn.net/QuietHRH/article/details/82345339
今日推荐