Mybatis&MybatisPlus参考文档

一、实现简单增删改查

1 创建一个maven项目

2 导入依赖

<dependencies>
  <!--mysql驱动-->
  <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.47</version>
  </dependency>
  <!--mybatis-->
  <dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.2</version>
  </dependency>
  <!--junit-->
  <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
  </dependency>
  <!--log4j,视需求选择-->
  <dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
  </dependency>
  <!--lombok-->
  <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.12</version>
  </dependency>
</dependencies>

<!--在build中配置中resources,来防止我们资源导出失败的问题,防止target上找不到文件-->
<build>
  <resources>
    <resource>
      <directory>src/main/resources</directory>
      <includes>
        <include>**/*.properties</include>
        <include>**/*.xml</include>
      </includes>
      <filtering>true</filtering>
    </resource>
    <resource>
      <directory>src/main/java</directory>
      <includes>
        <include>**/*.properties</include>
        <include>**/*.xml</include>
      </includes>
      <filtering>true</filtering>
    </resource>
  </resources>
</build>

3 编写pojo实体类

User.java

package com.lu.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private int id;
    private String name;
    private String pwd;
}

4 编写Dao接口和Mapper文件

4.1 UserMapper.java

package com.lu.dao;

import com.lu.pojo.User;

import java.util.List;

public interface UserMapper {

    int addUser(User user);

    int deleteUserById(int id);

    int updateUser(User user);

    User queryUserById(int id);

    List<User> queryAllUser();
  
    //通过注解写sql,就写下接口,Mapper.xml不用写了,
    //本质:反射机制实现的,底层:动态代理
  	@Update("update mybatis.user set name = #{name},pwd =#{pwd} where id = #{id}")
  	int updateUser2(User user);
   
    @Select("select * from mybatis.user")
    List<User> queryAllUser2();
}

4.2 UserMapper.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="com.lu.dao.UserMapper">

    <insert id="addUser" parameterType="User">
        insert into mybatis.user(id, name, pwd) VALUES (#{id},#{name},#{pwd})
    </insert>

    <delete id="deleteUserById" parameterType="int">
        delete from mybatis.user where id = #{id}
    </delete>
    
    <update id="updateUser" parameterType="User">
        update mybatis.user set name = #{name},pwd =#{pwd} where id = #{id}
    </update>

    <select id="queryUserById" parameterType="int" resultType="User">
        select * from user where id = #{id}
    </select>

    <select id="queryAllUser" resultType="User">
        select * from mybatis.user
    </select>
</mapper>

5 编写核心配置文件

5.1 db.properties

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8
username=root
password=123456

5.2 log4j.properties

## Global logging configuration 开发时候建议使用 debug
log4j.rootLogger=DEBUG, stdout
## Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

#控制台输出的相关设置
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
#log4j.appender.console.layout.ConversionPattern=[%c]-%m%n
log4j.appender.console.layout.ConversionPattern=%5p [%t] - %m%n

#文件输出的相关设置
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./log/rzk.log
log4j.appender.file.MaxFileSize=10mb
log4j.appender.file.Threshold=DEBUG
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n

#日志输出级别
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG

5.3 mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

    <!--这边也可以写死,然后别的地方进行引用-->
    <properties resource="db.properties"/>

    <settings>
        <!--标准日志工厂的实现-->
        <!--<setting name="logImpl" value="STDOUT_LOGGING"/>-->
        <setting name="logImpl" value="LOG4J"/>
    </settings>

    <typeAliases>
        <!--这边可以整个包引入,也可以单个引入,注意顺序
            实体类较少的情况下,可以用前一种,还可以自定义别名
            实体类较多的情况下,可以使用后一种,默认别名为首字母小写的类名,比如user,如果需要改别名,可以在类上面通过注解@Alias("user")定义
        -->
<!--        <typeAlias type="com.lu.pojo.User" alias="User"/>-->
        <package name="com.lu.pojo"/>
    </typeAliases>

    <environments default="development">
        <environment>
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="com/lu/dao/UserMapper.xml"/>
    </mappers>
</configuration>

6 编写工具类,获取SqlSession

package com.lu.utils;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;

public class MybatisUtils {

    private static SqlSessionFactory sqlSessionFactory;

    static {
        //获取sqlSessionFactory对象
        try {
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //    从 SqlSessionFactory 中获取 SqlSession
    //    既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。
    //    SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句。例如:
    public static SqlSession getSqlSession() {
        return sqlSessionFactory.openSession(true);
    }
}

7 开始测试

package com.lu.dao;

import com.lu.pojo.User;
import com.lu.utils.MybatisUtils;
import junit.framework.TestCase;
import org.apache.ibatis.session.SqlSession;

import java.util.List;

public class UserMapperTest extends TestCase {

    public void testAddUser() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        try {
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            int result = mapper.addUser(new User(11, "123", "1234"));
            System.out.println(result);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            sqlSession.close();
        }
    }

    public void testDeleteUserById() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        try {
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            int result = mapper.deleteUserById(5);
            System.out.println(result);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            sqlSession.close();
        }
    }

    public void testUpdateUser() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        try {
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            int result = mapper.updateUser(new User(11, "天真123", "12344444"));
            System.out.println(result);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            sqlSession.close();
        }
    }

    public void testQueryUserById() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        try {
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            User user = mapper.queryUserById(11);
            System.out.println(user.toString());
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            sqlSession.close();
        }
    }

    public void testQueryAllUser() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        try {
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            List<User> list = mapper.queryAllUser();
            System.out.println(list.toString());
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            sqlSession.close();
        }
    }

}

