04_MyBatis Single Table CRUD and Multiple Table Processing Association Operations

MyBatis single form CRUD operation

The CRUD operation of single standard is mainly based on how to write high-quality SQL statements. If the column and entity attributes in the table do not correspond to each other in single standard operation, it is suggested to use aliases for mapping.

# The difference between {}/ ${value}

  • # {} denotes placeholders
  • The ${value} is a splicing of SQL strings where value must be written. If the parameter type is an entity class, then the attribute name in the entity class is written here.

Writing of Fuzzy Query SQL Statement

- SQL:select * from tb_user where username like '%username%'

- MyBatis:
	- select * from tb_user where username like concat('%',#{username},'%')
    
	- select * from tb_user where username like "%"#{username}""%";
	
	- select * from tb_user where username LIKE '%${value}%' ;
	    - ###If the transfer is a simple data type, value must be written in ${}

Reconstructing Extracting Repeated SQL

Principle of Reconstruction: Write once, no more than three times, if more than three times, need to be reconstructed.

There is an SQL fragment in MyBatis. Extract duplicated SQL

<sql id="tbuser">
	username,
	password,
	email,
	phone
</sql>

Use <include refid="tbuser"/>
Object-oriented design features: encapsulation, inheritance, polymorphism.
Principle of Reconstruction: Write once, no more than three times, if more than three times, need to be reconstructed.

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="shop.tbzj.mapper.UserMapper">

    <sql id="tbUserInfo">
        a.id,
          a.username,
          a.password,
          a.phone,
          a.email,
          a.created,
          a.update
    </sql>

    <select id="selectAll" resultType="TbUser">
        SELECT
          <include refid="tbUserInfo"/>
        FROM
          tbuser AS a
    </select>

    <select id="selectByUsername" resultType="TbUser">
       SELECT

        <include refid="tbUserInfo"/>
  FROM
	tbuser AS a
  WHERE
	username

	LIKE CONCAT("%",#{username},"%");

    </select>
</mapper>

Writing of mapping file for multi-table association operation

Single table or one-to-one result mapping

- If entity attributes and column names are inconsistent in a form operation, in addition to using aliases,
 You can also use `resultMap'for one-to-one mapping in addition to.
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="shop.tbzj.mapper.UserMapper">

    <sql id="tbUserInfo">
        a.id,
          a.username,
          a.password,
          a.phone,
          a.email,
          a.created,
          a.update
    </sql>

    <select id="selectAll" resultMap="tbUserMapping">
        SELECT
          <include refid="tbUserInfo"/>
        FROM
          tbuser AS a
    </select>

    <!-- resultMap Ultimately, the result is mapped to pojo On, type It specifies which one to map to. pojo -->
    <resultMap id="tbUserMapping" type="TbUser">
        <!-- Primary key ,It's very important. If it is multiple fields,Define multiple id -->
        <!-- property: The primary key is in pojo Property name in -->
        <!-- column: Column name of primary key in database -->
       <!--Primary key -->
        <id column="id" property="id"/>
        <!-- Define common attributes -->
        <result column="username" property="user_name"/>
        <result column="password" property="password"/>
        <result column="phone" property="phone"/>
        <result column="email" property="email"/>
        <result column="created" property="created"/>
        <result column="update" property="update"/>
    </resultMap>


<select id="selectByUsername" resultMap="tbUserMapping">
       SELECT
        <include refid="tbUserInfo"/>
        FROM
        	tbuser AS a
        WHERE
        	username
        LIKE CONCAT("%",#{username},"%");
</select>

user_name in entity class TbUser is inconsistent with username field in database tbuser table. Result Map is used for result set mapping.

Relevant Result Set Mapping

One-on-one

For example, an order belongs to a user.

Username and userName can map results, but user_name and username cannot map result sets.

For example, the relationship between the user table and the order table is that a user corresponds to multiple orders. There are two ways to process the mapping of query results.

  • Result set mapping uses resultType.
    Specialized use of a pojo class contains order information and user information.
    For example:
    public class UserOrder extends Order{
    //The following fields are user information fields
    //Inheritance is used to inherit the non-private fields of the Order class.
        private Long id;
        private String user_name;
        private String password;
        private String phone;
        private String email;
        private Date created;
        private Date update;
        
    }
    
    //Write "UserOrder" in resultType.
    
    
    <select id="queryOrderUser" resultType="orderUser">
	SELECT
    	o.id,
    	o.user_id
    	userId,
    	o.number,
    	o.createtime,
    	o.note,
    	u.username,
    	u.address
	FROM
	    `order` o
	LEFT JOIN 
	    `user` u ON o.user_id = u.id
</select>
    
//One drawback is that inheritance in java does not inherit private ownership. If the subclass accesses the non-private attributes and methods of the parent class, they are accessed by the keyword super().

//Classes modified by final cannot be inherited.
  • Result set mapping using resultMap
<resultMap type="order" id="orderUserResultMap">
	<id property="id" column="id" />
	<result property="userId" column="user_id" />
	<result property="number" column="number" />
	<result property="createtime" column="createtime" />
	<result property="note" column="note" />

	<!-- association : Configure one-to-one attributes -->
	<!-- property:order Inside User Property name -->
	<!-- javaType:Attribute type -->
	<association property="user" javaType="user">
		<!-- id:Declare the primary key to indicate user_id Is the unique identifier of the associated query object-->
		<id property="id" column="user_id" />
		<result property="username" column="username" />
		<result property="address" column="address" />
	</association>
</resultMap>

<!-- One-to-one associations, queries orders, orders containing user attributes -->
<select id="queryOrderUserResultMap" resultMap="orderUserResultMap">
	SELECT
	o.id,
	o.user_id,
	o.number,
	o.createtime,
	o.note,
	u.username,
	u.address
	FROM
	`order` o
	LEFT JOIN `user` u ON o.user_id = u.id
</select>
One-to-many result mapping

For example, a user has one or more orders

public class User{
    private int id;
    private String username;
    private Date birthday;
    private String addres;
    //A user has multiple orders stored using the List process.
    private List<Order> orders;
}
UserMapper.xml Writing:

<resultMap type="user" id="userOrderResultMap">
	<id property="id" column="id" />
	<result property="username" column="username" />
	<result property="birthday" column="birthday" />
	<result property="sex" column="sex" />
	<result property="address" column="address" />

	<!-- Configure one-to-many relationships -->
	<collection property="orders" javaType="list" ofType="order">
		<!-- The key to configuration is association. Order Unique ID -->
		<id property="id" column="oid" />
		<result property="number" column="number" />
		<result property="createtime" column="createtime" />
		<result property="note" column="note" />
	</collection>
</resultMap>

<!-- One-to-many association, querying orders and querying orders placed by the user at the same time -->
<select id="queryUserOrder" resultMap="userOrderResultMap">
	SELECT
	u.id,
	u.username,
	u.birthday,
	u.sex,
	u.address,
	o.id oid,
	o.number,
	o.createtime,
	o.note
	FROM
	`user` u
	LEFT JOIN `orders` o ON u.id = o.user_id
</select>
    

Insertion data return primary key problem

  • The table primary key type in MySQL is self-increasing
public class Order {
    private Long id;
    private String name;
    private Double price;
    }

OrderMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="shop.tbzj.mapper.OrderMapper">
    <insert id="insertOrder" useGeneratedKeys="true" keyProperty="id">
          insert into tb_order(name,price)values(#{name},#{price});
    </insert>
</mapper>

Reference resources Chinese official website MyBatis
useGeneratedKeys= "true" opens to get the primary key
keyProperty= "id" is configured to map the acquired primary key to the entity class attribute ID

Test:

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import shop.tbzj.entity.Order;
import shop.tbzj.mapper.OrderMapper;


@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring-context.xml")
public class TestOrder {

    @Autowired
    private OrderMapper orderMapper;

    @Test
    public void insertOrder() {
        Order order = new Order();
        order.setName("tom2");
        order.setPrice(22.3);

        orderMapper.insertOrder(order);
        //Insert a data and return the primary key id to the id in the entity class Order
        System.out.println(order.toString());
    }

}

  • The table primary key type in MySQL is UUID type
<! - Save the order without parameterType because it's in spring-contxt.xml
    Configured in sqlSession Factroy
-->
<insert id="saveOrder">
	<! - SelectKey tag returns the primary key - >.
	Key Column: Which column in the table corresponding to the primary key
	Key Property: Which property in the pojo corresponding to the primary key
	<! - order: The sql to execute the query id before executing the insert statement or the sql UUID to execute the query id after executing the insert statement is BEFORE-->
	<! -- resultType: Set the type of id returned - >
	<selectKey keyColumn="id" keyProperty="id" order="BEFORE"
		resultType="string">
		SELECT LAST_INSERT_ID()
	</selectKey>
	insert into tb_order(id,name,price)values(#{id},#{name},#{price})
</insert>

select last_insert_id(); see what the last insert value is.

How to resolve primary key ID conflict in distributed cluster?
    The discussion here is about id for automatic growth: setting the step size
        One drawback is that if the number of clusters is changed, the step size needs to be reset.
        
    Query self-incremental step size
    SHOW VARIABLES LIKE 'auto_inc%'
    Modify the self-increasing step size
    SET @@auto_increment_increment=10;
    Modify the starting value
    SET @@auto_increment_offset=5;

Keywords: SQL Mybatis xml Attribute

Added by AlGale on Mon, 22 Jul 2019 09:37:06 +0300