论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. 遇到问题容易排查
相关推荐
20岁30年经验的码农14 小时前
Spring Cloud Gateway 网关技术文档
java
likuolei15 小时前
XML DOM 节点类型
xml·java·服务器
ZHE|张恒16 小时前
Spring Bean 生命周期
java·spring
代码or搬砖18 小时前
MyBatisPlus中的常用注解
数据库·oracle·mybatis
q***385118 小时前
SpringCloud实战十三:Gateway之 Spring Cloud Gateway 动态路由
java·spring cloud·gateway
小白学大数据18 小时前
Python爬虫伪装策略:如何模拟浏览器正常访问JSP站点
java·开发语言·爬虫·python
程序员西西19 小时前
SpringBoot接口安全:APIKey保护指南
java·spring boot·计算机·程序员·编程·编程开发
summer_west_fish19 小时前
单体VS微服务:架构选择实战指南
java·微服务·架构
v***85719 小时前
Ubuntu介绍、与centos的区别、基于VMware安装Ubuntu Server 22.04、配置远程连接、安装jdk+Tomcat
java·ubuntu·centos
烤麻辣烫20 小时前
黑马程序员大事件后端概览(表现效果升级版)
java·开发语言·学习·spring·intellij-idea