当前位置:首页 > 科技  > 软件

分享Spring Data JPA的一些技巧和优秀实践

来源: 责编: 时间:2023-10-08 07:05:01 199观看
导读在现代软件开发中,Spring Boot已成为构建稳健和可扩展应用程序的主要框架。当涉及到与数据库的交互时,Java持久化API(JPA)提供了一种方便高效的方式来管理关系型数据。为了确保Spring Boot应用程序的可维护性、可读性和可

在现代软件开发中,Spring Boot已成为构建稳健和可扩展应用程序的主要框架。当涉及到与数据库的交互时,Java持久化API(JPA)提供了一种方便高效的方式来管理关系型数据。为了确保Spring Boot应用程序的可维护性、可读性和可扩展性,在创建使用JPA进行数据访问的Repository接口时,遵循最佳实践至关重要。Uyj28资讯网——每日最新资讯28at.com

Uyj28资讯网——每日最新资讯28at.com

命名规范

遵循Spring Data的Repository接口命名惯例。命名惯例应为EntityNameRepository或
EntityNameRepositoryCustom(用于自定义Repository方法)。
Uyj28资讯网——每日最新资讯28at.com

public interface UserRepository extends JpaRepository<User, Long> {    // 此处可以自定义方法}

领域特定的Repository接口

在软件工程中,关注点分离是一个核心原则,强调每个组件应具有明确定义的责任。在Spring Boot应用程序的上下文中,使用领域特定的存储库接口与该原则一致,允许在不同实体类型及其相应数据访问操作之间保持清晰的区分。Uyj28资讯网——每日最新资讯28at.com

好处Uyj28资讯网——每日最新资讯28at.com

  1. 模块化和清晰性:每个存储库接口专注于一个实体类型。这种模块化确保存储库方法简洁且与其处理的实体类型相关,使代码库更具可读性和可理解性。
  2. 封装性:领域特定的存储库接口封装了与特定实体相关的数据访问操作。这种隔离减少了意外误用或在错误的实体上执行不适当查询的可能性。
  3. 类型安全性:通过为每个实体使用接口,可以获得强类型的好处。这有助于在编译期间捕获错误,而不是在运行时。
  4. 维护性:当需要对特定实体的数据访问方法进行更改或增强时,你知道要去找哪个相应的Repository接口。这种有针对性的方法简化了维护和调试过程。

考虑一个示例,有一个电子商务应用程序,其中有两个主要实体:产品和分类。通过使用领域特定的Repository接口,我们可以将每个实体的数据访问逻辑保持分离并组织良好。Uyj28资讯网——每日最新资讯28at.com

public interface ProductRepository extends JpaRepository<Product, Long> {    List<Product> findByCategory(Category category);}

在此示例中,该ProductRepository接口包括一个查询方法findByCategory,该方法根据产品的关联类别来检索产品。Uyj28资讯网——每日最新资讯28at.com

类似地,该CategoryRepository接口可以只关注与类别相关的数据访问操作。Uyj28资讯网——每日最新资讯28at.com

public interface CategoryRepository extends JpaRepository<Category, Long> {    Category findByName(String name);}

通过利用领域特定的Repository接口,我们可以创建一个更有组织且易于理解的数据访问层,该层与应用程序的实体结构保持一致。这种关注点分离不仅提高了代码质量,而且随着应用程序随着时间的推移而发展,也有利于维护和扩展。Uyj28资讯网——每日最新资讯28at.com

查询方法

Spring Data JPA 提供了一种遵循命名约定来定义Repository方法的便捷方法,称为“查询方法”。这种方法通过方法名称表达查询,从而无需为常见操作编写显式 SQL 或 JPQL 查询。利用查询方法可以增强代码库的可读性和可维护性。Uyj28资讯网——每日最新资讯28at.com

查询方法的命名约定基于实体的属性名称。通过将findBy、getBy、readBy或 queryBy等前缀与属性名称组合,可以创建有意义的查询方法。Uyj28资讯网——每日最新资讯28at.com

@Entitypublic class Book {    @Id    @GeneratedValue(strategy = GenerationType.IDENTITY)    private Long id;        private String title;    private String author;    private int publicationYear;    private String genre;    // Getters and setters}public interface BookRepository extends JpaRepository<Book, Long> {    List<Book> findByAuthorAndPublicationYearAndGenre(String author, int publicationYear, String genre);}

也可以通过向查询方法添加可选参数来进一步扩展。比如需要按作者和流派搜索书籍,而不指定出版年份:Uyj28资讯网——每日最新资讯28at.com

public interface BookRepository extends JpaRepository<Book, Long> {    List<Book> findByAuthorAndGenreAndPublicationYear(String author, String genre, int publicationYear);        List<Book> findByAuthorAndGenre(String author, String genre);}

Spring Data JPA 根据方法名称和参数名称自动生成相应的 SQL 查询,使复杂的查询场景变得更加容易,而无需编写原生 SQL 查询。Uyj28资讯网——每日最新资讯28at.com

自定义查询方法

虽然查询方法提供了一种强大的机制,可以根据命名约定从方法名称生成查询,但在某些情况下需要更复杂的查询。对于这些场景,Spring Data JPA 可以使用@Query注解定义自己的自定义查询方法。Uyj28资讯网——每日最新资讯28at.com

@Query注解能够直接在Repository接口中定义 JPQL(Java 持久性查询语言)或原生 SQL 查询。这种方法可以更加灵活地构建涉及多个实体、复杂联接或其他非标准操作的查询。Uyj28资讯网——每日最新资讯28at.com

public interface UserRepository extends JpaRepository<User, Long> {    @Query("SELECT u FROM User u WHERE CONCAT(u.firstName, ' ', u.lastName) LIKE %:keyword%")    List<User> findUsersByFullNameKeyword(@Param("keyword") String keyword);}

在使用 JPQL 还无法实现的特定于数据库的功能时,还可以使用原生 SQL 查询。以下是自定义原生 SQL 查询方法的示例:Uyj28资讯网——每日最新资讯28at.com

public interface ProductRepository extends JpaRepository<Product, Long> {    @Query(value = "SELECT * FROM products p WHERE p.price > :minPrice", nativeQuery = true)    List<Product> findProductsAboveMinPrice(@Param("minPrice") BigDecimal minPrice);}

在此示例中,@Query 注解使用 nativeQuery = true来表示查询是用原生 SQL 编写的。该查询的意图是检索价格高于指定最低价格的产品。Uyj28资讯网——每日最新资讯28at.com

自定义查询方法有几个好处:Uyj28资讯网——每日最新资讯28at.com

