mybatis primary key auto-increment, associated query, dynamic sql

mybatis primary key auto-increment, associated query, dynamic sql

primary key auto increment

selectKey tag (annotation)

selectKey tag

<!-- 新增用户 -->
<insert id="insertUser" parameterType="com.mybatis.po.User">
    <selectKey keyProperty="userId" order="AFTER" resultType="java.lang.Integer">
        SELECT LAST_INSERT_ID()
    </selectKey>
    INSERT INTO tb_user(user_name,blog_url,remark)
    VALUES(#{
    
    userName},#{
    
    blogUrl},#{
    
    remark})
</insert>

selectKey annotation

@Insert(" insert into table(c1,c2) values (#{c1},#{c2}) ")
@SelectKey(resultType = long.class,keyColumn = "id",before = false,statement = "SELECT LAST_INSERT_ID() AS id",keyProperty = "id")

Parameter explanation:

  • before=false: Since mysql supports self-increasing primary keys, execute the insert statement first, and then obtain the self-increasing primary key value
  • keyColumn: the field name of the self-increasing primary key
  • keyProperty: The entity class corresponds to the storage field. Note that the data type is consistent with the resultType
  • statement: the sql statement actually executed

The value returned by SelectKey exists in the entity class and is thread-safe, so the id will be safely incremented regardless of whether the insertion is successful or not

useGeneratedKeys attribute, keyProperty attribute

xml file method

<!-- 新增用户 -->
<insert id="insertUser" useGeneratedKeys="true" keyProperty="userId" parameterType="com.mybatis.po.User">
    INSERT INTO tb_user(user_name,blog_url,remark)
    VALUES(#{
    
    userName},#{
    
    blogUrl},#{
    
    remark})
</insert>

Annotation method

@Insert("INSERT INTO tb_user(user_name,blog_url,remark)  VALUES(#{userName},#{blogUrl},#{remark}")
@Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")

Parameter explanation:

  • The useGeneratedKeys attribute indicates the use of self-increasing primary keys
  • The keyProperty attribute is the property name of the Java wrapper class object
  • The keyColumn attribute is the field name in the mysql table

non-autoincrement primary key

The uuid type and Oracle's sequence primary key nextval are both generated before insert. In fact, the uuid() method and nextval() method of SQL are executed, so the configuration of the SQL mapping file is similar to the above configuration, and < selectKey is still used > tag pair, but the order attribute is set to before (because it is executed before insert), and the resultType is set according to the actual type of the primary key

UUID configuration

<selectKey keyProperty="userId" order="BEFORE" resultType="java.lang.String">
    SELECT uuid()
</selectKey>

Oracle sequence configuration

<selectKey keyProperty="userId" order="BEFORE" resultType="java.lang.String">
    SELECT 序列名.nextval() FROM DUAL
</selectKey>

Association query

add dependencies

<dependencies>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.2</version>
        </dependency>

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.0</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.34</version>
        </dependency>
    </dependencies>
spring:
  #DataSource数据源
  datasource:
    url: jdbc:mysql://localhost:3306/mybatis_test?useSSL=false&amp
    username: root
    password: root
    driver-class-name: com.mysql.jdbc.Driver

#MyBatis配置
mybatis:
  type-aliases-package: com.mye.hl07mybatis.api.pojo #别名定义
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #指定 MyBatis 所用日志的具体实现,未指定时将自动查找
    map-underscore-to-camel-case: true #开启自动驼峰命名规则(camel case)映射
    lazy-loading-enabled: true #开启延时加载开关
    aggressive-lazy-loading: false #将积极加载改为消极加载(即按需加载),默认值就是false
    lazy-load-trigger-methods: "" #阻挡不相干的操作触发,实现懒加载
    cache-enabled: true #打开全局缓存开关(二级环境),默认值就是true

Use @One annotation to implement one-to-one association query

Requirement: Obtain user information and obtain a one-to-many association permission list at the same time

Create entity class

@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserInfo {
    
    
    private int userId; //用户编号
    private String userAccount; //用户账号
    private String userPassword; //用户密码
    private String blogUrl; //博客地址
    private String remark; //备注
    private IdcardInfo idcardInfo; //身份证信息
}

