Self-study Mybatis series (3) - mapper of MyBatis


Written in the front: I am very grateful for the book "Mybatis Technical Principles and Practical Combat". Most of the places are in the book. I hope I can write more about my own understanding in the following articles. And most importantly! I feel so ashamed (shy face) every time I knock on the book without thinking. Be sure to pay attention to these issues later. Finally, I would like to thank the friends who liked, commented and corrected, you are the roar! ! !


Mapper mapper

The mapper is a good thing, according to the official documentation:

The true power of MyBatis is in the Mapped Statements. This is where the magic happens.

The simple translation is: The real power of Mybatis comes from its mapping statement , where the miracle is witnessed!
Mapper XML files are relatively simple. If you compare them with the equivalent JDBC code, you will save 95% of the code! The purpose of MyBatis is to focus on SQL and try to save us time and energy for other parts.
The Mapper XML file has only a few first-level elements. Let me introduce:

  • cache - cache configuration for the given namespace.
  • cache-ref - Reference cache configuration from another namespace.
  • resultMap - the most complex and powerful element, describing how to load objects from a database result set
  • parameterMap- Obsolete!
  • sql - A reusable block of SQL that can be referenced by other statements.
  • insert - Maps INSERT statements.
  • update - Maps UPDATE statements.
  • delete - Maps the DELETE statement.
  • select - Maps SELECT statements.

We will break them one by one!

select

The select statement is the statement we use the most in Mybatis. We use query statements more often than we use modify statements, and for inserts, updates, or deletes, they may contain many choices. Just give an example:

<select id="selectPerson" parameterType="int" resultType="map">
         SELECT * FROM PERSON WHERE ID = #{id}
</select>

This statement accepts a parameter of type int (or Integer) and returns data of type Map.
Note the parameter notation: #{id}
Let's see what the code looks like if we use JDBC:

// JDBC代码,不是Mybatis
      String sql = "SELECT * FROM PERSON WHERE ID=?";
      PreparedStatement ps = conn.prepareStatement(sql);
      ps.setInt(1,id);

It is conceivable that if there are many fields, we will be writing a lot of repetitive code in the traditional way, which is not only boring, but also prone to errors. E.g:

<select
  id="selectPerson"
  parameterType="int"
  parameterMap="deprecated"
  resultType="hashmap"
  resultMap="personResultMap"
  flushCache="false"
  useCache="true"
  timeout="10000"
  fetchSize="256"
  statementType="PREPARED"
  resultSetType="FORWARD_ONLY">

Explain one by one:

  • id: It is unique in combination with the Mapper namespace.
  • parameterType: Can you give the full name of the class, or the alias of the class, but it must be defined internally or customized.
  • parameterMap: Will be deprecated soon.
  • resultType: The type of the return value, aliases can also be used, and cannot be used at the same time as resultMap!
  • resultMap: It can perform powerful mapping functions and solve many mapping difficulties. It cannot be used with resultType at the same time. resultMap gives us the opportunity to define the mapping rules ourselves.
  • flushCache: If set to true, the local cache and the second level cache will be cleared. Defaults to false.
  • useCache: The default is true, which is the switch to start the second-level cache.
  • timeout: Set the timeout parameter, and throw an exception when the timeout is exceeded. The unit is seconds. The default value is provided by the manufacturer.
  • fetchSize: Set the total number of fetched records.
  • statementType: Set which JDBC Statement work to use. Possible values: STATEMENT, PREPARED. The default is PREPARED.
    -resultSetType: Values ​​are FORWARD_ONLY, SCROLL_SENSITIVE, SCROLL_INSENSITIVE. The default is unset (depending on the driver).

There are three ways to pass multiple parameters to the mapper:
1. Use Map to pass parameters.
2. Use annotations to pass parameters.
3. Use JavaBean to pass parameters.
First of all, using Map to pass parameters will lead to the loss of business readability, and it is difficult to continue to expand and maintain. This method is not recommended here.
Secondly, use the @Param annotation to pass multiple parameters. The use of this method is affected by the number of parameters. If there are a lot of parameters, do you need to write more than n @Param? So in general, if the number of parameters is less than five, it is best to use this method.
Finally, if there are more than five parameters, we use JavaBeans.

insert、update、delete

Paste the code first, show the element, the code of the official document, and feel it:

<insert
  id="insertAuthor"
  parameterType="domain.blog.Author"
  flushCache="true"
  statementType="PREPARED"
  keyProperty=""
  keyColumn=""
  useGeneratedKeys=""
  timeout="20">