  • 灵活性:可以创建更适合特定要求的查询。
  • 复杂操作:自定义查询适合复杂的连接操作或需要使用特定于数据库的函数。
  • 性能:在某些情况下,原生 SQL 查询可能会为特定场景提供更好的性能。

使用原生 SQL 查询时必须谨慎,因为如果处理不当,可能会导致特定于数据库的代码和潜在的安全漏洞(例如 SQL 注入)。Uyj28资讯网——每日最新资讯28at.com

通过使用自定义查询方法,我们可以在查询方法命名约定的便利性和处理更复杂或专门的数据检索场景的灵活性之间取得平衡。Uyj28资讯网——每日最新资讯28at.com

自定义Repository接口

在Repository层中分离关注点是一个好习惯,这意味着需要将标准 Spring Data JPA 方法与自定义方法分开。这种分离增强了代码组织、可读性和可维护性,并促进了单一职责原则。Uyj28资讯网——每日最新资讯28at.com

首先创建一个自定义Repository接口来保存专用方法。该接口不应直接扩展JpaRepository,因为这会导致自定义方法与标准方法混杂在一起。Uyj28资讯网——每日最新资讯28at.com

public interface UserRepositoryCustom {    List<User> findActiveUsers();}

接下来,为自定义Repository接口创建一个实现类。实现类遵循命名规范<EntityName>RepositoryImpl,并且应该放置在与Repository接口相同的包中。Uyj28资讯网——每日最新资讯28at.com

@Repositorypublic class UserRepositoryImpl implements UserRepositoryCustom {    @PersistenceContext    private EntityManager entityManager;    @Override    public List<User> findActiveUsers() {        TypedQuery<User> query = entityManager.createQuery("SELECT u FROM User u WHERE u.active = true", User.class);        return query.getResultList();    }}

最后,通过扩展标准 Spring Data JPA Repository接口 ( JpaRepository) 和自定义Repository接口 ( UserRepositoryCustom) 来创建主Repository接口。Uyj28资讯网——每日最新资讯28at.com

public interface UserRepository extends JpaRepository<User, Long>, UserRepositoryCustom {    // Spring Data JPA 方法与自定义方法}

通过遵循这种方法,我们可以在 Spring Data JPA 提供的常见 CRUD 操作与自定义专用方法之间保持清晰的分离。使代码更加模块化且更易于理解。Uyj28资讯网——每日最新资讯28at.com

分页和排序

在处理大型数据集时,高效的分页和排序机制对于提供流畅的用户体验和优化查询性能至关重要。Uyj28资讯网——每日最新资讯28at.com

分页涉及将结果集划分为较小的页面,以避免一次获取所有数据。Spring Data JPA 的Pageable接口提供了一种定义分页参数的方法,包括所需的页码、每页的条目数(页面大小)和排序方式。Uyj28资讯网——每日最新资讯28at.com

public interface ProductRepository extends JpaRepository<Product, Long> {    Page<Product> findByCategory(Category category, Pageable pageable);}

在此示例中,该方法findByCategory返回一个Page<Product>.Uyj28资讯网——每日最新资讯28at.com

排序可以根据一个或多个字段以特定顺序排列查询结果。Spring Data JPA 的Sort类能够为Repository方法指定排序方式。Uyj28资讯网——每日最新资讯28at.com

public interface ProductRepository extends JpaRepository<Product, Long> {    List<Product> findByCategoryOrderByPriceAsc(Category category);}

在此示例中,findByCategoryOrderByPriceAsc方法根据给定类别检索产品,并按价格升序,后缀OrderByPriceAsc表示排序顺序。Uyj28资讯网——每日最新资讯28at.com

可以结合分页和排序来按特定顺序检索分页结果。例如:Uyj28资讯网——每日最新资讯28at.com

public interface ProductRepository extends JpaRepository<Product, Long> {    Page<Product> findByCategoryOrderByPriceAsc(Category category, Pageable pageable);}

通过提供Pageable参数,可以指定页码、页面大小和排序标准。Spring Data JPA 负责生成适当的查询来获取请求的数据。Uyj28资讯网——每日最新资讯28at.com

@Servicepublic class ProductService {    @Autowired    private ProductRepository productRepository;    public Page<Product> getProductsByCategoryWithPaginationAndSorting(Category category, int pageNumber, int pageSize) {        // 创建 Pageable 对象来进行分页和排序        Pageable pageable = PageRequest.of(pageNumber, pageSize, Sort.by(Sort.Direction.ASC, "price"));                return productRepository.findByCategoryOrderByPriceAsc(category, pageable);    }}

最后,我们可以在 Controller 中使用Service方法来检索分页和排序的结果,如下所示:Uyj28资讯网——每日最新资讯28at.com

@RestController@RequestMapping("/products")public class ProductController {    @Autowired    private ProductService productService;    @GetMapping    public ResponseEntity<Page<Product>> getProductsByCategory(            @RequestParam("category") Long categoryId,            @RequestParam("page") int pageNumber,            @RequestParam("size") int pageSize) {        Category category = new Category();        category.setId(categoryId);        Page<Product> products = productService.getProductsByCategoryWithPaginationAndSorting(category, pageNumber, pageSize);        return ResponseEntity.ok(products);    }}

幂等方法

在设计和实现Repository方法时,特别是那些修改数据的方法时,遵循幂等原则非常重要,以确保多次调用具有相同参数的相同方法不会导致意外行为。Uyj28资讯网——每日最新资讯28at.com

例如,在电子商务应用程序中,如果多次下具有相同详细信息的订单,则应该产生相同的结果,并且不会创建多个重复订单。Uyj28资讯网——每日最新资讯28at.com

使用事务性操作

修改数据时,使用事务操作是一个很好的做法。Spring Data JPA 提供开箱即用的事务管理。使用事务确保操作期间发生错误,则回滚更改,从而保持数据的完整性。Uyj28资讯网——每日最新资讯28at.com

@Servicepublic class OrderService {    @Autowired    private OrderRepository orderRepository;    @Transactional    public void placeOrder(User user, Product product) {        // 检查订单是否已存在        Order existingOrder = orderRepository.findByUserAndProduct(user, product);        if (existingOrder == null) {            // 创建一个新订单            Order newOrder = new Order();            newOrder.setUser(user);            newOrder.setProduct(product);            newOrder.setOrderDate(LocalDateTime.now());            orderRepository.save(newOrder);        } else {            // 如果订单已存在,在不需要操作        }    }}

幂等性检查

对于某些操作,我们可能需要实施幂等性检查。意味着在执行某个操作之前,需要检查该操作是否已经执行过,以防止多余的操作。Uyj28资讯网——每日最新资讯28at.com

@Servicepublic class OrderService {    @Autowired    private OrderRepository orderRepository;    @Transactional    public void processOrder(Long orderId) {        Order order = orderRepository.findById(orderId).orElse(null);        if (order != null && !order.isProcessed()) {            // 执行处理逻辑            order.setProcessed(true);        }    }}

在此示例中,processOrder方法检查订单是否已被处理,以防止多次处理同一订单。Uyj28资讯网——每日最新资讯28at.com

通过遵循这些实践,可以确保Repository方法保持幂等性。这不仅可以防止意外的副作用,还可以使应用程序更加健壮和可预测,特别是在处理意外错误或故障时。Uyj28资讯网——每日最新资讯28at.com

单元测试

为Repository接口编写单元测试对于确保其正确性至关重要。使用JUnit和Mockito等工具来模拟数据库交互并验证Repository方法是否按预期运行。Uyj28资讯网——每日最新资讯28at.com

// User.java@Entitypublic class User {    @Id    @GeneratedValue(strategy = GenerationType.IDENTITY)    private Long id;    private String username;    private String email;    // getters and setters}// UserRepository.javapublic interface UserRepository extends JpaRepository<User, Long> {    User findByUsername(String username);}import static org.junit.jupiter.api.Assertions.assertEquals;import static org.mockito.Mockito.when;@RunWith(MockitoJUnitRunner.class)public class UserRepositoryTest {    @InjectMocks    private UserService userService;    @Mock    private UserRepository userRepository;    @Test    public void testFindByUsername() {        // Arrange        String username = "zhangsan";        User user = new User();        user.setId(1L);        user.setUsername(username);        user.setEmail("zhangsan@example.com");        when(userRepository.findByUsername(username)).thenReturn(user);        // Act        User foundUser = userService.findByUsername(username);        // Assert        assertEquals(username, foundUser.getUsername());    }}

@DataJpaTest是一个专门用于JPA测试的 Spring Boot 注解。当使用 @DataJpaTest 时,Spring Boot 会设置一个最小的 Spring 应用程序上下文,其中仅包含 JPA 测试所需的组件。这样测试就可以访问已配置的内存数据库,并且 Spring 将自动配置和管理 EntityManager 和Repository,这样可以以更集成的方式进行测试。Uyj28资讯网——每日最新资讯28at.com

@DataJpaTestpublic class UserRepositoryTest {    @Autowired    private TestEntityManager entityManager;    @Autowired    private UserRepository userRepository;    @Test    public void testFindByUsername() {        // Arrange        String username = "zhangsan";        User user = new User();        user.setUsername(username);        user.setEmail("zhangsan@example.com");        entityManager.persist(user);        // Act        User foundUser = userRepository.findByUsername(username);        // Assert        assertEquals(username, foundUser.getUsername());    }}

使用@DataJpaTest优点:Uyj28资讯网——每日最新资讯28at.com

