最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring Data JPA 實戰(zhàn)指南

 更新時間:2026年04月30日 08:12:50   作者:014-code  
本文主要介紹了Spring Data JPA 實戰(zhàn)指南,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

用過 MyBatis 再用 JPA,可能會覺得 JPA 很別扭——SQL 都不用寫了,框架自動搞定。

但用久了會發(fā)現(xiàn),JPA 寫起來其實很爽,尤其單表操作,幾乎不需要寫 SQL。

基礎(chǔ)配置

依賴

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
</dependency>

配置

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/test?useSSL=false
    username: root
    password: 123456
  jpa:
    hibernate:
      ddl-auto: update  # 開發(fā)用 update,生產(chǎn)用 validate
    show-sql: true      # 打印 SQL
    properties:
      hibernate:
        format_sql: true

ddl-auto 幾個選項:

  • update:自動更新表結(jié)構(gòu)(不會刪數(shù)據(jù))
  • create:每次啟動刪表重建
  • validate:只驗證,不改表
  • none:什么都不做

實體映射

基本映射

@Entity
@Table(name = "sys_user")
@Data
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @Column(name = "user_name", length = 50, nullable = false)
    private String userName;
    private Integer age;
    @Column(columnDefinition = "varchar(20) default 'ACTIVE'")
    private String status;
    @Column(name = "create_time")
    private LocalDateTime createTime;
    @Transient  // 不映射到數(shù)據(jù)庫
    private String tempField;
}

主鍵生成策略

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)  // MySQL 自增
// 或
@GeneratedValue(strategy = GenerationType.SEQUENCE)  // Oracle、序列
// 或
@GeneratedValue(strategy = GenerationType.UUID)      // UUID
private String id;

Repository 基礎(chǔ) CRUD

繼承 JpaRepository 就有基本的增刪改查:

public interface UserRepository extends JpaRepository<User, Long> {
    // 繼承來的方法:
    // save(entity)       - 保存或更新
    // findById(id)      - 查詢
    // deleteById(id)    - 刪除
    // count()           - 計數(shù)
    // existsById(id)    - 是否存在
}
@Service
@RequiredArgsConstructor
public class UserService {
    private final UserRepository userRepository;
    public User createUser(String name, Integer age) {
        User user = new User();
        user.setUserName(name);
        user.setAge(age);
        return userRepository.save(user);  // 自動 insert
    }
    public Optional<User> getUser(Long id) {
        return userRepository.findById(id);  // 自動 select
    }
    public void deleteUser(Long id) {
        userRepository.deleteById(id);  // 自動 delete
    }
    public User updateUser(Long id, String newName) {
        User user = userRepository.findById(id)
            .orElseThrow(() -> new RuntimeException("用戶不存在"));
        user.setUserName(newName);
        return userRepository.save(user);  // 自動 update
    }
}

方法名查詢(單表神器)

這是 JPA 最爽的地方——不用寫 SQL,方法名就是查詢。

基礎(chǔ)規(guī)則

public interface UserRepository extends JpaRepository<User, Long> {
    // 等值查詢:findBy + 字段名
    List<User> findByUserName(String userName);
    // → SELECT * FROM sys_user WHERE user_name = ?
    // 模糊查詢:findBy + 字段名 + Like
    List<User> findByUserNameLike(String userName);
    // → SELECT * FROM sys_user WHERE user_name LIKE ?
    // 多條件:findBy + 字段1 + And + 字段2
    List<User> findByUserNameAndAge(String userName, Integer age);
    // → SELECT * FROM sys_user WHERE user_name = ? AND age = ?
    // Or 條件
    List<User> findByUserNameOrAge(String userName, Integer age);
    // → SELECT * FROM sys_user WHERE user_name = ? OR age = ?
}

常用關(guān)鍵詞

// 大于/小于/等于
List<User> findByAgeGreaterThan(Integer age);      // age > ?
List<User> findByAgeLessThan(Integer age);        // age < ?
List<User> findByAgeGreaterThanEqual(Integer age); // age >= ?
List<User> findByStatusEquals(String status);      // status = ?
// BETWEEN 范圍
List<User> findByAgeBetween(Integer min, Integer max);
// → WHERE age BETWEEN ? AND ?
// IN 查詢
List<User> findByUserNameIn(List<String> names);
// → WHERE user_name IN (?, ?, ?)
// NULL 判斷
List<User> findByEmailIsNull();
List<User> findByEmailIsNotNull();
// True/False
List<User> findByActiveTrue();   // WHERE active = true
List<User> findByActiveFalse();  // WHERE active = false
// 排序
List<User> findByStatusOrderByAgeDesc(String status);
// → WHERE status = ? ORDER BY age DESC

分頁和排序