8 注意点

  1. Mybatis-config.xml中,注意标签顺序,不能乱,否则报错。

  2. typeAliases标签可以给一个包下面的pojo设置默认别名,也可以单独给一个pojo设置别名,视实际场景而定

    <typeAliases>
      <!--这边可以整个包引入,也可以单个引入,注意顺序
          实体类较少的情况下,可以用前一种,还可以自定义别名
          实体类较多的情况下,可以使用后一种,默认别名为首字母小写的类名,比如user,如果需要改别名,
    			可以在类上面通过注解 @Alias("user") 定义
     -->
      <typeAlias type="com.lu.pojo.User" alias="User"/>
      <package name="com.lu.pojo"/>
    </typeAliases>
    
  3. 这边的log4j.properties 配置不一定准确,实际应用请自行百度。

  4. 如果在Mybatis-config.xml配置的setting中没有设置,默认不输出,STDOUT_LOGGING为标准日志,如果用的话,什么都不用配置,LOG4J需要配置log4j.properties

    <settings>
    	<!--标准日志工厂的实现-->
    	<!--<setting name="logImpl" value="STDOUT_LOGGING"/>-->
    	<setting name="logImpl" value="LOG4J"/>
    </settings>
    
  5. 解决属性名和字段名不一致的问题(2种解决办法)

    <!--1.as别名-->
    <select id="getUserById" resultMap="UserMap">
      select id,name,pwd as password from mybatis.user where id = #{id}
    </select>
    
    <!--2.结果集映射-->
    <resultMap id="UserMap" type="User">
      <!--column数据库中的字段,property实体类中的字段-->
      <!--<result column="id" property="id"/>-->
      <!--<result column="name" property="name"/>-->
      <result column="pwd" property="password"/>
    </resultMap>
    
    <select id="getUserById" resultMap="UserMap">
      select id,name,pwd from mybatis.user where id = #{id}
    </select>
    
    <!--3.spring的话也可以用注解-->
    @Table(name = "tab_user")
    Column
    

9 中文文档地址

https://mybatis.org/mybatis-3/zh/index.html

二、作用域(Scope)和生命周期

不同作用域和生命周期类别是至关重要的,因为错误的使用会导致非常严重的并发问题。

SqlSessionFactoryBuilder

  • 一旦创建SqlSessionFactory就不需要他了,局部变量
  • 局部变量

SqlSessionFactory

  • 说白了就是可以想象为数据库连接池
  • SqlSessionFactory一旦被创建,就应该在应用的运行期间一直存在,没有任何理由丢弃它或者重新创建另一个实例
  • 因此SqlSessionFactory的最佳作用域就是应用作用域
  • 最简单的就是使用单例模式或者静态单例模式

SqlSession

  • 连接到连接池的一个请求
  • SqlSession的实例不是线程安全的,因此不能被共享,所以它的最佳作用域就是请求或者方法作用域
  • 用完之后要赶紧关闭,否则资源被占用!

img

三、分页

limit分页(基于sql实现)

接口

List<User> getUserByLimit(Map<String,Integer> map);

mapper

<select id="getUserByLimit" parameterType="map" resultType="user">
    select * from mybatis.user limit #{startIndex},#{pageSize}
</select>

测试

@Test
public void getUserByLimit() {
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

    Map<String, Integer> map = new HashMap<String, Integer>();
    map.put("startIndex", 1);
    map.put("pageSize", 3);

    List<User> userList = userMapper.getUserByLimit(map);

    for (User user : userList) {
        System.out.println(user);
    }

    sqlSession.close();
}

RowBounds分页(基于Java代码实现)

接口

List<User> getUserByRowBounds();

mapper

<select id="getUserByRowBounds" parameterType="map" resultType="user">
     select * from mybatis.user
</select>

测试

@Test
public void getUserByRowBounds() {
  SqlSession sqlSession = MybatisUtils.getSqlSession();
  //RowBounds实现
  RowBounds rowBounds = new RowBounds(1, 2);//下标为1的开始,即第二个开始,取2个
  List<User> userList = sqlSession.selectList("com.lu.dao.UserMapper.getUserByRowBounds", null, rowBounds);
  for (User user : userList) {
    System.out.println(user);
  }
  sqlSession.close();
}

分页插件(例如:PageHelper)

https://pagehelper.github.io/

四、多表查询

多对一(多个学生对应一个老师)

目标:

select s.id,s.name,t.name from Student s,Teacher t where s.tid = t.id

pojo

package com.lu.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    private int id;
    private String name;
    private Teacher teacher;
}
package com.lu.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Teacher {
    private int id;
    private String name;
}

接口

List<Student> getStudent();

List<Student> getStudent2();

mapper

按照查询嵌套处理

<!--1.按照查询嵌套处理-->
<select id="getStudent" resultMap="StudentTeacher">
    select * from mybatis.student
</select>

<resultMap id="StudentTeacher" type="Student">
    <result property="id" column="id"/>
    <result property="name" column="name"/>
    <!--复杂属性,我们需要单独处理
            对象:association
            集合:collection
        -->
    <association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>
</resultMap>

<!--这个貌似不用谢mapper接口???但是为了规范,尽量都写下吧-->
<select id="getTeacher" resultType="Teacher">
    select * from mybatis.teacher where id = #{tid}