  1. 为JPA相关组件提供轻量级、针对性的测试环境。
  2. 它使用必要的配置设置 Spring 应用程序上下文,从而更容易编写Repository测试。
  3. 自动配置内存数据库,确保测试的隔离性和速度。

错误处理

在进行数据访问操作时,可能会发生异常,例如数据库连接问题、约束违规和数据完整性问题。Spring Data JPA 通过自动将 JPA 特定的异常转换为 Spring 的DataAccessException来简化错误处理,这样就可以在整个应用程序中以一致的方式处理异常。Uyj28资讯网——每日最新资讯28at.com

考虑一个示例,尝试将重复的用户名插入数据库,这时会发生唯一约束冲突。Uyj28资讯网——每日最新资讯28at.com

@Entitypublic class User {    @Id    @GeneratedValue(strategy = GenerationType.IDENTITY)    private Long id;    @Column(unique = true)    private String username;    private String email;    // getters and setters}public interface UserRepository extends JpaRepository<User, Long> {    User findByUsername(String username);}

在这种情况下,如果尝试插入具有重复用户名的新用户名,则会抛出ConstraintViolationException异常。Uyj28资讯网——每日最新资讯28at.com

@Servicepublic class UserService {    @Autowired    private UserRepository userRepository;    public User createUser(User user) {        try {            return userRepository.save(user);        } catch (DataAccessException ex) {            // 处理异常            throw new CustomDataAccessException("An error occurred while saving the user.", ex);        }    }}

在UserService中,我们使用一个try-catch块来捕获DataAccessException。Spring Data JPA 自动将底层 JPA 异常转换为更通用的DataAccessException. 然后,我们可以根据应用程序的要求处理此异常。Uyj28资讯网——每日最新资讯28at.com

为了使错误处理的信息更丰富,我们可以创建扩展 SpringDataAccessException或其子类的自定义异常类。例如:Uyj28资讯网——每日最新资讯28at.com

public class CustomDataAccessException extends DataAccessException {    public CustomDataAccessException(String msg, Throwable cause) {        super(msg, cause);    }}

接下来,在Controller中处理异常:Uyj28资讯网——每日最新资讯28at.com

@RestController@RequestMapping("/users")public class UserController {    @Autowired    private UserService userService;    @PostMapping    public ResponseEntity<?> createUser(@RequestBody User user) {        try {            User createdUser = userService.createUser(user);            return ResponseEntity.status(HttpStatus.CREATED).body(createdUser);        } catch (CustomDataAccessException ex) {            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ex.getMessage());        }    }}

总结

在 Spring Boot 应用程序中使用 JPA 创建Repository接口时遵循最佳实践对于实现可维护、可扩展和有组织的代码至关重要。通过遵循最佳实践,开发人员可以构建强大的数据访问层,与更广泛的应用程序架构无缝集成。这种方法促进了模块化,增强了可测试性,确保了明确的职责分离,并最终有助于开发高质量的 Spring Boot 应用程序。Uyj28资讯网——每日最新资讯28at.com

本文链接:http://www.28at.com/showinfo-26-12271-0.html分享Spring Data JPA的一些技巧和优秀实践

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 十个超级高效的IntelliJ IDEA插件

下一篇: 掌握C/C++中的静态变量与静态成员!

标签:
  • 热门焦点
  • 把LangChain跑起来的三个方法