@Data
@AllArgsConstructor
@NoArgsConstructor
public class IdcardInfo {
    
    
    public int id; //身份证ID
    public int userId; //用户编号
    public String idCardCode; //身份证号码
}

one-to-one relational query

@Repository
@Mapper
public interface UserMapper {
    
    
    /**
     * 获取用户信息和身份证信息
     * 一对一关联查询
     */
    @Select("SELECT * FROM tb_user WHERE user_id = #{userId}")
    @Results(id = "userAndIdcardResultMap", value = {
    
    
            @Result(property = "userId", column = "user_id", javaType = Integer.class, jdbcType = JdbcType.INTEGER, id = true),
            @Result(property = "userAccount", column = "user_account",javaType = String.class, jdbcType = JdbcType.VARCHAR),
            @Result(property = "userPassword", column = "user_password",javaType = String.class, jdbcType = JdbcType.VARCHAR),
            @Result(property = "blogUrl", column = "blog_url",javaType = String.class, jdbcType = JdbcType.VARCHAR),
            @Result(property = "remark", column = "remark",javaType = String.class, jdbcType = JdbcType.VARCHAR),
            @Result(property = "idcardInfo",column = "user_id",
                    one = @One(select = "com.mye.hl07mybatis.api.mapper.UserMapper.getIdcardInfo", fetchType = FetchType.LAZY))
    })
    UserInfo getUserAndIdcardInfo(@Param("userId")int userId);
 
    /**
     * 根据用户ID,获取身份证信息
     */
    @Select("SELECT * FROM tb_idcard WHERE user_id = #{userId}")
    @Results(id = "idcardInfoResultMap", value = {
    
    
            @Result(property = "id", column = "id"),
            @Result(property = "userId", column = "user_id"),
            @Result(property = "idCardCode", column = "idCard_code")})
    IdcardInfo getIdcardInfo(@Param("userId")int userId);
}

Use @Many annotation to implement one-to-many association query

Requirement: Obtain user information and obtain a one-to-many association permission list at the same time

Create entity class

@Data
@AllArgsConstructor
@NoArgsConstructor
public class RoleInfo {
    
    
    private int id; //权限ID
    private int userId; //用户编号
    private String roleName; //权限名称
}

@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserInfo {
    
    
    private int userId; //用户编号
    private String userAccount; //用户账号
    private String userPassword; //用户密码
    private String blogUrl; //博客地址
    private String remark; //备注
    private IdcardInfo idcardInfo; //身份证信息
    private List<RoleInfo> roleInfoList; //权限列表
}

One-to-many relational query

/**
 * 获取用户信息和权限列表
 * 一对多关联查询
 * @author pan_junbiao
 */
@Select("SELECT * FROM tb_user WHERE user_id = #{userId}")
@Results(id = "userAndRolesResultMap", value = {
    
    
        @Result(property = "userId", column = "user_id", javaType = Integer.class, jdbcType = JdbcType.INTEGER, id = true),
        @Result(property = "userAccount", column = "user_account",javaType = String.class, jdbcType = JdbcType.VARCHAR),
        @Result(property = "userPassword", column = "user_password",javaType = String.class, jdbcType = JdbcType.VARCHAR),
        @Result(property = "blogUrl", column = "blog_url",javaType = String.class, jdbcType = JdbcType.VARCHAR),
        @Result(property = "remark", column = "remark",javaType = String.class, jdbcType = JdbcType.VARCHAR),
        @Result(property = "roleInfoList",column = "user_id", many = @Many(select = "com.pjb.mapper.UserMapper.getRoleList", fetchType = FetchType.LAZY))
})
public UserInfo getUserAndRolesInfo(@Param("userId")int userId);
 
/**
 * 根据用户ID,获取权限列表
 * @author pan_junbiao
 */
@Select("SELECT * FROM tb_role WHERE user_id = #{userId}")
@Results(id = "roleInfoResultMap", value = {
    
    
        @Result(property = "id", column = "id"),
        @Result(property = "userId", column = "user_id"),
        @Result(property = "roleName", column = "role_name")})
public List<RoleInfo> getRoleList(@Param("userId")int userId);

MyBatisDynamic SQL

script

Under the annotation version, the use of dynamic SQL needs to include the sql statement in the script tag.

If you use special symbols in <script></script>, use java escape characters, such as double quotes, ""use \"\"instead

<script></script>

