MyBatis multi-table query + dynamic sql


MyBatis multi-table query

Set MyBatis execution log in the global configuration file

mybatis:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

1. Multi-table one-to-one query

Suppose there is a user table and article table, and an association relationship in the entity class.

User Entity Class

@Getter
@Setter
@ToString
public class UserInfo {
    
    
    private int id;
    private String name;
    private String password;
}

Article entity class

@Data
public class BlogInfo {
    
    
    private int blogId;
    private String title;
    private String content;
    private Integer userId;
    private Timestamp postTime;
    private String time;
    private UserInfo userInfo;
}

If you want the query result to contain UserInfo information, you need to use it, and you need to use <association>tags for one-to-one mapping, because an article can only correspond to one author.

Controller controller code

@Controller
@ResponseBody
public class BlogController {
    
    
    @Resource
    private BlogService blogService;

    @RequestMapping("/getAllBlog")
    public List<BlogInfo> getAllBlog() {
    
    
        return blogService.getAllBlog();
    }
}

Service service layer code

@Service
public class BlogService {
    
    
    @Resource
    private BlogMapper blogMapper;
    public List<BlogInfo> getAllBlog() {
    
    
        return blogMapper.getAllBlog();
    }
}

BlogMap interface definition

@Mapper
public interface BlogMapper {
    
    

    List<BlogInfo> getAllBlog();
}

MyBatis interface implements xml configuration file

<?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="com.example.demo.mapper.BlogMapper">
    <resultMap id="BlogBean" type="com.example.demo.model.BlogInfo">
        <!-- 映射主键 -->
        <id column="blogId" property="blogId"></id>
        <!-- 普通列映射(表字段->实体类) -->
        <result column="title" property="title"></result>
        <result column="content" property="content"></result>
        <result column="userId" property="userId"></result>
        <result column="postTime" property="postTime"></result>
        <!-- 关联关系 -->
        <association property="userInfo"
                    resultMap="com.example.demo.mapper.UserMapper.UserBean"
                    columnPrefix="u_">

        </association>
    </resultMap>

    <select id="getAllBlog" resultMap="BlogBean">
        select u.userId u_userId,u.username u_username,b.blogId,b.title,b.postTime,b.userId from blog b left join user u on u.userId=b.userId
    </select>
</mapper>

Use <association>labels, which represent a one-to-one result mapping:

  • propertyAttribute: Specify BlogInfothe corresponding associated attribute in the article class, that is, the user instanceuserInfo
  • resultMapAttribute: Specifies the result set mapping of the association relationship, that is, the mapping relationship between the attribute of the UserInfo object and the table
  • columnPrefixAttribute: When binding a one-to-one object, columnPrefix+ is used association.resultMap.columnto map the result set field. association.resultMap.columnRefers to the resultMap attribute in <association>the tag , and columnthe field in the corresponding result set mapping.

insert image description here

Partial results of Postman test printing