    把LangChain跑起来的三个方法

    使用LangChain开发LLM应用时,需要机器进行GLM部署,好多同学第一步就被劝退了,那么如何绕过这个步骤先学习LLM模型的应用,对Langchain进行快速上手?本片讲解3个把LangChain跑起来
  • 在线图片编辑器,支持PSD解析、AI抠图等

    在线图片编辑器,支持PSD解析、AI抠图等

    自从我上次分享一个人开发仿造稿定设计的图片编辑器到现在,不知不觉已过去一年时间了,期间我经历了裁员失业、面试找工作碰壁,寒冬下一直没有很好地履行计划.....这些就放在日
  • .NET 程序的 GDI 句柄泄露的再反思

    .NET 程序的 GDI 句柄泄露的再反思

    一、背景1. 讲故事上个月我写过一篇 如何洞察 C# 程序的 GDI 句柄泄露 文章,当时用的是 GDIView + WinDbg 把问题搞定,前者用来定位泄露资源,后者用来定位泄露代码,后面有朋友反
  • 三分钟白话RocketMQ系列—— 如何发送消息

    三分钟白话RocketMQ系列—— 如何发送消息

    我们知道RocketMQ主要分为消息 生产、存储(消息堆积)、消费 三大块领域。那接下来,我们白话一下,RocketMQ是如何发送消息的,揭秘消息生产全过程。注意,如果白话中不小心提到相关代
  • 共享单车的故事讲到哪了?

