iT邦幫忙

2024 iThome 鐵人賽

DAY 10
0

這邊來認識一些我們可能會用到的一些資料庫查詢操作

根據前面的 products 結構來插入一些資料熟悉一些操作的用法吧。

INSERT INTO products (name, price, description) VALUES
('薩爾達傳說:曠野之息', 59.99, '設定在幻想世界中的開放世界動作冒險遊戲。'),
('超級瑪利歐:奧德賽', 49.99, '以瑪利歐為主角的平臺遊戲,探索各種世界。'),
('集合啦!動物森友會', 54.99, '在無人島上進行發展的生活模擬遊戲。'),
('最終幻想 VII 重製版', 69.99, '經典 RPG 的重製版,具有更新的圖像和遊戲玩法。'),
('巫師3:狂獵', 39.99, '開放世界 RPG,玩家扮演狩魔獵人傑洛特。'),
('電馭叛客2077', 59.99, '設定在反烏托邦未來世界的開放世界 RPG。'),
('對馬戰鬼', 59.99, '設定在日本封建時代的動作冒險遊戲。'),
('碧血狂殺2', 49.99, '以西部為主題的開放世界動作冒險遊戲。'),
('黑帝斯', 24.99, '在地下城中進行逃脫的類 Roguelike 遊戲。'),
('我們之中', 4.99, '在太空船上進行的多人派對遊戲,涉及團隊合作與背叛。');

操作查詢方法

(一) 根據欄位值的相等條件

前面一篇有提到可以直接透過欄位名稱來查找,JPA會自動幫我們對應,最常用到的就是 findById,如果想要查找其他欄位就可以直接改成像是 findByName, findByPrice 等等都可以讓 JPA 幫我們匹配。

這邊根據 findByName 我們可以透過名稱找到對應商品

controller

    @GetMapping("/q")
    public Product getProductsByName(@RequestParam String name) {
        return productService.getProductByName(name);
    }

service


@Service
public class ProductService {
    @Autowired
    private ProductRepository productRepository;

    public Product getProductByName(String name) {
        return productRepository.findByName(name);
    }
}

repository

public interface ProductRepository extends JpaRepository<Product, Integer> {
    Product findByName(String name);
}

https://ithelp.ithome.com.tw/upload/images/20240902/20150977BLTg7Zm4IW.png

(二) 範圍條件

可以根據數值的範圍來進行查詢,像是這邊可以用價錢來進行示範

他的格式會像 findBy{判斷欄位}GreaterThanEqual()

  • 大於 findByPriceGreaterThan()
  • 大於等於 findByPriceGreaterThanEqual()
  • 小於 findByPriceLessThan()
  • 小於等於 findByPriceLessThanEqual()

這邊用大於等於

controller

    @GetMapping("/priceGreaterThanEqual")
    public List<Product> getProductsByPriceGreaterThanEqual(@RequestParam int range) {
        return productService.getProductGreaterThanEqual(range);
    }

service

@Service
public class ProductService {
    @Autowired
    private ProductRepository productRepository;

    public List<Product> getProductGreaterThanEqual(int range) {
        return productRepository.findByPriceGreaterThanEqual(range);
    }

}

repository

@Repository
public interface ProductRepository extends JpaRepository<Product, Integer> {
    Product findByName(String name);
    List<Product> findByPriceGreaterThanEqual(int range);
}

查詢大於 60 元剛好只有 69.99 元的最終幻想符合
https://ithelp.ithome.com.tw/upload/images/20240902/20150977HBj3KmiXkx.png

多個條件

可透過 And 或 Or 組合

controller


    @GetMapping("/nameOrPrice")
    public List<Product> getProductsByNameOrPrice(@RequestParam String name, @RequestParam double price) {
        return productService.getProductByNameOrPrice(name, price);
    }

service

    public List<Product> getProductByNameOrPrice(String name, double price) {
        return productRepository.findByNameOrPrice(name, price);
    }

repository

@Repository
public interface ProductRepository extends JpaRepository<Product, Integer> {
    List<Product> findByNameOrPrice(String name, double price);
}

https://ithelp.ithome.com.tw/upload/images/20240902/20150977UIMYJWNpeV.png
or 的話只要其中一項條件符合就會執行,像是下面有搜出 name = 黑帝斯 也有搜出 price = 49.99

原生 SQL

使用 JPA 如果不夠彈性你也可使用原生的語法 @Query

