杨柳依 于2020年2月26日创建,最近更新于 2020年2月26日。

数据库准备

运行脚本tb_user.sql

  1. # 创建数据库mybatisplus(字符集utf8mb4是utf8的超集,兼容四字节的unicode)
  2. CREATE DATABASE `mybatisplus` CHARACTER SET 'utf8';
  3. # 选择mybatisplus数据库
  4. USE mybatisplus;
  5. # 创建tb_user表
  6. CREATE TABLE `tb_user` (
  7. `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  8. `user_name` varchar(20) NOT NULL COMMENT '用户名',
  9. `password` varchar(20) NOT NULL COMMENT '密码',
  10. `name` varchar(30) DEFAULT NULL COMMENT '姓名',
  11. `age` int(11) DEFAULT NULL COMMENT '年龄',
  12. `email` varchar(50) DEFAULT NULL COMMENT '邮箱',
  13. PRIMARY KEY (`id`)
  14. ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
  15. # 填充数据
  16. INSERT INTO `tb_user` VALUES (1, 'zhangsan', '123456', '张三', 18, 'test1@itcast.cn');
  17. INSERT INTO `tb_user` VALUES (2, 'lisi', '123456', '李四', 20, 'test2@itcast.cn');
  18. INSERT INTO `tb_user` VALUES (3, 'wangwu', '123456', '王五', 19, 'test3@itcast.cn');
  19. INSERT INTO `tb_user` VALUES (4, 'zhaoliu', '123456', '赵六', 21, 'test4@itcast.cn');
  20. INSERT INTO `tb_user` VALUES (5, 'sunqi', '666666', '孙七', 24, 'test5@itcast.cn');

基本整合

1. MyBatis-Plus与普通Maven项目进行整合

新建Maven项目,groupId为cn.itcast.mp,artifactId为itcast-mybatis-plus-simple,Project name为itcast-mybatis-plus-simple,POM文件如下:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5. <modelVersion>4.0.0</modelVersion>
  6. <groupId>cn.itcast.mp</groupId>
  7. <artifactId>itcast-mybatis-plus-simple</artifactId>
  8. <version>1.0-SNAPSHOT</version>
  9. <!-- 指定Java版本 -->
  10. <properties>
  11. <java.version>1.8</java.version>
  12. <maven.compiler.source>1.8</maven.compiler.source>
  13. <maven.compiler.target>1.8</maven.compiler.target>
  14. </properties>
  15. <dependencies>
  16. <!-- mybatis-plus插件依赖 -->
  17. <dependency>
  18. <groupId>com.baomidou</groupId>
  19. <artifactId>mybatis-plus</artifactId>
  20. <version>3.3.1</version>
  21. </dependency>
  22. <!-- MySQL驱动 -->
  23. <dependency>
  24. <groupId>mysql</groupId>
  25. <artifactId>mysql-connector-java</artifactId>
  26. <version>5.1.6</version>
  27. </dependency>
  28. <!-- druid连接池 -->
  29. <dependency>
  30. <groupId>com.alibaba</groupId>
  31. <artifactId>druid</artifactId>
  32. <version>1.0.11</version>
  33. </dependency>
  34. <!-- 简化bean代码的工具包 -->
  35. <dependency>
  36. <groupId>org.projectlombok</groupId>
  37. <artifactId>lombok</artifactId>
  38. <optional>true</optional>
  39. <version>1.18.4</version>
  40. </dependency>
  41. <!-- junit单元测试 -->
  42. <dependency>
  43. <groupId>org.junit.jupiter</groupId>
  44. <artifactId>junit-jupiter-api</artifactId>
  45. <version>5.5.2</version>
  46. </dependency>
  47. <!-- 日志 -->
  48. <dependency>
  49. <groupId>org.slf4j</groupId>
  50. <artifactId>slf4j-log4j12</artifactId>
  51. <version>1.6.4</version>
  52. </dependency>
  53. </dependencies>
  54. </project>

src/main/resources/下新建日志配置文件log4j.properties,内容如下:

  1. log4j.rootLogger=DEBUG,A1
  2. log4j.appender.A1=org.apache.log4j.ConsoleAppender
  3. log4j.appender.A1.layout=org.apache.log4j.PatternLayout
  4. log4j.appender.A1.layout.ConversionPattern=[%t] [%c]-[%p] %m%n

src/main/resources/下新建mybatis配置文件mybatis-config.xml,内容如下:

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  3. "http://mybatis.org/dtd/mybatis-3-config.dtd">
  4. <configuration>
  5. <environments default="development">
  6. <environment id="development">
  7. <transactionManager type="JDBC"/>
  8. <!-- mysql配置信息 -->
  9. <dataSource type="POOLED">
  10. <property name="driver" value="com.mysql.jdbc.Driver"/>
  11. <property name="url" value="jdbc:mysql://localhost:3306/mybatisplus"/>
  12. <property name="username" value="root"/>
  13. <property name="password" value="123456"/>
  14. </dataSource>
  15. </environment>
  16. </environments>
  17. <!-- mapper文件路径(不可少) -->
  18. <mappers>
  19. <mapper resource="UserMapper.xml"/>
  20. </mappers>
  21. </configuration>

src/main/resources/下新建mapper文件UserMapper.xml,就算没有自定义查询也必须要有该文件,内容如下:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <mapper namespace="cn.itcast.mp.simple.mapper.UserMapper">
  6. </mapper>

上面的namespace用于指定对应的UserMapper类,typeresultType用于指定对应实体User

src/main/java/下新建包cn.itcast.mp.simple.pojocn.itcast.mp.simple.mapper,在pojo包内新建User类:

  1. package cn.itcast.mp.simple.pojo;
  2. import com.baomidou.mybatisplus.annotation.TableName;
  3. import lombok.AllArgsConstructor;
  4. import lombok.Data;
  5. import lombok.NoArgsConstructor;
  6. @Data // 作用于类上,是以下注解的集合:@ToString @EqualsAndHashCode @Getter @Setter @RequiredArgsConstructor
  7. @NoArgsConstructor // 作用于类上,用于生成构造函数
  8. @AllArgsConstructor // 作用于类上,用于生成构造函数
  9. @TableName("tb_user") // 指定对应数据库表名
  10. public class User {
  11. private Long id;
  12. private String userName;
  13. private String password;
  14. private String name;
  15. private Integer age;
  16. private String email;
  17. }

mapper包内新建UserMapper类:

  1. package cn.itcast.mp.simple.mapper;
  2. import cn.itcast.mp.simple.pojo.User;
  3. import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  4. import java.util.List;
  5. public interface UserMapper extends BaseMapper<User> {
  6. }

注意,使用接口UserMapper继承MyBatis-Plus提供的基类BaseMapper<T>即可使用MyBatis-Plus提供的功能

至此,准备工作完成,我们可以测试MyBatis-Plus是否能正常工作了,在src/test/java/下新建同名包cn.itcast.mp.simple,在simple包内新建测试类TestMybatisPlus

  1. package cn.itcast.mp.simple;
  2. import cn.itcast.mp.simple.mapper.UserMapper;
  3. import cn.itcast.mp.simple.pojo.User;
  4. import com.baomidou.mybatisplus.core.MybatisSqlSessionFactoryBuilder;
  5. import org.apache.ibatis.io.Resources;
  6. import org.apache.ibatis.session.SqlSession;
  7. import org.apache.ibatis.session.SqlSessionFactory;
  8. import org.junit.jupiter.api.Test;
  9. import java.io.InputStream;
  10. import java.util.List;
  11. public class TestMybatisPlus {
  12. @Test
  13. public void testFindAll() throws Exception {
  14. String config = "mybatis-config.xml";
  15. InputStream inputStream = Resources.getResourceAsStream(config);
  16. // 使用MybatisSqlSessionFactoryBuilder完成整合
  17. SqlSessionFactory sqlSessionFactory = new MybatisSqlSessionFactoryBuilder().build(inputStream);
  18. SqlSession sqlSession = sqlSessionFactory.openSession();
  19. UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
  20. // 测试查询
  21. List<User> users = userMapper.selectList(null);
  22. users.forEach(System.out::println);
  23. }
  24. }

运行结果如下:

  1. ==> Preparing: SELECT id,user_name,password,name,age,email FROM tb_user
  2. ==> Parameters:
  3. <== Total: 5
  4. User(id=1, userName=zhangsan, password=123456, name=张三, age=18, email=test1@itcast.cn)
  5. User(id=2, userName=lisi, password=123456, name=李四, age=20, email=test2@itcast.cn)
  6. User(id=3, userName=wangwu, password=123456, name=王五, age=19, email=test3@itcast.cn)
  7. User(id=4, userName=zhaoliu, password=123456, name=赵六, age=21, email=test4@itcast.cn)
  8. User(id=5, userName=sunqi, password=666666, name=孙七, age=24, email=test5@itcast.cn)

可以看到,UserMapperselectList方法我们没有定义,该方法是MyBatis-Plus提供的。

如果我们需要使用自定义方法,可以在UserMapper类中新建方法:

  1. public interface UserMapper extends BaseMapper<User> {
  2. // 使用ResultMap映射字段名
  3. List<User> findAll();
  4. // sql语句内重命名
  5. List<User> findAll2();
  6. }

由于User类中字段与数据库中字段名不完全一致,我们使用2种方法来处理,在UserMapper.xml文件mapper节点下加入以下内容:

  1. <!-- 配置别名 -->
  2. <resultMap id="userMap" type="cn.itcast.mp.simple.pojo.User">
  3. <!--主键字段对应-->
  4. <id property="id" column="id"/>
  5. <!--非主键字段对应(每个都要对应,就算一模一样)-->
  6. <result property="userName" column="user_name"/>
  7. <result property="password" column="password"/>
  8. <result property="name" column="name"/>
  9. <result property="age" column="age"/>
  10. <result property="email" column="email"/>
  11. </resultMap>
  12. <!--配置查询所有(使用配置别名)-->
  13. <select id="findAll" resultMap="userMap">
  14. select * from tb_user;
  15. </select>
  16. <!--配置查询所有(使用查询时别名)-->
  17. <select id="findAll2" resultType="cn.itcast.mp.simple.pojo.User">
  18. select id, user_name userName, password, name, age, email from tb_user;
  19. </select>

TestMybatisPlus类新建测试方法testCustomFindAll

  1. @Test
  2. public void testCustomFindAll() throws Exception {
  3. String config = "mybatis-config.xml";
  4. InputStream inputStream = Resources.getResourceAsStream(config);
  5. // 使用MybatisSqlSessionFactoryBuilder完成整合
  6. SqlSessionFactory sqlSessionFactory = new MybatisSqlSessionFactoryBuilder().build(inputStream);
  7. SqlSession sqlSession = sqlSessionFactory.openSession();
  8. UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
  9. // 测试查询1
  10. List<User> users1 = userMapper.findAll();
  11. users1.forEach(System.out::println);
  12. // 测试查询2
  13. List<User> users2 = userMapper.findAll2();
  14. users2.forEach(System.out::println);
  15. }

结果为:

  1. ==> Preparing: select * from tb_user;
  2. ==> Parameters:
  3. <== Total: 5
  4. User(id=1, userName=zhangsan, password=123456, name=张三, age=18, email=test1@itcast.cn)
  5. User(id=2, userName=lisi, password=123456, name=李四, age=20, email=test2@itcast.cn)
  6. User(id=3, userName=wangwu, password=123456, name=王五, age=19, email=test3@itcast.cn)
  7. User(id=4, userName=zhaoliu, password=123456, name=赵六, age=21, email=test4@itcast.cn)
  8. User(id=5, userName=sunqi, password=666666, name=孙七, age=24, email=test5@itcast.cn)
  9. ==> Preparing: select id, user_name userName, password, name, age, email from tb_user;
  10. ==> Parameters:
  11. <== Total: 5
  12. User(id=1, userName=zhangsan, password=123456, name=张三, age=18, email=test1@itcast.cn)
  13. User(id=2, userName=lisi, password=123456, name=李四, age=20, email=test2@itcast.cn)
  14. User(id=3, userName=wangwu, password=123456, name=王五, age=19, email=test3@itcast.cn)
  15. User(id=4, userName=zhaoliu, password=123456, name=赵六, age=21, email=test4@itcast.cn)
  16. User(id=5, userName=sunqi, password=666666, name=孙七, age=24, email=test5@itcast.cn)

2. MyBatis-Plus与Spring项目进行整合

新建Maven项目,groupId为cn.itcast.mp,artifactId为itcast-mybatis-plus-spring,Project name为itcast-mybatis-plus-spring,POM文件如下:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5. <modelVersion>4.0.0</modelVersion>
  6. <groupId>cn.itcast.mp</groupId>
  7. <artifactId>itcast-mybatis-plus-spring</artifactId>
  8. <version>1.0-SNAPSHOT</version>
  9. <properties>
  10. <!-- 指定Java版本 -->
  11. <java.version>1.8</java.version>
  12. <maven.compiler.source>1.8</maven.compiler.source>
  13. <maven.compiler.target>1.8</maven.compiler.target>
  14. <!-- 指定Spring版本 -->
  15. <spring.version>5.1.6.RELEASE</spring.version>
  16. </properties>
  17. <dependencies>
  18. <!-- Spring相关 -->
  19. <dependency>
  20. <groupId>org.springframework</groupId>
  21. <artifactId>spring-webmvc</artifactId>
  22. <version>${spring.version}</version>
  23. </dependency>
  24. <dependency>
  25. <groupId>org.springframework</groupId>
  26. <artifactId>spring-jdbc</artifactId>
  27. <version>${spring.version}</version>
  28. </dependency>
  29. <dependency>
  30. <groupId>org.springframework</groupId>
  31. <artifactId>spring-test</artifactId>
  32. <version>${spring.version}</version>
  33. </dependency>
  34. <!-- mybatis-plus插件依赖 -->
  35. <dependency>
  36. <groupId>com.baomidou</groupId>
  37. <artifactId>mybatis-plus</artifactId>
  38. <version>3.3.1</version>
  39. </dependency>
  40. <!-- MySQL驱动 -->
  41. <dependency>
  42. <groupId>mysql</groupId>
  43. <artifactId>mysql-connector-java</artifactId>
  44. <version>5.1.6</version>
  45. </dependency>
  46. <!-- druid连接池 -->
  47. <dependency>
  48. <groupId>com.alibaba</groupId>
  49. <artifactId>druid</artifactId>
  50. <version>1.0.11</version>
  51. </dependency>
  52. <!-- 简化bean代码的工具包 -->
  53. <dependency>
  54. <groupId>org.projectlombok</groupId>
  55. <artifactId>lombok</artifactId>
  56. <optional>true</optional>
  57. <version>1.18.4</version>
  58. </dependency>
  59. <!-- junit单元测试 -->
  60. <dependency>
  61. <groupId>org.junit.jupiter</groupId>
  62. <artifactId>junit-jupiter-api</artifactId>
  63. <version>5.5.2</version>
  64. </dependency>
  65. <!-- 日志 -->
  66. <dependency>
  67. <groupId>org.slf4j</groupId>
  68. <artifactId>slf4j-log4j12</artifactId>
  69. <version>1.6.4</version>
  70. </dependency>
  71. </dependencies>
  72. </project>

src/main/resources/下新建日志配置文件log4j.properties,内容如下:

  1. log4j.rootLogger=DEBUG,A1
  2. log4j.appender.A1=org.apache.log4j.ConsoleAppender
  3. log4j.appender.A1.layout=org.apache.log4j.PatternLayout
  4. log4j.appender.A1.layout.ConversionPattern=[%t] [%c]-[%p] %m%n

src/main/resources/下新建数据库配置文件jdbc.properties,内容如下:

  1. jdbc.driver=com.mysql.jdbc.Driver
  2. jdbc.url=jdbc:mysql://localhost:3306/mybatisplus
  3. jdbc.username=root
  4. jdbc.password=123456

src/main/resources/下新建Spring配置文件applicationContext.xml,内容如下:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. xsi:schemaLocation="http://www.springframework.org/schema/beans
  6. http://www.springframework.org/schema/beans/spring-beans.xsd
  7. http://www.springframework.org/schema/context
  8. http://www.springframework.org/schema/context/spring-context.xsd">
  9. <context:property-placeholder location="classpath:*.properties"/>
  10. <!-- 定义数据源 -->
  11. <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
  12. destroy-method="close">
  13. <property name="url" value="${jdbc.url}"/>
  14. <property name="username" value="${jdbc.username}"/>
  15. <property name="password" value="${jdbc.password}"/>
  16. <property name="driverClassName" value="${jdbc.driver}"/>
  17. <property name="maxActive" value="10"/>
  18. <property name="minIdle" value="5"/>
  19. </bean>
  20. <!-- 这里使用MP提供的sqlSessionFactory,完成了Spring与MP的整合 -->
  21. <bean id="sqlSessionFactory"
  22. class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
  23. <property name="dataSource" ref="dataSource"/>
  24. </bean>
  25. <!-- 扫描mapper接口,使用的依然是Mybatis原生的扫描器 -->
  26. <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
  27. <property name="basePackage" value="cn.itcast.mp.simple.mapper"/>
  28. </bean>
  29. </beans>

src/main/java/下新建包cn.itcast.mp.spring.pojocn.itcast.mp.spring.mapper,在pojo包内新建User类:

package cn.itcast.mp.spring.pojo;

import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName("tb_user")
public class User {

    private Long id;
    private String userName;
    private String password;
    private String name;
    private Integer age;
    private String email;
}

mapper包内新建UserMapper类:

package cn.itcast.mp.spring.mapper;

import cn.itcast.mp.spring.pojo.User;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;

public interface UserMapper extends BaseMapper<User> {

}

接入完成,接下来测试MyBatis-Plus是否能正常工作,在src/test/java/下新建包cn.itcast.mp.spring,在spring包内新建测试类TestMyBatisPlusWithSpring

package cn.itcast.mp.spring;

import cn.itcast.mp.spring.mapper.UserMapper;
import cn.itcast.mp.spring.pojo.User;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;

import java.util.List;

@ExtendWith(SpringExtension.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml") // 指定Spring配置文件
public class TestMyBatisPlusWithSpring {

    @Autowired
    private UserMapper userMapper;

    @Test
    public void testSelectList() {
        List<User> users = userMapper.selectList(null);
        users.forEach(System.out::println);
    }
}

注意,由于test文件夹没有resources文件,所以直接运行会报错,可以将src/main/resources文件夹复制到test/文件夹下,再运行testSelectList方法,结果如下:

==> Preparing: SELECT id,user_name,password,name,age,email FROM tb_user 
==> Parameters: 
<== Total: 5
User(id=1, userName=zhangsan, password=123456, name=张三, age=18, email=test1@itcast.cn)
User(id=2, userName=lisi, password=123456, name=李四, age=20, email=test2@itcast.cn)
User(id=3, userName=wangwu, password=123456, name=王五, age=19, email=test3@itcast.cn)
User(id=4, userName=zhaoliu, password=123456, name=赵六, age=21, email=test4@itcast.cn)
User(id=5, userName=sunqi, password=666666, name=孙七, age=24, email=test5@itcast.cn)

3. MyBatis-Plus与SpringBoot项目进行整合

用IDEA新建SpringBoot项目,Group为cn.itcast.mp,Artifact为itcast-mybatis-plus-springboot,Name为itcast-mybatis-plus-springboot,Package为cn.itcast.mp.springboot,选择LombokJDBC APIMySQL Driver依赖。

pom.xml中添加依赖:

<!-- mybatis-plus的SpringBoot支持 -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.3.1</version>
</dependency>

<!-- druid连接池 -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.0.11</version>
</dependency>

在配置文件application.properties中添加如下内容:

# 项目名称
spring.application.name=itcast-mybatis-plus-springboot
# 开启彩色日志
spring.output.ansi.enabled=always
# 数据库连接
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mp?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&useSSL=false
spring.datasource.username=root
spring.datasource.password=123456
# 开启SQL执行日志
logging.level.cn.itcast.mp.springboot.mapper=debug

cn.itcast.mp.springboot包下新建pojo.User类:

package cn.itcast.mp.springboot.pojo;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName("tb_user")
public class User {

    @TableId(type = IdType.AUTO) // 指定id为自增长类型
    private Long id;

    private String userName;

    @TableField(select = false) // 查询时不返回该字段
    private String password;

    private String name;

    private Integer age;

    @TableField(value = "email") // 指定数据库中的表字段名
    private String mail;

    @TableField(exist = false) // 在数据库中不存在
    private String address;
}

cn.itcast.mp.springboot包下新建mapper.UserMapper类:

package cn.itcast.mp.springboot.mapper;

import cn.itcast.mp.springboot.pojo.User;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;

public interface UserMapper extends BaseMapper<User> {

}

cn.itcast.mp.springboot包下新建config.MyBatisPlusConfig类:

package cn.itcast.mp.springboot.config;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@MapperScan("cn.itcast.mp.springboot.mapper")
public class MyBatisPlusConfig {

}

准备工作完成,在ItcastMybatisPlusSpringbootApplicationTests类中注入UserMapper,并新建测试方法test

@Autowired
private UserMapper userMapper;

// 测试功能
@Test
public void test() {
    List<User> users = userMapper.selectList(null);
    users.forEach(System.out::println);
}

运行方法,结果为:

==> Preparing: SELECT id,user_name,name,age,email AS mail FROM tb_user 
==> Parameters: 
<== Total: 5
User(id=1, userName=zhangsan, password=null, name=张三, age=18, mail=test1@itcast.cn, address=null)
User(id=2, userName=lisi, password=null, name=李四, age=20, mail=test2@itcast.cn, address=null)
User(id=3, userName=wangwu, password=null, name=王五, age=19, mail=test3@itcast.cn, address=null)
User(id=4, userName=zhaoliu, password=null, name=赵六, age=21, mail=test4@itcast.cn, address=null)
User(id=5, userName=sunqi, password=null, name=孙七, age=24, mail=test5@itcast.cn, address=null)

注意,userName字段能正确显示,是因为MyBatis Plus自动驼峰为true(MyBatis自动驼峰默认为false),可通过mybatis-plus.configuration.map-underscore-to-camel-case=false来设置;password字段使用@TableField(select = false)设置查询时不返回该字段内容;mail字段使用@TableField(value = "email")设置数据库中字段名;address字段使用@TableField(exist = false)指明数据库中不存在该字段。

基本使用

以下操作均以上一步操作中的SpringBoot项目作为示范,其它项目类似

1. 配置文件

可以在application.properties中指定MyBatis-Plus的配置文件路径:

# MyBatis-Plus全局配置文件,config-location和configuration不能同时使用
mybatis-plus.config-location=classpath:mybatis-config.xml

在同级目录下创建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>

</configuration>

也可以直接在application.properties中进行配置:

# 实体对象的扫描包,自定义mapper文件时可以只用写类名
mybatis-plus.type-aliases-package=cn.itcast.mp.springboot.pojo
# 指定Mapper文件路径,有*代表可以扫描所有依赖的classpath下的文件,没有*只扫描当前resources目录下的文件
mybatis-plus.mapper-locations=classpath*:mybatis/*.xml
# 全局id生成策略
mybatis-plus.global-config.db-config.id-type=auto
# 全局表名前缀
mybatis-plus.global-config.db-config.table-prefix=tb_

2. 插入

ItcastMybatisPlusSpringbootApplicationTests类中新建测试方法testInsert

@Test
public void testInsert() {
    User user = new User();
    user.setUserName("caocao");
    user.setPassword("123456");
    user.setName("曹操");
    user.setAge(30);
    user.setMail("1@itcast.cn");

    // INSERT INTO tb_user ( user_name, password, name, age, email ) VALUES ( ?, ?, ?, ?, ? )
    int result = userMapper.insert(user); // 返回数据库受影响的行数
    System.out.println("result => " + result);

    // 获取自增长id
    System.out.println("id => " + user.getId());
}

3. 更新

3.1 根据主键进行更新

// 根据主键进行更新
@Test
public void testUpdateById() {
    User user = new User();
    user.setId(1L);
    user.setAge(19);

    // UPDATE tb_user SET age=? WHERE id=? 
    int result = userMapper.updateById(user);
    System.out.println("result => " + result);
}

3.2 根据条件进行更新(使用QueryWrapper)

// 根据条件进行更新(使用QueryWrapper)
@Test
public void testUpdate() {
    User user = new User();
    user.setAge(19);
    user.setPassword("666");

    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.eq("user_name", "zhangsan");
    // UPDATE tb_user SET password=?, age=? WHERE (user_name = ?)
    int result = userMapper.update(user, wrapper);
    System.out.println("result => " + result);
}

3.3 根据条件进行更新(使用UpdateWrapper)

// 根据条件进行更新(使用UpdateWrapper)
@Test
public void testUpdate2() {
    UpdateWrapper<User> wrapper = new UpdateWrapper<>();
    wrapper.set("age", 21).set("password", "999") // 更新字段
        .eq("user_name", "zhangsan"); // 条件
    // UPDATE tb_user SET age=?,password=? WHERE (user_name = ?)
    int result = userMapper.update(null, wrapper);
    System.out.println("result => " + result);
}

4. 删除

4.1 根据id删除数据

// 根据id删除数据
@Test
public void testDeleteById() {
    // DELETE FROM tb_user WHERE id=? 
    int result = userMapper.deleteById(6);
    System.out.println("result => " + result);
}

4.2 根据条件删除数据(使用Map)

// 根据条件删除数据(使用Map)
@Test
public void testDeleteByMap() {
    Map<String, Object> map = new HashMap<>();
    // 多条件是and关系
    map.put("user_name", "zhangsan");
    map.put("password", "999");
    // DELETE FROM tb_user WHERE password = ? AND user_name = ?
    int result = userMapper.deleteByMap(map);
    System.out.println("result => " + result);
}

4.3 根据条件删除数据(使用QueryWrapper)

// 根据条件删除数据(使用QueryWrapper)
@Test
public void testDelete() {
    // 用法1
    // QueryWrapper<User> wrapper = new QueryWrapper<>();
    // wrapper.eq("user_name", "caocao")
    //         .eq("password", "123456");  // 条件之间加上".or()"可以变成"或"

    // 用法2
    User user = new User();
    user.setPassword("123456");
    user.setUserName("lisi");
    QueryWrapper<User> wrapper = new QueryWrapper<>(user);
    // DELETE FROM tb_user WHERE user_name=? AND password=? 
    int result = userMapper.delete(wrapper);
    System.out.println("result => " + result);
}

4.4 根据id批量删除

// 根据id批量删除
@Test
public void testDeleteBatchIds() {
    // DELETE FROM tb_user WHERE id IN ( ? , ? ) 
    int result = userMapper.deleteBatchIds(Arrays.asList(7, 8));
    System.out.println("result => " + result);
}

5. 查询

5.1 根据id查询

// 根据id查询
@Test
public void testSelectById() {
    // SELECT id,user_name,name,age,email AS mail FROM tb_user WHERE id=? 
    User user = userMapper.selectById(3);
    System.out.println(user);
}

5.2 根据id批量查询

// 根据id批量查询
@Test
public void testSelectBatchIds() {
    // SELECT id,user_name,name,age,email AS mail FROM tb_user WHERE id IN ( ? , ? , ? , ? ) 
    List<User> users = userMapper.selectBatchIds(Arrays.asList(3, 4, 5, 100));
    users.forEach(System.out::println);
}

5.3 查询一条数据

// 查询一条数据
@Test
public void testSelectOne() {
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.eq("user_name", "sunqi")
        .or().eq("id", "100"); // 结果超过1条时会抛出异常
    // SELECT id,user_name,name,age,email AS mail FROM tb_user WHERE (user_name = ? OR id = ?) 
    User user = userMapper.selectOne(wrapper);
    System.out.println(user);
}

5.4 查询记录条数

// 查询记录条数
@Test
public void testSelectCount() {
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.gt("age", 24); // age>24
    // SELECT COUNT( 1 ) FROM tb_user WHERE (age > ?) 
    int result = userMapper.selectCount(wrapper);
    System.out.println("result => " + result);
}

5.5 查询符合条件的集合

// 查询符合条件的集合
@Test
public void testSelectList() {
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.le("age", 24); // age<=24
    // 当参数为null时同样会把null当做sql语句的一部分,如果想忽略值为null的条件,可以使用同名方法
    // wrapper.le(age != null, "age", 24); 这样当age为null时则不会将age作为查询条件之一
    wrapper.like("email", "test"); // 多条件之间默认是AND关系
    // SELECT id,user_name,name,age,email AS mail FROM tb_user WHERE (age <= ? AND email LIKE ?) 
    List<User> users = userMapper.selectList(wrapper); // wrapper为null则为查询所有
    users.forEach(System.out::println);
}

5.6 分页查询

分页查询需要先配置分页插件,以下两种方式二选一即可:

  • mybatis-config.xml配置文件中configuration节点下添加插件:xml <plugins> <plugin interceptor="com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor"></plugin> </plugins>

  • MyBatisPlusConfig类中添加插件:java // 配置分页插件 @Bean public PaginationInterceptor paginationInterceptor() { return new PaginationInterceptor(); }

然后即可进行分页查询:

// 分页查询
@Test
public void testSelectPage() {
    Page<User> page = new Page<>(2, 2); // 查询第2页,每页2条
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.like("email", "test");
    // SELECT COUNT(1) FROM tb_user WHERE (email LIKE ?)
    // SELECT id,user_name,name,age,email AS mail FROM tb_user WHERE (email LIKE ?) LIMIT ?,?
    Page<User> iPage = userMapper.selectPage(page, wrapper);
    System.out.println("数据总条数:" + iPage.getTotal());
    System.out.println("数据总页数:" + iPage.getPages());
    System.out.println("当前页数:" + iPage.getCurrent());
    iPage.getRecords().forEach(System.out::println);
}

5.7 自定义方法

自定义查询可以采用注解,也可以采用配置文件的方式。在UserMapper接口中新建方法:

@Select("select * from tb_user where id=#{id}")
User findById(long id);

User findByName(String name);

resources文件夹下新建文件mybatis/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="cn.itcast.mp.springboot.mapper.UserMapper">

    <select id="findByName" resultType="User">
        select id, user_name, password, name, age, email as mail
        from tb_user
        where name = #{name}
    </select>

</mapper>

然后就可以使用自定义方法了:

// 自定义方法
@Test
public void testConstomFind() {
    User user = userMapper.findById(3L);
    System.out.println(user);
    User user2 = userMapper.findByName("王五");
    System.out.println(user2);
}

5.8 条件构造器 —— allEq

// 条件构造器 —— allEq
@Test
public void testAllEq() {
    Map<String, Object> params = new HashMap<>();
    params.put("name", "李四");
    params.put("age", "20");
    params.put("password", null);

    QueryWrapper<User> wrapper = new QueryWrapper<>();
    // SELECT id,user_name,name,age,email AS mail FROM tb_user WHERE (password IS NULL AND name = ? AND age = ?)
    // wrapper.allEq(params); // 包括null值比较

    // SELECT id,user_name,name,age,email AS mail FROM tb_user WHERE (name = ? AND age = ?)
    // wrapper.allEq(params, false); // 不包括null值比较

    // SELECT id,user_name,name,age,email AS mail FROM tb_user WHERE (password IS NULL AND age = ?)
    wrapper.allEq((k, v) -> (k.equals("age") || k.equals("id") || k.equals("password")), params); // 符合表达式才作为查询条件

    List<User> users = userMapper.selectList(wrapper);
    users.forEach(System.out::println);
}

5.9 基本比较操作

常用比较操作符如下:

方法 eq ne gt ge lt le between notBetween
操作 = !=或者<> > >= < <= BETWEEN 值1 AND 值2 NOT BETWEEN 值1 AND 值2
方法 in notIn
操作 IN (value.get(0), value.get(1),…) NOT IN (value.get(0), value.get(1),…)
// 基本比较操作
@Test
public void testCompare() {
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    // SELECT id,user_name,name,age,email AS mail FROM tb_user WHERE (password = ? AND age >= ? AND name IN (?,?,?))
    wrapper.eq("password", "123456")
        .ge("age", 20)
        .in("name", "李四", "王五", "赵六");
    List<User> users = userMapper.selectList(wrapper);
    users.forEach(System.out::println);
}

5.10 模糊查询

方法 like likeLeft likeRight
操作 左右模糊 左边模糊(以给定值结尾) 右边模糊(以给定值开头)
// 模糊查询
@Test
public void testLike() {
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    // wrapper.likeLeft("name", "五");
    wrapper.likeRight("age", 2); // 数字也可以进行模糊匹配(先转成字符串)
    // SELECT id,user_name,name,age,email AS mail FROM tb_user WHERE (age LIKE ?) 
    List<User> users = userMapper.selectList(wrapper);
    users.forEach(System.out::println);
}

5.11 排序

方法 orderBy orderByAsc orderByDesc
操作 默认升序 升序 降序
@Test
public void testOrderBy() {
    QueryWrapper<User> wrapper = new QueryWrapper<>();

    // SELECT id,user_name,name,age,email AS mail FROM tb_user ORDER BY password DESC,age DESC
    // wrapper.orderByDesc("password", "age"); // 先按password倒序,再按age倒序

    // SELECT id,user_name,name,age,email AS mail FROM tb_user ORDER BY password DESC,age ASC
    wrapper.orderByDesc("password") // 先按password倒序
        .orderByAsc("age"); // 再按age升序

    List<User> users = userMapper.selectList(wrapper);
    users.forEach(System.out::println);
}

5.12 逻辑操作符

多条件连接默认为AND,多条件之间使用.or()进行连接则表示OR

// 逻辑操作符
@Test
public void testOr() {
    QueryWrapper<User> wrapper = new QueryWrapper<>();

    // SELECT id,user_name,name,age,email AS mail FROM tb_user WHERE (name = ? OR age = ?)
    wrapper.eq("name", "王五")
        .or().eq("age", 21);

    List<User> users = userMapper.selectList(wrapper);
    users.forEach(System.out::println);
}

5.13 指定查询字段

// 指定查询字段
@Test
public void testSelect() {
    QueryWrapper<User> wrapper = new QueryWrapper<>();

    // SELECT id,name,age FROM tb_user WHERE (name = ? OR age = ?)
    wrapper.eq("name", "王五")
        .or().eq("age", 21)
        .select("id", "name", "age"); // 指定查询字段

    List<User> users = userMapper.selectList(wrapper);
    users.forEach(System.out::println);
}

ActiveRecord

Active Record 是一种数据访问设计模式,它可以帮助你实现数据对象Object到关系数据库的映射,数据对象自身负责持久化。

User类继承Model<T>类即可:

public class User extends Model<User> {
    // ...
}

src/test/java/cn/itcast/mp/springboot文件夹下新建一个测试类ActiveRecordTest,无须注入UserMapper即可直接使用数据对象自身提供的数据持久化方法,方法名与使用Mapper类一致:

package cn.itcast.mp.springboot;

import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class ActiveRecordTest {
       // 无须注入UserMapper

    // 根据主键查询
    @Test
    public void testSelectById() {
        User user = new User();
        user.setId(2L);
        // SELECT id,user_name,name,age,email AS mail FROM tb_user WHERE id=?
        User result = user.selectById(); // 或者直接向方法传入id
        System.out.println(result);
    }

    // 插入
    @Test
    public void testInsert() {
        User user = new User();
        user.setUserName("liubei");
        user.setPassword("666");
        user.setName("刘备");
        user.setAge(30);
        user.setMail("liubei@itcast.cn");
        // INSERT INTO tb_user ( user_name, password, name, age, email ) VALUES ( ?, ?, ?, ?, ? )
        boolean result = user.insert();
        System.out.println("result => " + result);
    }

    // 根据主键更新
    @Test
    public void testUpdateById() {
        User user = new User();
        user.setId(12L);
        user.setAge(31);
        // UPDATE tb_user SET age=? WHERE id=?
        boolean result = user.updateById();  // 这里不接收参数
        System.out.println("result => " + result);
    }

    // 根据条件更新
    @Test
    public void testUpdate() {
        User user = new User();
        user.setPassword("111111");
        UpdateWrapper<User> wrapper = new UpdateWrapper<>();
        wrapper.eq("user_name", "liubei");
        // UPDATE tb_user SET password=? WHERE (user_name = ?)
        boolean result = user.update(wrapper);
        System.out.println("result => " + result);
    }

    // 根据主键删除
    @Test
    public void testDeleteById() {
        User user = new User();
        user.setId(10L);
        // DELETE FROM tb_user WHERE id=?
        boolean result = user.deleteById(); // 或者直接向方法传入id
        System.out.println("result => " + result);
    }

    // 根据条件删除
    @Test
    public void testDelete() {
        User user = new User();
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("name", "刘备");
        // DELETE FROM tb_user WHERE (name = ?)
        boolean result = user.delete(wrapper);
        System.out.println("result => " + result);
    }

    // 根据条件查询
    @Test
    public void testSelect() {
        User user = new User();
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.ge("age", 25);
        // SELECT id,user_name,name,age,email AS mail FROM tb_user WHERE (age >= ?)
        List<User> users = user.selectList(wrapper);
        users.forEach(System.out::println);
    }
}

Oracle中使用序列生成主键值

MySQL中可以设定主键自增长,但是Oracle数据库不支持设置,需要使用序列来生成id值。

1. 数据库准备

这里使用docker进行安装Oracle,如果已有Oracle环境,该步骤可以省略。

# 拉取镜像
docker pull sath89/oracle-12c

# 创建容器
docker create --name=oracle -p 1521:1521 sath89/oracle-12c

# 启动容器
docker start oracle && docker logs -f oracle

# 出现以下内容即启动成功
Database ready to use. Enjoy! ;)

# 用户名:system
# 密码:oracle

使用navicat进行连接,注意连接类型为Basic,服务名为xe

接下来创建表及序列(注意,Oracle不支持#注释,只能使用--注释):

-- 创建表,表名以及字段名都要大写
CREATE TABLE "TB_USER" (
    "ID" NUMBER(20) VISIBLE NOT NULL,
    "USER_NAME" VARCHAR2(255 BYTE) VISIBLE,
    "PASSWORD" VARCHAR2(255 BYTE) VISIBLE,
    "NAME" VARCHAR2(255 BYTE) VISIBLE,
    "AGE" NUMBER(10) VISIBLE,
    "EMAIL" VARCHAR2(255 BYTE) VISIBLE
);

-- 创建序列
CREATE SEQUENCE SEQ_USER START WITH 1 INCREMENT BY 1;

在Navicat中选择其它选项卡,点击序列,可以查看到我们刚刚创建的SEQ_USER序列。

2. Java准备

由于版权原因,Maven中央仓库中没有Oracle的jdbc驱动包,我们手动将驱动包安装到Maven仓库,在ojdbc8.jar所在目录下运行以下命令:

mvn install:install-file -DgroupId=com.oracle -DartifactId=ojdbc8 -Dversion=19.3.0 -Dpackaging=jar -Dfile=ojdbc8.jar

安装完成后ojdbc8.jar的Maven坐标为,并添加到SpringBoot项目的POM文件中:

<dependency>
    <groupId>com.oracle</groupId>
    <artifactId>ojdbc8</artifactId>
    <version>19.3.0</version>
</dependency>

接着修改配置文件application.properties,将数据库连接修改为:

# Oracle设置
spring.datasource.driver-class-name=oracle.jdbc.OracleDriver
spring.datasource.url=jdbc:oracle:thin:@49.233.88.245:1521:xe
spring.datasource.username=system
spring.datasource.password=oracle

MyBatisPlusConfig配置类中配置生成器:

// 配置Oracle序列生成器
@Bean
public OracleKeyGenerator oracleKeyGenerator() {
    return new OracleKeyGenerator();
}

接着在User上添加注解@KeySequence(value = "SEQ_USER"),修改id生成策略:

// ...
@KeySequence(value = "SEQ_USER")
public class User extends Model<User> {

    @TableId(type = IdType.INPUT) // 指定id为输入类型
    private Long id;
    // ...
}

3. 测试

运行方法ItcastMybatisPlusSpringbootApplicationTests#testInsert(),成功插入一条数据,运行结果如下:

==> Preparing: SELECT SEQ_USER.NEXTVAL FROM DUAL 
==> Parameters: 
<== Total: 1
==> Preparing: INSERT INTO tb_user (id, user_name, password, name, age, email) VALUES (?,?,?,?,?,?) 
==> Parameters: 1(Long), caocao(String), 123456(String), 曹操(String), 30(Integer), 1@itcast.cn(String)
<== Updates: 1
result => 1
id => 1

插件

1. 插件机制

src/main/java/cn/itcast/mp/springboot/目录下新建一个包plugins用于放置插件,在plugins包下新建MyInterceptor类:

package cn.itcast.mp.springboot.plugins;

import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;

import java.util.Properties;

@Intercepts({@Signature(
        type = Executor.class,
        method = "update",
        args = {MappedStatement.class, Object.class})})
public class MyInterceptor implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // 拦截方法,具体业务逻辑编写的位置
        return invocation.proceed();
    }

    @Override
    public Object plugin(Object target) {
        // 创建target对象的代理对象,目的是将当前拦截器加入到该对象中
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
        // 属性设置
    }
}

MyInterceptor配置到MyBatisPlusConfig中:

// 注入自定义拦截器(插件)
@Bean
public MyInterceptor myInterceptor() {
    return new MyInterceptor();
}

2. SQL分析插件

该插件只能在开发环境中使用,不建议在生产环境中使用(性能原因)

MyBatisPlusConfig中进行配置:

// SQL分析插件
@Bean
public SqlExplainInterceptor sqlExplainInterceptor() {
    SqlExplainInterceptor sqlExplainInterceptor = new SqlExplainInterceptor();
    List<ISqlParser> list = new ArrayList<>();
    list.add(new BlockAttackSqlParser()); // 全表更新/删除阻断器
    // 添加解析器
    sqlExplainInterceptor.setSqlParserList(list);
    return sqlExplainInterceptor;
}

测试,在ActiveRecordTest类中添加测试方法,运行会抛出异常:

// 测试全表更新阻断
@Test
public void testUpdateAll() {
    User user = new User();
    user.setPassword("111111");
    boolean result = user.update(null);
    System.out.println("result => " + result);
}

3. 性能分析插件[TODO]

性能分析拦截器,用于输出每条SQL语句及其执行时间,可以设置最大执行时间,超过时间会抛出异常。官方推荐使用p6spy

添加依赖:

<dependency>
    <groupId>p6spy</groupId>
    <artifactId>p6spy</artifactId>
    <version>3.7.0</version>
</dependency>

添加配置文件spy.properties

4. 乐观锁插件

意图:当更新一条记录的时候,希望这条记录没有被别人更新

实现: ①取出记录时,获取当前version;

            ②更新时带上version;

            ③执行更新时,`set version=newVersion where version=oldVersion`

            ④如果version不对则更新失败

MyBatisPlusConfig中进行配置:

// 乐观锁插件
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
    return new OptimisticLockerInterceptor();
}

为表添加version字段,并且设置初始值为1:

ALTER TABLE `tb_user`
ADD COLUMN `version` int(10) NULL AFTER `email`;

UPDATE `tb_user` SET `version`=1;

为实体对象User添加version字段:

// 乐观锁版本字段
@Version
private Integer version;

新建测试方法testUpdateVersion()

// 测试乐观锁
@Test
public void testUpdateVersion() {
    User user = new User();
    user.setId(4L);
    Integer version = user.selectById().getVersion();
    System.out.println("插入之前的version:" + version);
    user.setPassword("222222");
    user.setVersion(version);
    System.out.println(user.getVersion());  // 这里还是之前的版本号

    // UPDATE tb_user SET password=?, version=? WHERE id=? AND version=?
    boolean result = user.updateById();
    System.out.println("version => " + user.getVersion()); // 不管成功与否版本号均会自增
    System.out.println("result => " + result);
}