    共享单车的故事讲到哪了?

    来源丨海克财经与共享充电宝相差不多,共享单车已很久没有被国内热点新闻关照到了。除了一再涨价和用户直呼用不起了。近日多家媒体再发报道称,成都、天津、郑州等地多个共享单
  • 得物宠物生意「狂飙」,发力“它经济”

    得物宠物生意「狂飙」,发力“它经济”

    作者|花花小萌主近日,得物宣布正式上线宠物鉴别,通过得物App内的&ldquo;在线鉴别&rdquo;,可找到鉴别宠物的选项。通过上传自家宠物的部位细节,就能收获拥有专业资质认证的得物鉴
  • “又被陈思诚骗了”

    “又被陈思诚骗了”

    作者|张思齐 出品|众面(ID:ZhongMian_ZM)如今的国产悬疑电影,成了陈思诚的天下。最近大爆电影《消失的她》票房突破30亿断层夺魁暑期档,陈思诚再度风头无两。你可以说陈思诚的
  • iQOO Neo8 Pro即将开售:到手价3099元起 安卓性能最强旗舰

    iQOO Neo8 Pro即将开售:到手价3099元起 安卓性能最强旗舰

    5月23日,iQOO如期举行了新品发布会,全新的iQOO Neo8系列也正式与大家见面,包含iQOO Neo8和iQOO Neo8 Pro两个版本,其中标准版搭载高通骁龙8+,而Pro版更
  • 滴滴违法违规被罚80.26亿 共存在16项违法事实

    滴滴违法违规被罚80.26亿 共存在16项违法事实

    滴滴违法违规被罚80.26亿 存在16项违法事实开始于2121年7月,历经一年时间,网络安全审查办公室对“滴滴出行”网络安全审查终于有了一个暂时的结束。据“网信
Top