Spring Data 2026 高级查询:数据访问的新境界
Spring Data 2026 高级查询:数据访问的新境界
别叫我大神,叫我 Alex 就好。今天我们来聊聊 Spring Data 2026 的高级查询功能,这是数据访问的新境界。
一、Spring Data 2026 概述
Spring Data 2026 是 Spring 生态系统中数据访问的最新版本,它带来了一系列强大的新特性和改进,旨在简化数据访问,提高查询效率。
核心优势
- 简化数据访问:减少样板代码,提高开发效率
- 强大的查询能力:支持复杂的查询场景
- 多数据源支持:无缝集成各种数据源
- 性能优化:内置查询优化机制
- 与现代 Java 特性集成:支持虚拟线程、模式匹配等
二、高级查询特性
1. 复杂条件查询
Spring Data 2026 提供了更强大的条件查询能力:
@Repository public interface UserRepository extends JpaRepository<User, Long> { // 基本条件查询 List<User> findByAgeGreaterThanAndActive(int age, boolean active); // 模糊查询 List<User> findByUsernameLike(String username); // 排序查询 List<User> findByActiveTrueOrderByCreatedAtDesc(); // 分页查询 Page<User> findByActiveTrue(Pageable pageable); } // 使用示例 @Service public class UserService { private final UserRepository userRepository; public UserService(UserRepository userRepository) { this.userRepository = userRepository; } public List<User> getActiveUsers(int minAge) { return userRepository.findByAgeGreaterThanAndActive(minAge, true); } public Page<User> getActiveUsersPage(int page, int size) { Pageable pageable = PageRequest.of(page, size, Sort.by(Sort.Direction.DESC, "createdAt")); return userRepository.findByActiveTrue(pageable); } }2. JPQL 查询
使用 JPQL 进行复杂查询:
@Repository public interface OrderRepository extends JpaRepository<Order, Long> { @Query("SELECT o FROM Order o WHERE o.user.id = :userId AND o.status = :status") List<Order> findByUserIdAndStatus(@Param("userId") Long userId, @Param("status") OrderStatus status); @Query("SELECT o FROM Order o JOIN o.items i WHERE i.productId = :productId") List<Order> findByProductId(@Param("productId") Long productId); @Query("SELECT o FROM Order o WHERE o.totalPrice > :minPrice ORDER BY o.createdAt DESC") Page<Order> findByTotalPriceGreaterThan(@Param("minPrice") BigDecimal minPrice, Pageable pageable); }3. 原生 SQL 查询
对于复杂场景,使用原生 SQL:
@Repository public interface ProductRepository extends JpaRepository<Product, Long> { @Query(value = "SELECT * FROM products WHERE price > :minPrice AND category = :category", nativeQuery = true) List<Product> findByPriceAndCategory(@Param("minPrice") BigDecimal minPrice, @Param("category") String category); @Query(value = "SELECT p.id, p.name, p.price, COUNT(o.id) as orderCount " + "FROM products p LEFT JOIN order_items oi ON p.id = oi.product_id " + "LEFT JOIN orders o ON oi.order_id = o.id " + "WHERE o.created_at BETWEEN :startDate AND :endDate " + "GROUP BY p.id, p.name, p.price " + "ORDER BY orderCount DESC", nativeQuery = true) List<Object[]> findTopSellingProducts(@Param("startDate") LocalDate startDate, @Param("endDate") LocalDate endDate); }三、查询方法进阶
1. 动态查询
使用 Specification 进行动态查询:
@Repository public interface UserRepository extends JpaRepository<User, Long>, JpaSpecificationExecutor<User> { } @Service public class UserService { private final UserRepository userRepository; public UserService(UserRepository userRepository) { this.userRepository = userRepository; } public List<User> searchUsers(UserSearchCriteria criteria) { Specification<User> spec = Specification.where(null); if (criteria.getMinAge() != null) { spec = spec.and((root, query, cb) -> cb.greaterThan(root.get("age"), criteria.getMinAge())); } if (criteria.getMaxAge() != null) { spec = spec.and((root, query, cb) -> cb.lessThan(root.get("age"), criteria.getMaxAge())); } if (criteria.getActive() != null) { spec = spec.and((root, query, cb) -> cb.equal(root.get("active"), criteria.getActive())); } if (criteria.getUsername() != null) { spec = spec.and((root, query, cb) -> cb.like(root.get("username"), "%" + criteria.getUsername() + "%")); } return userRepository.findAll(spec); } @Data public static class UserSearchCriteria { private Integer minAge; private Integer maxAge; private Boolean active; private String username; } }2. 投影查询
使用投影减少数据传输:
// 接口投影 interface UserProjection { String getUsername(); String getEmail(); int getAge(); } @Repository public interface UserRepository extends JpaRepository<User, Long> { List<UserProjection> findByActiveTrue(); @Query("SELECT u.username as username, u.email as email, u.age as age FROM User u WHERE u.active = true") List<UserProjection> findActiveUsersWithProjection(); } // 类投影 @Data class UserDTO { private String username; private String email; public UserDTO(String username, String email) { this.username = username; this.email = email; } } @Repository public interface UserRepository extends JpaRepository<User, Long> { List<UserDTO> findByActiveTrue(); }3. 批量操作
提高批量操作性能:
@Repository public interface ProductRepository extends JpaRepository<Product, Long> { @Modifying @Query("UPDATE Product p SET p.price = p.price * :multiplier WHERE p.category = :category") int updatePricesByCategory(@Param("category") String category, @Param("multiplier") double multiplier); @Modifying @Query("DELETE FROM Product p WHERE p.stock < :minStock") int deleteByStockLessThan(@Param("minStock") int minStock); } @Service @Transactional public class ProductService { private final ProductRepository productRepository; public ProductService(ProductRepository productRepository) { this.productRepository = productRepository; } public void updatePrices(String category, double multiplier) { productRepository.updatePricesByCategory(category, multiplier); } public void cleanupLowStockProducts(int minStock) { productRepository.deleteByStockLessThan(minStock); } }四、性能优化
1. 缓存策略
集成 Spring Cache 提高查询性能:
@Configuration @EnableCaching public class CacheConfig { @Bean public CacheManager cacheManager() { SimpleCacheManager cacheManager = new SimpleCacheManager(); cacheManager.setCaches(Arrays.asList( new ConcurrentMapCache("users"), new ConcurrentMapCache("products"), new ConcurrentMapCache("orders") )); return cacheManager; } } @Service public class UserService { private final UserRepository userRepository; public UserService(UserRepository userRepository) { this.userRepository = userRepository; } @Cacheable(value = "users", key = "#id") public User getUserById(Long id) { return userRepository.findById(id) .orElseThrow(() -> new UserNotFoundException(id)); } @CachePut(value = "users", key = "#user.id") public User updateUser(User user) { return userRepository.save(user); } @CacheEvict(value = "users", key = "#id") public void deleteUser(Long id) { userRepository.deleteById(id); } }2. 查询优化
优化查询执行计划:
@Repository public interface OrderRepository extends JpaRepository<Order, Long> { // 使用 JOIN FETCH 避免 N+1 问题 @Query("SELECT o FROM Order o JOIN FETCH o.items WHERE o.id = :id") Optional<Order> findByIdWithItems(@Param("id") Long id); // 使用索引提示 @Query(value = "SELECT * FROM orders o USE INDEX (idx_orders_user_id) WHERE o.user_id = :userId", nativeQuery = true) List<Order> findByUserIdWithIndex(@Param("userId") Long userId); } @Service public class OrderService { private final OrderRepository orderRepository; public OrderService(OrderRepository orderRepository) { this.orderRepository = orderRepository; } public Order getOrderWithItems(Long id) { return orderRepository.findByIdWithItems(id) .orElseThrow(() -> new OrderNotFoundException(id)); } }3. 异步查询
使用虚拟线程进行异步查询:
@Service public class ProductService { private final ProductRepository productRepository; public ProductService(ProductRepository productRepository) { this.productRepository = productRepository; } @Async public CompletableFuture<List<Product>> getProductsByCategoryAsync(String category) { return CompletableFuture.supplyAsync(() -> productRepository.findByCategory(category) ); } public CompletableFuture<Page<Product>> getProductsPageAsync(int page, int size) { Pageable pageable = PageRequest.of(page, size); return CompletableFuture.supplyAsync(() -> productRepository.findAll(pageable) ); } }五、多数据源支持
1. 多数据源配置
@Configuration public class DataSourceConfig { @Bean @Primary @ConfigurationProperties(prefix = "spring.datasource.primary") public DataSource primaryDataSource() { return DataSourceBuilder.create().build(); } @Bean @ConfigurationProperties(prefix = "spring.datasource.secondary") public DataSource secondaryDataSource() { return DataSourceBuilder.create().build(); } @Bean @Primary public LocalContainerEntityManagerFactoryBean primaryEntityManagerFactory( EntityManagerFactoryBuilder builder, @Qualifier("primaryDataSource") DataSource dataSource) { return builder .dataSource(dataSource) .packages("com.example.domain.primary") .persistenceUnit("primary") .build(); } @Bean public LocalContainerEntityManagerFactoryBean secondaryEntityManagerFactory( EntityManagerFactoryBuilder builder, @Qualifier("secondaryDataSource") DataSource dataSource) { return builder .dataSource(dataSource) .packages("com.example.domain.secondary") .persistenceUnit("secondary") .build(); } @Bean @Primary public JpaTransactionManager primaryTransactionManager( @Qualifier("primaryEntityManagerFactory") EntityManagerFactory entityManagerFactory) { return new JpaTransactionManager(entityManagerFactory); } @Bean public JpaTransactionManager secondaryTransactionManager( @Qualifier("secondaryEntityManagerFactory") EntityManagerFactory entityManagerFactory) { return new JpaTransactionManager(entityManagerFactory); } } @Repository @Transactional(transactionManager = "primaryTransactionManager") public interface UserRepository extends JpaRepository<User, Long> { } @Repository @Transactional(transactionManager = "secondaryTransactionManager") public interface ProductRepository extends JpaRepository<Product, Long> { }2. 跨数据源事务
@Service public class OrderService { private final UserRepository userRepository; private final ProductRepository productRepository; private final OrderRepository orderRepository; public OrderService(UserRepository userRepository, ProductRepository productRepository, OrderRepository orderRepository) { this.userRepository = userRepository; this.productRepository = productRepository; this.orderRepository = orderRepository; } @Transactional(transactionManager = "primaryTransactionManager") public Order createOrder(OrderRequest request) { // 检查用户 User user = userRepository.findById(request.getUserId()) .orElseThrow(() -> new UserNotFoundException(request.getUserId())); // 检查产品(跨数据源) Product product = checkProductStock(request.getProductId(), request.getQuantity()); // 创建订单 Order order = new Order(); order.setUserId(user.getId()); order.setProductId(product.getId()); order.setQuantity(request.getQuantity()); order.setTotalPrice(product.getPrice().multiply(BigDecimal.valueOf(request.getQuantity()))); order.setStatus(OrderStatus.CREATED); return orderRepository.save(order); } @Transactional(transactionManager = "secondaryTransactionManager") public Product checkProductStock(Long productId, int quantity) { Product product = productRepository.findById(productId) .orElseThrow(() -> new ProductNotFoundException(productId)); if (product.getStock() < quantity) { throw new InsufficientStockException(productId, quantity); } // 扣减库存 product.setStock(product.getStock() - quantity); productRepository.save(product); return product; } }六、实践案例:电商平台数据访问
场景描述
构建一个电商平台的数据访问层,支持用户、产品、订单等实体的复杂查询。
实现方案
// 用户仓库 @Repository public interface UserRepository extends JpaRepository<User, Long>, JpaSpecificationExecutor<User> { Optional<User> findByUsername(String username); List<User> findByActiveTrue(); @Query("SELECT u FROM User u JOIN u.orders o WHERE o.status = :status GROUP BY u.id") List<User> findUsersWithOrdersByStatus(@Param("status") OrderStatus status); } // 产品仓库 @Repository public interface ProductRepository extends JpaRepository<Product, Long> { List<Product> findByCategory(String category); List<Product> findByPriceBetween(BigDecimal minPrice, BigDecimal maxPrice); @Query("SELECT p FROM Product p WHERE p.stock > 0 ORDER BY p.createdAt DESC") Page<Product> findAvailableProducts(Pageable pageable); @Query(value = "SELECT p.* FROM products p WHERE p.id IN (SELECT oi.product_id FROM order_items oi GROUP BY oi.product_id ORDER BY COUNT(*) DESC LIMIT :limit)", nativeQuery = true) List<Product> findTopSellingProducts(@Param("limit") int limit); } // 订单仓库 @Repository public interface OrderRepository extends JpaRepository<Order, Long> { List<Order> findByUserId(Long userId); List<Order> findByStatus(OrderStatus status); @Query("SELECT o FROM Order o JOIN FETCH o.items WHERE o.id = :id") Optional<Order> findByIdWithItems(@Param("id") Long id); @Query("SELECT o FROM Order o WHERE o.createdAt BETWEEN :startDate AND :endDate") List<Order> findByDateRange(@Param("startDate") LocalDateTime startDate, @Param("endDate") LocalDateTime endDate); } // 订单服务 @Service public class OrderService { private final OrderRepository orderRepository; private final UserRepository userRepository; private final ProductRepository productRepository; public OrderService(OrderRepository orderRepository, UserRepository userRepository, ProductRepository productRepository) { this.orderRepository = orderRepository; this.userRepository = userRepository; this.productRepository = productRepository; } public Order createOrder(OrderRequest request) { // 验证用户 User user = userRepository.findById(request.getUserId()) .orElseThrow(() -> new UserNotFoundException(request.getUserId())); // 验证产品和库存 Product product = productRepository.findById(request.getProductId()) .orElseThrow(() -> new ProductNotFoundException(request.getProductId())); if (product.getStock() < request.getQuantity()) { throw new InsufficientStockException(request.getProductId(), request.getQuantity()); } // 创建订单 Order order = new Order(); order.setUserId(user.getId()); order.setStatus(OrderStatus.CREATED); order.setTotalPrice(product.getPrice().multiply(BigDecimal.valueOf(request.getQuantity()))); // 创建订单项 OrderItem item = new OrderItem(); item.setProductId(product.getId()); item.setQuantity(request.getQuantity()); item.setPrice(product.getPrice()); order.addItem(item); // 保存订单 order = orderRepository.save(order); // 扣减库存 product.setStock(product.getStock() - request.getQuantity()); productRepository.save(product); return order; } public Order getOrderWithItems(Long orderId) { return orderRepository.findByIdWithItems(orderId) .orElseThrow(() -> new OrderNotFoundException(orderId)); } public List<Order> getOrdersByDateRange(LocalDateTime startDate, LocalDateTime endDate) { return orderRepository.findByDateRange(startDate, endDate); } }七、总结与建议
Spring Data 2026 为我们提供了强大的高级查询能力,使数据访问变得更加简单和高效。以下是一些关键建议:
- 合理使用查询方法:根据场景选择合适的查询方式
- 优化查询性能:使用缓存、索引、JOIN FETCH 等技术
- 简化数据传输:使用投影减少不必要的数据加载
- 处理复杂场景:使用 Specification、JPQL 或原生 SQL
- 多数据源管理:合理配置和使用多数据源
这其实可以更优雅一点,通过合理使用 Spring Data 2026 的高级查询特性,我们可以构建出更高效、更可维护的数据访问层。
别叫我大神,叫我 Alex 就好。希望这篇文章能帮助你更好地理解和使用 Spring Data 2026 的高级查询功能。欢迎在评论区分享你的使用经验!
