在 Java EE 进阶 --- SpringBoot 的学习过程中,数据库操作是绕不开的一环。Mybatis 作为一款优秀的持久层框架,与 SpringBoot 的集成更是简化了繁琐的 JDBC 操作,提高了开发效率。本文将带你从零开始,掌握 SpringBoot 集成 Mybatis 的基础知识,并分享一些实战中的避坑经验。
问题场景重现:告别繁琐的 JDBC
在传统的 Java EE 项目中,使用 JDBC 操作数据库需要编写大量的重复代码,例如获取连接、预编译 SQL、设置参数、执行查询、处理结果集、关闭连接等等。这些代码不仅冗长,而且容易出错。例如,忘记关闭连接就可能导致连接池耗尽,最终影响整个应用的性能。而且,SQL 语句与 Java 代码的耦合度很高,不利于后期的维护和扩展。因此,我们需要一种更加简洁、高效、灵活的数据库操作方式。
底层原理深度剖析:Mybatis 的奥秘
Mybatis 本质上是一个半自动化的 ORM(Object-Relational Mapping)框架。它通过 XML 或注解的方式,将 SQL 语句与 Java 方法进行映射,从而实现 SQL 与 Java 代码的解耦。Mybatis 的核心组件包括:
- SqlSessionFactoryBuilder:用于创建 SqlSessionFactory。
- SqlSessionFactory:用于创建 SqlSession。
- SqlSession:Mybatis 的核心接口,用于执行 SQL 语句、提交事务、回滚事务等。
- Mapper 接口:定义了数据库操作的方法,Mybatis 会根据 Mapper 接口生成代理对象,并将方法调用委托给 SqlSession 执行相应的 SQL 语句。
Mybatis 的工作流程大致如下:
- 加载 Mybatis 配置文件(mybatis-config.xml)。
- 创建 SqlSessionFactory。
- 通过 SqlSessionFactory 创建 SqlSession。
- 通过 SqlSession 获取 Mapper 接口的代理对象。
- 调用 Mapper 接口的方法,Mybatis 会根据方法名和参数,找到对应的 SQL 语句并执行。
- 处理结果集,将查询结果映射成 Java 对象。
- 关闭 SqlSession。
具体代码/配置解决方案:SpringBoot + Mybatis 最佳实践
- 添加依赖
首先,在 pom.xml 文件中添加 SpringBoot 和 Mybatis 的依赖:
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version> <!-- 使用最新的版本 -->
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version> <!-- 根据你的数据库版本选择 -->
</dependency>
- 配置数据源
在 application.properties 或 application.yml 文件中配置数据源:
spring.datasource.url=jdbc:mysql://localhost:3306/your_database?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
spring.datasource.username=your_username
spring.datasource.password=your_password
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
或者使用 YAML 格式:
spring:
datasource:
url: jdbc:mysql://localhost:3306/your_database?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
username: your_username
password: your_password
driver-class-name: com.mysql.cj.jdbc.Driver
- 创建 Mapper 接口
定义一个 Mapper 接口,用于声明数据库操作的方法:
package com.example.mapper;
import com.example.entity.User;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper // 必须添加 @Mapper 注解,让 Spring 扫描到该接口
public interface UserMapper {
User selectUserById(Integer id);
List<User> selectAllUsers();
int insertUser(User user);
int updateUser(User user);
int deleteUserById(Integer id);
}
- 编写 XML 映射文件
创建一个 XML 文件,用于配置 SQL 语句与 Mapper 接口方法的映射关系。XML 文件需要放在 src/main/resources/mapper 目录下,并且文件名要与 Mapper 接口名相同(例如 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="com.example.mapper.UserMapper">
<select id="selectUserById" parameterType="java.lang.Integer" resultType="com.example.entity.User">
SELECT * FROM user WHERE id = #{id}
</select>
<select id="selectAllUsers" resultType="com.example.entity.User">
SELECT * FROM user
</select>
<insert id="insertUser" parameterType="com.example.entity.User">
INSERT INTO user (name, age) VALUES (#{name}, #{age})
</insert>
<update id="updateUser" parameterType="com.example.entity.User">
UPDATE user SET name = #{name}, age = #{age} WHERE id = #{id}
</update>
<delete id="deleteUserById" parameterType="java.lang.Integer">
DELETE FROM user WHERE id = #{id}
</delete>
</mapper>
- 编写 Service 层代码
在 Service 层调用 Mapper 接口的方法,实现业务逻辑:
package com.example.service;
import com.example.entity.User;
import com.example.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public User getUserById(Integer id) {
return userMapper.selectUserById(id);
}
public List<User> getAllUsers() {
return userMapper.selectAllUsers();
}
public int insertUser(User user) {
return userMapper.insertUser(user);
}
public int updateUser(User user) {
return userMapper.updateUser(user);
}
public int deleteUserById(Integer id) {
return userMapper.deleteUserById(id);
}
}
- 在 Controller 层调用 Service 层代码
在 Controller 层接收请求,调用 Service 层的方法,并将结果返回给客户端:
package com.example.controller;
import com.example.entity.User;
import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/users")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/{id}")
public User getUserById(@PathVariable Integer id) {
return userService.getUserById(id);
}
@GetMapping
public List<User> getAllUsers() {
return userService.getAllUsers();
}
@PostMapping
public int insertUser(@RequestBody User user) {
return userService.insertUser(user);
}
@PutMapping("/{id}")
public int updateUser(@PathVariable Integer id, @RequestBody User user) {
user.setId(id);
return userService.updateUser(user);
}
@DeleteMapping("/{id}")
public int deleteUserById(@PathVariable Integer id) {
return userService.deleteUserById(id);
}
}
实战避坑经验总结
- ResultMap 的使用:当数据库字段名与 Java 对象的属性名不一致时,可以使用 ResultMap 进行映射。ResultMap 可以将数据库字段名与 Java 对象的属性名进行关联,从而实现正确的映射。
- 动态 SQL 的使用:在复杂的查询场景下,可以使用动态 SQL 拼接 SQL 语句。Mybatis 提供了
<if>、<choose>、<when>、<otherwise>、<where>、<set>、<foreach>等标签,用于构建动态 SQL。 - 事务管理:在需要保证数据一致性的场景下,需要使用事务管理。SpringBoot 提供了
@Transactional注解,可以方便地进行事务管理。建议使用 Spring 的声明式事务,避免手动管理事务带来的风险。 - SQL 注入风险:要避免 SQL 注入风险,尽量使用预编译 SQL(PreparedStatement),不要直接拼接 SQL 语句。Mybatis 默认使用预编译 SQL,可以有效防止 SQL 注入。
- 连接池配置:根据应用的并发量,合理配置数据库连接池的大小。连接池过小会导致请求排队等待,影响应用的性能;连接池过大会占用过多的系统资源。可以使用 Druid、HikariCP 等高性能连接池。
- 日志打印:开启 Mybatis 的日志功能,可以方便地查看执行的 SQL 语句和参数,有助于调试和排查问题。可以在
application.properties或application.yml文件中配置日志级别:logging.level.com.example.mapper=DEBUG。 - Nginx 负载均衡:在高并发场景下,可以考虑使用 Nginx 进行反向代理和负载均衡。Nginx 可以将请求分发到多个应用服务器上,从而提高应用的并发处理能力。同时,可以使用宝塔面板等工具简化 Nginx 的配置和管理。
掌握了以上 SpringBoot 集成 Mybatis 的基础知识和实战经验,相信你一定能够轻松应对各种数据库操作场景。在实际开发中,还需要不断学习和探索,才能更好地利用 Mybatis 提高开发效率。
冠军资讯
代码一只喵