MyBatis-Plus(简称MP)是一个MyBatis的增强工具,在MyBatis的基础上只做增强而不做改变。它支持所有MyBatis原生的特性,因此引入MyBatis-Plus不会对现有的MyBatis构架产生任何影响。MyBatis-Plus旨在简化开发、提高效率,特别是简化了CRUD(增删改查)操作。
MyBatis-Plus的常见使用场景
- 数据权限控制:在查询数据时,自动添加当前用户可访问的数据范围的WHERE条件。
- 多租户支持:在查询数据时,自动添加租户ID的WHERE条件,以区分不同租户的数据。
- 动态表名:根据不同的请求参数,动态修改SQL语句中的表名,以实现数据分片或数据隔离等功能。
- 加密解密:对数据库中的敏感数据进行加密,查询数据时进行解密。
- 缓存优化:通过缓存某些查询结果来提高系统性能,可以将缓存对象作为拦截器的属性来管理。
MyBatis-Plus通过启动加载XML配置时注入单表SQL操作来简化开发工作,提高生产率。总的来说,MyBatis-Plus是一个强大的MyBatis增强工具,为开发者提供了更多的便利和灵活性。
Springboot集成Mybatisplus
涉及的模块
- springboot-mybatisplus:mysql测试,端口号18086
但在此模块中我们会通过springbootTest和Controller两种方式来进行测试。
本示例依赖一个基础开发框架,这部分详细可参考:动手开发基于Springboot的基础开发框架-01
模块结构说明
-
类文件说明
- SystemLogController.java:controller,它会调用ISystemLogDao接口
- ISystemLogDao.java:Dao接口
- SystemLogQuery:ISystemLogDao接口参数
- SystemLogDaoImpl.java:ISystemLogDao接口实现
- SystemLogMapper.java:mybatis Mapper接口
- SystemLogEntity.java:数据库实体类
-
文件夹
- resources/mybatis:mybatis配置文件,一般与SystemLogMapper.java一一对应
-
测试类
- SystemLogControllerTest:测试 LoadBalanceController.java URI接口功能
- SystemLogDaoTest:测试 ISystemLogDao.java 接口实现功能
数据库脚本
数据库脚本
CREATE TABLE `jdemo`.`t_sys_record_demo` (
`uuid` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`biz_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '业务ID',
`user_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '操作用户ID',
`track_uid` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '链路ID',
`code` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '操作代码',
`custom_code` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '操作2级代码',
`status` int NULL DEFAULT NULL COMMENT '记录状态:1可查询,0不可查询',
`ctime` datetime NULL DEFAULT NULL,
`utime` datetime NULL DEFAULT NULL,
`cid` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`cname` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`uuid`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
java实体类
注意下列@TableName
中的值要和数据库表名一致。
@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
@TableName("t_sys_record_demo")
public class SystemLogEntity extends DBEntity {
private String bizId;
private String userId;
private String trackUid;
private String code;
private String customCode;
private Integer status;
@TableField(value = "cid", fill = FieldFill.INSERT, insertStrategy = FieldStrategy.NEVER, updateStrategy = FieldStrategy.NEVER)
private String cid;
@TableField(value = "cname", fill = FieldFill.INSERT, insertStrategy = FieldStrategy.NEVER, updateStrategy = FieldStrategy.NEVER)
private String cname;
}
模块配置
Maven 依赖
这里需要注意mybatisplus分2和3两个版本,3版本对应的springboot3,2对应的是springboot2,这两个mybatisplus版本并不兼容。
<dependencies>
<!--数据库相关-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
</dependency>
<!--工具包-->
<dependency>
<groupId>com.korgs</groupId>
<artifactId>framework-persistence</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
framework-persistence是笔者开发的一个基础jar包,在最后的源码中可以找到。
Invalid value type for attribute ‘factoryBeanObjectType’: java.lang.String 这个错误是由于版本不对引起的, 因为mybatis2和3不相互兼容,这主要是jdk版本不同导致的,其它三方插件也有这个问题。
application.properties配置
spring.profiles.active = dev
spring.application.name=springbootMybatisplus
server.port=18086
#debug=true
management.endpoints.web.exposure.include = *
management.endpoint.health.show-details=always
##mybatis Server
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/jdemo?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=12345678
spring.datasource.druid.initial-size=5
spring.datasource.druid.min-idle=5
spring.datasource.druid.max-active=20
spring.datasource.druid.max-wait=60000
spring.datasource.druid.validation-query=SELECT 1 FROM DUAL
spring.datasource.druid.max-pool-prepared-statement-per-connection-size=5
spring.datasource.druid.test-while-idle=true
spring.datasource.druid.test-on-borrow=false
spring.datasource.druid.test-on-return=false
spring.datasource.druid.time-between-eviction-runs-millis=60000
spring.datasource.druid.min-evictable-idle-time-millis=100000
spring.datasource.druid.filters=stat
#
##mybatis plugs
mybatis-plus.mapper-locations=classpath:/mybatis/*Mapper.xml
mybatis-plus.configuration.map-underscore-to-camel-case=true
mybatis-plus.configuration.default-statement-timeout=20000
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
注意上面配置中的mybatis-plus.configuration.log-impl
和mybatis-plus.mapper-locations
。前者用于日志打印,在发布应用时需要注释掉,后者用来指定Mapper.xml文件存放的classpath地址。
修改 SpringbootApplication启动类
配置@MapperScan
注解,比如@MapperScan("com.korgs.dao")
表示要查找的mybatis bean类。
@Slf4j
@SpringBootApplication(scanBasePackages = {"com.korgs", "cn.hutool.extra.spring"})
@Configuration
@EnableConfigurationProperties
@ServletComponentScan
@RestController
@MapperScan("com.korgs.dao")
public class SpringbootMybatisplusApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootMybatisplusApplication.class, args);
}
@GetMapping("/helloworld")
public BaseResponse helloWorld(){
log.info(LogGenerator.trackLog()
+ "msg="+ "I am busy to handle this request.");
return BaseResponse.success("hello world");
}
}
程序实现
定义ISystemLogDao接口
定义供上层类调用的数据库操作接口
接口定义
public interface ISystemLogDao extends IService<SystemLogEntity> {
List<SystemLogEntity> listByCondition(SystemLogQuery query);
IPage<SystemLogEntity> pageSystemLog(IPage<SystemLogEntity> iPage, String bizId, String code);
}
接口实现
@Repository
@Primary
public class SystemLogDaoImpl extends ServiceImpl<SystemLogMapper, SystemLogEntity> implements ISystemLogDao {
@Override
public List<SystemLogEntity> listByCondition(SystemLogQuery query) {
LambdaQueryWrapper<SystemLogEntity> queryWrapper = Wrappers.lambdaQuery();
if(StrUtil.isNotEmpty(query.getCode())){
queryWrapper.eq(SystemLogEntity::getCode, query.getCode());
}
if(StrUtil.isNotEmpty(query.getBizId())){
queryWrapper.eq(SystemLogEntity::getBizId, query.getBizId());
}
return list(queryWrapper);
}
@Override
public IPage<SystemLogEntity> pageSystemLog(IPage<SystemLogEntity> iPage, String bizId, String code) {
return this.getBaseMapper().pageSystemLog(iPage, bizId, code);
}
}
接口参数
@Data
public class SystemLogQuery {
private String bizId;
private String code;
}
定义Mapper实现
一个Mapper实现类对应一个Mapper.xml,即使Mapper.xml为空实现也需要配置。
Mapper接口定义
public interface SystemLogMapper extends BaseMapper<SystemLogEntity> {
IPage<SystemLogEntity> pageSystemLog(IPage<SystemLogEntity> iPage,
@Param("bizId") String bizId,
@Param("code") String code);
}
Mapper接口对应的Mapper.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.korgs.dao.SystemLogMapper">
<select id="pageSystemLog" resultType="com.korgs.dao.SystemLogEntity">
select
t_sys_record_demo.*
from
t_sys_record_demo
where 1=1
<if test="bizId != null">
and t_sys_record_demo.biz_id = #{bizId}
</if>
<if test="code != null">
and upper(t_sys_record_demo.code) LIKE upper(CONCAT('%',#{code},'%'))
</if>
</select>
</mapper>
上述配置文件中:
- mapper标签:配置为SystemLogMapper.java类的全路径
- select标签中的id属性:配置为SystemLogMapper.java类中定义的接口名称
-
- select标签中的resultType属性:定义为sql语句要返回的实体对象的全路径,此值也与SystemLogMapper.java中相应的接口返回参数相对应。
编写Controller Restful
@Slf4j
@RestController
@RequestMapping("/api/load")
public class SystemLogController {
@Autowired
private ISystemLogDao iSystemLogDao;
@GetMapping("/v1/hello-content")
public ListResponse<SystemLogEntity> loadHelloContent(String uuid){
log.info("{} uuid ={}", LogGenerator.trackLog(), uuid);
List<SystemLogEntity> list = iSystemLogDao.list();
log.info("{} uuid={} size={}", LogGenerator.trackLog(), uuid, CollUtil.size(list));
return ListResponse.success(list);
}
}
使用SpringbootTest测试
测试Dao接口
@SpringBootTest
public class SystemLogDaoTest {
private static final Logger logger = LoggerFactory.getLogger(SystemLogDaoTest.class);
@Autowired
private ISystemLogDao iSystemLogDao;
/*注意此处要引用 import org.junit.jupiter.api.Test;*/
/*全表搜索*/
@Test
public void iSystemLogDao() {
List<SystemLogEntity> list = iSystemLogDao.list();
logger.info(JSONUtil.toJsonStr(list));
}
/*增加操作*/
@Test
public void iSystemLogDaoInsert() {
SystemLogEntity systemLogEntity = new SystemLogEntity();
systemLogEntity.setUuid(UUIDUtil.uuid32());
iSystemLogDao.save(systemLogEntity);
}
/*删除操作*/
@Test
public void iSystemLogDaoDelete() {
iSystemLogDao.removeById("3006316502a24b6b8b5eac4d1a8f6e5a");
}
/*更新操作*/
@Test
public void iSystemLogDaoUpdate() {
SystemLogEntity systemLogEntity = new SystemLogEntity();
systemLogEntity.setUuid("a4dd3bcf2a134941a4a1fb9119028600");
systemLogEntity.setCode("heart");
iSystemLogDao.updateById(systemLogEntity);
}
/*分页查询*/
@Test
public void iSystemLogDaoPage() {
IPage<SystemLogEntity> iPage = new Page<SystemLogEntity>(1, 3);
iPage = iSystemLogDao.pageSystemLog(iPage, "001", "lung");
List<SystemLogEntity> logEntityIPage = iPage.getRecords();
logger.info(JSONUtil.toJsonStr(logEntityIPage));
}
}
测试Controller服务
@SpringBootTest
@AutoConfigureMockMvc
public class SystemLogControllerTest {
@Autowired
protected MockMvc mockMvc;
private HttpHeaders httpHeaders = new HttpHeaders();
private static final ObjectMapper mapper = new ObjectMapper();
// @Before
public void setBasicAuth() throws Exception {
// 设置basicAuth
String basicAuthString = "Basic " + Base64.getEncoder().encodeToString("aaa:bbb".getBytes());
httpHeaders.set("Authorization", basicAuthString);
}
@Test
public void testController() throws Exception {
MvcResult mvcResult = mockMvc.perform(get("/api/load//v1/hello-content")
.contentType(MediaType.APPLICATION_JSON_VALUE)
// 设定basicAuth到请求header中
.headers(httpHeaders)
.param("uuid", "12312312"))
// 打印详细的请求以及返回内容
.andDo(print())
// 判断HttpStatus是200,如果不是表示失败
.andExpect(status().isOk())
// 返回结果给mvcResult
.andReturn();
// 获取mvcResult的body
String resutlStr = mvcResult.getResponse().getContentAsString(Charset.defaultCharset());
ListResponse response = mapper.readValue(resutlStr, ListResponse.class);
// 判断结果是否成功
assertEquals("0", response.getStatus().toString());
}
}
程序源码下载
Springboot集成Mybatispuls操作mysql数据库