// 分頁:參數(shù)加 Pageable
Page<User> findByStatus(String status, Pageable pageable);
// 排序:Sort
List<User> findByStatus(String status, Sort sort);
// 使用
@Service
public class UserService {
    public Page<User> getUserPage(int page, int size) {
        Pageable pageable = PageRequest.of(page, size, Sort.by("age").descending());
        return userRepository.findByStatus("ACTIVE", pageable);
    }
}

@Query 自定義查詢

方法名解決不了的,用 @Query。

JPQL 查詢

@Query("SELECT u FROM User u WHERE u.userName = ?1")
User findByName(String userName);
// 占位符 ?1、?2 按參數(shù)順序
@Query("SELECT u FROM User u WHERE u.userName = ?1 AND u.age > ?2")
List<User> findByNameAndAge(String name, Integer age);
// 命名參數(shù)(更清晰)
@Query("SELECT u FROM User u WHERE u.userName = :name AND u.age > :age")
List<User> findByNameAndAgeV2(@Param("name") String name, @Param("age") Integer age);

多表聯(lián)查

假設(shè) User 關(guān)聯(lián) Department:

@Entity
public class User {
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "dept_id")
    private Department department;
}
// 查詢用戶并帶出部門名稱
@Query("SELECT u FROM User u JOIN FETCH u.department WHERE u.id = :id")
User findByIdWithDepartment(@Param("id") Long id);

原生 SQL

@Query(value = "SELECT * FROM sys_user WHERE user_name = :name", nativeQuery = true)
User findByNameNative(@Param("name") String name);
// 原生 SQL 分頁(注意 countQuery)
@Query(
    value = "SELECT * FROM sys_user WHERE status = :status ORDER BY age DESC",
    countQuery = "SELECT count(*) FROM sys_user WHERE status = :status",
    nativeQuery = true
)
Page<User> findByStatusPage(@Param("status") String status, Pageable pageable);

@Modifying 修改操作

@Modifying
@Query("UPDATE User u SET u.status = :status WHERE u.id = :id")
int updateStatus(@Param("id") Long id, @Param("status") String status);
@Modifying
@Query("DELETE FROM User u WHERE u.status = 'INACTIVE'")
void deleteInactiveUsers();

記得在 Service 層加事務(wù):

@Transactional
public void updateStatus(Long id, String status) {
    userRepository.updateStatus(id, status);
}

一對多 / 多對一

實體定義

@Entity
@Table(name = "department")
@Data
public class Department {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    @OneToMany(mappedBy = "department", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    private List<User> users;
}
@Entity
@Table(name = "sys_user")
@Data
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String userName;
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "dept_id")
    private Department department;
}

查詢

// 根據(jù)部門查用戶
List<User> findByDepartmentId(Long deptId);

// 根據(jù)用戶查部門(直接訪問屬性就行)
User user = userRepository.findById(id).orElseThrow(...);
String deptName = user.getDepartment().getName();  // 懶加載,會再查一次

// 一次性查出來(解決 N+1)
@Query("SELECT u FROM User u JOIN FETCH u.department WHERE u.id = :id")
User findByIdWithDept(@Param("id") Long id);

常見問題

1. 懶加載異常

// 報錯:LazyInitializationException
User user = userRepository.findById(1L).orElseThrow(...);
String deptName = user.getDepartment().getName();  // session 已關(guān)閉

解決:在 Service 層加 @Transactional,或者用 JOIN FETCH 一次性加載。

2. N+1 問題

// N+1:查 1 個用戶,再查 N 次部門
List<User> users = userRepository.findAll();
// SELECT * FROM sys_user
// SELECT * FROM department WHERE id = ?
// SELECT * FROM department WHERE id = ?
// ...

解決:用 @EntityGraphJOIN FETCH

@EntityGraph(attributePaths = {"department"})
List<User> findAllWithDept();

// 或
@Query("SELECT u FROM User u JOIN FETCH u.department")
List<User> findAllWithDept();

3. save 和 update 的區(qū)別

// save() - 如果 id 已存在就是 update,不存在就是 insert
User user = new User();
user.setId(1L);  // id 存在,變成 update
user.setUserName("newName");
userRepository.save(user);  // UPDATE

總結(jié)

方式適用場景
繼承 JpaRepository基本 CRUD
方法名查詢單表簡單查詢
@Query + JPQL多表關(guān)聯(lián)、復(fù)雜查詢
@Query + 原生 SQL特定數(shù)據(jù)庫語法
JOIN FETCH解決懶加載和 N+1

JPA 最大的好處是不用寫 SQL,單表操作特別爽。但多表關(guān)聯(lián)和復(fù)雜查詢,還是得用 @Query。用久了會發(fā)現(xiàn),JPA + @Query 配合起來,效率比 MyBatis 高多了。