</select>

按照结果嵌套处理(推荐)

<!--2.按照结果嵌套-->
<select id="getStudent2" resultMap="StudentTeacher2">
    select s.id as sid, s.name as sname, t.id as t_id,t.name as tname
    from mybatis.student s,
    mybatis.teacher t
    where s.tid = t.id;
</select>

<resultMap id="StudentTeacher2" type="Student">
    <result property="id" column="sid"/>
    <result property="name" column="sname"/>
    <association property="teacher" javaType="Teacher">
        <result property="id" column="t_id"/>
        <result property="name" column="tname"/>
    </association>
</resultMap>

一对多

目标:

select t.id as t_id, t.name as tname, s.id as sid, s.name as sname,s.tid as tid
from teacher t,student s
where t.id = s.tid and t.id = #{tid};

pojo

package com.lu.pojo;

import lombok.Data;

@Data
public class Student {
    private int id;
    private String name;
    //关联老师的id
    private int tid;
}
package com.lu.pojo;

import lombok.Data;

import java.util.List;

@Data
public class Teacher {
    private int id;
    private String name;
    //一个老师有多个学生
    private List<Student> studentList;
}

接口

List<Teacher> getTeacher();

//获取指定老师下的所有学生及老师的信息
Teacher getTeacherById(@Param("tid") int id);

//获取指定老师下的所有学生及老师的信息
Teacher getTeacherById2(@Param("tid") int id);

mapper

按照结果嵌套(推荐)

<!--1.按照结果嵌套处理-->
<select id="getTeacherById" resultMap="TeacherStudent">
    select t.id as t_id, t.name as tname, s.id as sid, s.name as sname,s.tid as tid
    from teacher t,student s
    where t.id = s.tid and t.id = #{tid};
</select>

<resultMap id="TeacherStudent" type="Teacher">
    <result property="id" column="t_id"/>
    <result property="name" column="tname"/>
    <collection property="studentList" ofType="Student">
        <result property="id" column="sid"/>
        <result property="name" column="sname"/>
        <result property="tid" column="tid"/>
    </collection>
</resultMap>

按照查询嵌套

<!--2.按照查询嵌套处理-->
<select id="getTeacherById2" resultMap="TeacherStudent2">
    select * from teacher where id =#{tid}
</select>

<resultMap id="TeacherStudent2" type="Teacher">
    <collection property="studentList" ofType="Student" select="getStudentByTeacherId" column="id"/>
</resultMap>

<select id="getStudentByTeacherId" resultType="Student">
    select * from student where tid = #{tid}
</select>

<!--查询全部老师相关信息-->
<select id="getTeacher" resultMap="TeacherStudent2">
    select * from teacher
</select>

多对多

参考下这个:

https://blog.csdn.net/ysvae/article/details/81090759?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link

小结

  • 关联association【多对一】

  • 集合collection 【一对多】

  • JavaType用来指定实体类中属性的类型

  • ofType用来指定映射到List或者集合中的pojo类型,泛型中的约束类型

注意点

  • 保证sql的可读性,尽量通俗易懂
  • 注意一对多和多对一中,属性名和字段的问题
  • 如果不好排查错误,可以用日志输出,log4j之类的

五、动态SQL

所谓的动态SQL,本质还是SQL语句,只是我们可以在SQL层面,去执行一个逻辑代码

IF

<select id="queryBlogIF" parameterType="map" resultType="blog">
  select * from mybatis.blog
  <where>
    <if test="title != null">
      title = #{title}
    </if>
    <if test="author != null">
      and author = #{author}
    </if>
  </where>
</select>

<update id="updateBlog" parameterType="map">
  update mybatis.blog
  <set>
    <if test="title != null">
      title = #{title},
    </if>
    <if test="author != null">
      author = #{author}
    </if>
  </set>
  where id = #{id}
</update>

Choose(when,otherwise)

<!-- 相当于switch -->
<select id="queryBlogChoose" parameterType="map" resultType="blog">
  select * from mybatis.blog
  <where>
    <choose>
      <when test="title != null">
        title = #{title}
      </when>
      <when test="author != null">
        author = #{author}
      </when>
      <otherwise>
        views = #{views}
      </otherwise>
    </choose>
  </where>
</select>

Trim(where,set)

案例(错误

<select id="findActiveBlogLike" resultType="Blog">
  SELECT * FROM BLOG
  WHERE
  <if test="state != null">
    state = #{state}
  </if>
  <if test="title != null">
    AND title like #{title}
  </if>
  <if test="author != null and author.name != null">
    AND author_name like #{author.name}
  </if>
</select>

如果没有匹配的条件会怎么样?最终这条 SQL 会变成这样:

SELECT * FROM BLOG
WHERE

这会导致查询失败。如果匹配的只是第二个条件又会怎样?这条 SQL 会是这样:

SELECT * FROM BLOG
WHERE
AND title like ‘someTitle’

这个查询也会失败。这个问题不能简单地用条件元素来解决。这个问题是如此的难以解决,以至于解决过的人不会再想碰到这种问题。

where

MyBatis 有一个简单且适合大多数场景的解决办法。而在其他场景中,可以对其进行自定义以符合需求。而这,只需要一处简单的改动:

<select id="findActiveBlogLike" resultType="Blog">
  SELECT * FROM BLOG
  <where>
    <if test="state != null">
         state = #{state}
    </if>
    <if test="title != null">
        AND title like #{title}
    </if>
    <if test="author != null and author.name != null">
        AND author_name like #{author.name}
    </if>
  </where>
</select>

where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。

如果 where 元素与你期望的不太一样,你也可以通过自定义 trim 元素来定制 where 元素的功能。比如,和 where 元素等价的自定义 trim 元素为:

<trim prefix="WHERE" prefixOverrides="AND |OR ">
  ...
</trim>

prefixOverrides 属性会忽略通过管道符分隔的文本序列(注意此例中的空格是必要的)。上述例子会移除所有 prefixOverrides 属性中指定的内容,并且插入 prefix 属性中指定的内容。

set

用于动态更新语句的类似解决方案叫做 setset 元素可以用于动态包含需要更新的列,忽略其它不更新的列。比如:

<update id="updateAuthorIfNecessary">
  update Author
    <set>
      <if test="username != null">username=#{username},</if>
      <if test="password != null">password=#{password},</if>
      <if test="email != null">email=#{email},</if>
      <if test="bio != null">bio=#{bio}</if>
    </set>
  where id=#{id}
</update>

这个例子中,set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)。

