论MyBatis和JPA权威性

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开始,因为:

  1. SQL直观,容易理解和调试
  2. 能真正理解数据库操作
  3. 遇到问题容易排查
相关推荐
小猪咪piggy4 小时前
【微服务】(1) Spring Cloud 概述
java·spring cloud·微服务
lkbhua莱克瓦244 小时前
Java基础——面向对象进阶复习知识点8
java·笔记·github·学习方法
m0_736927044 小时前
Spring Boot自动配置与“约定大于配置“机制详解
java·开发语言·后端·spring
GL-Yang5 小时前
2025年-集合类面试题
java·面试
你不是我我5 小时前
【Java 开发日记】我们来说一说 Redisson 的原理
java·开发语言
李憨憨5 小时前
Java处理大型 Excel 文件(超过 100 万行)难题
java
老K的Java兵器库6 小时前
Collections 工具类 15 个常用方法源码:sort、binarySearch、reverse、shuffle、unmodifiableXxx
java·开发语言·哈希算法
武子康6 小时前
Java-153 深入浅出 MongoDB 全面的适用场景分析与选型指南 场景应用指南
java·开发语言·数据库·mongodb·性能优化·系统架构·nosql
救救孩子把6 小时前
从 JDK 8 到 JDK 23:HotSpot 垃圾回收器全景演进与深度剖析
java·开发语言·jvm·jdk