MyBatis 是一个轻量级的持久层框架,使用 SQL 查询语句来访问数据库。它与 Java 对象建立映射关系,通过配置文件或注解来管理 SQL 语句,灵活性高且与数据库操作直接相关,适合需要手动优化 SQL 的场景。与全自动 ORM(对象关系映射)工具如 Hibernate 相比,MyBatis 更注重开发者的 SQL 控制权。
在 MyBatis 项目中,典型的目录结构如下:
mybatis-demo
├── src
│ ├── main
│ │ ├── java
│ │ │ ├── com
│ │ │ │ ├── example
│ │ │ │ │ ├── controller # 控制层
│ │ │ │ │ ├── entity # 实体类(POJO)
│ │ │ │ │ ├── mapper # Mapper 接口
│ │ │ │ │ ├── service # 业务层服务类
│ │ │ │ │ ├── service.impl # 业务层实现类
│ │ │ │ │ ├── config # MyBatis 和数据库配置类
│ │ ├── resources
│ │ │ ├── mybatis-config.xml # MyBatis 核心配置文件
│ │ │ ├── mapper # Mapper XML 文件(SQL 语句)
│ │ │ ├── application.properties # 数据库配置
├── pom.xml # Maven 依赖文件
SqlSessionFactory
SqlSessionFactory
是 MyBatis 的核心工厂类,负责创建 SqlSession
。我们可以通过它来配置数据源和事务等,并用来创建执行 SQL 语句的 SqlSession
对象。
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession
SqlSession
是数据库操作的主要接口,包含执行 SQL 查询、插入、更新、删除等方法。SqlSession
是非线程安全的,且通常与数据库会话一一对应。
try (SqlSession session = sqlSessionFactory.openSession()) {
UserMapper mapper = session.getMapper(UserMapper.class);
User user = mapper.findUserById(1);
}
Mapper 是 MyBatis 的核心,映射 SQL 语句与 Java 方法。通过定义接口和 SQL 映射文件(或注解),实现业务数据访问。
public interface UserMapper {
User findUserById(int id);
}
分页是 Web 应用程序中常见的需求。MyBatis 本身不包含分页功能,但可以通过 SQL 语句的 LIMIT
子句和 MyBatis 插件如 PageHelper
实现分页。
SELECT * FROM users LIMIT #{offset}, #{limit};
在 MyBatis 中,我们可以通过在 SQL 查询中使用 LIMIT
参数来控制分页逻辑:
<select id="findUsers" resultType="User">
SELECT * FROM users LIMIT #{offset}, #{limit}
select>
在 Mapper 中定义分页查询接口:
public interface UserMapper {
List<User> findUsers(@Param("offset") int offset, @Param("limit") int limit);
}
然后通过 Service 层调用分页方法:
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public List<User> getUsers(int page, int pageSize) {
int offset = (page - 1) * pageSize;
return userMapper.findUsers(offset, pageSize);
}
}
MyBatis 动态 SQL 提供了极大的灵活性,可以根据条件动态生成 SQL 语句。常用标签包括
、
、
等。
<select id="findUser" parameterType="map" resultType="User">
SELECT * FROM users WHERE 1=1
<if test="id != null">
AND id = #{id}
if>
<if test="name != null">
AND name = #{name}
if>
select>
这种方式使得我们能够根据不同的条件生成不同的查询语句,减少 SQL 代码的重复。
MyBatis 提供了两级缓存机制来优化性能。一级缓存是 SqlSession
级别的缓存,默认开启;二级缓存是全局缓存,需要手动配置。
一级缓存是 SqlSession
内部的缓存,生命周期为 SqlSession
的生命周期,查询相同的数据时会直接从缓存中读取。
二级缓存是跨 SqlSession
的全局缓存。要启用二级缓存,我们需要在配置文件中配置:
<cache/>
然后在每个映射文件的
标签下开启缓存:
<cache/>
MyBatis 可以与 Spring 无缝集成,Spring 负责管理事务、依赖注入,MyBatis 负责执行 SQL 语句。
SqlSessionFactoryBean
在 Spring 配置文件中配置 SqlSessionFactoryBean
,用于管理 MyBatis 的会话工厂:
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mapperLocations" value="classpath:com/example/mapper/*.xml"/>
bean>
在使用 MyBatis 时,事务的管理是一个重要的问题。通过 Spring,我们可以轻松使用 @Transactional
注解来管理事务。
@Transactional
public void saveUser(User user) {
userMapper.insertUser(user);
}
MyBatis 支持通过日志输出 SQL 语句,帮助开发者调试 SQL 查询。可以在配置文件中设置日志级别:
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
settings>
下面是一个完整的 MyBatis 项目示例,展示了从数据库连接配置到 CRUD 操作的整个流程。
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50),
email VARCHAR(50)
);
pom.xml
<dependencies>
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>2.2.0version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starterartifactId>
dependency>
<dependency>
<groupId>com.h2databasegroupId>
<artifactId>h2artifactId>
<scope>runtimescope>
dependency>
dependencies>
mybatis-config.xml
DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
settings>
configuration>
application.properties
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
User.java
public class User {
private Integer id;
private String name;
private String email;
// Getters and setters
}
UserMapper.java
public interface UserMapper {
@Insert("INSERT INTO users (name, email) VALUES (#{name}, #{email})")
void insertUser(User user);
@Select("SELECT * FROM users WHERE id = #{id}")
User findUserById(int id);
@Update("UPDATE users SET name=#{name}, email=#{email} WHERE id=#{id}")
void updateUser(User user);
@Delete("DELETE FROM users WHERE id = #{id}")
void deleteUser(int id);
}
UserMapper.xml
<mapper namespace="com.example.mapper.UserMapper">
<insert id="insertUser" parameterType="com.example.entity.User">
INSERT INTO users (name, email) VALUES (#{name}, #{email})
insert>
<select id="findUserById" resultType="com.example.entity.User" parameterType="int">
SELECT * FROM users WHERE id = #{id}
select>
<update id="updateUser" parameterType="com.example.entity.User">
UPDATE users SET name=#{name}, email=#{email} WHERE id=#{id}
update>
<delete id="deleteUser" parameterType="int">
DELETE FROM users WHERE id = #{id}
delete>
mapper>
UserService.java
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public void addUser(User user) {
userMapper.insertUser(user);
}
public User getUserById(int id) {
return userMapper.findUserById(id);
}
public void updateUser(User user) {
userMapper.updateUser(user);
}
public void deleteUser(int id) {
userMapper.deleteUser(id);
}
}
UserController.java
@RestController
@RequestMapping("/users")
public class UserController {
@Autowired
private UserService userService;
@PostMapping
public void createUser(@RequestBody User user) {
userService.addUser(user);
}
@GetMapping("/{id}")
public User getUser(@PathVariable int id) {
return userService.getUserById(id);
}
@PutMapping("/{id}")
public void updateUser(@PathVariable int id, @RequestBody User user) {
user.setId(id);
userService.updateUser(user);
}
@DeleteMapping("/{id}")
public void deleteUser(@PathVariable int id) {
userService.deleteUser(id);
}
}
通过以上完整的 MyBatis 示例项目,我们展示了从数据库配置到 CRUD 操作的整个过程。通过 MyBatis 与 Spring 的集成,开发者可以实现高效的持久层操作,并通过动态 SQL、缓存和分页功能增强应用的灵活性和性能。