来看看与 set 元素等价的自定义 trim 元素吧:

<trim prefix="SET" suffixOverrides=",">  ...</trim>

Foreach

动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)。比如:

<select id="selectPostIn" resultType="domain.blog.Post">  SELECT *  FROM POST P  WHERE ID in  <foreach item="item" index="index" collection="list"      open="(" separator="," close=")">        #{item}  </foreach></select>

foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。这个元素也不会错误地添加多余的分隔符,看它多智能!

提示 你可以将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象作为集合参数传递给 foreach。当使用可迭代对象或者数组时,index 是当前迭代的序号,item 的值是本次迭代获取到的元素。当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。

script

要在带注解的映射器接口类中使用动态 SQL,可以使用 script 元素。比如:

    @Update({"<script>",
      "update Author",
      "  <set>",
      "    <if test='username != null'>username=#{username},</if>",
      "    <if test='password != null'>password=#{password},</if>",
      "    <if test='email != null'>email=#{email},</if>",
      "    <if test='bio != null'>bio=#{bio}</if>",
      "  </set>",
      "where id=#{id}",
      "</script>"})
    void updateAuthorValues(Author author);

多数据库支持

如果配置了 databaseIdProvider,你就可以在动态代码中使用名为 “_databaseId” 的变量来为不同的数据库构建特定的语句。比如下面的例子:

<insert id="insert">
  <selectKey keyProperty="id" resultType="int" order="BEFORE">
    <if test="_databaseId == 'oracle'">
      select seq_users.nextval from dual
    </if>
    <if test="_databaseId == 'db2'">
      select nextval for seq_users from sysibm.sysdummy1"
    </if>
  </selectKey>
  insert into users values (#{id}, #{name})
</insert>

注意点

where标签下的and貌似可以不写,没啥用

六、事务(待完善)

七、Mybatis-plus

快速开始

  1. new 一个springboot项目
  2. 引入依赖
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- test -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-test</artifactId>
  <scope>test</scope>
</dependency>
<!-- lombok -->
<dependency>
  <groupId>org.projectlombok</groupId>
  <artifactId>lombok</artifactId>
  <optional>true</optional>
</dependency>
<!-- mybatis-plus -->
<dependency>
  <groupId>com.baomidou</groupId>
  <artifactId>mybatis-plus-boot-starter</artifactId>
  <version>3.0.5</version>
</dependency>
<!-- mysql驱动 -->
<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <version>5.1.47</version>
</dependency>
<!-- junit -->
<dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>4.12</version>
  <scope>test</scope>
</dependency>
  1. 配置数据源和日志输出

    application.properties

#数据库连接配置
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus?useSSL=false&useUnicode=true&characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=123456

#配置日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
  1. 写实体类
package com.lu.pojo;

import lombok.Data;

@Data
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
}
  1. 写mapper接口
package com.lu.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.lu.pojo.User;
import org.springframework.stereotype.Repository;

@Repository
public interface UserMapper extends BaseMapper<User> {

}
  1. 启动类上配置mapper扫描路径
package com.lu;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

//扫描mapper文件夹
@MapperScan("com.lu.mapper")
@SpringBootApplication
public class MybatisPlusApplication {

	public static void main(String[] args) {
		SpringApplication.run(MybatisPlusApplication.class, args);
	}

}
  1. 写测试类
package com.lu.mapper;

import com.lu.mapper.UserMapper;
import com.lu.pojo.User;
import org.junit.Assert;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.List;

@RunWith(SpringRunner.class)
@SpringBootTest
class UserMapperTest {

    //继承了BaseMapper,所有默认方法都来自父类,也可以自己写方法
    @Autowired
    private UserMapper userMapper;

    @Test
    public void testSelect() {
        //参数是一个Wrapper,条件构造器,这里我们先不用null
        //查询全部用户
        List<User> userList = userMapper.selectList(null);
        userList.forEach(System.out::println);
    }

}

主键生成

分布式系统唯一ID生成方案汇总 : https://blog.csdn.net/CodingNO1/article/details/106874295/

规则设置

通过@TableId注解控制,不用注解控制默认为雪花算法

package com.lu.pojo;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;

@Data
public class User {
    //对应数据库的主键
    @TableId(type = IdType.ID_WORKER)
    private Long id;
    private String name;
    private Integer age;
    private String email;
}