@Query 裡面要第一個參數註明是 nativeQuery = true , 第二個參數是 vlaue = “{sql 語法}” ,也可以把 value 省略,直接用 SQL 字串放第二個參數,注意這邊 SQL 語法結尾請不要加分號 “;”

參數的帶入也可以用 :param 的方式,這邊其實寫法有很多種,大家就找到自己喜歡或是團隊易懂的方式來撰寫。

*如果 nativeQuery 沒有開啟就是使用 JPQL

//    用 """ """ 可以不用顧慮換行問題
//    @Query(
//            nativeQuery = true,
//            value = """
//                SELECT *
//                FROM `products`
//                WHERE `name` = ?1 OR `price` = ?2
//            """
//    )
		// JPQL 須注意如果語法長中間可能換行及空格導致語法錯誤
		@Query("SELECT p FROM Product p WHERE p.name = :name OR p.price = :price")

		// Native SQL 須注意如果語法長中間可能換行及空格導致語法錯誤
    @Query(
            nativeQuery = true,
            value = "SELECT * FROM products WHERE name = ?1 OR price = ?2"
    )
    List<Product> findByNameOrPriceNative(String name, double price);

排序(Sorting)與分頁(Pagination)

Sort 物件

利用 Sort 物件可以做到排序,看是要升序(ASC)或是降序(DESC),這個物件是可以直接帶入 repository 的方法中告知 JPA 要進行排序

// asc
Sort sort = Sort.by({欄位}).ascending() 
// desc
Sort sort = Sort.by({欄位}).descending();

以撈出全部資料 Service 方法為例,根據價錢進行升序

    public List<Product> getAllProducts() {
        Sort sort = Sort.by("price").ascending();
        return productRepository.findAll(sort);
    }

可以看到顯示資料就照價錢由小到大排了

https://ithelp.ithome.com.tw/upload/images/20240903/20150977FBBLSm2UcJ.png
Sort 也可以整合下面分頁物件一起做到排序及分頁

Pageable 物件

Pageabe 是一個介面,通常會放入三個參數來透過 PageRequest 方法實作

  • 第一個參數 page 表示第幾頁(需要特別注意第一頁是0)
  • 第二個參數 limit 表示回傳資料筆數上限
  • 第三個參數 sort 表示排序物件
Pageable pageable = PageRequest.of(page, limit, sort);

把上面的 Sort 物件一起帶進去,並且告知我要取得第一頁的 3 筆資料

public Page<Product> getAllProducts() {
        Sort sort = Sort.by("price").ascending();

        Pageable pageable = PageRequest.of(0,3, sort);

        Page<Product> productPage = productRepository.findAll(pageable);

        return productPage;
    }

回傳的資料可以看到確實有排序,還有提供分頁的相關資訊,也只顯示出第一頁的 3 筆資料

{
    "content": [
        {
            "id": 4,
            "name": "最終幻想 VII 重製版",
            "price": 69.99,
            "description": "經典 RPG 的重製版,具有更新的圖像和遊戲玩法。"
        },
        {
            "id": 1,
            "name": "薩爾達傳說:曠野之息",
            "price": 59.99,
            "description": "設定在幻想世界中的開放世界動作冒險遊戲。"
        },
        {
            "id": 6,
            "name": "電馭叛客2077",
            "price": 59.99,
            "description": "設定在反烏托邦未來世界的開放世界 RPG。"
        }
    ],
    "pageable": {
        "pageNumber": 0,
        "pageSize": 3,
        "sort": {
            "empty": false,
            "sorted": true,
            "unsorted": false
        },
        "offset": 0,
        "paged": true,
        "unpaged": false
    },
    "totalPages": 4,
    "totalElements": 10,
    "last": false,
    "size": 3,
    "number": 0,
    "sort": {
        "empty": false,
        "sorted": true,
        "unsorted": false
    },
    "numberOfElements": 3,
    "first": true,
    "empty": false
}

以上就是基本的一些查詢跟應用,對於許多網站的搜尋及資料的查找都是相當基本的用法,Spring Data Jpa 也提供給我們許多方便的用法,還有一定的彈性可以自行撰寫原生 SQL。那下篇來講一些關於資料庫關聯的一些操作介紹吧。


Ref:

相關文章也會同步更新我的部落格,有興趣也可以在裡面找其他的技術分享跟資訊。


上一篇
Day 9 - Spring Data JPA (1) 基礎應用架構
下一篇
Day 11 - Spring Data JPA (3)資料庫關聯 1 : 1
系列文
關於我和 Spring Boot 變成家人的那件事30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言