MyBatis 是一个轻量级的持久化框架(ORM 工具),在 Spring Boot 中也可以很好地用来操作 MySQL 等数据库。相比 Spring Data JPA,MyBatis 的特点是更灵活,你可以手动控制 SQL 语句,而不是完全依赖自动生成的查询。它通过映射文件(XML)或注解将 Java 方法与 SQL 关联起来,非常适合需要精细控制 SQL 的场景。
下面我详细讲解 MyBatis 在 Spring Boot 中的使用方式。
如何在 Spring Boot 中使用 MyBatis?
1. 添加依赖
在 pom.xml 中加入 MyBatis 的 Spring Boot Starter 和 MySQL 驱动:
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
2. 配置数据源
在 application.properties 或 application.yml 中配置 MySQL 连接:
spring.datasource.url=jdbc:mysql://localhost:3306/mydb
spring.datasource.username=root
spring.datasource.password=yourpassword
# 可选:MyBatis 配置
mybatis.mapper-locations=classpath:mapper/*.xml # XML 映射文件位置
mybatis.type-aliases-package=com.example.entity # 实体类包路径
3. 定义实体类
创建一个普通的 Java 类(POJO),用来映射数据库表。不需要像 JPA 那样加注解:
package com.example.entity;
public class User {
private Long id;
private String name;
private String email;
// 无参构造函数
public User() {}
// 有参构造函数、getter 和 setter
public User(String name, String email) {
this.name = name;
this.email = email;
}
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 String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
}
4. 定义 Mapper 接口
创建一个接口,定义数据库操作方法。可以用注解直接写 SQL,也可以用 XML 映射文件。
方法一:使用注解
package com.example.mapper;
import com.example.entity.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Update;
import org.apache.ibatis.annotations.Delete;
import java.util.List;
@Mapper
public interface UserMapper {
@Select("SELECT * FROM user WHERE id = #{id}")
User findById(Long id);
@Select("SELECT * FROM user")
List<User> findAll();
@Insert("INSERT INTO user(name, email) VALUES(#{name}, #{email})")
void insert(User user);
@Update("UPDATE user SET name = #{name}, email = #{email} WHERE id = #{id}")
void update(User user);
@Delete("DELETE FROM user WHERE id = #{id}")
void delete(Long id);
}
@Mapper表示这是一个 MyBatis 的映射接口。#{}是参数占位符,MyBatis 会自动把方法参数映射到 SQL。
方法二:使用 XML 映射文件
如果 SQL 比较复杂,推荐用 XML 文件:
- 创建接口:
package com.example.mapper; import com.example.entity.User; import org.apache.ibatis.annotations.Mapper; import java.util.List; @Mapper public interface UserMapper { User findById(Long id); List<User> findAll(); void insert(User user); void update(User user); void delete(Long id); } - 在
src/main/resources/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="findById" resultType="com.example.entity.User"> SELECT * FROM user WHERE id = #{id} </select> <select id="findAll" resultType="com.example.entity.User"> SELECT * FROM user </select> <insert id="insert" parameterType="com.example.entity.User"> INSERT INTO user(name, email) VALUES(#{name}, #{email}) </insert> <update id="update" parameterType="com.example.entity.User"> UPDATE user SET name = #{name}, email = #{email} WHERE id = #{id} </update> <delete id="delete"> DELETE FROM user WHERE id = #{id} </delete> </mapper>namespace对应 Mapper 接口的全限定名。id对应接口中的方法名。
5. 使用 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 {
private final UserMapper userMapper;
@Autowired
public UserService(UserMapper userMapper) {
this.userMapper = userMapper;
}
public User getUser(Long id) {
return userMapper.findById(id);
}
public List<User> getAllUsers() {
return userMapper.findAll();
}
public void addUser(User user) {
userMapper.insert(user);
}
public void updateUser(User user) {
userMapper.update(user);
}
public void deleteUser(Long id) {
userMapper.delete(id);
}
}
6. 配置扫描(可选)
如果不用 @Mapper,可以在启动类上加 @MapperScan 扫描 Mapper 接口:
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.example.mapper")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
7. 测试
可以用 Controller 调用 Service,或者直接测试:
@RestController
public class UserController {
private final UserService userService;
@Autowired
public UserController(UserService userService) {
this.userService = userService;
}
@GetMapping("/users/{id}")
public User getUser(@PathVariable Long id) {
return userService.getUser(id);
}
@PostMapping("/users")
public void addUser(@RequestBody User user) {
userService.addUser(user);
}
}
MyBatis 的核心功能
-
SQL 灵活性:
- 你可以完全掌控 SQL,适合复杂查询。
- 支持动态 SQL(在 XML 中用
<if>、<foreach>等标签)。
-
映射:
- 参数和结果自动映射到 Java 对象。
- 支持一对一、一对多关系(需配置)。
-
轻量级:
- 不像 JPA 那样依赖 ORM 的复杂特性,性能更可控。
优势
- SQL 控制:开发者可以编写精确的 SQL,优化性能。
- 简单:没有 JPA 的学习成本,直接上手。
- 灵活:支持动态 SQL 和复杂映射。
注意事项
- 手动 SQL:不像 Spring Data JPA 那样自动生成,需要自己写。
- 主键回填:如果需要插入后返回自增 ID,需配置(如
<insert>加useGeneratedKeys)。 - 事务:在 Service 层加
@Transactional管理事务。
总结
MyBatis 在 Spring Boot 中通过 Mapper 接口和 SQL 映射(注解或 XML)实现数据库操作。它适合需要精细控制 SQL 的场景,比如复杂的报表查询。
示例
在使用 MyBatis 实现权限管理功能时,我们需要设计一个合理的数据库结构,并通过 MyBatis 的 Mapper 接口和映射文件(或注解)来实现查询、修改等操作。权限管理通常涉及用户(User)、角色(Role)和权限(Permission)之间的关系,常见的设计是基于 RBAC(Role-Based Access Control,基于角色的访问控制) 模型。
下面我将一步步讲解如何用 MyBatis 在 Spring Boot 中实现权限管理的 CRUD 操作,包括数据库设计、实体类、Mapper 接口和具体功能的实现。
1. 数据库设计
假设我们基于 RBAC 模型,设计以下表结构:
-
users(用户表)
id (bigint, 主键,自增) username (varchar, 用户名) password (varchar, 密码) -
roles(角色表)
id (bigint, 主键,自增) name (varchar, 角色名,如 "admin", "user") -
permissions(权限表)
id (bigint, 主键,自增) name (varchar, 权限名,如 "read", "write") -
user_roles(用户-角色关联表,多对多)
user_id (bigint, 外键,关联 users.id) role_id (bigint, 外键,关联 roles.id) -
role_permissions(角色-权限关联表,多对多)
role_id (bigint, 外键,关联 roles.id) permission_id (bigint, 外键,关联 permissions.id)
这个结构允许用户拥有多个角色,每个角色拥有多个权限,支持灵活的权限分配。
2. 添加依赖
确保 pom.xml 中有 MyBatis 和 MySQL 的依赖:
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
3. 配置数据源
在 application.properties 中:
spring.datasource.url=jdbc:mysql://localhost:3306/rbac_db
spring.datasource.username=root
spring.datasource.password=yourpassword
mybatis.mapper-locations=classpath:mapper/*.xml
mybatis.type-aliases-package=com.example.entity
4. 定义实体类
基于表结构,创建对应的 Java 类:
User.java
package com.example.entity;
import java.util.List;
public class User {
private Long id;
private String username;
private String password;
private List<Role> roles; // 用户的角色列表
// 构造函数、getter 和 setter
public User() {}
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
public List<Role> getRoles() { return roles; }
public void setRoles(List<Role> roles) { this.roles = roles; }
}
Role.java
package com.example.entity;
import java.util.List;
public class Role {
private Long id;
private String name;
private List<Permission> permissions; // 角色的权限列表
// 构造函数、getter 和 setter
public Role() {}
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 List<Permission> getPermissions() { return permissions; }
public void setPermissions(List<Permission> permissions) { this.permissions = permissions; }
}
Permission.java
package com.example.entity;
public class Permission {
private Long id;
private String name;
// 构造函数、getter 和 setter
public Permission() {}
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; }
}
5. 定义 Mapper 接口和 XML
UserMapper.java
package com.example.mapper;
import com.example.entity.User;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserMapper {
User findById(Long id); // 查询用户及其角色
void insert(User user); // 添加用户
void update(User user); // 更新用户信息
void delete(Long id); // 删除用户
void addUserRole(Long userId, Long roleId); // 为用户分配角色
void removeUserRole(Long userId, Long roleId); // 删除用户角色
}
UserMapper.xml
在 src/main/resources/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">
<!-- 结果映射:用户及其角色 -->
<resultMap id="UserWithRoles" type="com.example.entity.User">
<id property="id" column="id"/>
<result property="username" column="username"/>
<result property="password" column="password"/>
<collection property="roles" ofType="com.example.entity.Role">
<id property="id" column="role_id"/>
<result property="name" column="role_name"/>
<collection property="permissions" ofType="com.example.entity.Permission">
<id property="id" column="permission_id"/>
<result property="name" column="permission_name"/>
</collection>
</collection>
</resultMap>
<!-- 查询用户及其角色和权限 -->
<select id="findById" resultMap="UserWithRoles">
SELECT
u.id, u.username, u.password,
r.id AS role_id, r.name AS role_name,
p.id AS permission_id, p.name AS permission_name
FROM users u
LEFT JOIN user_roles ur ON u.id = ur.user_id
LEFT JOIN roles r ON ur.role_id = r.id
LEFT JOIN role_permissions rp ON r.id = rp.role_id
LEFT JOIN permissions p ON rp.permission_id = p.id
WHERE u.id = #{id}
</select>
<!-- 插入用户 -->
<insert id="insert" parameterType="com.example.entity.User" useGeneratedKeys="true" keyProperty="id">
INSERT INTO users(username, password) VALUES(#{username}, #{password})
</insert>
<!-- 更新用户 -->
<update id="update" parameterType="com.example.entity.User">
UPDATE users SET username = #{username}, password = #{password} WHERE id = #{id}
</update>
<!-- 删除用户 -->
<delete id="delete">
DELETE FROM users WHERE id = #{id}
</delete>
<!-- 添加用户角色 -->
<insert id="addUserRole">
INSERT INTO user_roles(user_id, role_id) VALUES(#{userId}, #{roleId})
</insert>
<!-- 删除用户角色 -->
<delete id="removeUserRole">
DELETE FROM user_roles WHERE user_id = #{userId} AND role_id = #{roleId}
</delete>
</mapper>
RoleMapper.java
package com.example.mapper;
import com.example.entity.Role;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface RoleMapper {
Role findById(Long id); // 查询角色及其权限
void insert(Role role); // 添加角色
void update(Role role); // 更新角色
void delete(Long id); // 删除角色
void addRolePermission(Long roleId, Long permissionId); // 为角色分配权限
void removeRolePermission(Long roleId, Long permissionId); // 删除角色权限
}
RoleMapper.xml
在 src/main/resources/mapper/RoleMapper.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.RoleMapper">
<!-- 结果映射:角色及其权限 -->
<resultMap id="RoleWithPermissions" type="com.example.entity.Role">
<id property="id" column="id"/>
<result property="name" column="name"/>
<collection property="permissions" ofType="com.example.entity.Permission">
<id property="id" column="permission_id"/>
<result property="name" column="permission_name"/>
</collection>
</resultMap>
<!-- 查询角色及其权限 -->
<select id="findById" resultMap="RoleWithPermissions">
SELECT
r.id, r.name,
p.id AS permission_id, p.name AS permission_name
FROM roles r
LEFT JOIN role_permissions rp ON r.id = rp.role_id
LEFT JOIN permissions p ON rp.permission_id = p.id
WHERE r.id = #{id}
</select>
<!-- 插入角色 -->
<insert id="insert" parameterType="com.example.entity.Role" useGeneratedKeys="true" keyProperty="id">
INSERT INTO roles(name) VALUES(#{name})
</insert>
<!-- 更新角色 -->
<update id="update" parameterType="com.example.entity.Role">
UPDATE roles SET name = #{name} WHERE id = #{id}
</update>
<!-- 删除角色 -->
<delete id="delete">
DELETE FROM roles WHERE id = #{id}
</delete>
<!-- 添加角色权限 -->
<insert id="addRolePermission">
INSERT INTO role_permissions(role_id, permission_id) VALUES(#{roleId}, #{permissionId})
</insert>
<!-- 删除角色权限 -->
<delete id="removeRolePermission">
DELETE FROM role_permissions WHERE role_id = #{roleId} AND permission_id = #{permissionId}
</delete>
</mapper>
PermissionMapper.java
package com.example.mapper;
import com.example.entity.Permission;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface PermissionMapper {
Permission findById(Long id);
void insert(Permission permission);
void update(Permission permission);
void delete(Long id);
}
PermissionMapper.xml
在 src/main/resources/mapper/PermissionMapper.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.PermissionMapper">
<select id="findById" resultType="com.example.entity.Permission">
SELECT id, name FROM permissions WHERE id = #{id}
</select>
<insert id="insert" parameterType="com.example.entity.Permission" useGeneratedKeys="true" keyProperty="id">
INSERT INTO permissions(name) VALUES(#{name})
</insert>
<update id="update" parameterType="com.example.entity.Permission">
UPDATE permissions SET name = #{name} WHERE id = #{id}
</update>
<delete id="delete">
DELETE FROM permissions WHERE id = #{id}
</delete>
</mapper>
6. 服务层实现
创建一个服务层来封装权限管理的业务逻辑:
UserService.java
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 org.springframework.transaction.annotation.Transactional;
@Service
public class UserService {
private final UserMapper userMapper;
@Autowired
public UserService(UserMapper userMapper) {
this.userMapper = userMapper;
}
public User getUser(Long id) {
return userMapper.findById(id);
}
@Transactional
public void addUser(User user) {
userMapper.insert(user);
}
@Transactional
public void updateUser(User user) {
userMapper.update(user);
}
@Transactional
public void deleteUser(Long id) {
userMapper.delete(id);
}
@Transactional
public void assignRole(Long userId, Long roleId) {
userMapper.addUserRole(userId, roleId);
}
@Transactional
public void removeRole(Long userId, Long roleId) {
userMapper.removeUserRole(userId, roleId);
}
}
RoleService.java
package com.example.service;
import com.example.entity.Role;
import com.example.mapper.RoleMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class RoleService {
private final RoleMapper roleMapper;
@Autowired
public RoleService(RoleMapper roleMapper) {
this.roleMapper = roleMapper;
}
public Role getRole(Long id) {
return roleMapper.findById(id);
}
@Transactional
public void addRole(Role role) {
roleMapper.insert(role);
}
@Transactional
public void updateRole(Role role) {
roleMapper.update(role);
}
@Transactional
public void deleteRole(Long id) {
roleMapper.delete(id);
}
@Transactional
public void assignPermission(Long roleId, Long permissionId) {
roleMapper.addRolePermission(roleId, permissionId);
}
@Transactional
public void removePermission(Long roleId, Long permissionId) {
roleMapper.removeRolePermission(roleId, permissionId);
}
}
PermissionService.java
package com.example.service;
import com.example.entity.Permission;
import com.example.mapper.PermissionMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class PermissionService {
private final PermissionMapper permissionMapper;
@Autowired
public PermissionService(PermissionMapper permissionMapper) {
this.permissionMapper = permissionMapper;
}
public Permission getPermission(Long id) {
return permissionMapper.findById(id);
}
@Transactional
public void addPermission(Permission permission) {
permissionMapper.insert(permission);
}
@Transactional
public void updatePermission(Permission permission) {
permissionMapper.update(permission);
}
@Transactional
public void deletePermission(Long id) {
permissionMapper.delete(id);
}
}
7. 测试功能
可以用 Controller 调用服务层,或者直接写测试代码:
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Bean
CommandLineRunner run(UserService userService, RoleService roleService, PermissionService permissionService) {
return args -> {
// 添加权限
Permission read = new Permission();
read.setName("read");
permissionService.addPermission(read);
// 添加角色
Role admin = new Role();
admin.setName("admin");
roleService.addRole(admin);
// 为角色分配权限
roleService.assignPermission(admin.getId(), read.getId());
// 添加用户
User user = new User();
user.setUsername("alice");
user.setPassword("123");
userService.addUser(user);
// 为用户分配角色
userService.assignRole(user.getId(), admin.getId());
// 查询用户及其权限
User foundUser = userService.getUser(user.getId());
System.out.println("User: " + foundUser.getUsername());
foundUser.getRoles().forEach(role -> {
System.out.println("Role: " + role.getName());
role.getPermissions().forEach(perm -> System.out.println("Permission: " + perm.getName()));
});
};
}
}
8. 关键点说明
- 多表查询:通过
<resultMap>和<collection>实现用户-角色-权限的嵌套映射。 - 事务管理:用
@Transactional确保分配角色或权限时数据一致性。 - 动态 SQL:如果需要更复杂的条件查询,可以在 XML 中用
<if>、<where>等标签。
总结
通过 MyBatis,我们可以用灵活的 SQL 和映射机制实现权限管理的 CRUD 操作。

浙公网安备 33010602011771号