Mybatis-Plus简介
官网:Mybatis-Plus官网传送门
简介
MyBatis-Plus(简称MP),一个MyBatis的增强工具,在MyBatis的基础上只做增强不做改变,为简化开发、提高效率而生。它提供了诸如自动生成SQL、通用CRUD操作、分页插件、性能分析插件等功能,使得开发人员可以减少对于繁琐SQL编写的工作,提高代码的简洁性和可维护性。
常见用法
-
CRUD操作:
- 插入数据:使用
insert
方法。 - 删除数据:根据主键ID删除使用
deleteById
方法,根据条件删除使用delete
方法,批量删除使用deleteBatchIds
方法。 - 更新数据:根据主键ID更新使用
updateById
方法,根据条件更新使用update
方法。 - 查询数据:根据主键ID查询使用
selectById
方法,批量查询使用selectBatchIds
方法,根据条件查询使用selectList
或selectPage
方法。
- 插入数据:使用
-
分页查询:
MyBatis-Plus提供了强大的分页插件,可以轻松实现分页查询。首先需要在配置类中启用分页插件,然后在查询方法中使用
Page
对象进行分页查询。 -
性能分析:
MyBatis-Plus内置了性能分析插件,可以输出SQL语句及其执行时间,帮助开发人员快速定位慢查询。
-
自定义全局通用操作:
MyBatis-Plus支持全局通用方法注入,可以在配置类中定义全局通用的方法,并在Mapper接口中直接使用。
常用注解
MyBatis-Plus中常用的注解主要包括以下几个:
- @TableName:
- 用于指定实体类对应的数据库表名。
- 当实体类名称与数据库表名不一致时,可以使用此注解进行映射。
- @TableId:
- 用于标识实体类的主键字段。
- 支持多种主键生成策略,如自增(IdType.AUTO)、手动输入(IdType.INPUT)、分布式全局唯一ID(IdType.ID_WORKER、IdType.ASSIGN_ID)等。
- @TableField:
- 用于标识实体类中的字段与数据库表中的字段的映射关系。
- 可以指定字段名、是否为数据库字段、自定义字段填充策略等。
- 例如,可以使用
@TableField(exist = false)
表示该属性不为数据库表字段,但又是必须使用的;使用@TableField(condition = SqlCondition.LIKE)
表示该属性可以模糊搜索。
- @Version:
- 用于实现乐观锁功能。
- 乐观锁是一种多用户并发控制的策略,通过版本号字段来实现数据的同步控制。
- @TableLogic:
- 用于实现逻辑删除功能。
- 逻辑删除是一种在数据库中标记数据为删除状态而不是物理删除的方式。
- 使用此注解后,执行删除操作时会将逻辑删除字段修改为指定的值(默认为1),执行查询操作时会自动过滤掉逻辑删除的数据(默认为0)。
- @EnumValue:
- 用于处理枚举字段。
- 可以将枚举类的值映射到数据库表中的字段上。
- @MapperScan:
- 用于扫描需要被MyBatis-Plus加载的Mapper接口。
- 常用于在Spring Boot启动类上指定Mapper接口所在的包路径。
- @Mapper:
- 作用于数据库中的实体类对应的Mapper接口上。
- 与
@MapperScan
相比,@Mapper
只能映射一个实体类对应的Mapper接口,而@MapperScan
可以映射整个包下的Mapper接口。
这些注解极大地简化了MyBatis-Plus的使用,使得开发人员可以更加专注于业务逻辑的实现,而不需要花费大量时间在繁琐的SQL编写和数据库表结构映射上。同时,这些注解也提供了丰富的配置选项,以满足不同场景下的需求。
常见问题及优化方案
-
查询性能问题:
- 当数据库中记录数量较大时,查询性能可能会受到影响。可以通过优化SQL语句、添加索引、使用分页查询等方式来提升查询性能。
- 避免全表扫描和未加索引的查询条件。
-
大数据量操作性能下降:
- 在大数据量插入、更新或删除操作时,SQL执行时间较长。可以通过批量操作、关闭自动填充功能等方式来提升性能。
- 使用MyBatis-Plus提供的批量插入、批量更新方法。
-
分页查询问题:
- 确保分页查询中传入了正确的分页参数,否则可能会导致返回全量数据。
- 合理使用MyBatis-Plus提供的分页插件和
Page
对象进行分页查询。
-
过度依赖通用方法:
- MyBatis-Plus提供了大量的通用CRUD方法,但开发者容易过度依赖这些方法,导致在某些复杂场景下生成的SQL不够优化。
- 在复杂查询场景下,可以使用XML文件或注解方式编写定制SQL语句。
Springboot项目集成Mybatis-Plus
场景:
Spring Boot项目中集成MyBatis-Plus,并实现多数据源配置 ,读写分离。
jdk及主要依赖版本说明:
jdk:1.8
springboot:2.6.4
mybatis-plus:3.5.7
mysql-connector:6.0.6
项目依赖
首先,在pom.xml
文件中添加必要的依赖,包括Spring Boot的启动器、MyBatis-Plus的启动器、数据库连接池(如Druid)以及MySQL的驱动等
<dependencies><!-- Spring Boot Starter Web --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- MyBatis-Plus Starter --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>${mp.version}</version></dependency><!-- Druid DataSource Starter --><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>${druid.version}</version></dependency><!-- MySQL Connector --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>${mysql-connector.version}</version></dependency><!-- MyBatis-Plus Dynamic DataSource Spring Boot Starter (可选,用于简化多数据源配置) --><dependency><groupId>com.baomidou</groupId><artifactId>dynamic-datasource-spring-boot-starter</artifactId><version>${dynamic-datasource.version}</version></dependency>
</dependencies>
配置文件
在application.yml
或application.properties
文件中配置多数据源的信息,包括主数据源(写)和从数据源(读)。
spring:datasource:dynamic:primary: master # 设置默认的数据源为主数据源datasource:master: # 主数据源配置url: jdbc:mysql://localhost:3306/master_db?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghaiusername: rootpassword: rootdriver-class-name: com.mysql.cj.jdbc.Drivertype: com.alibaba.druid.pool.DruidDataSourceslave_1: # 从数据源配置(可以有多个从数据源)url: jdbc:mysql://localhost:3306/slave_db_1?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghaiusername: rootpassword: rootdriver-class-name: com.mysql.cj.jdbc.Drivertype: com.alibaba.druid.pool.DruidDataSource
数据源配置类
如果没有使用dynamic-datasource-spring-boot-starter
,则需要手动配置数据源。以下是一个示例配置类:
@Configuration
public class DataSourceConfig {@Primary@Bean(name = "masterDataSource")@ConfigurationProperties(prefix = "spring.datasource.dynamic.datasource.master")public DataSource masterDataSource() {return DataSourceBuilder.create().build();}@Bean(name = "slaveDataSource")@ConfigurationProperties(prefix = "spring.datasource.dynamic.datasource.slave_1")public DataSource slaveDataSource() {return DataSourceBuilder.create().build();}// 配置数据源路由等逻辑(如果使用动态数据源则不需要手动配置)
}
但如果你使用了dynamic-datasource-spring-boot-starter
,则上述配置类可以省略,因为它会自动根据配置文件加载数据源。
使用@DS
注解指定数据源
在Service层的方法或类上使用@DS
注解来指定使用哪个数据源。默认情况下,会使用主数据源;如果需要读取操作使用从数据源,可以在方法上指定@DS("slave_1")
。
@Service
public class UserService {@Autowiredprivate UserMapper userMapper;// 默认使用主数据源(写操作)public void addUser(User user) {userMapper.insert(user);}// 指定使用从数据源(读操作)@DS("slave_1")public List<User> getUsers() {return userMapper.selectList(null);}
}
Mapper接口与实体类
创建Mapper接口和对应的实体类,这些类通常与MyBatis-Plus的单数据源配置相同。
// User实体类
public class User {private Long id;private String name;// 其他字段...// getters and setters...
}// UserMapper接口
public interface UserMapper extends BaseMapper<User> {// 可以添加自定义的Mapper方法(如果需要)
}
启动类
在Spring Boot的启动类上添加@MapperScan
注解来扫描Mapper接口。
@SpringBootApplication
@MapperScan("com.example.mapper")
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}
测试与验证
启动Spring Boot应用程序,并通过Controller层调用Service层的方法,验证写主读从的数据源切换是否生效。
生产环境配置样例
在生产环境中配置多数据源信息时,需要特别注意配置的准确性、安全性以及可维护性。以下是一个相对合理的application.yml
配置样例,以及配置时需要注意的关键点:(或许有坑,仅供参考)
spring:datasource:dynamic:primary: master # 设置默认的数据源为主数据源strict: true # 严格匹配数据源,未匹配到指定数据源时抛异常datasource:master: # 主数据源配置url: jdbc:mysql://db-master.example.com:3306/master_db?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&useSSL=falseusername: master_userpassword: ENC(encrypted_master_password) # 使用加密后的密码(如使用Jasypt等加密工具)driver-class-name: com.mysql.cj.jdbc.Drivertype: com.alibaba.druid.pool.DruidDataSourcedruid:initial-size: 5min-idle: 5max-active: 20max-wait: 60000time-between-eviction-runs-millis: 60000min-evictable-idle-time-millis: 300000validation-query: SELECT 1 FROM DUALtest-while-idle: truetest-on-borrow: falsetest-on-return: falsepool-prepared-statements: truemax-pool-prepared-statement-per-connection-size: 20stat-view-servlet:enabled: truefilter:stat:log-slow-sql: trueslow-sql-millis: 2000slave_1: # 从数据源配置(可以有多个从数据源)url: jdbc:mysql://db-slave1.example.com:3306/slave_db_1?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&useSSL=falseusername: slave_user_1password: ENC(encrypted_slave_password_1) # 使用加密后的密码driver-class-name: com.mysql.cj.jdbc.Drivertype: com.alibaba.druid.pool.DruidDataSource# 可以根据需要从druid配置中复制相关配置项
配置时需要注意的关键点
- 数据源URL:
- 确保数据库URL正确无误,包括IP地址、端口号、数据库名以及必要的连接参数。
- 在生产环境中,通常不会使用
localhost
,而是使用实际的数据库服务器地址。
- 数据库用户名和密码:
- 使用具有适当权限的数据库用户。
- 密码应使用加密工具进行加密存储,避免明文密码泄露。
- 驱动类名称:
- 确保使用与数据库版本相匹配的JDBC驱动类。
- 连接池配置:
- 根据实际业务需求配置连接池的大小,包括初始大小、最小空闲连接数、最大活跃连接数等。
- 配置连接池的其他相关参数,如连接验证查询、空闲连接测试、连接泄漏检测等。
- 安全性:
- 避免在配置文件中存储敏感信息,如明文密码。
- 使用加密工具对敏感信息进行加密存储。
- 确保配置文件具有适当的访问权限,防止未经授权的访问。
- 可维护性:
- 使用易于理解和维护的配置格式,如YAML或Properties。
- 对配置项进行注释,说明其用途和取值范围。
- 将配置文件与代码库分离,以便进行版本控制和审计。
- 数据源切换:
- 确保在代码中正确使用数据源切换注解或逻辑,以实现读写分离。
- 对数据源切换进行充分的测试,以确保其正确性和可靠性。
- 监控和日志:
- 配置数据源监控和日志记录,以便及时发现和解决数据库连接问题。
- 监控数据库连接池的使用情况,包括连接数、活动连接数、空闲连接数等。
通过以上配置和注意事项,可以在生产环境中实现多数据源的安全、可靠和高效配置。
如何在Mybatis-Plus中执行自定义sql
在MyBatis-Plus中执行自定义SQL主要有两种方式:使用XML映射文件和注解方式。
使用XML映射文件
步骤:
-
创建Mapper接口:定义一个Mapper接口,这个接口可以继承
BaseMapper
(如果你还需要使用MyBatis-Plus提供的通用方法),也可以不继承。 -
编写XML映射文件:在
resources/mapper
目录下创建一个与Mapper接口同名的XML文件。在这个XML文件中,你可以编写自定义的SQL语句。 -
在Mapper接口中定义方法:这些方法的名字和参数需要与XML文件中的SQL语句相匹配。
-
配置MyBatis-Plus:确保你的MyBatis-Plus配置正确,能够扫描到你的Mapper接口和XML文件。
示例:
Mapper接口:
public interface UserMapper {// 自定义查询方法List<User> selectUsersByCondition(@Param("condition") String condition);
}
XML映射文件(UserMapper.xml
):
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mapper.UserMapper"><select id="selectUsersByCondition" resultType="com.example.entity.User">SELECT * FROM tb_user WHERE some_column LIKE CONCAT('%', #{condition}, '%')</select></mapper>
使用注解方式
步骤:
-
创建Mapper接口:直接在Mapper接口的方法上使用MyBatis提供的注解(如
@Select
、@Update
、@Insert
、@Delete
等)来编写SQL语句。 -
配置MyBatis-Plus:确保你的MyBatis-Plus配置正确,能够扫描到你的Mapper接口。
示例:
Mapper接口:
public interface UserMapper extends BaseMapper<User> {// 自定义查询方法,使用注解方式@Select("SELECT * FROM tb_user WHERE some_column LIKE CONCAT('%', #{condition}, '%')")List<User> selectUsersByCondition(@Param("condition") String condition);
}
注意事项
- 当使用XML映射文件时,确保XML文件的命名和位置正确,并且与Mapper接口在同一命名空间中。
- 当使用注解方式时,确保注解中的SQL语句正确,并且参数占位符与方法参数相匹配。
- 在Spring Boot项目中,通常不需要手动配置MyBatis-Plus的Mapper扫描路径,因为可以通过
@MapperScan
注解在启动类上指定扫描路径。 - 如果你的Mapper接口继承了
BaseMapper
,那么你仍然可以在接口中定义自定义方法,这些方法不会与BaseMapper
中的方法冲突。
通过以上两种方式,你可以在MyBatis-Plus中灵活地执行自定义SQL语句,以满足不同业务场景的需求。
SqlRunner
在MyBatis-Plus中,如果不使用XML和注解来执行自定义SQL语句,实际上是比较受限的,因为MyBatis-Plus的设计初衷就是为了简化CRUD操作,并提供了一套强大的条件构造器来生成动态SQL。然而,仍然有一些方法可以间接地实现自定义SQL的执行,但通常这些方法并不是MyBatis-Plus推荐的主流做法。
一种可能的方法是使用MyBatis-Plus提供的SqlRunner
类(如果版本支持的话),这个类允许你直接执行原生SQL语句。但请注意,这种方法可能并不是所有版本的MyBatis-Plus都支持,而且它通常用于执行一些较为简单的SQL操作,比如查询、插入、更新和删除等。
以下是一个使用SqlRunner
执行自定义SQL的示例(假设MyBatis-Plus支持此功能):
// 假设你要执行一个查询操作
String sql = "SELECT * FROM user WHERE name = ?";
List<User> users = SqlRunner.db().selectList(sql, "特定用户名");// 假设你要执行一个插入操作
String insertSql = "INSERT INTO user (name, age) VALUES (?, ?)";
SqlRunner.db().insert(insertSql, "新用户", 25);
配置文件中需要启用sql-runner
mybatis-plus:global-config:enable-sql-runner: true
然而,需要注意的是,SqlRunner
类的使用可能并不是所有MyBatis-Plus项目中的标准做法,因为它绕过了MyBatis-Plus的Mapper接口和XML映射文件,直接执行了原生SQL。这可能会导致一些与MyBatis-Plus的ORM框架特性不兼容的问题,比如事务管理、缓存机制等。
另外,如果你确实需要在MyBatis-Plus中执行复杂的自定义SQL,而且又不希望使用XML或注解,那么你可能需要考虑以下替代方案:
-
使用MyBatis的原生API:虽然这会增加一些复杂性,但你可以通过MyBatis的
SqlSession
来执行原生SQL语句。这通常需要你手动管理SQL会话和事务。 -
使用存储过程或函数:将复杂的SQL逻辑封装在数据库端的存储过程或函数中,并通过MyBatis-Plus(或MyBatis)调用这些存储过程或函数。这可以简化应用程序中的代码,但可能会增加数据库的复杂性。
-
考虑使用其他ORM框架:如果MyBatis-Plus的限制无法满足你的需求,你可以考虑使用其他更灵活的ORM框架,比如Hibernate或JPA等。这些框架可能提供了更多的自定义SQL执行方式。
综上所述,虽然MyBatis-Plus提供了强大的条件构造器和通用Mapper来简化CRUD操作,但在某些情况下你可能需要执行自定义SQL语句。在不使用XML和注解的情况下,你可以考虑使用SqlRunner
(如果可用)、MyBatis的原生API、存储过程或函数,或者考虑使用其他ORM框架来满足你的需求。然而,请务必权衡这些方法的优缺点,并根据你的具体项目需求做出选择。