可选类型

public enum IdType {
    AUTO(0), //数据库ID自增 
    NONE(1), //该类型为未设置主键类型
    INPUT(2), //用户输入ID

    /* 以下3种类型、只有当插入对象ID 为空,才自动填充。 */ 
    ID_WORKER(3), //全局唯一ID (idWorker) 
    UUID(4), //全局唯一ID (UUID) 
    ID_WORKER_STR(5); //字符串全局唯一ID (idWorker 的字符串表示)
}

雪花算法(snowflake)

​ snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID。其核心思想是:使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是0。具体实现的代码可以参看https://github.com/twitter/snowflake。

代码实现:

public class IdWorker
{
    private long workerId;
    private long datacenterId;
    private long sequence = 0L;

    private static long twepoch = 1288834974657L;

    private static long workerIdBits = 5L;
    private static long datacenterIdBits = 5L;
    private static long maxWorkerId = -1L ^ (-1L << (int)workerIdBits);
    private static long maxDatacenterId = -1L ^ (-1L << (int)datacenterIdBits);
    private static long sequenceBits = 12L;

    private long workerIdShift = sequenceBits;
    private long datacenterIdShift = sequenceBits + workerIdBits;
    private long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
    private long sequenceMask = -1L ^ (-1L << (int)sequenceBits);

    private long lastTimestamp = -1L;
    private static object syncRoot = new object();

