【JavaEE进阶】MyBatis 操纵数据库(3)

打印 上一主题 下一主题

主题 1545|帖子 1545|积分 4635


  
欢迎关注个人主页:逸狼

  
  
创造不易,可以点点赞吗

  
如有错误,欢迎指出~

  
  动态SQL

动态SQL是Mybatis的强⼤特性之⼀,可以大概完成差别条件下差别的sql拼接
<if>标签

注册分为两种字段:必填字段和⾮必填字段,那如果在添加⽤⼾的时候有不确定的字段传⼊,程序应 该如何实现呢? 这个时候就需要使⽤动态标签来判定了,
<if>标签中test 属性是必须的,用于判定条件是否建立。如果条件表达式的结果为 true,则会将 <if> 标签内的 SQL 片断包罗在终极生成的 SQL 语句中;如果结果为 false,则会忽略该 SQL 片断。⽐如添加的时候性别gender为⾮必填字段,具体实现如 下:
接口
  1.     Integer insertByCondition(UserInfo userInfo);
复制代码
Mapper.xml实现: 
  1.     <insert id="insertByCondition">
  2.         INSERT INTO user_info (
  3.         username,
  4.         `password`,
  5.         age,
  6.         <!-- 动态判断是否添加 gender 列 -->
  7.         <if test="gender != null">
  8.             gender
  9.         </if>
  10.         )
  11.         VALUES (
  12.         #{username},
  13.         #{password},
  14.         #{age},
  15.         <!-- 动态判断是否添加 gender 值 -->
  16.         <if test="gender != null">
  17.             #{gender}
  18.         </if>
  19.         )
  20.     </insert>
复制代码
注解方式实现(不发起) 
  1. @Insert("<script>" +
  2. "INSERT INTO userinfo (username,`password`,age," +
  3. "<if test='gender!=null'>gender,</if>)" +
  4. "VALUES(#{username},#{age}," +
  5. "<if test='gender!=null'>#{gender},</if>)"+
  6. "</script>")
  7. Integer insertUserByCondition(UserInfo userInfo);
复制代码
留意test中的gender,是传⼊对象中的属性,不是数据库字段


  • Q:可不可以不进⾏判定,直接把字段设置为null呢?
  • A:不可以,这种环境下,如果gender字段有默认值,就会设置为默认值
<trim>标签

之前的插⼊⽤⼾功能,只是有⼀个gender字段可能是选填项,如果有多个字段,⼀般思量使⽤标签结 合标签,对多个字段都采取动态⽣成的⽅式。 标签中有如部属性:

  • prefix:表⽰整个语句块,以prefix的值作为前缀
  • suffix:表⽰整个语句块,以suffix的值作为后缀
  • prefixOverrides:表⽰整个语句块要去除掉的前缀
  • suffixOverrides:表⽰整个语句块要去除掉的后缀
调整Mapper.xml的插⼊语句为:
  1. <insert id="insertByCondition2">
  2.     INSERT INTO user_info
  3.     <trim prefix="(" suffix=")" suffixOverrides=",">
  4.         <if test="username != null">
  5.             username,
  6.         </if>
  7.         <if test="password != null">
  8.             `password`,
  9.         </if>
  10.         <if test="age != null">
  11.             age,
  12.         </if>
  13.         <if test="gender != null">
  14.             gender,
  15.         </if>
  16.         <if test="phone != null">
  17.             phone
  18.         </if>
  19.     </trim>
  20.     VALUES
  21.     <trim prefix="(" suffix=")" suffixOverrides=",">
  22.         <if test="username != null">
  23.             #{username},
  24.         </if>
  25.         <if test="password != null">
  26.             #{password},
  27.         </if>
  28.         <if test="age != null">
  29.             #{age},
  30.         </if>
  31.         <if test="gender != null">
  32.             #{gender},
  33.         </if>
  34.         <if test="phone != null">
  35.             #{phone}
  36.         </if>
  37.     </trim>
  38. </insert>
复制代码
<where>标签

看下⾯这个场景,系统会根据我们的筛选条件,动态组装where条件

需求:传⼊的⽤⼾对象,根据属性做where条件查询,⽤⼾对象中属性不为null的,都为查询条件.如 username为"a",则查询条件为whereusername="a"
  1.     <select id="selectByConditoin2" resultType="com.example.demo.model.UserInfo">
  2.         select * from user_info
  3.         where
  4.             <if test="gender != null">
  5.                 gender = #{gender}
  6.             </if>
  7.             <if test="age != null">
  8.                 and age = #{age}
  9.             </if>
  10.     </select>
复制代码
当条件gender和age都没有时,报错如下 