到此這篇關(guān)于Spring Data JPA 實戰(zhàn)指南的文章就介紹到這了,更多相關(guān)Spring Data JPA 實戰(zhàn)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java面向國際化項目開發(fā)需遵循的命名規(guī)范

    java面向國際化項目開發(fā)需遵循的命名規(guī)范

    這篇文章主要為大家介紹了在參與開發(fā)國際化項目時需遵循的java命名規(guī)范,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步
    2022-03-03
  • SpringBoot靜態(tài)方法調(diào)用Spring容器bean的三種解決方案

    SpringBoot靜態(tài)方法調(diào)用Spring容器bean的三種解決方案

    在SpringBoot中靜態(tài)方法調(diào)用Spring容器bean時出現(xiàn)的null值問題,本文就來介紹一下SpringBoot靜態(tài)方法調(diào)用Spring容器bean的三種解決方案,文中通過示例代碼介紹的非常詳細,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2025-01-01
  • Java中BigDecimal與0比較的一個坑實戰(zhàn)記錄

    Java中BigDecimal與0比較的一個坑實戰(zhàn)記錄

    BigDecimal屬于大數(shù)據(jù),精度極高,不屬于基本數(shù)據(jù)類型,屬于java對象,下面這篇文章主要給大家介紹了關(guān)于Java中BigDecimal與0比較的一個坑的相關(guān)資料,需要的朋友可以參考下
    2022-12-12
  • Java如何基于okhttp請求SSE接口流式返回詳解

    Java如何基于okhttp請求SSE接口流式返回詳解

    對于流式返回,Spring Boot提供了兩種不同的方式,下面這篇文章主要給大家介紹了關(guān)于Java如何基于okhttp請求SSE接口流式返回的相關(guān)資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2024-03-03
  • SpringBoot中WebClient的實踐過程

    SpringBoot中WebClient的實踐過程

    本文介紹了SpringBoot中WebClient的使用,包括配置、使用場景以及優(yōu)化策略,幫助開發(fā)者更高效地進行服務(wù)間通信,WebClient具有非阻塞式I/O、強大的功能、靈活性等優(yōu)點,適用于高并發(fā)場景,通過合理配置和優(yōu)化,可以顯著提升服務(wù)間通信的效率和可靠性
    2025-12-12
  • Java 棧和隊列的相互轉(zhuǎn)換詳解

    Java 棧和隊列的相互轉(zhuǎn)換詳解

    棧和隊列,嚴(yán)格意義上來說,也屬于線性表,因為它們也都用于存儲邏輯關(guān)系為 "一對一" 的數(shù)據(jù),但由于它們比較特殊,因此將其單獨作為一章,做重點講解
    2022-02-02
  • java實現(xiàn)大文件分割與合并的實例代碼

    java實現(xiàn)大文件分割與合并的實例代碼

    java實現(xiàn)大文件分割與合并的實例代碼,需要的朋友可以參考一下
    2013-03-03
  • SpringBoot整合MQTT小結(jié)匯總

    SpringBoot整合MQTT小結(jié)匯總

    MQTT 客戶端是運行 MQTT 庫并通過網(wǎng)絡(luò)連接到 MQTT 代理的任何設(shè)備,是一種基于發(fā)布/訂閱(publish/subscribe)模式的“輕量級”通訊協(xié)議,該協(xié)議構(gòu)建于 TCP/IP 協(xié)議上,由 IBM 于 1999 年發(fā)明,對SpringBoot整合MQTT相關(guān)知識感興趣的朋友一起看看吧
    2022-01-01
  • 四個Java常見分布式鎖的選型和性能對比

    四個Java常見分布式鎖的選型和性能對比

    當(dāng)涉及到分布式系統(tǒng)中的并發(fā)控制和數(shù)據(jù)一致性時,分布式鎖是一種常見的解決方案,本文將對幾種常見的分布式鎖實現(xiàn)原理、實現(xiàn)示例、應(yīng)用場景以及優(yōu)缺點進行詳細分析,需要的可以參考一下
    2023-05-05
  • Spring Cloud Config 使用本地配置文件方式

    Spring Cloud Config 使用本地配置文件方式

    這篇文章主要介紹了Spring Cloud Config 使用本地配置文件方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-07-07

最新評論

晋州市| 保亭| 宜君县| 边坝县| 通山县| 宾川县| 兴海县| 普安县| 咸丰县| 岳西县| 会昌县| 杭锦旗| 突泉县| 伊金霍洛旗| 台安县| 舟曲县| 从化市| 武义县| 渭源县| 灌阳县| 梧州市| 突泉县| 保山市| 绥滨县| 西吉县| 尚志市| 曲周县| 香格里拉县| 岳阳市| 子洲县| 盐山县| 大渡口区| 临泉县| 沙河市| 南雄市| 三门峡市| 吉水县| 南充市| 准格尔旗| 蓬莱市| 宜良县|