<where> tag, <if> tag

if: By judging the dynamic splicing of sql statements, it is generally used to judge query conditions

When the query condition of the query statement cannot be defined exactly due to different input parameters, you can use the <where> tag pair to wrap the SQL query condition that needs to be dynamically specified, and in the <where> tag pair, you can use <if test=" ..."> conditions to set SQL query conditions according to the situation

When using label pairs to wrap the if conditional statement, the first and or or in the query condition will be ignored

<!-- 查询用户信息 -->
<select id="queryUserInfo" parameterType="com.mybatis.po.UserParam" resultType="com.mybatis.po.User">
    SELECT * FROM tb_user
    <where>
        <if test="userId > 0">
            and user_id = #{userId}
        </if>
        <if test="userName!= null and userName!=''">
            and user_name like '%${userName}%'
        </if>
        <if test="sex!=null and sex!=''">
            and sex = #{sex}
        </if>
    </where>
</select>
@Select({
    
    "<script>" +
            " select * from tb_user " +
            "<where>" +
            "<if test = 'userId != null and userId !=\"\" '> " +
            "and user_Id = #{userId} " +
            "</if>" +
            "<if test = 'userPassword != null and userPassword !=\"\" '> " +
            "and user_password like CONCAT('%',#{userPassword},'%')" +
            "</if>" +
            "</where>" +
            "</script>"})

<sql> fragment

MyBatis provides the ability to encapsulate highly reusable SQL statements into "SQL fragments". You can import the SQL statement by declaring it in the mapping configuration that needs to use the SQL fragment. The format for declaring the SQL fragment is as follows:

<sql id="query_user_where">
    <!-- 要复用的SQL语句 -->
</sql>

example:

<!--用户查询条件SQL片段-->
<sql id="query_user_where">
    <if test="userId>0">
        AND user_id = #{userId}
    </if>
    <if test="userName!=null and userName!=''">
        AND user_name like '%${userName}%'
    </if>
    <if test="sex!=null and sex!=''">
        AND sex = #{sex}
    </if>
</sql>
 
<!-- 查询用户信息 -->
<select id="queryUserInfo" parameterType="com.mybatis.po.UserParam" resultType="com.mybatis.po.User">
    SELECT * FROM tb_user
    <where>
        <include refid="query_user_where"/>
        <!-- 这里可能还会引入其他的SQL片段 -->
    </where>
</select>
  • id is the unique identifier of the SQL fragment and cannot be repeated

  • SQL fragments support dynamic SQL statements, but it is recommended not to use the <where> tag in the SQL fragment, but to write the <where> tag in the called SQL method, because the SQL method may also introduce other SQL fragments, If there are <where> tags in these multiple SQL fragments, it will cause statement conflicts.

  • The SQL mapping configuration can also import the SQL fragment in the external Mapper file, just add the namespace information of the Mapper file where it is located before the id of the SQL fragment filled in the refid attribute (such as: test.query_user_where)

<foreach> tag

<foreach> tag attribute description:

Attributes illustrate
index When the iteration object is an array or a list, it indicates the number of current iterations.
item When the iterable object is an array or a list, it represents the elements of the current iteration.
collection The currently traversed object.
open What does the traversal SQL start with.
close What does the traversal SQL end with.
separator After traversing once, the characters added at the end, etc.

need:

SELECT * FROM tb_user WHERE user_id=2 OR user_id=4 OR user_id=5;
-- 或者
SELECT * FROM tb_user WHERE user_id IN (2,4,5);

case:

<!-- 使用foreach标签,拼接or语句 -->
<sql id="query_user_or">
    <if test="ids!=null and ids.length>0">
        <foreach collection="ids" item="user_id" open="AND (" close=")" separator="OR">
            user_id=#{user_id}
        </foreach>
    </if>
</sql>

<!-- 使用foreach标签,拼接in语句 -->
<sql id="query_user_in">
    <if test="ids!=null and ids.length>0">
        AND user_id IN
        <foreach collection="ids" item="user_id" open="(" close=")" separator=",">
            #{user_id}
        </foreach>
    </if>
