论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. 遇到问题容易排查
相关推荐
whn19772 分钟前
达梦数据库的整体负载变化查看
java·开发语言·数据库
小满、2 分钟前
RabbitMQ:Fanout、Direct、Topic 交换机、队列声明与消息转换器
java·分布式·消息队列·rabbitmq·spring amqp
檀越剑指大厂12 分钟前
【Idea系列】换行处理
java·ide·intellij-idea
wanghowie25 分钟前
01.04 Java基础篇|泛型、注解与反射实战
java·开发语言·windows
深圳佛手28 分钟前
Java大对象(如 List、Map)如何复用?错误的方法是?正确的方法是?
java·jvm·windows
言之。33 分钟前
Claude Code Skills 实用使用手册
java·开发语言
苹果醋333 分钟前
JAVA设计模式之策略模式
java·运维·spring boot·mysql·nginx
千寻技术帮37 分钟前
10370_基于Springboot的校园志愿者管理系统
java·spring boot·后端·毕业设计
Rinai_R37 分钟前
关于 Go 的内存管理这档事
java·开发语言·golang
聆风吟º39 分钟前
【Spring Boot 报错已解决】彻底解决 “Main method not found in class com.xxx.Application” 报错
java·spring boot·后端