Mybaits(二)——查询参数问题(参数绑定、模糊查询、主键回填)、ORM映射(ResultMap结果集、TypeHandler类型转换器)、一对多映射(ResultMap的继承、懒加载)

6 篇文章 1 订阅
5 篇文章 0 订阅

Mybaits(二)——查询参数问题(参数绑定、模糊查询、主键回填)、ORM映射(ResultMap结果集、TypeHandler类型转换器)、一对多映射(ResultMap的继承、懒加载)

一、查询参数问题

1、前期准备

依赖导入:
在这里插入图片描述

mybatis-config.xml:
在这里插入图片描述

然后实体类:
在这里插入图片描述

然后 bookMapper:
在这里插入图片描述

测试:
在这里插入图片描述
在这里插入图片描述

2、参数绑定

a、默认一个参数

在这里插入图片描述

测试代码:
在这里插入图片描述

结果:
在这里插入图片描述

b、注解参数绑定(多个参数的情况下)

在这里插入图片描述
在这里插入图片描述
这里的多个参数比如集合、数组等或者直接就是三四个参数,不可以直接用参数名去引用,只能用 mybatis 原生提供的,原生提供的是 arg0,arg1,arg2…这种按顺序来,或者 param1,param2,param3…这种。如果要用参数名,需要用注解 @Param(“xx”) 。

测试:
在这里插入图片描述

c、map 参数绑定

如果是 map 类型的参数,可以当成一个普通对象来处理,比如里面有什么属性,可以直接写属性名。
在这里插入图片描述如果 map 类型加了别名,比如 m,则调用这个参数的时候需要 m.xxx 来调用。调用方式直接变了。
在这里插入图片描述
测试:
在这里插入图片描述

结果:
在这里插入图片描述

3、模糊查询

a、方式一—— #符号(推荐)

模糊查询数据库写法是 x%,这里不仅要处理百分号 % 的问题,还要处理字符传入的问题。
在这里插入图片描述
通过这种方式,传入数据,然后拼接百分号 %,即可完成模糊查询。

测试:
在这里插入图片描述

结果:
在这里插入图片描述
通过查看日志,看看这种方式怎么实现的:
在这里插入图片描述可以看到是通过占位符的方式来完成。这种就可以防止 sql 语句注入。

b、方式二——$符号(不推荐,不过有时候只能用这种方式)

在这里插入图片描述
结果:
在这里插入图片描述
可以看到这个是直接通过拼接的方式完成的。这种就有 sql 注入的风险。

# 和 $ 的区别:
        # 用的是 PreparedStatement,参数有占位符,后来再为占位符提供具体的参数,可以防止 sql 注入。
        $ 用的是 Statement,参数直接通过字符拼接加到 sql 中。

c、分组排序时只能用 $ 符号

也有不得不用 $ 符号的时候,比如分组排序的时候,用的 order by id desc ,如果用的是 # 符号,则明显起不了作用,用 $ 才有作用。

如果想把列的参数当做名字传进来,基本只能用 $ 符号。

4、主键回填

以前增加数据时要取到 ID,用的是主键回填的方式,这里有几种方式可以:

a、last_insert_id()

在数据库中执行 last_insert_id()这个函数,就可以取到,这个函数的意思是获取刚刚插入的数据 ID:
在这里插入图片描述
然后测试:
在这里插入图片描述
结果:
在这里插入图片描述

b、useGeneratedKeys —— 主键回填

在这里插入图片描述

c、使用 UUID 生成随机数作为 ID

还有一种需求就是 UUID 作为 ID。一般情况下,都是建议主键自增,主键自增存储效率高一些,主键索引是一个 B+ 树,有顺序的话都是一直往后面追加的。如果主键不是自增的话,主键就需要先找个合适的位置再插入,这种插入效率就会比较低。

如果用的是 UUID 来作为主键,这个时候就有两种需求,一种是 Java 生成 UUID ,再插入;还有一种是使用数据库的函数生成 UUID ,作为主键:
在这里插入图片描述

用 Java 代码生成的 UUID ,就没有主键回填的问题;用数据库的函数生成 UUID ,就需要主键回填:
在这里插入图片描述

二、ORM映射

1、MyBatis自动ORM失效

在这里插入图片描述
自动 ORM 映射有条件,就是属性名跟字段名要一一对应,或者说推断出来的要对应。

如果字段名跟属性名不对应,还可以在 sql 语句中使用别名 as 的方式来对应,但这种方式不算好的办法,不好复用。

一般用的是 mybatis 中的结果映射集:resultMap。

2、resultMap 结果集

在这里插入图片描述
使用这个结果集,以后映射关系会方便很多。

3、有参构造与无参构造

在这里插入图片描述

如果有这三种构造方法,会优先使用哪一种呢?
答案是:先是无参,如果没有无参就完整的有参,接着就是残缺的有参构造。

