mybatis动态SQL的运用

news2024/11/24 12:44:52

一、mybatis动态SQL

update 表名 set name=?,age=? where id=?

如果我们的前台没有传参,比如没有传入我们的name值,name就会把字段值改为null,这就违背了我们编码的初衷。

许多人会使用类似于where 1 = 1 来作为前缀,在代码中会用if判断是否为null,再用and进行一个sql拼接。

我们可以用常用的几个标签:

1、if

if标签里面,test里面的条件满足了,才会把后面的sql语句进行拼接

<!-- 示例 -->
<select id="updateByPrimaryKeySelective" parameterType="com.tgq.model.Book">
        SELECT * FROM Book WHERE price>= 9.9
        <if test="name != null and name != ''">
            AND name like '%${name}%'
        </if>
</select>

2、foreach

我们再调用删除的方法的时候,通常会与SQL语句中的IN查询条件结合使用。

delete from student where id in()

parameterType为List(链表)或者Array(数组),后面在引用时,参数名必须为list或者array。如在foreach标签中,collection属性则为需要迭代的集合,由于入参是个List,所以参数名必须为list。

<select id="selectById" resultType="com.tgq.model.Book" parameterType="java.util.List" >
      select
      <include refid="Base_Column_List"/>
      from t_mvc_book
      where bid in
      <foreach collection="bids" item="bid" open="(" separator="," close=")">
          #{bid}
      </foreach>
  </select>

测试一下结果

   @Test
    public void selectById() {
        List<Integer> bids = Arrays.asList(new Integer[]{30, 31, 32, 33});
        bookbiz.selectById(bids).forEach(System.out::println);
    }

3、choose、when、otherwise

你可以使用choosewhenotherwise元素来实现类似于switch语句的逻辑。

<select id="getUser" parameterType="int" resultType="User">
  SELECT * FROM users
  WHERE 1=1
  <choose>
    <when test="id != null">
      AND id = #{id}
    </when>
    <when test="name != null">
      AND name = #{name}
    </when>
    <otherwise>
      AND status = 'ACTIVE'
    </otherwise>
  </choose>
</select>

如果传入的id不为空,则会在SQL语句中包含AND id = #{id}这个条件;如果传入的name不为空,则会在SQL语句中包含AND name = #{name}这个条件;否则,会在SQL语句中包含AND status = 'active'这个条件。

二、mybatis模糊查询

我们写入一个xml文件,log4j2.xml 用于打印出来你的sql语句

<?xml version="1.0" encoding="UTF-8"?>

<!-- status : 指定log4j本身的打印日志的级别.ALL< Trace < DEBUG < INFO < WARN < ERROR
	< FATAL < OFF。 monitorInterval : 用于指定log4j自动重新配置的监测间隔时间,单位是s,最小是5s. -->
