一、整合mybatis
博主之前也写过Spring整合Mybatis相关的博客
【Spring】spring整合mybatis
那么Spring Boot框架是如何整合Mybatis的呢?
我们直接去Mybatis的git官网地址:https://github.com/mybatis
进入spring-boot-starter这个模块,然后切换Tag到最新的,进入mybatis-spring-boot-starter这个模块
接着就可以在pom文件中找到这个启动类的坐标信息了
- 首先引入启动器相关依赖
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
然后我们还是照惯例分析一下相关的自动配置类MybatisAutoConfiguration
可以发现除了基本的配置绑定类(配置项以mybatis开头)等相关信息之外
这个类还完成了SqlSessionFactory
和SqlSessionTemplate
的自动配置
另外还引入了一个类AutoConfiguredMapperScannerRegistrar
,它会自动扫描@Mapper标注的接口,将这些接口认定是操作mybatis的接口
@Configuration
@ConditionalOnClass({SqlSessionFactory.class, SqlSessionFactoryBean.class})
@ConditionalOnSingleCandidate(DataSource.class)
@EnableConfigurationProperties({MybatisProperties.class})
@AutoConfigureAfter({DataSourceAutoConfiguration.class, MybatisLanguageDriverAutoConfiguration.class})
public class MybatisAutoConfiguration implements InitializingBean {
...
// 自动注入SqlSessionFactory这个bean
@Bean
@ConditionalOnMissingBean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
}
...
// 自动注入SqlSessionTemplate,它组合了SqlSession
@Bean
@ConditionalOnMissingBean
public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
ExecutorType executorType = this.properties.getExecutorType();
return executorType != null ? new SqlSessionTemplate(sqlSessionFactory, executorType) : new SqlSessionTemplate(sqlSessionFactory);
}
...
public static class AutoConfiguredMapperScannerRegistrar implements BeanFactoryAware, EnvironmentAware, ImportBeanDefinitionRegistrar {
private BeanFactory beanFactory;
private Environment environment;
public AutoConfiguredMapperScannerRegistrar() {
}
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
if (!AutoConfigurationPackages.has(this.beanFactory)) {
MybatisAutoConfiguration.logger.debug("Could not determine auto-configuration package, automatic mapper scanning disabled.");
} else {
MybatisAutoConfiguration.logger.debug("Searching for mappers annotated with @Mapper");
List<String> packages = AutoConfigurationPackages.get(this.beanFactory);
...
- 配置mybatis相关配置
我们可以将原来mybatis全局配置文件mybatis-config.xml中的配置都放在yaml文件中
保持原样也可以,通过mybatis.config-location导入就可以
#mybatis相关配置
mybatis:
# config-location: classpath:mybatis/mybatis-config.xml # 此配置项为mybatis全局配置文件所在位置,注意这里和下面的configuration不能同时存在
mapper-locations: classpath:mapper/*.xml # 此配置项为sql映射文件所在位置
configuration: #mybatis全局配置文件中的所有配置项都可以在此处配置
map-underscore-to-camel-case: true # 开启驼峰命名
- 编写业务测试代码
首先在数据库表中存入对应数据
接着编写Mapper接口类UserMapper.java和对应的SQL映射文件UserMapper.xml
接口类需要使用@Mapper注解修饰(如果嫌麻烦,也可以在spring boot启动类上加一个@MapperScan注解,设置mapper接口类的路径即可)
如果不想写SQL映射文件,也可以使用注解完成相关的CRUD操作
SQL映射文件中某些复杂的属性,可以使用@Options注解进行绑定
package com.decade.mapper;
import com.decade.pojo.UserInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@Mapper
public interface UserMapper {
public UserInfo queryUserInfoById(@Param("id") String id);
}
<?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.decade.mapper.UserMapper">
<select id="queryUserInfoById" resultType="com.decade.pojo.UserInfo">
select * from t_decade_user where id = #{id}
</select>
</mapper>
然后编写对应的Service层和poji类
package com.decade.service;
import com.decade.pojo.UserInfo;
public interface UserService {
UserInfo queryUserInfoById(String id);
}
package com.decade.service.impl;
import com.decade.mapper.UserMapper;
import com.decade.pojo.UserInfo;
import com.decade.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper mapper;
@Override
public UserInfo queryUserInfoById(String id) {
return mapper.queryUserInfoById(id);
}
}
package com.decade.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserInfo {
private String id;
private String name;
private Integer age;
private String sex;
}
最后,写一个controller接口进行测试
@GetMapping(value = "/queryUserById")
@ResponseBody
public UserInfo queryUserById(@RequestParam("userId") String id) {
return userService.queryUserInfoById(id);
}
验证结果如下
二、整合Mybatis-plus
官方地址:Mybatis-plus
- 引入依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.1</version>
</dependency>
分析自动配置类MybatisPlusAutoConfiguration
,它的作用和上面的MybatisAutoConfiguration
类似
- 通过分析配置绑定类
MybatisPlusProperties
得知,配置项以mybatis-plus开头 MybatisPlusAutoConfiguration
完成了SqlSessionFactory
和SqlSessionTemplate
的自动配置
还引入了AutoConfiguredMapperScannerRegistrar
,它会自动扫描@Mapper标注的接口,将这些接口认定是操作mybatis的接口- mapperLocations是自动配置好的,默认值为classpath*:/mapper/**/*.xml,也就是说它默认指定SQL映射文件放在类路径下的mapper文件夹下
与Mybatis不同之处在于,Mapper接口类中可以通过继承BaseMapper<T>
这个类实现基本的CRUD操作
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.baomidou.mybatisplus.core.mapper;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.annotations.Param;
public interface BaseMapper<T> extends Mapper<T> {
int insert(T entity);
int deleteById(Serializable id);
int deleteByMap(@Param("cm") Map<String, Object> columnMap);
int delete(@Param("ew") Wrapper<T> queryWrapper);
int deleteBatchIds(@Param("coll") Collection<? extends Serializable> idList);
int updateById(@Param("et") T entity);
int update(@Param("et") T entity, @Param("ew") Wrapper<T> updateWrapper);
T selectById(Serializable id);
List<T> selectBatchIds(@Param("coll") Collection<? extends Serializable> idList);
List<T> selectByMap(@Param("cm") Map<String, Object> columnMap);
T selectOne(@Param("ew") Wrapper<T> queryWrapper);
Integer selectCount(@Param("ew") Wrapper<T> queryWrapper);
List<T> selectList(@Param("ew") Wrapper<T> queryWrapper);
List<Map<String, Object>> selectMaps(@Param("ew") Wrapper<T> queryWrapper);
List<Object> selectObjs(@Param("ew") Wrapper<T> queryWrapper);
<E extends IPage<T>> E selectPage(E page, @Param("ew") Wrapper<T> queryWrapper);
<E extends IPage<Map<String, Object>>> E selectMapsPage(E page, @Param("ew") Wrapper<T> queryWrapper);
}
所以,一些简单的SQL逻辑我们可以直接使用父类中的方法来执行
package com.decade.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.decade.pojo.UserInfoPlus;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserMapperPlus extends BaseMapper<UserInfoPlus> {
}
注意:这里BaseMapper中的泛型会自动关联SQL执行的表名,所以,我们如果表名和实体类的名称无法对应,我们可以使用@TableName
注解来更改自动关联的表名
如果实体类中有些字段在表中不存在,也可以使用@TableField(exist = false)
来避免查询时出错
package com.decade.pojo;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("t_decade_user")
public class UserInfoPlus {
@TableField(exist = false)
private String aaa;
private String id;
private String name;
private Integer age;
private String sex;
}
最后,我们写一个测试方法进行测试
package com.decade;
import com.decade.mapper.UserMapperPlus;
import com.decade.pojo.UserInfoPlus;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class SpringbootWebApplicationTests {
@Autowired
private UserMapperPlus mapperPlus;
@Test
public void testMybatisPlus() {
final UserInfoPlus user = mapperPlus.selectById("001");
System.out.println(user.toString());
}
}
运行结果如下
如有错误,欢迎指正!!!