Mybatis入门学习记录( 二 ) : mapper的多参数映射和resultMap结果集

一、mapper参数映射

        当mapper.xml在接受java的mapper接口传输过来的参数时,我们如果只传输一个参数时我们可以这么传输:

public User queryById(Integer id);

同时我们可以这么接收参数:

<!-- 
    resultType是遍历后得到的结果的类型,可自定义,
    parameterType是传入的参数的类型,也可以是自己写的实体类 
-->    
    <select id="queryById" parameterType="int"  resultType="com.fs.entity.User">
       select * from  tb_user   where id = #{id}
    </select>

编译测试类:

public class UserMapperTest {
    private UserMapper userMapper;
    private SqlSession sqlSession;

    @Before
    public void setUp() throws Exception {
        //怎么得到Mapper接口的实现类的对象
        // sqlSession.getMapper(Mapper接口的Class类型)  得到Mapper接口的实现类的对象
        //加载解析: mybatis的主配置文件:mybatis-config.xml
        InputStream in = Resources.getResourceAsStream("mybatis-config.xml");

        //通过第一步解析的结果,创建SqlSessionFactory对象, 构建者模式: SqlSessionFactoryBuilder
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);

        //通过SqlSessionFactory对象创建SqlSession(使用的核心对象)
        sqlSession = sqlSessionFactory.openSession();

        userMapper =sqlSession.getMapper(UserMapper.class);
    }

    @Test
    public void queryById() {
//        userMapper.queryById(1);
        System.out.println(userMapper.queryById(1));
    }
}

测试结果:

这样是不会有任何问题的,但是当我们要传输多个参数时:

public User queryByNameAndPwd(String username,String password);
<!-- 
    resultType是遍历后得到的结果的类型,可自定义,
    parameterType是传入的参数的类型,也可以是自己写的实体类 
-->     
    <select id="queryByNameAndPwd" resultMap="userResultMap">
        SELECT * FROM  tb_user WHERE username = #{username} AND PASSWORD=#{password}
    </select>

运行后,出现报错,情况如下!

Caused by: org.apache.ibatis.binding.BindingException: Parameter 'username' not found. Available parameters are [0, 1, param1, param2]

那么这个问题怎么解决?这里我们有以下几种种解决方法:

①在xml中引用参数的地方设置为#{0}, #{1},.....等(这是从0开始)

<!-- 
    resultType是遍历后得到的结果的类型,可自定义,
    parameterType是传入的参数的类型,也可以是自己写的实体类 
--> 
<select id="queryByNameAndPwd" resultMap="userResultMap">
        SELECT * FROM  tb_user WHERE username = #{0} AND PASSWORD=#{1}
    </select>

②在xml中引用参数的地方设置为#{param1} ,#{param2}.....等(这是从1开始)

<!-- 
    resultType是遍历后得到的结果的类型,可自定义,
    parameterType是传入的参数的类型,也可以是自己写的实体类 
--> 
    <select id="queryByNameAndPwd" resultMap="userResultMap">
        SELECT * FROM  tb_user WHERE username = #{param1} AND PASSWORD=#{param1}
    </select>

③引用注解:@Param()给参数起个别名(推荐),因为这样具有更高的代码可读性

public User queryByNameAndPwd(@Param("username") String username, @Param("password")String password);

然后在xml中我们只需要使用别名代表参数即可!

<!-- 
    resultType是遍历后得到的结果的类型,可自定义,
    parameterType是传入的参数的类型,也可以是自己写的实体类 
-->  
    <select id="queryByNameAndPwd" resultMap="userResultMap">
        SELECT * FROM  tb_user WHERE username = #{username} AND PASSWORD=#{password}
    </select>

上述三种均可成功,在这就展示一次结果就好了!

④不同于以上几种,我们可以选择不用一个一个地写入参数,我们可以利用JAVA的封装思想将参数封装成一个实体类再作为参数传入!(举例)

实体类:

import lombok.Data;
@Data
public class User {
    private Integer id;
    private String username;
    private String password;
}

测试类:

@Test
    public void queryById() {
//        userMapper.queryById(1);
        User user = new User();
        user.setId(1);
        user.setUsername("admin");
        System.out.println(userMapper.queryById(user));
    }

接口方法:

public User queryById(User user);

statement:

<!-- 
    resultType是遍历后得到的结果的类型,可自定义,
    parameterType是传入的参数的类型,也可以是自己写的实体类 
-->    
    <select id="queryById" parameterType="int"  resultType="com.fs.entity.User">
       select * from user  where id = #{id} and username = #{username}
    </select>

