Mybatis

执行方案出现如下情况,即有的数据没有被成功赋值:

解决方式:

通过给字段起别名
通过resultMap的方式手动定义字段和属性的映射

resultMap是Mybatis用于解决数据库列名与POJO属性名不匹配问题的强大工具,它可以在查询,插入,更新操作中灵活地重命名参数。

标签

sql标签:将需要复用的sql片段放进去
同时有很多个mapper接口可能会用到这一段sql,我们可以将其提取出来。
往往结合include标签,将sql的id引入进来

<sql id="brand_column">
 id, brand_name as brandName, company_name as companyName, ordered, description, status
 </sql>

<select id="selectAll" resultType="brand">
    select
    <include refid="brand_column" />
    from tb_brand;
 </select>

resultMap标签:

在上面只需要指定字段名和属性名不一样的映射,而一样的则不需要专门定义出来。
并且将来通过resultMap来指定id,而不是resultType

 <resultMap id="brandResultMap" type="brand">
    <!--
            id:完成主键字段的映射
                column:表的列名
                property:实体类的属性名
            result:完成一般字段的映射
                column:表的列名
                property:实体类的属性名
        -->
    <result column="brand_name" property="brandName"/>
    <result column="company_name" property="companyName"/>
 </resultMap>


 <select id="selectAll" resultMap="brandResultMap">
    select *
    from tb_brand;
 </select

 parameterType:
用于指定参数类型,这里我们mapper接口的方法中,传入AddressBook的引用参数
当然mapper接口无参不用指定
返回值为AddressBook类型,不用写全类名
这里还涉及到动态sql,常用的where标签和if标签

<select id="list" parameterType="AddressBook" resultType="AddressBook">
    select * from address_book
    <where>
        <if test="userId != null">
            and user_id = #{userId}
        </if>
        <if test="phone != null">
            and phone = #{phone}
        </if>
        <if test="isDefault != null">
            and is_default = #{isDefault}
        </if>
    </where>
</select>

占位符

mybatis提供了两种占位符:
#{} :参数占位符,执行SQL时,会将 #{} 占位符替换为?,将来自动设置参数值。从上述例子可以看出使用#{} 底层使用的是 PreparedStatement 
${} :变量占位符,拼接SQL。底层使用的是statement,会存在SQL注入问题

这里提一嘴statement与preparedStatement:
statement 每条sql语句都会编译一次,导致如果是相同的sql也会重复编译,影响性能,并且存在sql注入的问题,不安全
而prepareddStatement 每条sql只会预编译一次,即相同的sql不会编译多次,并且能防止sql注入

SQL语句中特殊字段处理

< 和 > 在xml文件中有特殊含义,我们需要进行转义

动态SQL

if标签:条件判断
 test属性:逻辑表达式

where标签
替换where关键字
会动态的去掉第一个条件前的 and
如果所有的参数没有值则不加where关键
注意:需要给每个条件前都加上 and 关键字。

 <where>
        <if test="status != null">
            and status = #{status}
        </if>
        <if test="companyName != null and companyName != '' ">
            and company_name like #{companyName}
        </if>
        <if test="brandName != null and brandName != '' ">
            and brand_name like #{brandName}
        </if>
    </where

 插入操作

在数据添加成功后,有时候需要获取插入数据库数据的主键
我们通过useGeneratedKeys打开主键自增,并且将主键的返回值封装到id属性
id为主键,我们在插入的时候直接跳过即可,不需要我们赋值

