论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. 遇到问题容易排查
相关推荐
西岭千秋雪_3 小时前
Zookeeper实现分布式锁
java·分布式·后端·zookeeper·wpf
MarcoPage4 小时前
Python 字典推导式入门:一行构建键值对映射
java·linux·python
脸大是真的好~5 小时前
黑马JAVAWeb-11 请求参数为数组-XML自动封装-XML手动封装-增删改查-全局异常处理-单独异常分别处理
java
Hello.Reader7 小时前
Data Sink定义、参数与可落地示例
java·前端·网络
2401_837088508 小时前
stringRedisTemplate.opsForHash().entries
java·redis
lkbhua莱克瓦2410 小时前
Java基础——集合进阶3
java·开发语言·笔记
蓝-萧10 小时前
使用Docker构建Node.js应用的详细指南
java·后端
多喝开水少熬夜10 小时前
Trie树相关算法题java实现
java·开发语言·算法
lkbhua莱克瓦2411 小时前
Java基础——集合进阶用到的数据结构知识点1
java·数据结构·笔记·github
音符犹如代码12 小时前
Java并发List实战:CopyOnWriteArrayList原理与ArrayList常见面试题
java·开发语言·面试·list