<Configuration status="WARN" monitorInterval="30">
    <Properties>
        <!-- 配置日志文件输出目录 ${sys:user.home} -->
        <Property name="LOG_HOME">/root/workspace/lucenedemo/logs</Property>
        <property name="ERROR_LOG_FILE_NAME">/root/workspace/lucenedemo/logs/error</property>
        <property name="WARN_LOG_FILE_NAME">/root/workspace/lucenedemo/logs/warn</property>
        <property name="PATTERN">%d{yyyy-MM-dd HH:mm:ss.SSS} [%t-%L] %-5level %logger{36} - %msg%n</property>
    </Properties>

    <Appenders>
        <!--这个输出控制台的配置 -->
        <Console name="Console" target="SYSTEM_OUT">
            <!-- 控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch) -->
            <ThresholdFilter level="trace" onMatch="ACCEPT"
                             onMismatch="DENY" />
            <!-- 输出日志的格式 -->
            <!-- %d{yyyy-MM-dd HH:mm:ss, SSS} : 日志生产时间 %p : 日志输出格式 %c : logger的名称
                %m : 日志内容,即 logger.info("message") %n : 换行符 %C : Java类名 %L : 日志输出所在行数 %M
                : 日志输出所在方法名 hostName : 本地机器名 hostAddress : 本地ip地址 -->
            <PatternLayout pattern="${PATTERN}" />
        </Console>

        <!--文件会打印出所有信息,这个log每次运行程序会自动清空,由append属性决定,这个也挺有用的,适合临时测试用 -->
        <!--append为TRUE表示消息增加到指定文件中,false表示消息覆盖指定的文件内容,默认值是true -->
        <File name="log" fileName="logs/test.log" append="false">
            <PatternLayout
                    pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
        </File>
        <!-- 这个会打印出所有的info及以下级别的信息,每次大小超过size, 则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档 -->
        <RollingFile name="RollingFileInfo" fileName="${LOG_HOME}/info.log"
                     filePattern="${LOG_HOME}/$${date:yyyy-MM}/info-%d{yyyy-MM-dd}-%i.log">
            <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch) -->
            <ThresholdFilter level="info" onMatch="ACCEPT"
                             onMismatch="DENY" />
            <PatternLayout
                    pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
            <Policies>
                <!-- 基于时间的滚动策略,interval属性用来指定多久滚动一次,默认是1 hour。 modulate=true用来调整时间:比如现在是早上3am,interval是4,那么第一次滚动是在4am,接着是8am,12am...而不是7am. -->
                <!-- 关键点在于 filePattern后的日期格式,以及TimeBasedTriggeringPolicy的interval, 日期格式精确到哪一位,interval也精确到哪一个单位 -->
                <!-- log4j2的按天分日志文件 : info-%d{yyyy-MM-dd}-%i.log -->
                <TimeBasedTriggeringPolicy interval="1"
                                           modulate="true" />
                <!-- SizeBasedTriggeringPolicy:Policies子节点, 基于指定文件大小的滚动策略,size属性用来定义每个日志文件的大小. -->
                <!-- <SizeBasedTriggeringPolicy size="2 kB" /> -->
            </Policies>
        </RollingFile>

        <RollingFile name="RollingFileWarn" fileName="${WARN_LOG_FILE_NAME}/warn.log"
                     filePattern="${WARN_LOG_FILE_NAME}/$${date:yyyy-MM}/warn-%d{yyyy-MM-dd}-%i.log">
            <ThresholdFilter level="warn" onMatch="ACCEPT"
                             onMismatch="DENY" />
            <PatternLayout
                    pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
            <Policies>
                <TimeBasedTriggeringPolicy />
                <SizeBasedTriggeringPolicy size="2 kB" />
            </Policies>
            <!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件,这里设置了20 -->
            <DefaultRolloverStrategy max="20" />
        </RollingFile>

        <RollingFile name="RollingFileError" fileName="${ERROR_LOG_FILE_NAME}/error.log"
                     filePattern="${ERROR_LOG_FILE_NAME}/$${date:yyyy-MM}/error-%d{yyyy-MM-dd-HH-mm}-%i.log">
            <ThresholdFilter level="error" onMatch="ACCEPT"
                             onMismatch="DENY" />
            <PatternLayout
                    pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
            <Policies>
                <!-- log4j2的按分钟 分日志文件 : warn-%d{yyyy-MM-dd-HH-mm}-%i.log -->
                <TimeBasedTriggeringPolicy interval="1"
                                           modulate="true" />
                <!-- <SizeBasedTriggeringPolicy size="10 MB" /> -->
            </Policies>
        </RollingFile>

    </Appenders>

    <!--然后定义logger,只有定义了logger并引入的appender,appender才会生效 -->
    <Loggers>
        <!--过滤掉spring和mybatis的一些无用的DEBUG信息 -->
        <logger name="org.springframework" level="INFO"></logger>
        <logger name="org.mybatis" level="INFO"></logger>

        <!-- 第三方日志系统 -->
        <logger name="org.springframework" level="ERROR" />
        <logger name="org.hibernate" level="ERROR" />
        <logger name="org.apache.struts2" level="ERROR" />
        <logger name="com.opensymphony.xwork2" level="ERROR" />
        <logger name="org.jboss" level="ERROR" />


        <!-- 配置日志的根节点 -->
        <root level="all">
            <appender-ref ref="Console" />
            <appender-ref ref="RollingFileInfo" />
            <appender-ref ref="RollingFileWarn" />
            <appender-ref ref="RollingFileError" />
        </root>

    </Loggers>