<update
  id="updateAuthor"
  parameterType="domain.blog.Author"
  flushCache="true"
  statementType="PREPARED"
  timeout="20">
<delete
  id="deleteAuthor"
  parameterType="domain.blog.Author"
  flushCache="true"
  statementType="PREPARED"
  timeout="20">

What exactly are they doing, I really don’t bother to write them here. Although there are many elements, few of them can be used. Children who understand SQL can learn immediately after reading the example:

<insert id="insertAuthor">
  insert into Author (id,username,password,email,bio)
  values (#{id},#{username},#{password},#{email},#{bio})
</insert>
<update id="updateAuthor">
  update Author set
    username = #{username},
    password = #{password},
    email = #{email},
    bio = #{bio}
  where id = #{id}
</update>
<delete id="deleteAuthor">
  delete from Author where id = #{id}
</delete>

Yes, the official documentation is so crude. We mainly discuss the issues that need to be addressed - primary key backfill and customization
First, we can use the keyProperty property to specify which is the primary key field, and use the userGeneratedKeys property to set whether the primary key is generated using the database's built-in strategy.
Take a chestnut:

<insert id="insertAuthor" useGeneratedKeys="true" keyProperty="id">
      insert into Author (username,password,email,bio)
      values (#{username},#{password},#{email},#{bio})
</insert>

Here, the id is specified as an auto-increment field. We create POJO, provide getter and setter methods, and we can backfill with the primary key.
However, sometimes we need to set the value of the primary key id according to some special relationships. For example, we require: if there is no record in the table t_role, we set id=1, otherwise we take the maximum id and add 2 to set a new primary key. At this time, we will Need to write like this:

<insert id="insertRole" parameterType="role" userGeneratedKeys="true" keyProperty="id">
      <selectKey keyProperty="id" resultType="int" order="BEFORE">
        select if(max(id) is null,1,max(id)+2) as newId from t_role
      </selectKey>
      insert into t_role
        (id, role_name,note)
      values
        (#{id}, #{rolename}, #{note})
    </insert>

sql

This element can be used to define reusable fragments of SQL code that can be included in other statements. It can be statically (during the loading phase) parameterized. Different property values ​​may differ in include instances. E.g:

  <sql id="userColumns"> 
      ${alias}.id,${alias}.username,${alias}.password 
  </sql>

Above we used the sql element to define userColumns, which can be easily referenced by the refid attribute of the include element to achieve the function of reuse. Please see:

  <select id="selectUsers" resultType="map">
      select
        <include refid="userColumns">
            <property name="alias" value="t1"/>
        </include>,
        <include refid="userColumns">
            <property name="alias" value="t2"/>
        </include>
         from t1
         cross join t2
    </select>

We can also give the refid parameter value

<sql id="someinclude">
  select * from <include refid="${tableName}" />
</sql>

This achieves the definition of one place, and can also be referenced in many places.


parameter

For stored procedures, there are three kinds of parameters: input parameters, output parameters, input and output parameters. In most cases, Mybatis goes back to infer the type of the returned data, so in most cases, do not configure the parameter type and result type. But the field type that returns null needs to be set, because Mybatis cannot determine what type of null is!
Regarding parameters, I would like to talk about the replacement and processing of special characters (#{} and {}) Here I want to say two points: 1. The #{} method can prevent SQL injection to a great extent. 2. Pay attention when using order by dynamic parameters when sorting, use Instead of #
3. Try to use #{}

resultMap

The resultMap element is the most important and powerful element in MyBatis. Just having this thing allows us to save 90% of the code. JDBC needs to retrieve data from ResultSets, that is, because resultMap does in some cases what Mybatis allows you to do, JDBC does not support.
resultMap mainly defines the mapping relationship of a result set. The current version of MyBatis only supports queries. The resultMap is very complicated. I can only briefly list its composition here. After I have a deep understanding of the specifics, I will open a separate episode to study it.
Elements in resultMap:

<resultMap>
    <constructor> <!-- 配置构造方法 -->
        <idArg/>
        <arg/>
    </constructor>
    <id/>  <!-- 定义主键 -->
    <result/>   <!-- 定义普通列的映射关系 -->
    <association/>    <!-- 一对一级联 -->
    <collection/>     <!-- 一对多级联 -->
    <discriminator>  <!-- 鉴别器级联 -->
        <case/>  <!-- 类似switch/case -->
    </discriminator>
</resultMap>

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324849594&siteId=291194637