Advanced MyBatis: Master MyBatis dynamic SQL, fuzzy query, and result mapping to make you stand out in interviews! !

Table of contents

I. Introduction

Two, MyBatis dynamic SQL

2.1.if element use

2.2.foreach element use

3. MyBatis fuzzy query

① Use #{field name}

②Use ${field name}

③Use concat{'%', #{field name}, '%'}

Summarize

4. MyBatis result mapping

4.1. Case demonstration

4.1.1.resultType for result mapping

4.1.2.resultMap for result mapping



I. Introduction

Working with databases has become a fundamental and essential skill in today's software development environment. When dealing with database-related tasks, SQL query statements are undoubtedly one of the most commonly used tools. However, as the complexity of the application continues to increase, we often need to write more complex SQL query statements to meet the requirements. This leads to the topic we are going to discuss today - MyBatis.

In this article, we'll dive into two important features of MyBatis: dynamic SQL and fuzzy queries. Dynamic SQL is a powerful feature of MyBatis, which allows us to write dynamically generated SQL statements in XML mapping files. Fuzzy query is a common query method when we process a large amount of data. It can help us quickly find records that meet certain conditions.

Additionally, we'll discuss MyBatis' result mapping capabilities. Result mapping is the process of mapping database query results to Java objects, which is one of the core functions of MyBatis. Through result mapping, we can convert complex database table structures into objects in Java, making program design more intuitive and simple.

Mastering these advanced features of MyBatis can not only improve our development efficiency, but also make us stand out in interviews. Therefore, whether you are a developer with some experience or a learner who is just getting started, it is worth taking the time to learn and understand this knowledge. In the following articles, we will introduce the usage and precautions of these features in detail, hoping to help you.

Two, MyBatis dynamic SQL

2.1.if element use

In previous writing, we must have written such code

update t_mvc_book bname=?,btype=?,bprice=?,..... where bid=?

What if our foreground jsp does not pass the parameter bname to the background?

update t_mvc_book bname=null, btype='science fiction', bprice=9.9,..... where bid=7

This will cause such a result. Originally, we didn’t pass the parameters just because we didn’t want to change the original field value. Instead, it became null instead.

Some people will think, can I pass a parameter? OK, but not necessary. If we use the dynamic SQL in Mybatis, this problem will be solved. It will change our sql statement into xml, and judge it through the if tag. If it is empty, the content in the judgment condition will not be spliced.

 <update id="updateByPrimaryKeySelective" parameterType="com.csdn.xw.model.Book" >
    update t_mvc_book
    <set >
      <if test="bname != null" >
        bname = #{bname,jdbcType=VARCHAR},
      </if>
      <if test="price != null" >
        price = #{price,jdbcType=REAL},
      </if>
    </set>
    where bid = #{bid,jdbcType=INTEGER}
  </update>

2.2.foreach element use

Let's assume another scenario: We must have written batch deletion of something in the process of writing code

Maybe something like this iterates over the array and then calls the delete method

for int id :ids

      orderItemsDao.delete(id)

It may also be splicing to splice the ids that need to be deleted

delete from t_oa_order where id in(...)

If we are using mybatis we can write like this

<select id="selectByBids" resultType="com.csdn.xw.model.Book" parameterType="java.lang.Integer" >
    select
    <include refid="Base_Column_List" />
    from t_mvc_book
    where bid in
    <foreach collection="bids" item="bid" open="(" close=")" separator=",">
      #{bid}
    </foreach>
  </select>

test it now

BookMapper

List<Book> selectByBids(@Param("bids") List bids);

BookBiz

 List<Book> selectByBids(List bids);

BookBizImpl

 @Override
    public List<Book> selectByBids(List bids) {
         return  bookMapper.selectByBids(bids);
    }

demo test class

@Test
    public void selectByBids() {
        System.out.println("测试的查询的方法");
        List<Integer> integers = Arrays.asList(new Integer[]{55, 56, 57, 58});
        bookBiz.selectByBids(integers).forEach(System.out::println);
    }

Test Results:

3. MyBatis fuzzy query

In order to highlight our effect display, we add a configuration file log4j2.xml

<?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>

The log4j2.xml file should be located at the root of the project's classpath, in the src/main/resources directory.

Tips:

The configuration file of Log4j2 is used to configure the format, level, target and other information of the log output. Log4j2 no longer supports the configuration method of the .properties file in Log4j 1.x, but supports configuration through json, xml or jsn.

Specifically, the log4j2.xml file contains the following sections:

  1. Configuration: Configuration information area, including Appenders, Loggers, etc.
  2. Appender: output target area, including console, file, database, etc.
  3. Logger: Logging area, including package name, class name, log level, etc.

There are three fuzzy query methods in MyBatis:

① Use #{field name}

<select id="like1" resultType="com.csdn.xw.model.Book" parameterType="java.lang.String" >
    select
    <include refid="Base_Column_List" />
    from t_mvc_book
    where bname like #{bname}
  </select>

Test Results: 

②Use ${field name}

<select id="like2" resultType="com.csdn.xw.model.Book" parameterType="java.lang.String" >
    select
    <include refid="Base_Column_List" />
    from t_mvc_book
    where bname like ${bname}
  </select>

Test Results:  

③Use concat{'%', #{field name}, '%'}

<select id="like3" resultType="com.csdn.xw.model.Book" parameterType="java.lang.String" >
  select
  <include refid="Base_Column_List" />
  from t_mvc_book
  where bname like concat('%',#{bname},'%')
</select>

Test Results: 

Summarize

Presumably you have also seen the differences between these three types. Let me summarize them for you below.

The difference between $ and # in mybatis

①$ is a placeholder for passing parameters, # is preprocessing SQL

②External form: $ pass parameter without quotation marks, # comes with quotation marks

Maybe you haven't felt that there is not much difference between quotation marks or not. Let me demonstrate it to you.

If I want to find out all the personnel information of the department according to the department number, use $ and # to test

#:select*from t_oa_employee where deptid=#{deptid}

        select*from t_oa_employee where deptid='10011'

$:select*from t_oa_employee where deptid=${deptid}

          select*from t_oa_employee where deptid=10011

From this point of view, it seems that there is really no difference. What if the front desk maliciously passes parameters?

http://localhost:8080/employee?deptid=10011 or 1=1

That way, the personnel information of the entire company will be found out.

③There is sql injection in the $ pass parameter, # does not exist

④$ can be used as a dynamic column to complete the development of dynamic sql

We must have encountered during the development process that the current field does not meet our needs, and then when we modify the database field, it is fine if it is changed to correct, but if it is wrong, it will be Barbie Q, and the dynamic column can achieve the parameters passed in Operate as a column that needs to be queried, for example:

Suppose we have a table named user_info, which contains fields such as id, name, age, gender, etc. Now we need to dynamically generate query columns according to the parameters passed in. You can use the following statement

<select id="getUserInfo" resultType="map">
  SELECT ${columnName}, ${columnAge}, ${columnGender}
  FROM user_info
</select>

Among them, columnName, columnAge, and columnGender respectively represent the column names to be queried. You can define a Map variable in the Java code, use the column name as the key, and pass in the corresponding value as the value. For example

Map<String, Object> columnMap = new HashMap<>();
columnMap.put("columnName", "name");
columnMap.put("columnAge", 18);
columnMap.put("columnGender", "男");

Then pass the columnMap into the mapper of MyBatis and call it.

In the end, the editor still recommends that you generally use # instead of $. The most commonly used is the third one.

4. MyBatis result mapping

There are multiple scenarios in using MyBatis, and the returned results are diverse, resultType/resultMap

① To return the corresponding entity class of a single table, there is only one query result, and resultType/resultMap can be used.

② To return the corresponding entity class of a single table, if there are multiple query results, you can use resultType/resultMap.

③Returns the results corresponding to multiple tables, and there is only one query result, usually resultType can also be used resultMap.

④Return results corresponding to multiple tables, there are multiple query results, usually resultType can also be used resultMap.

⑤ To return a single column segment, if there is only one query result, use resultType.

⑥ To return a single column segment, if there are multiple query results, use resultType.

  The summary is that the processing of result sets in Mybatis is divided into two types:

resultMap: suitable for cases where the return value is a custom entity class

resultType: The data type suitable for using the return value is non-custom, that is, the type provided by jdk

 In the case of a single table, both resultType and resultMap can be used.
1 Use resultMap to return the mapping relationship, which refers to the relationship between entity classes and database fields

2 Use resultType to return List<T>

3 Use resultType to return a single object

4 Use resultType to return List<Map> [applicable to multi-table query return result set]

5 Use resultType to return Map<String, Object> [applicable to multi-table query and return a single result set]

4.1. Case demonstration

4.1.1.resultType for result mapping

Suppose we have a user table user with the following fields: id, name, age, gender, email. Now it is necessary to query user information based on these fields and return a User object.

First, we need to define a User class for storing query results:

public class User {
    private int id;
    private String name;
    private int age;
    private String gender;
    private String email;
    // getter和setter方法省略
}

Then, in the mapper file of MyBatis, we can use resultType to map the query result to the User object. The specific configuration is as follows:

<select id="getUserById" resultType="com.example.User">
  SELECT id, name, age, gender, email
  FROM user
  WHERE id = #{id}
</select>

In the above configuration, we used the resultType attribute to specify the fully qualified name of the Java object to which the query result is mapped. In this way, when the query statement is executed, MyBatis will automatically map the query result to the specified Java object.

4.1.2.resultMap for result mapping

Suppose we have an order table order, which contains the following fields: id, user_id, product_id, price, quantity. Now it is necessary to query order information based on these fields and return an Order object.

First, we need to define an Order class for storing query results:

public class Order {
    private int id;
    private int userId;
    private int productId;
    private double price;
    private int quantity;
    // getter和setter方法省略
}

Then, in the mapper file of MyBatis, we can use resultMap to map the query results to the Order object. The specific configuration is as follows:

<resultMap id="OrderResultMap" type="com.example.Order">
  <id property="id" column="id" />
  <result property="userId" column="user_id" />
  <result property="productId" column="product_id" />
  <result property="price" column="price" />
  <result property="quantity" column="quantity" />
</resultMap>

<select id="getOrderById" resultMap="OrderResultMap">
  SELECT id, user_id, product_id, price, quantity
  FROM order
  WHERE id = #{id}
</select>

In the above configuration, we defined a resultMap called "OrderResultMap", whose type attribute specifies the fully qualified name of the Java object to be mapped. Next, we specified the corresponding attribute name and column name in the database table for each field. Finally, refer to the resultMap in the query statement to map the query result to the Order object.

It should be noted that if a field in the query result does not have a corresponding property in the Java object, the field will be mapped as null. In addition, if a field in the query result has multiple corresponding properties in the Java object, the value of the field will be mapped to a list or array.

 
 

My sharing is over here, welcome to the comment area to discuss and communicate! !

If you find it useful, please give it a thumbs up ♥ ♥

Guess you like

Origin blog.csdn.net/weixin_74318097/article/details/132412704