</Configuration>

1、mybatis模糊查询的三种方式

  1. 第一种
    <select id="like01" resultType="com.tgq.model.Book" parameterType="java.util.List">
            select
            <include refid="Base_Column_List"/>
            from t_mvc_book
            where bname like #{bname}
        </select>

    测试的结果

     @Test
        public void like01() {
            bookbiz.like01("%圣%").forEach(System.out::println);
        }
    

     

  2. 第二种:$需要单引号,$传参是占位符的形式
     

     <select id="like02" resultType="com.tgq.model.Book" parameterType="java.util.List">
            select
            <include refid="Base_Column_List"/>
            from t_mvc_book
            where bname like '${bname}'
        </select>

     测试的结果

      @Test
        public void like02() {
            bookbiz.like02("%圣%").forEach(System.out::println);
        }
    

     

  3. 第三种
     

    <select id="like03" resultType="com.tgq.model.Book" parameterType="java.util.List">
            select
            <include refid="Base_Column_List"/>
            from t_mvc_book
            where bname like concat('%',#{bname},'%')
        </select>

     测试的结果

        @Test
        public void like03() {
            bookbiz.like03("%圣%").forEach(System.out::println);
        }
    

2、mybatis中#与$的区别

  1. $是占位符赋值,#是预处理SQL。
  2. 外在形式,$传参不带引号''#传参自带引号''
  3. $传参存在sql注入,#不存在。
  4. $可以用来做动态列,完成动态sql的开发。

三、MyBatis结果映射(单表多表查询)

<resultMap id="BaseResultMap" type="com.tgq.model.Book">
        <constructor>
            <idArg column="bid" jdbcType="INTEGER" javaType="java.lang.Integer"/>
            <arg column="bname" jdbcType="VARCHAR" javaType="java.lang.String"/>
            <arg column="price" jdbcType="REAL" javaType="java.lang.Float"/>
        </constructor>
    </resultMap>

这个代码中,column属性写的是数据库里面的字段,里面有一个name的属性,是实体类里面的字段,当数据库里面的字段喝实体类里面的字段是一样的可以不用写name属性;

如果数据库里面出现了下划线,比如data_time,就需要在

<arg column="data_time",name="DataTime" jdbcType="VARCHAR" javaType="java.lang.String"/>

使用mybatis的各种场景

使用mybatis的各种场景,返回的结果是多样的,resultType/resultMap

  1. 返回单表的对应的实体类,仅有一个查询结果,可以用resultType/resultMap。
    • 使用了resultType

       <select id="selectresultType" resultType="com.tgq.model.Book" parameterType="java.lang.Integer">
              select
              <include refid="Base_Column_List"/>
              from t_mvc_book
              where bid = #{bid,jdbcType=INTEGER}
          </select>
    • 编写接口实现接口
      Book selectresultType(Integer bid);
          @Override
          public Book selectresultType(Integer bid) {
              return bookMapper.selectresultType(bid);
          }

    • 测试方法
          @Test
          public void selectresultType() {
              System.out.println("测试resultType查询");
              Book book = bookbiz.selectByPrimaryKey(12);
              System.out.println(book);
          }
    • 测试结果

       

  2. 返回单表的对应的实体类,有多个查询结果,可以用resultType/resultMap。

     

    • resultType/resultMap。resultType一个或多个都用实体对象
      <select id="selectresultType01" resultType="com.tgq.model.Book">
              select
              <include refid="Base_Column_List"/>
              from t_mvc_book
          </select>
      
          <select id="selectresultMap01" resultMap="BaseResultMap">
              select
              <include refid="Base_Column_List"/>
              from t_mvc_book
          </select>

    • 编写接口方法和实现接口
          List<Book> selectresultType01();
      
          List<Book> selectresultMap01();
      @Override
          public List<Book> selectresultType01() {
              return bookMapper.selectresultType01();
          }
      
          @Override
          public List<Book> selectresultMap01() {
              return bookMapper.selectresultMap01();
          }

    • 测试方法
          @Test
          public void selectresultType01() {
              bookbiz.selectresultType01().forEach(System.out::println);
          }
      
          @Test
          public void selectresultMap01() {
              bookbiz.selectresultMap01().forEach(System.out::println);
          }
      

    • 测试结果是一样的
  3. 返回多表的对应的实体类,仅有一个查询结果,通常用resultType,也可以用resultMap。
  4. 返回多表的对应的实体类,有多个查询结果,通常用resultType,也可以用resultMap。

     

    • 编写配置,我们可以不用配置的表,可以调用其他的表
      <select id="select01" resultType="java.util.Map" parameterType="java.util.Map">
              select s.*, sc.cid, sc.score
              from t_mysql_student s,
                   t_mysql_score sc
              where s.sid = sc.sid
                and sc.sid = #{sid}
                and sc.cid = #{cid}
          </select>
      
          <select id="select02" resultType="java.util.Map" parameterType="java.util.Map">
              select s.*, sc.cid, sc.score
              from t_mysql_student s,
                   t_mysql_score sc
              where s.sid = sc.sid
          </select>

    • 编写接口和实现类
          Map select01(Map map);
      
          List<Map> select02(Map map);
          @Override
          public Map select01(Map map) {
              return bookMapper.select01(map);
          }
      
          @Override
          public List<Map> select02(Map map) {
              return bookMapper.select02(map);
          }

    • 测试方法
          @Test
          public void select01() {
              Map map = new HashMap();
              map.put("sid", "01");
              map.put("cid", "01");
              System.out.println(bookbiz.select01(map));
          }
      
          @Test
          public void select02() {
              Map map = new HashMap();
              map.put("sid", "01");
              map.put("cid", "01");
              bookbiz.select02(map).forEach(System.out::println);
          }

    • 测试结果

  5. 返回单个列表,仅有一个查询结果,就用resultType。
  6. 返回单个列表,有多个查询结果,就用resultType。
    • 配置xml
      <!--单个-->
          <select id="selectByString01" resultType="java.lang.String" parameterType="java.lang.Integer">
              select bname
              from t_mvc_book
              where bid = #{bid,jdbcType=INTEGER}
          </select>
          <!--多个-->
          <select id="selectByString02" resultType="java.lang.String" parameterType="java.lang.String">
              select bname
              from t_mvc_book
              where bname like concat('%', #{bname}, '%')
          </select>
    • 编写接口和实现接口

          String selectByString01(Integer bid);
      
          List<String> selectByString02(String bname);
        @Override
          public String selectByString01(Integer bid) {
              return bookMapper.selectByString01(bid);
          }
      
          @Override
          public List<String> selectByString02(String bname) {
              return bookMapper.selectByString02(bname);
          }

    • 测试方法

          @Test
          public void selectByString01() {
              System.out.println(bookbiz.selectByString01(60));
          }
      
          @Test
          public void selectByString02() {
              Map map = new HashMap();
              map.put("sid", "01");
              map.put("cid", "01");
              bookbiz.selectByString02("圣墟").forEach(System.out::println);
          }

    • 测试结果

resultType:对应返回类型。

resultMap:对应返回映射关系,指的是实体类与数据表字段关系。

单表查询,返回单列,返回多表查询结果,是用resultType

查询的结果,需要有关属性的体现,那么就用resultMap

上一章【mybatis入门Idea搭建】

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/913293.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Socket编程入门

Socket编程 套接字的类型 套接字分为两种类型 Stream Sockets&#xff0c;流格式&#xff0c;传输使用的是TCP协议Datagram Sockets&#xff0c;数据包格式&#xff0c;传输使用的是UDP协议 结构体 在不同类型电脑中&#xff0c;字节的排列顺序是不同的&#xff1a;大端序…

uniapp项目添加人脸识别功能,可用作登录,付款,流程审批前的安全校验

本案例使用了hbuilder插件商城中的活体检验插件&#xff0c;可自行前往作者处下载查看&#xff0c; 效果图如下 此插件需要在manifest.json中勾选 实现流程 1&#xff1a;前往hbuilder插件市场下载插件 2&#xff1a;在页面中导入import face from "/uni_modules/mcc-…

成集云 | 维格表会员/租约/合同到期同步企微提醒 | 解决方案

源系统成集云目标系统 方案介绍 维格表是一种新一代的团队数据协作和项目管理工具&#xff0c;由深圳维格智数科技有限公司研发。它结合了可视化数据库、电子表格、实时网络协同、低代码开发技术四项功能&#xff0c;且支持API与可视化看板&#xff0c;操作简单&#xff0c;能…

【数据结构入门指南】二叉树

【数据结构入门指南】二叉树 一、二叉树的概念二、现实中的二叉树三、特殊的二叉树四、二叉树的性质五、二叉树的存储结构5.1 顺序结构5.2 链式结构 一、二叉树的概念 二叉树是一棵特殊的树。一棵二叉树是结点的一个有限集合&#xff0c;该节点&#xff1a; ①&#xff1a;或者…

Vue 2 插槽

可以先阅读组件基础-简单了解通过插槽分发内容。 一、插槽定义 插槽将子组件标签间的内容分发到子组件模板的<slot>标签位置。 如果没有<slot>标签&#xff0c;那么该内容将被丢弃。 二、编译作用域 内容在哪个作用域编译&#xff0c;就可以访问哪个作用域的数据…

SMS 与 WhatsApp 营销,哪个方式最适合你的业务?

SMS和 WhatsApp营销越来越受欢迎&#xff0c;因为它们为企业提供了接触目标受众的有效方式。超过 91%的客户希望收到来自企业的 SMS消息&#xff0c;使用WhatsAppAPI发送的消息的打开率高达99% &#xff0c;这证明了这两种形式的消息传递对于希望及时与客户沟通的企业来说变得重…

火山引擎发布自研视频编解码芯片 压缩效率提升30%

8月22日&#xff0c;火山引擎视频云宣布其自研的视频编解码芯片已成功出片。经验证&#xff0c;该芯片的视频压缩效率相比行业主流硬件编码器可提升30%以上&#xff0c;未来将服务于抖音、西瓜视频等视频业务&#xff0c;并将通过火山引擎视频云开放给企业客户。 火山引擎总裁…

C语言好题解析(四)

目录 选择题一选择题二选择题三选择题四选择题五编程题一 选择题一 已知函数的原型是&#xff1a; int fun(char b[10], int *a); 设定义&#xff1a; char c[10];int d; &#xff0c;正确的调用语句是&#xff08; &#xff09; A: fun(c,&d); B: fun(c,d); C: fun(&…

安防视频监控平台EasyNVR平台启用国标级联的操作步骤来啦!

安防视频监控汇聚EasyNVR视频集中存储平台&#xff0c;是基于RTSP/Onvif协议的安防视频平台&#xff0c;可支持将接入的视频流进行全平台、全终端分发&#xff0c;分发的视频流包括RTSP、RTMP、HTTP-FLV、WS-FLV、HLS、WebRTC等格式。 为提高用户体验&#xff0c;让用户更加便捷…

再JAVA中如何使用qsort对类进行排序?

目录 结论&#xff1a; 解析&#xff1a; 结论&#xff1a; import java.util.Arrays;class Person implements Comparable<Person>{public String name;public int age;public Person(String name, int age) {this.name name;this.age age;}Overridepublic Stri…

关于Springboot项目打包的配置问题

一、打包方式的不同致使jar包运行性能及docker部署的效率问题 1.1方式一 <build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source&…

保护函数返回的利器——Linux Shadow Call Stack

写在前面 提到内核栈溢出的漏洞缓解&#xff0c;许多朋友首先想到的是栈内金丝雀&#xff08;Stack Canary&#xff09;。今天向大家介绍一项在近年&#xff0c;于Android设备中新增&#xff0c;且默默生效的安全机制——影子调用栈&#xff1a;SCS&#xff08;Shadow Call St…

GEE/PIE遥感大数据处理与典型案例

随着航空、航天、近地空间等多个遥感平台的不断发展&#xff0c;近年来遥感技术突飞猛进。由此&#xff0c;遥感数据的空间、时间、光谱分辨率不断提高&#xff0c;数据量也大幅增长&#xff0c;使其越来越具有大数据特征。对于相关研究而言&#xff0c;遥感大数据的出现为其提…

亚马逊前台又更新了?这个功能有点意思!

亚马逊最近动作频频&#xff0c;之前听说过&#xff0c;亚马逊的IT团队换了一批新人&#xff0c;目前界面也在进行迭代改版。只不过各项新功能的改版&#xff0c;让卖家们应接不暇。由于新功能的改变都会对卖家们的业务产生影响&#xff0c;这直接关系到卖家的切身利益&#xf…

leetcode1109. 航班预订统计(java)

差分数组 leetcode1109. 航班预订统计差分数组解题代码演示 上期经典 leetcode1109. 航班预订统计 难度 - 中等 原题链接 - 1109. 航班预订统计 这里有 n 个航班&#xff0c;它们分别从 1 到 n 进行编号。 有一份航班预订表 bookings &#xff0c;表中第 i 条预订记录 bookings…

查询速度最高提升50倍!火山引擎ByteHouse在广告投放领域实践分享

更多技术交流、求职机会&#xff0c;欢迎关注字节跳动数据平台微信公众号&#xff0c;回复【1】进入官方交流群 据QuestMobile报告显示&#xff0c;移动互联网已经进入了下半场&#xff0c;在使用人数和使用时长方面已经没有明显增长&#xff0c;互联网已经流量趋于饱和。 作为…

【升职加薪秘籍】我在服务监控方面的实践(6)-业务维度的mysql监控

大家好,我是蓝胖子&#xff0c;关于性能分析的视频和文章我也大大小小出了有一二十篇了&#xff0c;算是已经有了一个系列&#xff0c;之前的代码已经上传到github.com/HobbyBear/performance-analyze&#xff0c;接下来这段时间我将在之前内容的基础上&#xff0c;结合自己在公…

电脑出现msvcp120.dll丢失的解决方法,教你三招快速解决

msvcp120.dll丢失是一件很常见的问题&#xff0c;出现msvcp120.dll丢失会导致电脑无法在正常运行&#xff0c;那么应该怎么解决这个问题呢&#xff0c;有什么办法可以快速的解决呢&#xff0c;今天教你三招快速解决msvcp120.dll丢失的方法。 一.msvcp120.dll文件丢失可能导致的…

深度学习入门(五):经典网络Alexnet实现

介绍 AlexNet是一个深度卷积神经网络架构&#xff0c;于2010年代初在深度学习重新引起人们关注时发挥了重要作用。它因在2012年的ImageNet大规模视觉识别挑战&#xff08;ILSVRC&#xff09;中获胜而闻名。 实现 创建了一个AlexNet网络的实例&#xff0c;并将一个随机生成的…

云服务之PaaS:PaaS怎么帮助企业走向云

一、前言 企业想要平滑地向云迁移&#xff0c;需要选择一个适合自己的云基础框架。PaaS(平台即服务)作为云计算的重要组成部分&#xff0c;可以为用户提供完整的应用生命周期管理和相关资源服务。开发人员可以在PaaS框架构建和自定义应用程序&#xff0c;这为企业大大地节省了金…