办理方法一
  1.     <select id="selectByConditoin2" resultType="com.example.demo.model.UserInfo">
  2.         select * from user_info
  3.         where 1=1
  4.             <if test="gender != null">
  5.                 and gender = #{gender}
  6.             </if>
  7.             <if test="age != null">
  8.                 and age = #{age}
  9.             </if>
  10.     </select>
复制代码

方法二: 使用<where>标签
只会在⼦元素有内容的环境下才插⼊where⼦句,⽽且会⾃动去除⼦句的开头的AND或 OR 以上标签也可以使⽤ 替换,但是此种 环境下,当⼦元素都没有内容时,where关键字也会保存
  1.     <select id="selectByConditoin" resultType="com.example.demo.model.UserInfo">
  2.         select * from user_info
  3.         <where>
  4.             <if test="gender != null">
  5.                 and gender = #{gender}
  6.             </if>
  7.             <if test="age != null">
  8.                 and age = #{age}
  9.             </if>
  10.         </where>
  11.     </select>
复制代码

<set>标签

  需求:根据传⼊的⽤⼾对象属性来更新⽤⼾数据,可以使⽤标签来指定动态内容. 接⼝界说:根据传⼊的⽤⼾id属性,修改其他不为null的属性
  1. <!--    <update id="updateByCondition">-->
  2. <!--        update user_info set-->
  3. <!--        <trim suffixOverrides=",">-->
  4. <!--            <if test="username!= null">-->
  5. <!--                username = #{username},-->
  6. <!--            </if>-->
  7. <!--            <if test="password != null">-->
  8. <!--                password = #{username},-->
  9. <!--            </if>-->
  10. <!--            <if test="gender">-->
  11. <!--                gender = #{gender}-->
  12. <!--            </if>-->
  13. <!--        </trim>-->
  14. <!--        where id = #{id}-->
  15. <!--    </update>-->
  16.     <update id="updateByCondition">
  17.         update user_info
  18.         <set>
  19.             <if test="username!= null">
  20.                 username = #{username},
  21.             </if>
  22.             <if test="password != null">
  23.                 password = #{username},
  24.             </if>
  25.             <if test="gender">
  26.                 gender = #{gender}
  27.             </if>
  28.         </set>
  29.         where id = #{id}
  30.     </update>
复制代码
动态的在SQL语句中插⼊set关键字,并会删掉额外的逗号.(⽤于update语句中) 以上标签也可以使⽤ 替换。
<foreach>标签

  对集合进⾏遍历时可以使⽤该标签。标签有如部属性:

  • collection:绑定⽅法参数中的集合,如List,Set,Map或数组对象
  • item:遍历时的每⼀个对象
  • open:语句块开头的字符串
  • close:语句块结束的字符串
  • separator:每次遍历之间间隔的字符串 需求:根据多个userid,删除⽤⼾数据
  1. <delete id="deleteByIds">
  2. delete from userinfo
  3. where id in
  4. <foreach collection="ids" item="id" separator="," open="(" close=")">
  5. #{id}
  6. </foreach>
  7. </delete>
复制代码
<include>标签

  问题分析: • 在xml映射⽂件中设置的SQL,有时可能会存在许多重复的⽚段,此时就会存在许多冗余的代码

我们可以对重复的代码⽚段进⾏抽取,将其通过 标签封装到⼀个SQL⽚段,然后再通过 标签进⾏引⽤。
• :界说可重⽤的SQL⽚段
• :通过属性refid,指定包罗的SQL⽚段

  1. <sql id="allColumn">
  2. id, username, age, gender, phone, delete_flag, create_time, update_time
  3. </sql>
复制代码
通过 标签在原来抽取的地⽅进⾏引⽤。操纵如下:
  1. <select id="queryAllUser" resultMap="BaseMap">
  2. select
  3. <include refid="allColumn"></include>
  4. from userinfo
  5. </select>
  6. 5<select id="queryById" resultType="com.example.demo.model.UserInfo">
  7. select
  8. <include refid="allColumn"></include>
  9. from userinfo where id= #{id}
  10. </select>
复制代码
案例演示-表⽩墙

前⾯的案例中,我们写了表⽩墙,但是⼀旦服务器重启,数据仍然会丢失. 要想数据不丢失,需要把数据存储在数据库中.接下来咱们借助MyBatis来实现数据的操纵
数据准备

  1. DROP TABLE IF EXISTS message_info;
  2. CREATE TABLE `message_info` (
  3. `id` INT ( 11 ) NOT NULL AUTO_INCREMENT,
  4. `from` VARCHAR ( 127 ) NOT NULL,
  5. `to` VARCHAR ( 127 ) NOT NULL,
  6. `message` VARCHAR ( 256 ) NOT NULL,
  7. `delete_flag` TINYINT ( 4 ) DEFAULT 0 COMMENT '0-正常, 1-删除',
  8. `create_time` DATETIME DEFAULT now(),
  9. `update_time` DATETIME DEFAULT now() ON UPDATE now(),
  10. PRIMARY KEY ( `id` )
  11. ) ENGINE = INNODB DEFAULT CHARSET = utf8mb4;