但是映射关系并不走有参构造方法的对应,走的是 get、set 方法。

在这里插入图片描述
然后去掉无参。
在这里插入图片描述
然后去掉这个有参。
在这里插入图片描述

可以看到顺序就是这样。

如果想要指定某个构造方法,可以通过下面这种方式:
在这里插入图片描述

4、TypeHandler——类型转换器

现在想要一种效果:在数据插入的时候,将 List 集合转为字符串,在数据读取的时候,将字符串自动转为 List。

比如一年级有两个班级,list 存储两个班级对象,存到数据库中时,只显示这两个班级的名字;那么这里就是 对象转为字符串了。取出来的时候,根据这个班级的名字取出对应的班级对象。

a、插入转换跟查询转换

那么此时可以用到 TypeHandler——类型转换器:
在这里插入图片描述

先测试一下:
在这里插入图片描述

可以看到输出没什么问题。

虽然最后多了个 逗号,不过不影响。

设置好后接着就是 mapper 文件设置:
在这里插入图片描述

然后测试结果:
在这里插入图片描述

查看数据库:
在这里插入图片描述

可以看到成功插入。

接着就是查询

//    下面的三个方法都是用于查询,虽然有三个方法,但干的都是一件事情。先看前两个,第一个方法是根据列名获取。
//     第二个方法时根据下标去获取。所以这里提供了两种方式

    /**
     *  查询的时候调用
     * @param resultSet
     * @param columnName 列名
     * @return  手动解析查询结果,返回 list 集合。
     * @throws SQLException
     */
    public List<String> getResult(ResultSet resultSet, String columnName) throws SQLException {
        String s = resultSet.getString(columnName);
//        查询到的 足球,篮球, 按照 “ ,” 拆分成数组,再将数组转换为集合。
        if (s !=null && "".equals(s)){
            List<String> list = Arrays.asList(s.split(","));
            return list;

        }
        return null;
    }

    public List<String> getResult(ResultSet resultSet, int columnIndex) throws SQLException {
//        这里的写法跟上面是通用的。
        String s = resultSet.getString(columnIndex);
//        查询到的 足球,篮球, 按照 “ ,” 拆分成数组,再将数组转换为集合。
        if (s !=null && !"".equals(s)){
            List<String> list = Arrays.asList(s.split(","));
            return list;

        }
        return null;
    }

    /**
     *  如果调用的是存储过程的话,会触发该方法。
     * @param cs
     * @param i
     * @return
     * @throws SQLException
     */
    public List<String> getResult(CallableStatement cs, int i) throws SQLException {
        //        这里的写法跟上面是通用的,只需要改动一点点地方
        String s = cs.getString(i);
//        查询到的 足球,篮球, 按照 “ ,” 拆分成数组,再将数组转换为集合。
        if (s !=null && "".equals(s)){
            List<String> list = Arrays.asList(s.split(","));
            return list;
        }
        return null;

    }

然后就是配置 mapper 文件:
在这里插入图片描述

接着就是测试:
在这里插入图片描述

可以看到,测试没问题。

b、全局指定(全局转换)

在 mybatis-config.xml 文件里面配置全局:
在这里插入图片描述

全局配置了这个,原先配置 typehandler 的地方 都可以去掉了。

按照这个测试,没有问题。

同样的,全局配置也可以不指定后面那两个,通过注解来指定:
在这里插入图片描述

然后注解,在类上面配置:
在这里插入图片描述

三、一对多映射

1、一对多

一对多跟一对一用法近似。

首先是年级类,然后是班级,一个年级有好几个班级。

先看下实体类:
在这里插入图片描述

在这里插入图片描述

然后是 mapper:
在这里插入图片描述
然后测试结果:
在这里插入图片描述

2、ResultMap的继承——extends

在一个 mapper 文件中,可能会有很多个 ResultMap ,不可避免的会发生很多重复的代码,比如:
在这里插入图片描述

红色框框中就很明显是重复了的代码,所以这里就需要通过继承,来完成代码的复用:
在这里插入图片描述
这样就能一段代码就能多次使用,不用写重复部分的代码,后面的只需要写不同部分的代码即可。

3、根据 xx 去查询 xx(不推荐,好处是懒加载)

还有个用法,这个用法用于查询,但是不太推荐。可以先获取年级,再根据年级ID获取班级;但是这么一来会执行很多次查询语句,但是有一个好处就是有懒加载,就是调用到查询班级的方法才会去查询班级,不然就不会调用这个方法。 这个功能是上面所没有的,因为上面的方法是一下子就把所有数据查出来了。

看代码:

接口:
在这里插入图片描述
clazz mapper 文件:
在这里插入图片描述
grade mapper 文件:
在这里插入图片描述

看结果:

第一种是查询所有,可以看到执行了好几条 sql 语句:
在这里插入图片描述

另一种结果是只查询年级名字,但是结果中不会去查询到班级的数据:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值