    public IdWorker(long workerId, long datacenterId)
    {

        // sanity check for workerId
        if (workerId > maxWorkerId || workerId < 0)
        {
            throw new ArgumentException(string.Format("worker Id can't be greater than %d or less than 0", maxWorkerId));
        }
        if (datacenterId > maxDatacenterId || datacenterId < 0)
        {
            throw new ArgumentException(string.Format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
        }
        this.workerId = workerId;
        this.datacenterId = datacenterId;
    }

    public long nextId()
    {
        lock (syncRoot)
        {
            long timestamp = timeGen();

            if (timestamp < lastTimestamp)
            {
                throw new ApplicationException(string.Format("Clock moved backwards.  Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
            }

            if (lastTimestamp == timestamp)
            {
                sequence = (sequence + 1) & sequenceMask;
                if (sequence == 0)
                {
                    timestamp = tilNextMillis(lastTimestamp);
                }
            }
            else
            {
                sequence = 0L;
            }

            lastTimestamp = timestamp;

            return ((timestamp - twepoch) << (int)timestampLeftShift) | (datacenterId << (int)datacenterIdShift) | (workerId << (int)workerIdShift) | sequence;
        }
    }

    protected long tilNextMillis(long lastTimestamp)
    {
        long timestamp = timeGen();
        while (timestamp <= lastTimestamp)
        {
            timestamp = timeGen();
        }
        return timestamp;
    }

    protected long timeGen()
    {
        return (long)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds;
    }
}

代码生成器

CRUD接口

Service CRUD 接口

说明:

  • 通用 Service CRUD 封装IService (opens new window)接口,进一步封装 CRUD 采用 get 查询单行 remove 删除 list 查询集合 page 分页 前缀命名方式区分 Mapper 层避免混淆,
  • 泛型 T 为任意实体对象
  • 建议如果存在自定义通用 Service 方法的可能,请创建自己的 IBaseService 继承 Mybatis-Plus 提供的基类
  • 对象 Wrapper条件构造器
Save
// 插入一条记录(选择字段,策略插入)
boolean save(T entity);
// 插入(批量)
boolean saveBatch(Collection<T> entityList);
// 插入(批量)
boolean saveBatch(Collection<T> entityList, int batchSize);
SaveOrUpdate
// TableId 注解存在更新记录,否插入一条记录
boolean saveOrUpdate(T entity);
// 根据updateWrapper尝试更新,否继续执行saveOrUpdate(T)方法
boolean saveOrUpdate(T entity, Wrapper<T> updateWrapper);
// 批量修改插入
boolean saveOrUpdateBatch(Collection<T> entityList);
// 批量修改插入
boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize);
Remove
// 根据 entity 条件,删除记录
boolean remove(Wrapper<T> queryWrapper);
// 根据 ID 删除
boolean removeById(Serializable id);
// 根据 columnMap 条件,删除记录
boolean removeByMap(Map<String, Object> columnMap);
// 删除(根据ID 批量删除)
boolean removeByIds(Collection<? extends Serializable> idList);
Update
// 根据 UpdateWrapper 条件,更新记录 需要设置sqlset
boolean update(Wrapper<T> updateWrapper);
// 根据 whereEntity 条件,更新记录
boolean update(T entity, Wrapper<T> updateWrapper);
// 根据 ID 选择修改
boolean updateById(T entity);
// 根据ID 批量更新
boolean updateBatchById(Collection<T> entityList);
// 根据ID 批量更新
boolean updateBatchById(Collection<T> entityList, int batchSize);
Get
// 根据 ID 查询
T getById(Serializable id);
// 根据 Wrapper,查询一条记录。结果集,如果是多个会抛出异常,随机取一条加上限制条件 wrapper.last("LIMIT 1")
T getOne(Wrapper<T> queryWrapper);
// 根据 Wrapper,查询一条记录
T getOne(Wrapper<T> queryWrapper, boolean throwEx);
// 根据 Wrapper,查询一条记录
Map<String, Object> getMap(Wrapper<T> queryWrapper);
// 根据 Wrapper,查询一条记录
<V> V getObj(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);
List
// 查询所有
List<T> list();
// 查询列表
List<T> list(Wrapper<T> queryWrapper);
// 查询(根据ID 批量查询)
Collection<T> listByIds(Collection<? extends Serializable> idList);
// 查询(根据 columnMap 条件)
Collection<T> listByMap(Map<String, Object> columnMap);
// 查询所有列表
List<Map<String, Object>> listMaps();
// 查询列表
List<Map<String, Object>> listMaps(Wrapper<T> queryWrapper);
// 查询全部记录
List<Object> listObjs();
// 查询全部记录
<V> List<V> listObjs(Function<? super Object, V> mapper);
// 根据 Wrapper 条件,查询全部记录
List<Object> listObjs(Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询全部记录
<V> List<V> listObjs(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);
Page
// 无条件分页查询
IPage<T> page(IPage<T> page);
// 条件分页查询
IPage<T> page(IPage<T> page, Wrapper<T> queryWrapper);
// 无条件分页查询
IPage<Map<String, Object>> pageMaps(IPage<T> page);
// 条件分页查询
IPage<Map<String, Object>> pageMaps(IPage<T> page, Wrapper<T> queryWrapper);
Count
// 查询总记录数
int count();
// 根据 Wrapper 条件,查询总记录数
int count(Wrapper<T> queryWrapper);
Chain(链式操作)
query
// 链式查询 普通
QueryChainWrapper<T> query();
// 链式查询 lambda 式。注意:不支持 Kotlin
LambdaQueryChainWrapper<T> lambdaQuery(); 

// 示例:
query().eq("column", value).one();
lambdaQuery().eq(Entity::getId, value).list();
update
// 链式更改 普通
UpdateChainWrapper<T> update();
// 链式更改 lambda 式。注意:不支持 Kotlin 
LambdaUpdateChainWrapper<T> lambdaUpdate();

// 示例:
update().eq("column", value).remove();
lambdaUpdate().eq(Entity::getId, value).update(entity);

Mapper CRUD 接口

说明:

  • 通用 CRUD 封装BaseMapper (opens new window)接口,为 Mybatis-Plus 启动时自动解析实体表关系映射转换为 Mybatis 内部对象注入容器
  • 泛型 T 为任意实体对象
  • 参数 Serializable 为任意类型主键 Mybatis-Plus 不推荐使用复合主键约定每一张表都有自己的唯一 id 主键
  • 对象 Wrapper条件构造器
Insert
// 插入一条记录
int insert(T entity);
Delete
// 根据 entity 条件,删除记录
int delete(@Param(Constants.WRAPPER) Wrapper<T> wrapper);
// 删除(根据ID 批量删除)
int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
// 根据 ID 删除
int deleteById(Serializable id);
// 根据 columnMap 条件,删除记录
int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
Update
// 根据 whereEntity 条件,更新记录
int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper<T> updateWrapper);
// 根据 ID 修改
int updateById(@Param(Constants.ENTITY) T entity);
Select
// 根据 ID 查询
T selectById(Serializable id);
// 根据 entity 条件,查询一条记录
T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

// 查询(根据ID 批量查询)
List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
// 根据 entity 条件,查询全部记录
List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 查询(根据 columnMap 条件)
List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
// 根据 Wrapper 条件,查询全部记录
List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询全部记录。注意: 只返回第一个字段的值
List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

// 根据 entity 条件,查询全部记录(并翻页)
IPage<T> selectPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询全部记录(并翻页)
IPage<Map<String, Object>> selectMapsPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询总记录数
Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

条件构造器

说明:

  • 以下出现的第一个入参boolean condition表示该条件是否加入最后生成的sql中,例如:query.like(StringUtils.isNotBlank(name), Entity::getName, name) .eq(age!=null && age >= 0, Entity::getAge, age)
  • 以下代码块内的多个方法均为从上往下补全个别boolean类型的入参,默认为true
  • 以下出现的泛型Param均为Wrapper的子类实例(均具有AbstractWrapper的所有方法)
  • 以下方法在入参中出现的R为泛型,在普通wrapper中是String,在LambdaWrapper中是函数(例:Entity::getId,Entity为实体类,getId为字段idgetMethod)
  • 以下方法入参中的R column均表示数据库字段,当R具体类型为String时则为数据库字段名(字段名是数据库关键字的自己用转义符包裹!)!而不是实体类数据字段名!!!,另当R具体类型为SFunction时项目runtime不支持eclipse自家的编译器!!!
  • 以下举例均为使用普通wrapper,入参为MapList的均以json形式表现!
  • 使用中如果入参的Map或者List,则不会加入最后生成的sql中!!!
  • 有任何疑问就点开源码看,看不懂函数点击我学习新知识(opens new window)

警告:

不支持以及不赞成在 RPC 调用中把 Wrapper 进行传输

  1. wrapper 很重
  2. 传输 wrapper 可以类比为你的 controller 用 map 接收值(开发一时爽,维护火葬场)
  3. 正确的 RPC 调用姿势是写一个 DTO 进行传输,被调用方再根据 DTO 执行相应的操作
  4. 我们拒绝接受任何关于 RPC 传输 Wrapper 报错相关的 issue 甚至 pr

AbstractWrapper

说明:

QueryWrapper(LambdaQueryWrapper) 和 UpdateWrapper(LambdaUpdateWrapper) 的父类
用于生成 sql 的 where 条件, entity 属性也用于生成 sql 的 where 条件
注意: entity 生成的 where 条件与 使用各个 api 生成的 where 条件没有任何关联行为

allEq
allEq(Map<R, V> params)
allEq(Map<R, V> params, boolean null2IsNull)
allEq(boolean condition, Map<R, V> params, boolean null2IsNull)

个别参数说明:

params : key为数据库字段名,value为字段值
null2IsNull : 为true则在mapvaluenull时调用 isNull 方法,为false时则忽略valuenull

  • 例1: allEq({id:1,name:"老王",age:null})—>id = 1 and name = '老王' and age is null
  • 例2: allEq({id:1,name:"老王",age:null}, false)—>id = 1 and name = '老王'
allEq(BiPredicate<R, V> filter, Map<R, V> params)
allEq(BiPredicate<R, V> filter, Map<R, V> params, boolean null2IsNull)
allEq(boolean condition, BiPredicate<R, V> filter, Map<R, V> params, boolean null2IsNull) 

个别参数说明:

filter : 过滤函数,是否允许字段传入比对条件中
paramsnull2IsNull : 同上

  • 例1: allEq((k,v) -> k.indexOf("a") >= 0, {id:1,name:"老王",age:null})—>name = '老王' and age is null
  • 例2: allEq((k,v) -> k.indexOf("a") >= 0, {id:1,name:"老王",age:null}, false)—>name = '老王'
eq
eq(R column, Object val)
eq(boolean condition, R column, Object val)
  • 等于 =
  • 例: eq("name", "老王")—>name = '老王'
ne
ne(R column, Object val)
ne(boolean condition, R column, Object val)
  • 不等于 <>
  • 例: ne("name", "老王")—>name <> '老王'
gt
gt(R column, Object val)
gt(boolean condition, R column, Object val)
  • 大于 >
  • 例: gt("age", 18)—>age > 18
ge
ge(R column, Object val)
ge(boolean condition, R column, Object val)
  • 大于等于 >=
  • 例: ge("age", 18)—>age >= 18
lt
lt(R column, Object val)
lt(boolean condition, R column, Object val)
  • 小于 <
  • 例: lt("age", 18)—>age < 18
le
le(R column, Object val)
le(boolean condition, R column, Object val)
  • 小于等于 <=
  • 例: le("age", 18)—>age <= 18
between
between(R column, Object val1, Object val2)
between(boolean condition, R column, Object val1, Object val2)
  • BETWEEN 值1 AND 值2
  • 例: between("age", 18, 30)—>age between 18 and 30
#notBetween
notBetween(R column, Object val1, Object val2)
notBetween(boolean condition, R column, Object val1, Object val2)
  • NOT BETWEEN 值1 AND 值2
  • 例: notBetween("age", 18, 30)—>age not between 18 and 30
#like
like(R column, Object val)
like(boolean condition, R column, Object val)
  • LIKE ‘%值%’
  • 例: like("name", "王")—>name like '%王%'
#notLike
notLike(R column, Object val)
notLike(boolean condition, R column, Object val)
  • NOT LIKE ‘%值%’
  • 例: notLike("name", "王")—>name not like '%王%'
#likeLeft
likeLeft(R column, Object val)
likeLeft(boolean condition, R column, Object val)
  • LIKE ‘%值’
  • 例: likeLeft("name", "王")—>name like '%王'
#likeRight
likeRight(R column, Object val)
likeRight(boolean condition, R column, Object val)
  • LIKE ‘值%’
  • 例: likeRight("name", "王")—>name like '王%'
#isNull
isNull(R column)
isNull(boolean condition, R column)
  • 字段 IS NULL
  • 例: isNull("name")—>name is null
#isNotNull
isNotNull(R column)
isNotNull(boolean condition, R column)
  • 字段 IS NOT NULL
  • 例: isNotNull("name")—>name is not null
#in
in(R column, Collection<?> value)
in(boolean condition, R column, Collection<?> value)
  • 字段 IN (value.get(0), value.get(1), …)
  • 例: in("age",{1,2,3})—>age in (1,2,3)
in(R column, Object... values)
in(boolean condition, R column, Object... values)
  • 字段 IN (v0, v1, …)
  • 例: in("age", 1, 2, 3)—>age in (1,2,3)
#notIn
notIn(R column, Collection<?> value)
notIn(boolean condition, R column, Collection<?> value)
  • 字段 NOT IN (value.get(0), value.get(1), …)
  • 例: notIn("age",{1,2,3})—>age not in (1,2,3)
notIn(R column, Object... values)
notIn(boolean condition, R column, Object... values)
  • 字段 NOT IN (v0, v1, …)
  • 例: notIn("age", 1, 2, 3)—>age not in (1,2,3)
#inSql
inSql(R column, String inValue)
inSql(boolean condition, R column, String inValue)
  • 字段 IN ( sql语句 )
  • 例: inSql("age", "1,2,3,4,5,6")—>age in (1,2,3,4,5,6)
  • 例: inSql("id", "select id from table where id < 3")—>id in (select id from table where id < 3)
#notInSql
notInSql(R column, String inValue)
notInSql(boolean condition, R column, String inValue)
  • 字段 NOT IN ( sql语句 )
  • 例: notInSql("age", "1,2,3,4,5,6")—>age not in (1,2,3,4,5,6)
  • 例: notInSql("id", "select id from table where id < 3")—>id not in (select id from table where id < 3)
#groupBy
groupBy(R... columns)
groupBy(boolean condition, R... columns)
  • 分组:GROUP BY 字段, …
  • 例: groupBy("id", "name")—>group by id,name
#orderByAsc
orderByAsc(R... columns)
orderByAsc(boolean condition, R... columns)
  • 排序:ORDER BY 字段, … ASC
  • 例: orderByAsc("id", "name")—>order by id ASC,name ASC
#orderByDesc
orderByDesc(R... columns)
orderByDesc(boolean condition, R... columns)
  • 排序:ORDER BY 字段, … DESC
  • 例: orderByDesc("id", "name")—>order by id DESC,name DESC
#orderBy
orderBy(boolean condition, boolean isAsc, R... columns)
  • 排序:ORDER BY 字段, …
  • 例: orderBy(true, true, "id", "name")—>order by id ASC,name ASC
#having
having(String sqlHaving, Object... params)
having(boolean condition, String sqlHaving, Object... params)
  • HAVING ( sql语句 )
  • 例: having("sum(age) > 10")—>having sum(age) > 10
  • 例: having("sum(age) > {0}", 11)—>having sum(age) > 11
#func
func(Consumer<Children> consumer)
func(boolean condition, Consumer<Children> consumer)
  • func 方法(主要方便在出现if…else下调用不同方法能不断链)
  • 例: func(i -> if(true) {i.eq("id", 1)} else {i.ne("id", 1)})
#or
or()
or(boolean condition)
  • 拼接 OR

注意事项:

主动调用or表示紧接着下一个方法不是用and连接!(不调用or则默认为使用and连接)

  • 例: eq("id",1).or().eq("name","老王")—>id = 1 or name = '老王'
or(Consumer<Param> consumer)
or(boolean condition, Consumer<Param> consumer)
  • OR 嵌套
  • 例: or(i -> i.eq("name", "李白").ne("status", "活着"))—>or (name = '李白' and status <> '活着')
#and
and(Consumer<Param> consumer)
and(boolean condition, Consumer<Param> consumer)
  • AND 嵌套
  • 例: and(i -> i.eq("name", "李白").ne("status", "活着"))—>and (name = '李白' and status <> '活着')
#nested
nested(Consumer<Param> consumer)
nested(boolean condition, Consumer<Param> consumer)
  • 正常嵌套 不带 AND 或者 OR
  • 例: nested(i -> i.eq("name", "李白").ne("status", "活着"))—>(name = '李白' and status <> '活着')
#apply
apply(String applySql, Object... params)
apply(boolean condition, String applySql, Object... params)
  • 拼接 sql

注意事项:

该方法可用于数据库函数 动态入参的params对应前面applySql内部的{index}部分.这样是不会有sql注入风险的,反之会有!

  • 例: apply("id = 1")—>id = 1
  • 例: apply("date_format(dateColumn,'%Y-%m-%d') = '2008-08-08'")—>date_format(dateColumn,'%Y-%m-%d') = '2008-08-08'")
  • 例: apply("date_format(dateColumn,'%Y-%m-%d') = {0}", "2008-08-08")—>date_format(dateColumn,'%Y-%m-%d') = '2008-08-08'")
#last
last(String lastSql)
last(boolean condition, String lastSql)
  • 无视优化规则直接拼接到 sql 的最后

注意事项:

只能调用一次,多次调用以最后一次为准 有sql注入的风险,请谨慎使用

  • 例: last("limit 1")
#exists
exists(String existsSql)
exists(boolean condition, String existsSql)
  • 拼接 EXISTS ( sql语句 )
  • 例: exists("select id from table where age = 1")—>exists (select id from table where age = 1)
#notExists
notExists(String notExistsSql)
notExists(boolean condition, String notExistsSql)
  • 拼接 NOT EXISTS ( sql语句 )
  • 例: notExists("select id from table where age = 1")—>not exists (select id from table where age = 1)

#QueryWrapper

说明:

继承自 AbstractWrapper ,自身的内部属性 entity 也用于生成 where 条件
及 LambdaQueryWrapper, 可以通过 new QueryWrapper().lambda() 方法获取

#select
select(String... sqlSelect)
select(Predicate<TableFieldInfo> predicate)
select(Class<T> entityClass, Predicate<TableFieldInfo> predicate)
  • 设置查询字段

说明:

以上方法分为两类.
第二类方法为:过滤查询字段(主键除外),入参不包含 class 的调用前需要wrapper内的entity属性有值! 这两类方法重复调用以最后一次为准

  • 例: select("id", "name", "age")
  • 例: select(i -> i.getProperty().startsWith("test"))

#UpdateWrapper

说明:

继承自 AbstractWrapper ,自身的内部属性 entity 也用于生成 where 条件
LambdaUpdateWrapper, 可以通过 new UpdateWrapper().lambda() 方法获取!

#set
set(String column, Object val)
set(boolean condition, String column, Object val)
  • SQL SET 字段
  • 例: set("name", "老李头")
  • 例: set("name", "")—>数据库字段值变为空字符串
  • 例: set("name", null)—>数据库字段值变为null
#setSql
setSql(String sql)
  • 设置 SET 部分 SQL
  • 例: setSql("name = '老李头'")
lambda
  • 获取 LambdaWrapper
    QueryWrapper中是获取LambdaQueryWrapper
    UpdateWrapper中是获取LambdaUpdateWrapper

#分页插件

Sequence主键

自定义ID生成器

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值