复制代码
引入依赖

  1. <dependency>
  2. <groupId>org.mybatis.spring.boot</groupId>
  3. <artifactId>mybatis-spring-boot-starter</artifactId>
  4. <version>3.0.3</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>com.mysql</groupId>
  8. <artifactId>mysql-connector-j</artifactId>
  9. <scope>runtime</scope>
  10. </dependency>
复制代码
设置MySQL账号暗码

  1. #驱动类名称
  2. spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
  3. #数据库连接的url
  4. spring.datasource.url=jdbc:mysql://127.0.0.1:3306/mybatis_test?
  5. characterEncoding=utf8&useSSL=false
  6. #连接数据库的⽤⼾名
  7. spring.datasource.username=root
  8. #连接数据库的密码
  9. spring.datasource.password=111111
  10. #指定mybatis输出⽇志的位置, 输出控制台
  11. mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
  12. #配置驼峰⾃动转换
  13. mybatis.configuration.map-underscore-to-camel-case=true
  14. # 配置 mybatis xml 的⽂件路径,在 resources/mapper 创建所有表的 xml ⽂件
  15. mybatis.mapper-locations=classpath:mapper/**Mapper.xml
复制代码
后端代码

model

  1. @Data
  2. public class MessageInfo {
  3.     private Integer id;
  4.     private String from;
  5.     private String to;
  6.     private String message;
  7.     private Integer deleteFlag;
  8.     private Date createTime;
  9.     private Date updateTime;
  10. }
复制代码
MessageInfoMapper 

  1. package com.example.demo3.mapper;
  2. import com.example.demo3.MessageInfo;
  3. import org.apache.ibatis.annotations.Insert;
  4. import org.apache.ibatis.annotations.Mapper;
  5. import org.apache.ibatis.annotations.Select;
  6. import java.util.List;
  7. @Mapper
  8. public interface MessageInfoMapper {
  9. //"INSERT INTO message_info (`from`, `to`, `message`) VALUES (#{from}, #{to}, #{message})"
  10.     @Insert("insert into message_info (`from`, `to`, `message`) values (#{from}, #{to}, #{message})")
  11.     Integer insert(MessageInfo messageInfo);
  12.     @Select("select * from message_info ")
  13.     List<MessageInfo> selectAll();
  14. }
复制代码

UserService

  1. package com.example.demo3;
  2. import com.example.demo3.mapper.MessageInfoMapper;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.stereotype.Service;
  5. import java.util.List;
  6. @Service
  7. public class MessageService {
  8.     @Autowired
  9.     private MessageInfoMapper messageInfoMapper;
  10.     public List<MessageInfo> selectAll(){
  11.         return messageInfoMapper.selectAll();
  12.     }
  13.     public void insertMessage(MessageInfo messageInfo) {
  14.         messageInfoMapper.insert(messageInfo);
  15.     }
  16. }
复制代码
UserController

  1. package com.example.demo3;
  2. import org.springframework.beans.factory.annotation.Autowired;
  3. import org.springframework.util.StringUtils;
  4. import org.springframework.web.bind.annotation.RequestBody;
  5. import org.springframework.web.bind.annotation.RequestMapping;
  6. import org.springframework.web.bind.annotation.RestController;
  7. import java.util.ArrayList;
  8. import java.util.List;
  9. @RestController
  10. @RequestMapping("/message")
  11. public class MessageController {
  12. //    List<MessageInfo> messageInfos = new ArrayList<>();
  13.     @Autowired
  14.     private MessageService messageService;
  15.     @RequestMapping(value = "/getList")
  16.     public List<MessageInfo> getList(){
  17.         return messageService.selectAll();
  18.     }
  19.     @RequestMapping(value = "/publish", produces = "application/json")
  20.     public String publish(@RequestBody MessageInfo messageInfo){
  21.         if(StringUtils.hasLength(messageInfo.getMessage())
  22.         && StringUtils.hasLength(messageInfo.getFrom())
  23.         && StringUtils.hasLength(messageInfo.getTo())){
  24. //            messageInfos.add(messageInfo);
  25. //            System.out.println(messageInfo);
  26.             messageService.insertMessage(messageInfo);
  27.             return "{"ok": 1}";
  28.         }
  29.         return "{"ok": 0}";
  30.     }
  31. }
复制代码
测试结果 

欣赏器访问的结果 


输⼊留⾔信息,点击提交,发现⻚⾯列表显⽰新的数据,并且数据库中也添加了⼀条记载. 
数据库中存储的结果 

 重启服务,⻚⾯显⽰不变.

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

冬雨财经

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表