[
    {
    
    
        "blogId": 2,
        "title": "Java基础",
        "content": null,
        "userId": 1,
        "postTime": "2022-02-25T11:50:52.000+00:00",
        "time": null,
        "userInfo": {
    
    
            "id": 1,
            "name": "admin",
            "password": null
        }
    },
    {
    
    
        "blogId": 5,
        "title": "我的第一篇博客",
        "content": null,
        "userId": 1,
        "postTime": "2022-02-25T14:05:22.000+00:00",
        "time": null,
        "userInfo": {
    
    
            "id": 1,
            "name": "admin",
            "password": null
        }
    },

If columnPrefix is ​​omitted, and there are exactly the same fields in the two tables, it will cause a query error

2. Many table one to many

One-to-many needs to use <collection>tags, and the usage <association>is the same as that of tags. For example, a user can publish multiple articles.

User Entity Class

@Getter
@Setter
@ToString
public class UserInfo {
    
    
    private int id;
    private String name;
    private String password;
    private List<BlogInfo> blogList;
}

Mapping xml configuration file

<?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="com.example.demo.mapper.UserMapper">
    <resultMap id="UserMap" type="com.example.demo.model.UserInfo">
        <!-- 映射主键的(表中主键和程序实体类中的主键) -->
        <id column="userId" property="id"></id>
        <!-- 普通字段映射 -->
        <result column="username" property="name"></result>
        <result column="password" property="password"></result>

        <!-- 外部关联管理 -->
        <collection property="blogList"
                    resultMap="com.example.demo.mapper.BlogMapper.BlogBean"
                    columnPrefix="b_">

        </collection>
    </resultMap>
    <select id="getAll" resultMap="UserMap">
        select u.userId,u.username,b.blogId b_blogId,b.title b_title,b.postTime b_postTime from user u left join blog b on u.userId=b.userId
    </select>


</mapper>
  • propertyThe attribute corresponds to the attribute blogList in the UserInfo class

Postman partial test results

insert image description here

Dynamic SQL

Dynamic SQL is one of the powerful features of MyBatis. When JDBC splices SQL, you must not forget to add necessary spaces. Pay attention to the comma in the last column name. Dynamic SQL can be used to complete SQL splicing in different scenarios.

MyBatisDynamic SQL

1. <if> tag

When filling in the information for registering certain accounts, there are required and non-required items. If the non-required items and a few more interfaces are fine, but if there are too many non-required items, it will not work. This When you need a dynamic label <if>to judge.

It is assumed that gender and age are optional.

Interface definition

int logonUser(String name, String password, String sex, Integer age);

data sheet

+----------+-------------+------+-----+---------+----------------+
| Field    | Type        | Null | Key | Default | Extra          |
+----------+-------------+------+-----+---------+----------------+
| id       | int(11)     | NO   | PRI | NULL    | auto_increment |
| name     | varchar(50) | NO   |     | NULL    |                |
| password | varchar(25) | NO   |     | NULL    |                |
| sex      | varchar(10) | YES  |     | NULL    |                |
| age      | int(11)     | YES  |     | NULL    |                |
+----------+-------------+------+-----+---------+----------------+

Note if<test=>that it is a fixed syntax, and the judgment fields inside must correspond to the names defined in the interface.

  • <if>The text in will be added if the conditions are met
<?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="com.example.demo.mapper.UserMapper">

    <insert id="logonUser">
        insert into userInfo(id,name,password
        <if test="sex!=null">
            ,sex
        </if>
        <if test="age!=null">
            ,age
        </if>
        ) value(null,#{name},#{password}
        <if test="sex!=null">
            ,#{sex}
        </if>
        <if test="age!=null">
            ,#{age}
        </if>
        )
    </insert>

</mapper>

If both age and sex are null, then the executed sql is

insert into userInfo(id,name,password ) value(null,?,? );

2. <trim> tag

In the previous new user operation, age and sex may be optional items. If there are multiple fields, it is generally considered to <trim>combine <if>tags with tags, and use dynamic generation for multiple fields

<trim>The tag has the following attributes

  • prefix : It represents the entire statement block, prefixed with the value of prefix (add the prefix character at the front of the statement block )
  • suffix : It represents the entire statement block, suffixed with the value of suffix (add the suffix character at the end of the statement block)
  • prefixOverrides : Indicates the prefix to be removed from the entire statement block (delete the first character that meets the condition in the statement block)
  • suffixOverrides : Indicates the suffix to be removed from the entire statement block (delete the character that satisfies the condition at the end of the statement block)

Then you can change the insert statement to the following:

<?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="com.example.demo.mapper.UserMapper">

        <insert id="logonUser">
            insert into userInfo
            <trim prefix="(" suffix=")" suffixOverrides=",">
                id,name,password,
                <if test="sex!=null">
                    sex,
                </if>
                <if test="age!=null">
                    age
                </if>
            </trim>
            value
            <trim prefix="(" suffix=")" suffixOverrides=",">
            null,#{name},#{password},
            <if test="sex!=null">
                #{sex},
            </if>
            <if test="age!=null">
                #{age}
            </if>

            </trim>
        </insert>


</mapper>

Suppose the code to call the interface is

userMapper.logonUser("张辉","123456","男",null);

The final SQL executed is

insert into userInfo ( id,name,password, sex ) value ( null,?,?, ? )
  • Based on the prefix configuration , the beginning part is added(
  • Based on the suffix configuration , the end part is added)
  • Many ifhave ,ended, use suffixOverrides to ,remove the end

3. <where> tag

When using a query statement, if there are multiple conditions, logical operations will be used. If some conditions are not met, it will appear and there is no condition judgment in front of it, causing SQL to report an error

select * from userInfo where and sex!=null and age!=null;

<where>This problem can be well solved by using

  • Generate where, if there is a query condition, where will be generated, if there is no query condition, where will be ignored
  • where will judge whether there is an and in front of the first query condition, and if so, it will be deleted

Find interface definition

List<User> findAllUser(String sex, int age);
<?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="com.example.demo.mapper.UserMapper">
    <select id="findAllUser" resultType="com.example.demo.model.User">
        select * from userInfo
        <where>
            <if test="sex!=null">
                sex=#{
    
    sex}
            </if>
            <if test="age!=null">
                and age=#{
    
    age}
            </if>
        </where>
    </select>

</mapper>

The above <where> tag can also be replaced by <trim prefix="where" prefixOverrides="and>

4. <set> tag

Update user data based on the passed in user object properties, you can use <set>tags to specify dynamic content.

Example:

Modify other attributes that are not null according to the user ID

Interface definition

int updateUserId(User user);

Interface implementation of xml file

  • <set>It will also automatically remove the ,end
  • <set>Labels can also be <trim prefix="set" suffixOverrides=",">replaced using
<?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="com.example.demo.mapper.UserMapper">
    <update id="updateUserId">
        update userInfo
        <set>
            <if test="name!=null">
                name=#{name},
            </if>
            <if test="password!=null">
                password=#{password},
            </if>
            <if test="sex!=null">
                sex=#{sex},
            </if>
            <if test="age!=null">
                age=#{age},
            </if>
        </set>
        where id=#{id}
    </update>

</mapper>

The final spliced ​​SQL

update userInfo SET name=?, password=?, sex=?, age=? where id=?

5. <foreach> tag

This tag can be used when traversing the collection. <foreachThe tag has the following attributes:

  • conection : the collection in the binding method, such as List, Set, Map or array object
  • item : each object when traversing
  • open : the string at the beginning of the statement block
  • close : the string at the end of the statement block
  • separtor : the string for the interval between each traversal

Suppose you want to delete multiple users by multiple user ids

Interface definition and test code

@Mapper
public interface UserMapper {
    
    
    // 方法定义
    int deleteListId(List<Integer> listId);
}


@SpringBootTest
class UserMapperTest {
    
    
    @Resource
    private UserMapper userMapper;

    @Test
    void deleteListId() {
    
    
        List<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3);

        userMapper.deleteListId(list);
    }
}

xml file

<?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="com.example.demo.mapper.UserMapper">
    <delete id="deleteListId">
        delete from userInfo where id in
        <foreach collection="listId" item="id" open="(" close=")" separator=",">
            #{id}
        </foreach>
    </delete>

</mapper>

There are 3 user IDs in my list collection, and the final assembled SQL

delete from userInfo where id in ( ? , ? , ? )

Guess you like

Origin blog.csdn.net/weixin_53946852/article/details/130168226