结果:

 这正是因为mybatis会在statement运行的时候,将里面的#{id}和#{username}自动与我们传入的User对象中的id和username进行映射,然后根据user对象中的信息进行查询!

但是哈,我说但是,如果你在传输的时候啊,加上了@Param()的话,那就会不太一样了!

然后mapper的java接口里这么写:

public User queryById(@Param("user") User user);

好家伙,那你可真是给自己找了麻烦,如果你这样写,那你就需要在你的statement里修改成这样:user.username和user.id

<!-- 
    resultType是遍历后得到的结果的类型,可自定义,
    parameterType是传入的参数的类型,也可以是自己写的实体类 
-->    
    <select id="queryById" parameterType="com.fs.entity.User"  resultType="com.fs.entity.User">
       select * from user  where id = #{user.id} and username = #{user.username}
    </select>

不改?还是写#{id}和#{username}?来,下面这个找不到参数的错误就是你不改的后果哦!

 改完运行test方法,OK搞定:

 二、resultMap结果集自定义

(一)基本的resultMap讲解

有时候啊,当我们查询的结果不是我们现有的实体类,或者字段名和自己写的实体类名有冲突,而你又不想再建一个实体类也不想改动现有的实体类咋办啊?(经典实体类设计者和数据库表设计者大型纷争现场)

那就自己定义一个结果集呗!

举个例子:

①我数据库中的图片路径的字段名是img_path:

 然后我给的实体类的图片路径名又是:gd_img:

得了,这回mybatis想救你都难了,只能自己手动映射一个结果集了:

其中:

  ①resultMap 里的 id 是这个结果集的名称,直接在你的statement中的resultType中填入就行
  ②resultMap 里的 type 就是实体类名称

  ③result 中的 id 是表示的唯一主键

  ④result 中的 property  是 实体类中对应的参数名
  ⑤result 中的 column   是 数据库中查询出来的对应的列名

    <!-- 
        id是这个结果集的名称,到时候直接在你的statement中的resultType中填入就行
        type就是实体类名称
     -->
    <resultMap id="GoodsContent" type="GoodsContent">
        <id property="gd_id" column="gd_id"/>
        <!-- 
            这里就是映射: 
            property  是实体类中对应的参数名
            column    是数据库中查询出来的对应的列明 
        -->
        <result property="gd_img" column="img_path"/>
        <result property="price" column="gd_price"/>
        <result property="s_id" column="s_id"/>
        <result property="s_name" column="s_name"/>
        <result property="g_data" column="g_data"/>
        <result property="g_datail" column="g_datail"/>
        <result property="g_name" column="g_name"/>
    </resultMap>

 然后在statement中这么写,只需要在statement中的resultMap中填入上面的resultMap的id即可:

    <select id="queryGoodContent" resultMap="GoodsContent">
        SELECT GD.gd_id,GD.gd_price,STO.s_id,STO.s_name,GS.g_data,GS.g_datail,GS.g_name,img.img_path
        FROM good_detail GD
        JOIN store STO ON GD.s_id = STO.s_id
        JOIN goods GS ON GS.g_id = GD.G_ID
        JOIN img_path img ON GD.gd_id = img.gd_id
        WHERE GD.gd_id = #{gdId}
    </select>

然后执行一下接口测试(controller和service就省略了,只展示结果,请忽略我的乱码,懒得改编码了):

 (二)resultMap的使用:结果集中嵌套多层list实体类结果集

很多人想问,为什么我查个数据要嵌套多层结果集啊?

那么假设你现在想要只能使用一个statement接口实现一个功能查询一个用户的所有的订单(多条),每条订单里又包括了多条订单详情,然后每个订单详情中又包含了多个商品

[ 一 ]resultMap嵌套一个实体类:

想要在resultMap中嵌套多层list集合实体类的话,我们首先需要的是这几个实体类(这里偷懒写在一个代码块中,但是实际是分开的):

//User实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
//用户表
public class User implements Serializable {
    private int id;
    private String username;
    private List<Orders> ordersList = new ArrayList<>();

}

//Orders实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Orders {
    private Integer oId;
    private String OData;
    private Integer uidV;
    private List<OrderDetail> orderDetailList = new ArrayList<>();
}

//OrderDetail实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class OrderDetail {
    private Integer odId;
    private String odData;
    private int gidV;
    private List<Goods> goodsList = new ArrayList<>();
}

//Goods商品类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Goods {
    private Integer gId;
    private String gName;
    private double gPrice;
}

