MyBatis和JPA都是常用的持久层框架,让我们来详细讲解两者的区别和使用方法。
1. JPA vs MyBatis 对比
特性 | Spring Data JPA | MyBatis |
---|---|---|
理念 | 面向对象,不用写SQL | SQL映射,需要写SQL |
SQL控制 | 自动生成SQL,也可自定义 | 完全手动控制SQL |
学习曲线 | 较陡峭,需要理解JPA规范 | 较平缓,就是写SQL |
灵活性 | 相对固定,复杂查询麻烦 | 非常灵活,复杂SQL优势明显 |
开发效率 | 简单CRUD效率极高 | 所有SQL都要自己写 |
适用场景 | 标准CRUD、快速开发 | 复杂查询、存储过程、现有数据库 |
2. Spring Data JPA 详细使用
2.1 添加依赖
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
2.2 配置数据库
properties
# application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# JPA配置
spring.jpa.database=mysql
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect
2.3 创建实体类(Entity)
java
package com.msb.entity;
import javax.persistence.*;
@Entity
@Table(name = "user") // 对应数据库表名
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY) // 自增主键
private Long id;
@Column(name = "name", length = 50, nullable = false)
private String name;
@Column(name = "email", unique = true)
private String email;
@Column(name = "age")
private Integer age;
// 必须有无参构造器
public User() {}
// 有参构造器
public User(String name, String email, Integer age) {
this.name = name;
this.email = email;
this.age = age;
}
// Getter和Setter方法
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; }
public Integer getAge() { return age; }
public void setAge(Integer age) { this.age = age; }
}
2.4 创建Repository接口
java
package com.msb.repository;
import com.msb.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.List;
// 继承JpaRepository,已经包含基本的CRUD方法
public interface UserRepository extends JpaRepository<User, Long> {
// 方法名自动生成查询
List<User> findByName(String name);
List<User> findByAgeGreaterThan(Integer age);
List<User> findByNameContaining(String keyword);
// 自定义查询
@Query("SELECT u FROM User u WHERE u.email LIKE %:email%")
List<User> findByEmailLike(@Param("email") String email);
@Query("SELECT u FROM User u WHERE u.age BETWEEN :minAge AND :maxAge")
List<User> findUsersByAgeRange(@Param("minAge") Integer minAge,
@Param("maxAge") Integer maxAge);
}
2.5 创建Service
java
package com.msb.service;
import com.msb.entity.User;
import com.msb.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
// 保存用户
public User saveUser(User user) {
return userRepository.save(user);
}
// 查询所有用户
public List<User> getAllUsers() {
return userRepository.findAll();
}
// 根据ID查询
public User getUserById(Long id) {
Optional<User> user = userRepository.findById(id);
return user.orElse(null); // 如果不存在返回null
}
// 根据姓名查询
public List<User> getUsersByName(String name) {
return userRepository.findByName(name);
}
// 查询年龄大于指定值的用户
public List<User> getUsersByAgeGreaterThan(Integer age) {
return userRepository.findByAgeGreaterThan(age);
}
// 删除用户
public void deleteUser(Long id) {
userRepository.deleteById(id);
}
}
2.6 创建Controller
java
package com.msb.controller;
import com.msb.entity.User;
import com.msb.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
// 获取所有用户
@GetMapping
public List<User> getAllUsers() {
return userService.getAllUsers();
}
// 根据ID获取用户
@GetMapping("/{id}")
public User getUserById(@PathVariable Long id) {
return userService.getUserById(id);
}
// 创建用户
@PostMapping
public User createUser(@RequestBody User user) {
return userService.saveUser(user);
}
// 更新用户
@PutMapping("/{id}")
public User updateUser(@PathVariable Long id, @RequestBody User user) {
user.setId(id);
return userService.saveUser(user);
}
// 删除用户
@DeleteMapping("/{id}")
public void deleteUser(@PathVariable Long id) {
userService.deleteUser(id);
}
// 根据姓名查询
@GetMapping("/search")
public List<User> searchUsersByName(@RequestParam String name) {
return userService.getUsersByName(name);
}
}
3. MyBatis 详细使用
3.1 添加依赖
xml
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
3.2 配置MyBatis
properties
# application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# MyBatis配置
mybatis.mapper-locations=classpath:mapper/*.xml
mybatis.type-aliases-package=com.msb.entity
mybatis.configuration.map-underscore-to-camel-case=true
3.3 创建实体类
java
package com.msb.entity;
public class User {
private Long id;
private String name;
private String email;
private Integer age;
// 构造器、getter、setter
public User() {}
public User(String name, String email, Integer age) {
this.name = name;
this.email = email;
this.age = age;
}
// getter和setter...
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; }
public Integer getAge() { return age; }
public void setAge(Integer age) { this.age = age; }
}
3.4 创建Mapper接口
java
package com.msb.mapper;
import com.msb.entity.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@Mapper
public interface UserMapper {
// 插入用户
int insert(User user);
// 根据ID查询
User selectById(Long id);
// 查询所有用户
List<User> selectAll();
// 根据姓名查询
List<User> selectByName(String name);
// 更新用户
int update(User user);
// 删除用户
int deleteById(Long id);
// 复杂查询:根据年龄范围查询
List<User> selectByAgeRange(@Param("minAge") Integer minAge,
@Param("maxAge") Integer maxAge);
// 复杂查询:统计用户数量
int countUsers();
}
3.5 创建Mapper XML文件
在 src/main/resources/mapper/UserMapper.xml
:
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.msb.mapper.UserMapper">
<!-- 结果映射 -->
<resultMap id="BaseResultMap" type="User">
<id column="id" property="id" />
<result column="name" property="name" />
<result column="email" property="email" />
<result column="age" property="age" />
</resultMap>
<!-- 插入用户 -->
<insert id="insert" parameterType="User" useGeneratedKeys="true" keyProperty="id">
INSERT INTO user (name, email, age)
VALUES (#{name}, #{email}, #{age})
</insert>
<!-- 根据ID查询 -->
<select id="selectById" parameterType="Long" resultMap="BaseResultMap">
SELECT id, name, email, age
FROM user
WHERE id = #{id}
</select>
<!-- 查询所有用户 -->
<select id="selectAll" resultMap="BaseResultMap">
SELECT id, name, email, age
FROM user
</select>
<!-- 根据姓名查询 -->
<select id="selectByName" parameterType="String" resultMap="BaseResultMap">
SELECT id, name, email, age
FROM user
WHERE name LIKE CONCAT('%', #{name}, '%')
</select>
<!-- 更新用户 -->
<update id="update" parameterType="User">
UPDATE user
SET name = #{name}, email = #{email}, age = #{age}
WHERE id = #{id}
</update>
<!-- 删除用户 -->
<delete id="deleteById" parameterType="Long">
DELETE FROM user WHERE id = #{id}
</delete>
<!-- 根据年龄范围查询 -->
<select id="selectByAgeRange" resultMap="BaseResultMap">
SELECT id, name, email, age
FROM user
WHERE age BETWEEN #{minAge} AND #{maxAge}
ORDER BY age ASC
</select>
<!-- 统计用户数量 -->
<select id="countUsers" resultType="int">
SELECT COUNT(*) FROM user
</select>
</mapper>
3.6 创建Service
java
package com.msb.service;
import com.msb.entity.User;
import com.msb.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 saveUser(User user) {
if (user.getId() == null) {
userMapper.insert(user);
} else {
userMapper.update(user);
}
return user;
}
public List<User> getAllUsers() {
return userMapper.selectAll();
}
public User getUserById(Long id) {
return userMapper.selectById(id);
}
public List<User> getUsersByName(String name) {
return userMapper.selectByName(name);
}
public void deleteUser(Long id) {
userMapper.deleteById(id);
}
public List<User> getUsersByAgeRange(Integer minAge, Integer maxAge) {
return userMapper.selectByAgeRange(minAge, maxAge);
}
public int getUserCount() {
return userMapper.countUsers();
}
}
3.7 创建Controller(与JPA版本类似)
java
package com.msb.controller;
import com.msb.entity.User;
import com.msb.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
@GetMapping
public List<User> getAllUsers() {
return userService.getAllUsers();
}
@GetMapping("/{id}")
public User getUserById(@PathVariable Long id) {
return userService.getUserById(id);
}
@PostMapping
public User createUser(@RequestBody User user) {
return userService.saveUser(user);
}
@PutMapping("/{id}")
public User updateUser(@PathVariable Long id, @RequestBody User user) {
user.setId(id);
return userService.saveUser(user);
}
@DeleteMapping("/{id}")
public void deleteUser(@PathVariable Long id) {
userService.deleteUser(id);
}
@GetMapping("/search")
public List<User> searchUsersByName(@RequestParam String name) {
return userService.getUsersByName(name);
}
@GetMapping("/age-range")
public List<User> getUsersByAgeRange(@RequestParam Integer minAge,
@RequestParam Integer maxAge) {
return userService.getUsersByAgeRange(minAge, maxAge);
}
@GetMapping("/count")
public int getUserCount() {
return userService.getUserCount();
}
}
4. 总结建议
选择JPA的情况:
- 项目简单,主要是CRUD操作
- 想要快速开发,不想写SQL
- 团队熟悉面向对象编程
选择MyBatis的情况:
- 复杂SQL查询,需要精细优化
- 已有数据库,表结构复杂
- 需要调用存储过程
- 团队SQL能力强
初学者建议:
从MyBatis开始,因为:
- SQL直观,容易理解和调试
- 能真正理解数据库操作
- 遇到问题容易排查