<insert id="add" useGeneratedKeys="true" keyProperty="id">
 insert into tb_brand (brand_name, company_name, ordered, description, status)
 values (#{brandName}, #{companyName}, #{ordered}, #{description}, #{status});
 </insert>

修改操作

set标签 :可以用于动态包含需要更新的列,忽略其它不更新的列。
当然,也会用到if标签和where标签

<update id="update">
 update tb_brand
 <set>
 <if test="brandName != null and brandName != ''">
 brand_name = #{brandName},
 </if>
 <if test="companyName != null and companyName != ''">
 company_name = #{companyName},
 </if>
 </set>
    where id = #{id};
 </update>

删除操作

删除一行

<delete id="deleteById">
 delete from tb_brand where id = #{id};
 </delete>

删除多行

会涉及到foreach标签,因为删除多行,一般都是以集合或者数组的形式传过来,我们可以遍历获取其中的值 

foreach标签

用来迭代任何可迭代的对象(如数组,集合)。
collection 属性: mybatis会将数组参数,封装为一个Map集合。
默认:array = 数组 当然,通过@Param注解,这样map集合名称和接口中的参数名一致
item 属性:本次迭代获取到的元素。
separator 属性:集合项迭代之间的分隔符。foreach 标签不会错误地添加多余的分隔符。也就是最后一次迭代不会加分隔符
open 属性:该属性值是在拼接SQL语句之拼接的语句,只会拼接一次
close 属性:该属性值是在拼接SQL语句拼接拼接的语句,只会拼接一次

 <delete id="deleteByIds">
 delete from tb_brand where id
 in
 <foreach collection="array" item="id" separator="," open="(" close=")">
 #{id}
 </foreach>
 ;
 </delete>
等价于
delete from tb_brand where id in (1,2,3);

 当mapper接口参数有多个的时候,考虑用@Param注解,增加可读性

User select(@Param("username") String username,@Param("password") String password);

原理:

我们在接口方法中定义多个参数,Mybatis 会将这些参数封装成 map 集合,其中value就是参数值,而key在没有使用 @Param注解时有以下命名规则:

以 arg开头 : 第一个参数就叫 arg0,第二个参数就叫 arg1,依次类推
以 param 开头 : 第一个参数就叫 param1,第二个参数就叫 param2,依次类推

这样的话可读性会非常差,建议使用@Param注解,Mybatis 会将 arg 开头的键名替换为对应注解的属性值。

Mybatis参数传递

这里涉及mapper接口参数是单个还是多个

多个参数:就是一次传了好几个参数,如上面代码

单个参数:一次传一个参数,这里的一个可以指一个集合、数组或者一个POJO对象
集合包括List、Collection、Map
实际代码中,List、Collection、Array最好是通过@Param注解指定key的名称,不然可读性不高

以上需要@Param注解指定key名称,因为当没有@Param注解时:

mybatis底层会自动将它们封装为map集合,然后会给一套默认的key,我们需要用它默认的key,如arg0这样的去获得我们真正的集合对象。如果我们用默认给的key,可读性不高

说了这么多,List、Collection、Array这种用的都比较少,一般都是直接传POJO对象,或者说传集合过来,然后我们进行批量删除或批量添加【通过foreach标签】。


而POJO、Map不需要通过@Param注解来指定

原因是:Map对象本身就是一个map,它就不会走mybatis底层的map封装;

而POJO对象,mybatis默认情况下会通过反射机制,按照POJO的属性名来与SQL中的占位符进行映射。所以如果POJO对象的属性名我们不需要去额外变动的话,就不需要@Param注解。
相反,如果我们需要去额外指定的话,我们可以通过@Param来指定名称
或者
使用resultMap来手动完成映射

下面是一条update语句,参数为POJO,即addresBook对象,我们不需要通过@Param去指定

void update(AddressBook addressBook);
<update id="update" parameterType="addressBook">
    update address_book
    <set>
        <if test="consignee != null">
            consignee = #{consignee},
        </if>
        <if test="sex != null">
            sex = #{sex},
        </if>
        <if test="phone != null">
            phone = #{phone},
        </if>
        <if test="detail != null">
            detail = #{detail},
        </if>
        <if test="label != null">
            label = #{label},
        </if>
        <if test="isDefault != null">
            is_default = #{isDefault},
        </if>
    </set>
    where id = #{id}
</update>

常见面试题

一、Dao接口中的方法,参数不同时,方法能重载吗?

可以的,我们通过if标签和test属性,通过动态sql进行动态的判断就可以了。

/**
 * Mapper接口里面方法重载
 */
public interface StuMapper {

 List<Student> getAllStu();

 List<Student> getAllStu(@Param("id") Integer id);
}


<select id="getAllStu" resultType="com.pojo.Student">
  select * from student
  <where>
    <if test="id != null">
      id = #{id}
    </if>
  </where>
</select>

二、Mapper接口【Dao接口】的工作原理是什么?

通常一个 xml 映射文件,都会写一个 Dao 接口与之对应。Dao 接口就是人们常说的 Mapper 接口,接口的全限名,就是映射文件中的 namespace 的值,接口的方法名,就是映射文件中 MappedStatement 的 id 值,接口方法内的参数,就是传递给 sql 的参数。 Mapper 接口是没有实现类的,当调用接口方法时,接口全限名+方法名拼接字符串作为 key 值,可唯一定位一个 MappedStatement。
在 MyBatis 中,每一个 <select>、 <insert>、 <update>、 <delete> 标签,都会被解析为一个 MappedStatement 对象。
Dao 接口的工作原理是 JDK 动态代理,MyBatis 运行时会使用 JDK 动态代理为 Dao 接口生成代理 proxy 对象,代理对象 proxy 会拦截接口方法,转而执行 MappedStatement 所代表的 sql,然后将 sql 执行结果返回。

三、Mybatis怎么执行一对一、一对多的关联查询?

  • 一对一,使用<resultMap>做配置
  • 一对多,使用<resultMap><collection>做配置
  • 多对多,使用<resultMap><collection>做配置

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值