</sql>
	@Insert("<script>" +
            "insert into tb_user(user_id,user_account,user_password,blog_url,blog_remark) values" +
            "<foreach collection = 'list' item = 'item' index='index' separator=','>" +
            "(#{item.userId},#{item.userAccount},#{item.userPassword},#{item.blogUrl},#{item.blogRemark})" +
            "</foreach>" +
            "</script>")
    int insertByList(@Param("list") List<UserInfo> userInfoList);

    @Select("<script>" +
            "select * from tb_user" +
            " WHERE user_id IN " +
            "<foreach collection = 'list' item = 'id' index='index' open = '(' separator= ',' close = ')'>" +
            "#{id}" +
            "</foreach>" +
            "</script>")
    List<UserInfo> selectByList(@Param("list") List<Integer> ids);
    
	@Update({
    
    "<script>" +
            "<foreach item='item' collection='list' index='index' open='' close='' separator=';'>" +
            " UPDATE tb_user " +
            "<set>" +
            "<if test='item.userAccount != null'>user_account = #{item.userAccount},</if>" +
            "<if test='item.userPassword != null'>user_password=#{item.userPassword}</if>" +
            "</set>" +
            " WHERE user_id = #{item.userId} " +
            "</foreach>" +
            "</script>"})
   	int updateBatch(@Param("list")List<UserInfo> userInfoList);

<choose> tag, <when> tag, <otherwise> tag

Sometimes we don't want to apply to all conditional statements, but just choose one of them. For this situation, MyBatis provides the choose element, which is a bit like the switch statement in Java.

<select id="queryUserChoose" parameterType="com.mybatis.po.UserParam" resultType="com.mybatis.po.User">
    SELECT * FROM tb_user
    <where>
        <choose>
            <when test="userId>0">
                AND user_id = #{userId}
            </when>
            <when test="userName!=null and userName!=''">
                AND user_name like '%${userName}%'
            </when>
            <otherwise>
                AND sex = '女'
            </otherwise>
        </choose>
    </where>
</select>
@Select("<script>"
            + "select * from tb_user "
            + "<where>"
            + "<choose>"
            + "<when test='userId != null and userId != \"\"'>"
            + "   and user_id = #{userId}"
            + "</when>"
            + "<otherwise test='userAccount != null and userAccount != \"\"'> "
            + "   and user_account like CONCAT('%', #{userAccount}, '%')"
            + "</otherwise>"
            + "</choose>"
            + "</where>"
            + "</script>")
    List<UserInfo> selectAll(UserInfo userInfo);

<trim> tag, <set> tag

MyBatis also provides the <trim> tag, we can customize the function of the <where> tag by customizing the <trim> tag. For example, a custom <trim> tag equivalent to the <where> tag

The prefixOverrides attribute ignores text sequences separated by pipes (note that spaces are also necessary in this case). Its effect is to remove all the content specified in the prefixOverrides attribute and insert the content specified in the prefix attribute.

Use the custom <trim> tag to customize the function of the <where> tag to obtain user information:

<!-- 查询用户信息 -->
<select id="queryUserTrim" parameterType="com.mybatis.po.UserParam" resultType="com..mybatis.po.User">
    SELECT * FROM tb_user
    <trim prefix="WHERE" prefixOverrides="AND |OR ">
        <if test="userId>0">
            and user_id = #{userId}
        </if>
        <if test="userName!=null and userName!=''">
            and user_name like '%${userName}%'
        </if>
        <if test="sex!=null and sex!=''">
            and sex = #{sex}
        </if>
    </trim>
</select>

In the SQL configuration method for modifying user information, use the <set> tag to filter redundant commas:

<!-- 修改用户信息 -->
<update id="updateUser" parameterType="com.pjb.mybatis.po.UserParam">
    UPDATE tb_user
    <set>
        <if test="userName != null">user_name=#{userName},</if>
        <if test="sex != null">sex=#{sex},</if>
        <if test="age >0 ">age=#{age},</if>
        <if test="blogUrl != null">blog_url=#{blogUrl}</if>
    </set>
    where user_id = #{userId}
</update>

Here, the <set> tag will dynamically prepend the SET keyword, and also delete irrelevant commas, because these commas are likely to be left behind the generated SQL statement after the conditional statement is used. Because the "if" element is used, if the last "if" is not matched but the previous one is matched, there will be a comma left at the end of the SQL statement.

Guess you like

Origin blog.csdn.net/weixin_43296313/article/details/128836464