文章目录
-
-
-
- 1. 前提说明
- 2. 技术点整合
- 3. 整合MyBatis
-
- 3.1 介绍mybatis-spring-boot-starter的工作原理
- 3.2 引入依赖
- 3.3 application.properties数据库连接配置
- 3.4 创建一张测试表,比如:employee表,其中包含id(INT)、name(VARCHAR)、age(INT)字段。
- 3.5 编写Druid连接池配置管理类
- 3.6 修改application类中导入配置管理类
- 3.7 编写Domain类,创建Emplyee表映射的对象Emplyee
- 3.7 创建Employee对应的Mapper接口
- 3.8 创建Employee对应的DAO接口及其实现类
- 3.9 创建Employee对应的Service接口及其实现类
- 3.10 创建Employee对应的Controller类
- 3.11 启动程序并访问执行
- 4. 梳理总结
- 5. 代码示例
-
-
1. 前提说明
如果大家做过很多业务系统的话,相信应该遇到过很多使用MyBatis访问数据库,本文章主要是介绍如何在SpringBoot整合MyBatis并通过注解的方式实现对关系型数据库(MySQL)进行增删改查操作。
2. 技术点整合
- SpringBoot
- SpringMVC
- Spring Core
- MyBatis
- Druid | 数据库连接池
3. 整合MyBatis
3.1 介绍mybatis-spring-boot-starter的工作原理
- 自动发现一个注册好的DataSource,以前的applicationContext.xml手动配置现在就不用了,@Configuration作用替代掉以前的xml配置文件;
- 自动创建一个SqlSessionFactory,并且将DataSource传入SqlSessionFactory中;
- 自动基于SqlSessionFactory创建一个SqlSessionTemplate;
- 扫描所有的Mapper,将SqlSessionTemplate注入其中,然后将Mapper注册到Spring容器上下文中
3.2 引入依赖
初始化SpringBoot项目,并引入相关依赖,具体如下:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 引入mybatis-spring-boot-starter依赖,用于mybatis与spring boot整合 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.3</version>
</dependency>
<!-- 引入mysql驱动依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
<!--<scope>runtime</scope>-->
</dependency>
<!-- 引入阿里的druid连接池依赖 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
3.3 application.properties数据库连接配置
SpringBoot在JDBC模块中默认的数据源是HikariCP,我这边使用的是阿里的Druid作为数据库连接池。
# MySQL驱动配置信息
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/oa?useUnicode=true&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=123321
spring.datasource.driverClassName=com.mysql.jdbc.Driver
# 连接池的配置信息
## 连接池初始大小
spring.datasource.initialSize=5
## 连接池最小空闲连接数量
spring.datasource.minIdle=5
## 连接池最大活跃连接数量
spring.datasource.maxActive=20
spring.datasource.maxWait=60000
spring.datasource.timeBetweenEvictionRunsMillis=60000
spring.datasource.minEvictableIdleTimeMillis=300000
spring.datasource.validationQuery=SELECT 1 FROM DUAL
spring.datasource.testWhileIdle=true
spring.datasource.testOnBorrow=false
spring.datasource.testOnReturn=false
spring.datasource.poolPreparedStatements=true
spring.datasource.maxPoolPreparedStatementPerConnectionSize=20
# spring.datasource.filters=stat,wall,log4j
spring.datasource.filters=stat,wall,slf4j
spring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
3.4 创建一张测试表,比如:employee表,其中包含id(INT)、name(VARCHAR)、age(INT)字段。
CREATE TABLE `employee` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(45) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=24 DEFAULT CHARSET=utf8;
3.5 编写Druid连接池配置管理类
/**
* Druid连接池配置管理类
*
* @author bamaw
* @date 2021-04-11 09:30
*
*
*
* 拓展:
* 我们现在要配置一个数据源,是基于开源的数据库连接池的组件来配置,如:c3p0、druid.
* 在没有springboot出现之前,我们使用传统的spring整合的方式,必然是在applicationContext.xml中去配置一个bean,
* datasource所有的配置都是放在applicationContext.xml中的
*
* 但是,现在springboot的核心思想是将全部的配置放在 application.properties中用于集中管理所有配置,同时将以前
* xml中的配置bean的形式通过java代码的注解形式配置bean
*
* 使用@Configuration标注,表示这是一个配置管理类,在这个类中可以将外部的application.properties中需要的配置加载进来,
* 使用@Value注解即可加载外部配置
*
*/
@Configuration
public class DruidConfig {
/**
* 因为spring boot是默认开启了资源过滤的
* 所以这里的配置,都会自动从application.properties配置文件中加载出来,设置到这个@Configuration类中
*/
@Value("${spring.datasource.url}")
private String dbUrl;
@Value("${spring.datasource.username}")
private String username;
@Value("${spring.datasource.password}")
private String password;
@Value("${spring.datasource.driverClassName}")
private String driverClassName;
@Value("${spring.datasource.initialSize}")
private int initialSize;
@Value("${spring.datasource.minIdle}")
private int minIdle;
@Value("${spring.datasource.maxActive}")
private int maxActive;
@Value("${spring.datasource.maxWait}")
private int maxWait;
@Value("${spring.datasource.timeBetweenEvictionRunsMillis}")
private int timeBetweenEvictionRunsMillis;
@Value("${spring.datasource.minEvictableIdleTimeMillis}")
private int minEvictableIdleTimeMillis;
@Value("${spring.datasource.validationQuery}")
private String validationQuery;
@Value("${spring.datasource.testWhileIdle}")
private boolean testWhileIdle;
@Value("${spring.datasource.testOnBorrow}")
private boolean testOnBorrow;
@Value("${spring.datasource.testOnReturn}")
private boolean testOnReturn;
@Value("${spring.datasource.poolPreparedStatements}")
private boolean poolPreparedStatements;
@Value("${spring.datasource.maxPoolPreparedStatementPerConnectionSize}")
private int maxPoolPreparedStatementPerConnectionSize;
@Value("${spring.datasource.filters}")
private String filters;
@Value("{spring.datasource.connectionProperties}")
private String connectionProperties;
/**
* 在这个配置类中,直接基于配置信息,创建出了一个bean,这个bean就是一个DataSource,
* 这个DataSource bean就会被纳入spring容器的管理范围之内
* @return
*/
/**
* @Bean
* 当我们手头拥有所有的配置信息之后,就可以使用@Bean注解 + 方法的形式,在方法中基于加载进来的配置参数来
* 创建你需要的各种bean,并将其返回,这个bean就会被注册到spring容器中去;
*
* @Primary
* 比如我们返回的datasource类型的bean,spring在进行bean装配的时候,比如有其他某个类用@Autowired来要求
* 装配一个Datasource bean,但是此时如果你的应用中配置了多个Datasource类型的bean,那么就会装配失败
* 所以在这个bean中标注一个@Primary 那么在出现多个同一类型的bean的时候,就会选择加了@primary的bean
*
*/
@Bean
@Primary
public DataSource dataSource(){
// 这里就是用外部加载进来的配置信息,创建出来一个Druid连接池
DruidDataSource datasource = new DruidDataSource();
datasource.setUrl(this.dbUrl);
datasource.setUsername(username);
datasource.setPassword(password);
datasource.setDriverClassName(driverClassName);
//configuration
datasource.setInitialSize(initialSize);
datasource.setMinIdle(minIdle);
datasource.setMaxActive(maxActive);
datasource.setMaxWait(maxWait);
datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
datasource.setValidationQuery(validationQuery);
datasource.setTestWhileIdle(testWhileIdle);
datasource.setTestOnBorrow(testOnBorrow);
datasource.setTestOnReturn(testOnReturn);
datasource.setPoolPreparedStatements(poolPreparedStatements);
datasource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
try {
datasource.setFilters(filters);
} catch (SQLException e) {
e.printStackTrace();
}
datasource.setConnectionProperties(connectionProperties);
return datasource;
}
}
3.6 修改application类中导入配置管理类
@SpringBootApplication
// 使用@Import就可以将其他的配置管理类导入进来
@Import(DruidConfig.class)
public class SpringbootMybatisApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootMybatisApplication.class, args);
}
}
3.7 编写Domain类,创建Emplyee表映射的对象Emplyee
public class Employee {
private Long id;
private String name;
private Integer age;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Employee{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
3.7 创建Employee对应的Mapper接口
@Mapper
public interface EmployeeMapper {
/**
* 获取所有的员工信息
* @return 所有员工清单
*/
@Select("SELECT * FROM employee")
@Results({
@Result(property = "id", column = "id", id = true),
@Result(property = "name", column = "name"),
@Result(property = "age", column = "age")
})
List<Employee> selectAllEmployee();
/**
* 通过员工id查询对应的员工信息
* @param id 员工id
* @return 单个员工信息
*/
@Select("SELECT * FROM employee WHERE id = #{id}")
@Results({
@Result(property = "id", column = "id", id = true),
@Result(property = "name", column = "name"),
@Result(property = "age", column = "age")
})
Employee selectEmployeeById(@Param("id") Long id);
/**
* 新增员工信息
* @param employee 员工信息
*/
@Insert("INSERT INTO employee(name,age) VALUES(#{name},#{age})")
@Options(useGeneratedKeys = true, keyProperty = "id")
void insertEmployee(Employee employee);
/**
* 修改员工信息
* @param employee 员工信息
*/
@Update("UPDATE employee SET `name` = #{name}, age = #{age} WHERE id = #{id}")
void updateEmployeeById(Employee employee);
/**
* 通过员工id 删除信息
* @param id 员工id
*/
@Delete("DELETE FROM employee WHERE id = #{id}")
void deleteEmployeeById(@Param("id") Long id);
}
3.7.1 注解配置说明
- 使用@Param
@Param
的作用是给参数命名,根据名字得到参数值,并将参数值传入sql语句中
- 使用@Results及@Result注解
对@Result
注解中的属性进行介绍:
- id:是否是主键字段
- column:数据库的字段名
- property:对象的成员名
- 增删改查操作提供的不同注解
- @Insert:实现新增
- @Update:实现更新
- @Delete:实现删除
- @Select:实现查询
3.8 创建Employee对应的DAO接口及其实现类
public interface EmployeeDAO {
/**
* 查询所有员工的信息
*
* @return 员工list集合
*/
List<Employee> getAllEmployee();
/**
* 通过员工id 查询对应的员工信息
* @param id 员工id
* @return 员工实体类
*/
Employee findEmployeeById(Long id);
/**
* 保存员工信息
*
* @param employee 员工实体类
*/
void saveEmployee(Employee employee);
/**
* 根据员工id 更新员工信息
*
* @param employee 员工实体类
*/
void updateEmployeeById(Employee employee);
/**
* 删除对应的员工信息
*
* @param id 员工id
*/
void removeEmployeeById(Long id);
}
@Repository
public class EmployeeDAOImpl implements EmployeeDAO {
/**
* 员工管理模块的mapper组件
*/
@Autowired
private EmployeeMapper employeeMapper;
@Override
public List<Employee> getAllEmployee() {
return employeeMapper.selectAllEmployee();
}
@Override
public Employee findEmployeeById(Long id) {
return employeeMapper.selectEmployeeById(id);
}
@Override
public void saveEmployee(Employee employee) {
employeeMapper.insertEmployee(employee);
}
@Override
public void updateEmployeeById(Employee employee) {
employeeMapper.updateEmployeeById(employee);
}
@Override
public void removeEmployeeById(Long id) {
employeeMapper.deleteEmployeeById(id);
}
}
3.9 创建Employee对应的Service接口及其实现类
public interface EmployService {
/**
* 查询所有员工的信息
*
* @return 员工list集合
*/
List<Employee> getAllEmployee();
/**
* 通过员工id 查询对应的员工信息
* @param id 员工id
* @return 员工实体类
*/
Employee findEmployeeById(Long id);
/**
* 保存员工信息
*
* @param employee 员工实体类
*/
void saveEmployee(Employee employee);
/**
* 根据员工id 更新员工信息
*
* @param employee 员工实体类
*/
void updateEmployeeById(Employee employee);
/**
* 删除对应的员工信息
*
* @param id 员工id
*/
void removeEmployeeById(Long id);
}
@Service
public class EmployServiceImpl implements EmployService {
/**
* 员工管理模块DAO组件
*/
@Autowired
private EmployeeDAO employeeDAO;
/**
* 查询所有员工的信息
*
* @return 员工list集合
*/
@Override
public List<Employee> getAllEmployee() {
return employeeDAO.getAllEmployee();
}
/**
* 通过员工id 查询对应的员工信息
* @param id 员工id
* @return 员工实体类
*/
@Override
public Employee findEmployeeById(Long id) {
return employeeDAO.findEmployeeById(id);
}
/**
* 保存员工信息
*
* @param employee 员工实体类
*/
@Override
public void saveEmployee(Employee employee) {
employeeDAO.saveEmployee(employee);
}
/**
* 根据员工id 更新员工信息
*
* @param employee 员工实体类
*/
@Override
public void updateEmployeeById(Employee employee) {
employeeDAO.updateEmployeeById(employee);
}
/**
* 删除对应的员工信息
*
* @param id 员工id
*/
@Override
public void removeEmployeeById(Long id) {
employeeDAO.removeEmployeeById(id);
}
}
3.10 创建Employee对应的Controller类
@RestController
@RequestMapping(value = "/api/v1.0/employee")
public class EmployeeController {
/**
* 员工管理模块Service组件
*/
@Autowired
private EmployService employService;
/**
* 查询所有员工的信息
*
* @return 员工list集合
*/
@GetMapping
public List<Employee> getAllEmployee() {
return employService.getAllEmployee();
}
/**
* 通过员工id 查询对应的员工信息
* @param id 员工id
* @return 员工实体类
*/
@GetMapping(value = "/find/{employeeId}")
public Employee findEmployeeById(@PathVariable(name = "employeeId") Long id) {
return employService.findEmployeeById(id);
}
/**
* 保存员工信息
*
* @param employee 员工实体类
*/
@PostMapping("/")
public String saveEmployee(@RequestBody Employee employee) {
employService.saveEmployee(employee);
return "success";
}
/**
* 根据员工id 更新员工信息
*
* @param employee 员工实体类
*/
@PutMapping(value = "update/{employeeId}")
public String updateEmployeeById(@PathVariable(value = "employeeId") Long employeeId,Employee employee) {
employee.setId(employeeId);
employService.updateEmployeeById(employee);
return "success";
}
/**
* 删除对应的员工信息
*
* @param id 员工id
*/
@DeleteMapping(value = "remove/{employeeId}")
public String removeEmployeeById(@PathVariable(value = "employeeId") Long id) {
employService.removeEmployeeById(id);
return "success";
}
}
3.11 启动程序并访问执行
我们可以通过postman对Employee表做增删改查的操作。如:我们进行删操作
4. 梳理总结
-
系统在启动的时候,首先会先扫描DruidConfig类,将外部的Druid连接池配置加载进来,同时初始化出来一个Druid连接池的DataSource bean对象出来;
-
接着通过mybatis-spring-boot-starter发现了一个DataSource bean对象,就会将其注入到SqlSessionFactory,再创建SqlSessionTemplate。通过扫描Mapper接口,将SqlSessionTemplate注入每个Mapper,然后将Mapper放入spring容器中来管理;
扫描二维码关注公众号,回复: 13541329 查看本文章 -
Spring Boot的
@ComponantScan
注解会自动扫描所有的bean,依次初始化实例以及注入依赖,EmployeeServiceImpl(将EmployeeMapper注入其中),EmployeeCongtroller(将EmployeeServiceImpl注入其中); -
此时浏览器发送请求后,会先由controlller处理,接着调用service,再调用dao,接着调用mapper,mapper底层会基于druid连接池访问到数据库,进行数据操作。
5. 代码示例
本文的相关例子可以查看下面仓库中的目录:
-Github:https://github.com/bamaw/springboot2.x-examples
-Gitee: https://gitee.com/bamaw/springboot2.x-examples
如果您觉得本文不错,欢迎Star支持,您的关注是我坚持的动力!