然后我们的mapper接口只需要传入一个用户id即可:

  public User queryUserAndOrderDetailByUid(@Param("uid")Integer uid);

接着我们去写mapper.xml中resultMap

这里就要引出我们resultMap中的另一个标签:<collection></collection>

这个标签可以当做是用于在一个结果集中嵌套生成了另一个结果集

而这个结果集中的property是指当前这个collection所表示实体类中的list集合的属性名

例如第一个collection中的property是ordersList,那代表的就是User实体类中的ordersList

然后我们配置好字段名和属性名的映射,我们的resultMap就完成了!

<resultMap id="UserAndAllOrderDetail" type="User">
    <!-- 先映射的是User的属性 -->
        <id property="id" column="id"/>
        <result property="username" column="username"/>
        <!--配置关联属性: orderDetailList
        集合属性:   collection
        属性:
        property: 关联属性名
        ofType: 集合的元素的类型, 映射的与集合的元素映射
        -->
        <collection property="ordersList" ofType="Orders">
            <id column="oid" property="oId"/>
            <result column="OData" property="OData"/>
            <collection property="orderDetailList" ofType="OrderDetail">
                <id property="odId" column="odId"/>
                <result column="odData" property="odData"/>
                <collection property="goodsList" ofType="Goods">
                    <id column="gId" property="gId" />
                    <result property="gName" column="gName"/>
                    <result property="gPrice" column="gPrice"/>
                </collection>
            </collection>
        </collection>
    </resultMap>

 然后我们去写mapper.xml中的statement:

<!-- 别学着我写*,不然会被项目组长骂(吧?) --> 
<select id="queryUserAndOrderDetailByUid" parameterType="int" resultMap="UserAndAllOrderDetail">
        SELECT * FROM USER u
        JOIN ORDERS o
        ON u.id = o.uidV
        JOIN orderdetail OD
        ON OD.oidV = o.oid
        JOIN GOODS G
        ON G.odIdV = OD.odid
        WHERE U.ID = #{uid}
    </select>

最后我们去写测试类Test:

public class UserOrderMapperTest {
    private UserOrderMapper userOrderMapper;
    private SqlSession sqlSession;
    @Before
    public void setUp() throws Exception {
        //怎么得到Mapper接口的实现类的对象
        // sqlSession.getMapper(Mapper接口的Class类型)  得到Mapper接口的实现类的对象
        //加载解析: mybatis的主配置文件:mybatis-config.xml
        InputStream in = Resources.getResourceAsStream("mybatis-config.xml");

        //通过第一步解析的结果,创建SqlSessionFactory对象, 构建者模式: SqlSessionFactoryBuilder
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);

        //通过SqlSessionFactory对象创建SqlSession(使用的核心对象)
        sqlSession = sqlSessionFactory.openSession();

        userOrderMapper =sqlSession.getMapper(UserOrderMapper.class);
    }
    @Test
    public void querayUserAndAllOrderDetailById(){
        System.out.println(userOrderMapper.queryUserAndOrderDetailByUid(1));

    }
}

好了,到这里我们就可以运行了,结果:

 为了直观点看我复制出来理一下顺序:

User(id=1, username=admin,

         ordersList=[

                Orders(oId=1, OData=简介1, uidV=null,

                        orderDetailList=[

                                OrderDetail(odId=1, odData=订单详情1, gidV=0,

                                        goodsList=[

                                                Goods(gId=1, gName=苹果, gPrice=10.0),

                                                Goods(gId=2, gName=香蕉, gPrice=5.0)]),

                                OrderDetail(odId=2, odData=订单详情2, gidV=0,

                                        goodsList=[

                                                Goods(gId=3, gName=葡萄, gPrice=7.0),

                                               Goods(gId=4, gName=橘子, gPrice=6.0)])]),

                Orders(oId=2, OData=简介2, uidV=null,

                        orderDetailList=[

                                OrderDetail(odId=3, odData=订单详情3, gidV=0,

                                        goodsList=[

                                                Goods(gId=5, gName=水蜜桃, gPrice=3.0),

                                                Goods(gId=6, gName=冬枣, gPrice=8.0)]),

                                OrderDetail(odId=4, odData=订单详情4, gidV=0,

                                        goodsList=[

                                                Goods(gId=7, gName=西瓜, gPrice=20.0),

                                                Goods(gId=8, gName=哈密瓜, gPrice=10.0)

])])])

那么到这里,mabatis的入门学习使用也就到一段落了,感谢各位赏脸浏览,不知道我讲清楚没有,望大佬轻喷,感恩戴德!

  • 6
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值