MyBatis中映射文件中数据库的操作

说明: *.src/mapper/*中所有接口对应的*.xml文件(快捷方式:1.Database连接MySQL并借助Mybatis datasource插件生成)

​ 作用:通过实现com.lycl.ssmdemo.mapper.*Mapper.java接口中的方法,进行相应的数据库操作。


[1]多表关联

​ ①一对多:对集合属性进行封装

	<!--一对多   对集合属性进行封装   ofType不能省略-->
    <collection property="questions" ofType="com.wanmait.demo.pojo.Question">
      <id column="question_id" jdbcType="INTEGER" property="id" />
      <result column="question_title" jdbcType="VARCHAR" property="title" />
    </collection>

​ ②多对一:对实体类中包含的实体类进行封装

	<!--多对一 对实体类中包含的实体类进行封装 javaType可以省略-->
    <association property="questionType" javaType="com.wanmait.demo.pojo.QuestionType">
      <id column="question_type_id" jdbcType="INTEGER" property="id" />
      <result column="question_type_title" jdbcType="VARCHAR" property="title" />
    </association>

[2]传参方式

​ ①传参param/arg

<select id="selectPage" resultMap="BaseResultMap">
    select <include refid="Base_Column_List"></include>
    from question_type
    where question_type.enable=1
    order by question_type.sort desc
    limit #{param1},#{param2}
    limit #{arg1},#{arg2}
  </select>

​ ②在Mapper接口中加@Param(“名称”)注解

​ 1.当Mapper接口中的参数为普通参数时(如Integer/String等),可以用自定义名称,也可以用param1,param2...(按照顺序)

//Mapper接口中
List<QuestionType> selectPage(@Param("offset") Integer offset,@Param("pageSize") Integer pageSize);
<!--mapping中的Mapper.xml中-->
 <select id="selectPage" resultMap="BaseResultMap">
    select <include refid="Base_Column_List"></include>
    from question_type
    where question_type.enable=1
    order by question_type.sort desc
    limit #{offset},#{pageSize}
    <!--注意:也可以用param,也能混用,但是一般不这么用
		limit #{param1},#{param2}-->
  </select>

​ 2.当Mapper接口中的参数为单个实体对象时(如new的Userinfo/Question 等),xml中要以“名称.属性名

//Mapper接口中
int insert(@Param("question") QuestionType record);
  <!--mapping中的Mapper.xml中-->
<insert id="insert" keyColumn="id" keyProperty="id" parameterType="com.wanmait.demo.pojo.QuestionType" useGeneratedKeys="true">
    insert into question_type (title,sort)
    values (#{question.title,jdbcType=VARCHAR}, #{sort,jdbcType=INTEGER})
</insert>

​ 3.当Mapper接口中的参数既有普通参数,又有实体对象时,要对所有的参数自定义名称,在xml中调用时,对象以“名称.属性名”,普通参数以“名称”即可。


[3]动态sql

拓展:

​ (1)trim的用法

作用:可以代替

属性:prefix 最前缀有谁

​ suffix 最后缀有谁

​ prefixOverrides 前缀省略谁

​ suffixOverrides 后缀省略谁

​ (2)concat的用法:

作用:拼接字符串,数据之间用逗号隔开

1.多条件查询:(在多条件查询时,写where条件时,前缀可能会出现多and或者or,需要去掉多余的and/or)

方法:

​ (1)可以去掉多余的and/or

​ (2)用代替 :

​ (3)在初始条件添加 1=1 这样就能保证剩余的条件开头可以接and/or

<select id="search" resultMap="BaseResultMap" parameterType="com.wanmait.demo.pojo.QuestionType">
    select <include refid="Base_Column_List"></include>
    from question_type
    /*where 1=1*/
    /*直接这样写可能会造成多一个and,
    方法一:
    		可以在where后加一个1=1 
    方法二:
    		直接写在<where></where>标签中,可以去掉多余的and/or
    */
     <!--<trim prefix="where" prefixOverrides="and|or">-->
   <where>
    <if test="title != null and title != ''">
    /*concat拼接字符串,数据之间用逗号隔开*/
       and title like concat('%',#{title} ,'%')
    </if>
    <if test="questionCount != null">
        and question_count=#{questionCount}
    </if>
    <if test="sort != null">
        and sort=#{sort}
    </if>
    <if test="enable != null">
        and enable=#{enable}
    </if>
   </where>
    <!--</trim>-->
  </select>

2.多条件修改:(在多条件修改时,写set条件时,后缀可能会出现多逗号,需要去掉多余的逗号)

方法:

​ (1)可以去掉多余的逗号

​ (2)用代替:

<update id="update">
    update question_type
    <!--<trim>可以代替<set>和<where>
          prefix 最前缀有谁
          suffix 最后缀有谁
          prefixOverrides 前缀省略谁
          suffixOverrides 后缀省略谁
        -->
    <trim prefix="set" suffixOverrides=",">
        <if test="title != null">
            title=#{title},
        </if>
        <if test="questionCount != null">
            question_count=#{questionCount},
        </if>
        <if test="sort != null">
            sort=#{sort}
        </if>
        where id = #{id}
        <!-- </set>-->
    </trim>
</update>

3.多条件增加:(在多条件增加时,写检索列和values条件时,后缀可能会出现多逗号,以及不确定是否何处添加括号

方法:

​ (1)检索列:

​ values:

<insert id="insertSelective" keyColumn="id" keyProperty="id" parameterType="com.wanmait.demo.pojo.QuestionType"
            useGeneratedKeys="true">
        insert into question_type
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="title != null">
                title,
            </if>
            <if test="questionCount != null">
                question_count,
            </if>
            <if test="sort != null">
                sort,
            </if>            
        </trim>
        <trim prefix="values (" suffix=")" suffixOverrides=",">
            <if test="title != null">
                #{title,jdbcType=VARCHAR},
            </if>
            <if test="questionCount != null">
                #{questionCount,jdbcType=INTEGER},
            </if>
            <if test="sort != null">
                #{sort,jdbcType=INTEGER},
            </if>     
        </trim>
    </insert>

[4]批量操作中数据的循环

方法:

​ (1)运行${ids}拼接实现批量操作,不需要循环:

​ 将QuestionTypeServiceImpl中ids字符串传入deleteBatch方法中形参列表中,xml中对ids进行拼接操作

​ 实现效果:“update question_type set enable = 0 where id in (” + ids + “)”

​ 即:update question_type set enable = 0 where id in (1,25,3,6)

<delete id="deleteBatch">
    update question_type set enable = 0 where id in (${ids})
</delete>

​ (2)运用对数据进行循环,实现#{id}的传输方式

​ 首先,QuestionTypeServiceImpl中将数据放入List集合/Integer[]数组中:

在xml中对list数据进行循环:

​ foreach属性:

​ collection:循环数组的类型

​ open:开始添加内容

​ close:结束添加内容

​ separator:每个数据间添加内容

​ item:循环的单个数据的名称

​ index:索引号的名称(一般没啥用)

​ 实现效果:update question_type set enable = 0 where id (?,?,?)

方法一:List集合:

QuestionTypeMapper.xml

<delete id="deleteBatch1">
    update question_type set enable = 0 where id
    in
    <foreach collection="list" open="(" close=")" separator="," item="id">
        #{id}
    </foreach>
</delete>

QuestionTypeServiceImpl:

 @Override
public void delete1(String ids) {
    String[] idStrArr = ids.split(",");
    List<Integer> idList = new ArrayList<>();
    for (String idStr : idStrArr) {
        idList.add(Integer.parseInt(idStr));
    }
    questionTypeMapper.deleteBatch1(idList);
}

方法二:Integer数组:

QuestionTypeMapper.xml

<delete id="deleteBatch2">
    update question_type set enable = 0 where id
    in
    <foreach collection="array" open="(" close=")" separator="," item="id">
        #{id}
    </foreach>
</delete>

QuestionTypeServiceImpl:

 @Override
public void delete2(String ids) {
    String[] idStrArr = ids.split(",");
    Integer[] idArr = new Integer[idStrArr.length];
    for (int i = 0; i < idArr.length; i++) {
        idArr[i] = Integer.parseInt(idStrArr[i]);
    }
    questionTypeMapper.deleteBatch2(idArr);
}

方法三:哈希HashMap:

QuestionTypeMapper接口:

void deleteBatch4(Map<String,Object> map);

QuestionTypeServiceImpl实现类:

 @Override
public void delete(String ids) {
    String[] idStrArr = ids.split(",");
    List<Integer> idList = new ArrayList<>();
    for (String idStr : idStrArr) {
        idList.add(Integer.parseInt(idStr));
    }
    Map<String,Object> map = new HashMap<>();
    map.put("idList",idList);
    map.put("title","a123");
    questionTypeMapper.deleteBatch4(map);
}

QuestionTypeMapper.xml:映射文件中的参数名要和业务逻辑层设置的map的键名要一致,不建议使用

<delete id="deleteBatch4">
    update question_type set enable = 0 where id
    in
    <foreach collection="idsList" open="(" close=")" separator="," item="id">
        #{id}
    </foreach>
    and title like concat('%',#{title},'%')
</delete>

拓展1:

​ 当传递多个参数时,在QuestionTypeMapper中运用@Param("名称")注解,则xml中foreach中collection的值为该名称 (SpringBoot中@Param注解可以省略,sp会自动加@Param,直接用形参名即可)

QuestionTypeMapper中的接口: @Param("ids")

void deleteBatch3(@Param("ids") List<Integer> ids,@Param("title") String title);

xml中:collection="ids"或者collection="param1"

<delete id="deleteBatch3">
    update question_type set enable = 0 where id
    in
    <foreach collection="ids" open="(" close=")" separator="," item="id">
        #{id}
    </foreach>
    and title like concat('%',#{title},'%')
</delete>

拓展2:

​ 相较于第一种方法(拼接),第二种方法(对问号设置值)的优点:

1.防止注入攻击

2.提高执行效率(由于使用的是连接池,所以同一条语句会被多次调用,之前写的DBHelper数据库工具类,每次用完都会关闭,并不会提高效率):

​ ①多次执行拼接类型的数据库语句,由于传的值不一样,使得相同结构的数据库语句,由于所传的数据不一样,导致数据库每次都会对该相同结构的语句进行语法检查。{例:update question_type set enable = 0 where id in (1,25,3,6)和update question_type set enable = 0 where id in (1,2)}数据库会对每条语句进行语法检查,则很多准备工作会进行重复执行

​ ②多次执行问号设置值的数据库语句,数据库只会对第一条语句进行检查,再调用该语句传入其他值时,则不会重复执行准备工作,提高了执行效率


[5]xml数据库映射中的选择结构(类似switch-case/if-else,有且只能有一个条件可以执行)

结构:

执行语句1

执行语句2

......

最终条件

<select id="search2" resultMap="BaseResultMap" parameterType="com.wanmait.demo.pojo.QuestionType">
    select
    <include refid="Base_Column_List"></include>
    from question_type
    <where>
        <choose>
            <when test="title != null and title != ''">
                title like concat('%',#{title} ,'%')
            </when>
            <when test="questionCount != null">
                question_count=#{questionCount}
            </when>
            <otherwise>
                enable=1
            </otherwise>
        </choose>
    </where>
</select>

[6]增删改返回自增长的id(无mybatis版详见MySql数据库.md

	1. 从数据库取值的名称:**keyColumn="id"**
	2. 将数据从放到对象的名称:**keyProperty="id"**
	3. 设置获取主键的开关:**useGeneratedKeys="true"**
 <insert id="insert" keyColumn="id" keyProperty="id" parameterType="com.wanmait.demo.pojo.Question" useGeneratedKeys="true">
    insert into question (title, question_type_id, userinfo_id,
    info, description, has_pic, pic)
    values (#{title,jdbcType=VARCHAR}, #{questionType.id,jdbcType=INTEGER}, #{userinfo.id,jdbcType=INTEGER},
    #{info,jdbcType=VARCHAR}, #{description,jdbcType=VARCHAR}, #{hasPic,jdbcType=BIT},
    #{pic,jdbcType=VARCHAR})
  </insert>

​ 使用实例:订单生成时,需要立刻拿到生成订单的id,以完成后续操作。

posted @ 2020-12-23 14:15  LYCL  阅读(239)  评论(0)    收藏  举报