Spring Data JPA深入应用教程

目录

  1. Spring Data JPA概述
  2. Repository接口详解
  3. 查询方法命名规则
  4. 自定义查询
  5. 分页与排序
  6. 事务管理
  7. 懒加载与N+1问题
  8. 实体关联映射
  9. 审计功能
  10. 多数据源配置
  11. 性能优化
  12. 测试策略
  13. 最佳实践
  14. 总结

Spring Data JPA概述

Spring Data JPA优势

Spring Data JPA是Spring Data项目的一部分,基于JPA规范,为数据访问层提供了简化实现。

核心特性

  • Repository抽象:通过接口定义数据访问方法
  • 查询方法生成:根据方法名自动生成查询
  • 分页排序支持:内置分页和排序功能
  • 事务管理:自动事务边界管理
  • 审计功能:封装用户和时间信息

Maven依赖配置

<dependencies>
    <!-- Spring Data JPA -->
    <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-jpa</artifactId>
        <version>2.7.5</version>
    </dependency>
    
    <!-- Hibernate Core -->
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-core</artifactId>
        <version>5.6.15.Final</version>
    </dependency>
    
    <!-- PostgreSQL Driver -->
    <dependency>
        <groupId>org.postgresql</groupId>
        <artifactId>postgresql</artifactId>
        <version>42.5.1</version>
    </dependency>
    
    <!-- H2 Database (测试用) -->
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <version>2.1.214</version>
        <scope>test</scope>
    </dependency>
    
    <!-- Testcontainers -->
    <dependency>
        <groupId>org.testcontainers</groupId>
        <artifactId>postgresql</artifactId>
        <version>1.17.6</version>
        <scope>test</scope>
    </dependency>
</dependencies>

Repository接口详解

基础Repository接口

实体类定义

@Entity
@Table(name = "users")
@EntityListeners(AuditingEntityListener.class)
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "user_seq")
    @SequenceGenerator(name = "user_seq", sequenceName = "user_id_seq", allocationSize = 1)
    private Long id;
    
    @Column(nullable = false, unique = true, length = 50)
    private String username;
    
    @Column(nullable = false, unique = true, length = 100)
    private String email;
    
    @Column(nullable = false)
    private String password;
    
    @Column(name = "first_name", length = 50)
    private String firstName;
    
    @Column(name = "last_name", length = 50)
    private String lastName;
    
    @Enumerated(EnumType.STRING)
    @Column(name = "user_status", nullable = false)
    private UserStatus status = UserStatus.ACTIVE;
    
    @Enumerated(EnumType.STRING)
    @Column(name = "user_role", nullable = false)
    private UserRole role = UserRole.USER;
    
    @CreatedDate
    @Column(name = "created_date", nullable = false, updatable = false)
    private LocalDateTime createdDate;
    
    @LastModifiedDate
    @Column(name = "last_modified_date")
    private LocalDateTime lastModifiedDate;
    
    @CreatedBy
    @Column(name = "created_by", updatable = false)
    private String createdBy;
    
    @LastModifiedBy
    @Column(name = "last_modified_by")
    private String lastModifiedBy;
    
    @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    private List<Order> orders = new ArrayList<>();
    
    // 构造函数、getters、setters
}

@Entity
@Table(name = "orders")
public class Order {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @Column(name = "order_number", unique = true, nullable = false)
    private String orderNumber;
    
    @Column(name = "total_amount", precision = 10, scale = 2)
    private BigDecimal totalAmount;
    
    @Enumerated(EnumType.STRING)
    @Column(name = "order_status", nullable = false)
    private OrderStatus status = OrderStatus.PENDING;
    
    @Column(name = "order_date", nullable = false)
    private LocalDateTime orderDate;
    
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_id", nullable = false)
    private User user;
    
    @OneToMany(mappedBy = "order", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    private List<OrderItem> items = new ArrayList<>();
    
    // 构造函数、getters、setters
}

Repository接口层次

// 继承JpaRepository获得CRUD功能
public interface UserRepository extends JpaRepository<User, Long> {
    
    // 根据用户名查找
    Optional<User> findByUsername(String username);
    
    // 根据邮箱查找
    Optional<User> findByEmail(String email);
    
    // 检查用户名是否存在
    boolean existsByUsername(String username);
    
    // 检查邮箱是否存在
    boolean existsByEmail(String email);
    
    // 根据状态查找用户
    List<User> findByStatus(UserStatus status);
    
    // 根据角色查找用户
    List<User> findByRole(UserRole role);
    
    // 根据用户名和状态查找
    Optional<User> findByUsernameAndStatus(String username, UserStatus status);
    
    // 查找用户名包含指定字符串的用户
    List<User> findByUsernameContainingIgnoreCase(String username);
    
    // 查找邮箱以指定域名结尾的用户
    List<User> findByEmailEndingWith(String emailDomain);
    
    // 根据创建日期范围查找用户
    List<User> findByCreatedDateBetween(LocalDateTime startDate, LocalDateTime endDate);
    
    // 统计不同状态的用户数量
    @Query("SELECT u.status, COUNT(u) FROM User u GROUP BY u.status")
    List<Object[]> countByStatus();
    
    // 分页查询用户
    Page<User> findByStatus(UserStatus status, Pageable pageable);
    
    // 排序查询
    List<User> findByOrderByCreatedDateDesc();
    
    // 删除指定状态之前的用户
    @Transactional
    @Modifying
    @Query("DELETE FROM User u WHERE u.createdDate < :cutoffDate")
    int deleteOldUsers(@Param("cutoffDate") LocalDateTime cutoffDate);
}

查询方法命名规则

关键字查询模式

基础查询关键字

public interface ProductRepository extends JpaRepository<Product, Long> {
    
    // FIND/GET 关键字查询
    List<Product> findByCategory(String category);
    Optional<Product> findByName(String name);
    
    // EXISTS 存在性查询
    boolean existsByName(String name);
    boolean existsByCategoryIgnoreCase(String category);
    
    // COUNT 计数查询
    long countByCategory(String category);
    long countByPriceGreaterThan(BigDecimal price);
    
    // DELETE 删除查询
    @Transactional
    void deleteByCategory(String category);
    
    // DISTINCT 去重查询
    List<String> findDistinctCategoryByNameContaining(String name);
    
    // TOP/LIMIT 限制结果数量
    List<Product> findTop5ByOrderByPriceDesc();
    List<Product> findFirst10ByCategoryOrderByNameAsc(string category);
    
    // AND/OR 逻辑操作
    List<Product> findByNameAndCategory(String name, String.category);
    List<Product> findByNameOrCategory(String name, String category);
    
    // BETWEEN 范围查询
    List<Product> findByPriceBetween(BigDecimal minPrice, BigDecimal maxPrice);
    List<Product> findByCreatedDateBetween(LocalDateTime startDate, LocalDateTime endDate);
    
    // COMPARISON 比较操作
    List<Product> findByPriceGreaterThan(BigDecimal price);
    List<Product> findByPriceGreaterThanEqual(BigDecimal price);
    List<Product> findByPriceLessThan(BigDecimal price);
    List<Product> findByPriceLessThanEqual(BigDecimal price);
    List<Product> findByPriceGreaterThanAndPriceLessThan(BigDecimal minPrice, BigDecimal maxPrice);
    
    // NULL 空值查询
    List<Product> findByNameIsNull();
    List<Product> findByCategoryIsNotNull();
    
    // LIKE 模糊查询
    List<Product> findByNameLike(String namePattern);
    List<Product> findByNameNotLike(String namePattern);
    
    // CONTAINING 包含查询
    List<Product> findByNameContaining(String name);
    List<Product> findByNameContainingIgnoreCase(String name);
    
    // STARTS_WITH/ENDING_WITH 前缀/后缀查询
    List<Product> findByNameStartsWith(String prefix);
    List<Product> findByNameEndingWith(String suffix);
    
    // REGEX 正则表达式查询
    @Query("SELECT p FROM Product p WHERE REGEXP_LIKE(p.name, :pattern)")
    List<Product> findByNameRegex(@Param("pattern") String pattern);
    
    // ORDER_BY 排序查询
    List<Product> findByCategoryOrderByNameAsc(String category);
    List<Product> findByCategoryOrderByPriceDescNameAsc(String category);
    
    // IN/NOT_IN 集合查询
    List<Product> findByCategoryIn(List<String> categories);
    List<Product> findByCategoryNotIn(List<String> categories);
}

复杂查询示例

public interface AdvancedRepository extends JpaRepository<Order, Long> {
    
    // 多条件复合查询
    List<Order> findByUserIdAndStatusAndOrderDateBetween(Long userId, 
                                                       OrderStatus status,
                                                       LocalDateTime startDate,
                                                       LocalDateTime endDate);
    
    // 金额范围查询
    @Query("SELECT o FROM Order o WHERE o.totalAmount BETWEEN :minAmount AND :maxAmount")
    List<Order> findByPriceRange(@Param("minAmount") BigDecimal minAmount,
                                 @Param("maxAmount") BigDecimal maxAmount);
    
    // 统计数据查询
    @Query("SELECT COUNT(o) FROM Order o WHERE o.status = :status")
    long countByStatus(@Param("status") OrderStatus status);
    
    @Query("SELECT AVG(o.totalAmount) FROM Order o WHERE o.user.id = :userId")
    BigDecimal findAverageAmountByUserId(@Param("userId") Long userId);
    
    @Query("SELECT SUM(o.totalAmount) FROM Order o WHERE o.orderDate >= :startDate")
    BigDecimal findTotalAmountSince(@Param("startDate") LocalDateTime startDate);
    
    // 分组查询
    @Query("SELECT o.status, COUNT(o), SUM(o.totalAmount) FROM Order o GROUP BY o.status")
    List<Object[]> getOrderStatistics();
    
    // 子查询
    @Query("SELECT o FROM Order o WHERE o.user.id IN " +
           "(SELECT u.id FROM User u WHERE u.status = :status)")
    List<Order> findByUserStatus(@Param("status") UserStatus status);
    
    // 复杂JOIN查询
    @Query("SELECT o FROM Order o JOIN o.user u JOIN o.items i " +
           "WHERE u.username = :username AND i.product.category = :category")
    List<Order> findByUsernameAndProductCategory(@Param("username") String username,
                                               @Param("category") String category);
}

自定义查询

@Query注解使用

JPQL查询

public interface CustomQueryRepository extends JpaRepository<User, Long> {
    
    // JPQL查询示例
    @Query("SELECT u FROM User u WHERE u.username = :username AND u.status = :status")
    Optional<User> findByUsernameAndStatus(@Param("username") String username,
                                          @Param("status") UserStatus status);
    
    // 使用原生SQL查询
    @Query(value = "SELECT * FROM users WHERE created_date >= ?1 AND status = ?2",
           nativeQuery = true)
    List<User> findRecentActiveUsers(LocalDateTime since, String status);
    
    // 投影查询 - 只返回指定字段
    @Query("SELECT new com.example.dto.UserSummaryDTO(u.id, u.username, u.email, " +
           "u.createdDate, u.status) FROM User u WHERE u.status = :status")
    List<UserSummaryDTO> findUserSummariesByStatus(@Param("status") UserStatus status);
    
    // 聚合查询
    @Query("SELECT COUNT(u), MIN(u.createdDate), MAX(u.createdDate) " +
           "FROM User u WHERE u.status = :status")
    Object[] getUserStatistics(@Param("status") UserStatus status);
    
    // CASE WHEN查询
    @Query("SELECT u, CASE WHEN u.createdDate >= :recentCutoff THEN 'RECENT' " +
           "ELSE 'OLD' END FROM User u")
    List<Object[]> classifyUsers(@Param("recentCutoff") LocalDateTime recentCutoff);
    
    // 窗口函数查询(PostgreSQL特有)
    @Query(value = "SELECT u.*, ROW_NUMBER() OVER (PARTITION BY status ORDER BY created_date) " +
           "FROM users u", nativeQuery = true)
    List<Object[]> findUsersWithRowNumber();
}

Specification动态查询

Specification实现

public class UserSpecifications {
    
    public static Specification<User> hasUsername(String username) {
        return (root, query, criteriaBuilder) -> 
            username == null ? null : criteriaBuilder.equal(root.get("username"), username);
    }
    
    public static Specification<User> hasStatus(UserStatus status) {
        return (root, query, criteriaBuilder) -> 
            status == null ? null : criteriaBuilder.equal(root.get("status"), status);
    }
    
    public static Specification<User> createdAfter(LocalDateTime date) {
        return (root, query, criteriaBuilder) -> 
            date == null ? null : criteriaBuilder.greaterThan(root.get("createdDate"), date);
    }
    
    public static Specification<User> emailContaining(String email) {
        return (root, query, criteriaBuilder) -> {
            if (email == null || email.trim().isEmpty()) {
                return null;
            }
            return criteriaBuilder.like(criteriaBuilder.lower(root.get("email")), 
                                       "%" + email.toLowerCase() + "%");
        };
    }
    
    public static Specification<User> usernameLike(String namePattern) {
        return (root, query, criteriaBuilder) -> {
            if (namePattern == null || namePattern.trim().isEmpty()) {
                return null;
            }
            return criteriaBuilder.or(
                criteriaBuilder.like(criteriaBuilder.lower(root.get("username")),
                                    "%" + namePattern.toLowerCase() + "%"),
                criteriaBuilder.like(criteriaBuilder.lower(root.get("firstName")),
                                    "%" + namePattern.toLowerCase() + "%"),
                criteriaBuilder.like(criteriaBuilder.lower(root.get("lastName")),
                                    "%" + namePattern.toLowerCase() + "%")
            );
        };
    }
    
    // 组合条件查询
    public static Specification<User> buildSearchSpecification(UserSearchCriteria criteria) {
        return Specification.where(hasUsername(criteria.getUsername()))
                           .and(hasStatus(criteria.getStatus()))
                           .and(createdAfter(criteria.getCreatedAfter()))
                           .and(emailContaining(criteria.getEmail()))
                           .and(usernameLike(criteria.getNamePattern()));
    }
}

使用Specification进行动态查询

@Service
public class UserSearchService {
    
    @Autowired
    private UserRepository userRepository;
    
    public Page<User> searchUsers(UserSearchCriteria criteria, Pageable pageable) {
        Specification<User> spec = UserSpecifications.buildSearchSpecification(criteria);
        return userRepository.findAll(spec, pageable);
    }
    
    public List<User> findUsersByComplexCriteria(UserSearchCriteria criteria) {
        Specification<User> spec = Specification.where(
            UserSpecifications.hasStatus(UserStatus.ACTIVE)
        ).and(
            UserSpecifications.createdAfter(LocalDateTime.now().minusDays(30))
        ).and(
            UserSpecifications.usernameLike(criteria.getNamePattern())
        );
        
        return userRepository.findAll(spec);
    }
    
    // 条件统计
    public Map<String, Long> getUserStatistics(UserSearchCriteria criteria) {
        Specification<User> spec = UserSpecifications.buildSearchSpecification(criteria);
        
        List<User> users = userRepository.findAll(spec);
        
        return users.stream()
            .collect(Collectors.groupingBy(
                user -> user.getStatus().name(),
                Collectors.counting()
            ));
    }
}

分页与排序

分页查询实现

基础分页配置

@Configuration
public class PaginationConfig {
    
    @Bean
    public PageRequest pageRequest() {
        return PageRequest.of(0, 20);
    }
}

分页查询服务

@Service
public class UserPaginationService {
    
    @Autowired
    private UserRepository userRepository;
    
    // 基础分页查询
    public Page<User> getAllUsers(Pageable pageable) {
        return userRepository.findAll(pageable);
    }
    
    // 条件分页查询
    public Page<User> findUsersByStatus(UserStatus status, Pageable pageable) {
        return userRepository.findByStatus(status, pageable);
    }
    
    // 自定义排序分页
    public Page<User> findUsersSortedBy(Sort sort) {
        Pageable pageable = PageRequest.of(0, 20, sort);
        return userRepository.findAll(pageable);
    }
    
    // 多字段排序
    public Page<User> findUsersWithMultiSort() {
        Sort sort = Sort.by(
            Sort.Direction.DESC, "createdDate",
            Sort.Direction.ASC, "username"
        );
        Pageable pageable = PageRequest.of(0, 20, sort);
        return userRepository.findAll(pageable);
    }
    
    // 条件分页 + 自定义排序
    public PagedModel<EntityModel<User>> findUsersPaged(UserSearchCriteria criteria,
                                                       Pageable pageable) {
        Specification<User> spec = UserSpecifications.buildSearchSpecification(criteria);
        Page<User> userPage = userRepository.findAll(spec, pageable);
        
        // 使用Spring HATEOAS的PagedModel
        return PagedModel.of(
            userPage.getContent().stream()
                .map(user -> EntityModel.of(user))
                .collect(Collectors.toList()),
            new PagedModel.PageMetadata(
                userPage.getSize(),
                userPage.getNumber(),
                userPage.getTotalElements(),
                userPage.getTotalPages()
            )
        );
    }
    
    // 分页查询统计信息
    public UserPaginationSummary getUserPaginationSummary(Page<User> userPage) {
        return UserPaginationSummary.builder()
            .totalElements(userPage.getTotalElements())
            .totalPages(userPage.getTotalPages())
            .currentPage(userPage.getNumber())
            .pageSize(userPage.getSize())
            .first(userPage.isFirst())
            .last(userPage.isLast())
            .hasNext(userPage.hasNext())
            .hasPrevious(userPage.hasPrevious())
            .build();
    }
}

分页查询控制器

@RestController
@RequestMapping("/api/users")
public class UserPaginationController {
    
    @Autowired
    private UserPaginationService userPaginationService;
    
    @GetMapping
    public ResponseEntity<PagedModel<EntityModel<User>>> getUsers(
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "20") int size,
            @RequestParam(defaultValue = "createdDate") String sortBy,
            @RequestParam(defaultValue = "desc") String sortDir,
            @RequestParam(required = false) String status,
            @RequestParam(required = false) String search) {
        
        // 构建排序条件
        Sort.Direction direction = "desc".equalsIgnoreCase(sortDir) ? 
            Sort.Direction.DESC : Sort.Direction.ASC;
        Sort sort = Sort.by(direction, sortBy);
        
        Pageable pageable = PageRequest.of(page, size, sort);
        
        // 构建搜索条件
        UserSearchCriteria criteria = UserSearchCriteria.builder()
            .status(status != null ? UserStatus.valueOf(status.toUpperCase()) : null)
            .namePattern(search)
            .build();
        
        PagedModel<EntityModel<User>> result = userPaginationService.findUsersPaged(criteria, pageable);
        
        return ResponseEntity.ok(result);
    }
    
    @GetMapping("/statistics")
    public ResponseEntity<Map<String, Object>> getUserStatistics() {
        Map<String, Object> statistics = new HashMap<>();
        
        // 总数统计
        statistics.put("totalUsers", userRepository.count());
        statistics.put("activeUsers", userRepository.countByStatus(UserStatus.ACTIVE));
        
        // 分页统计
        Page<User> recentUsers = userRepository.findByCreatedDateGreaterThan(
            LocalDateTime.now().minusDays(30), PageRequest.of(0, 1));
        statistics.put("totalPages", recentUsers.getTotalPages());
        
        return ResponseEntity.ok(statistics);
    }
}

事务管理

事务配置与使用

事务配置类

@Configuration
@EnableTransactionManagement
public class TransactionConfig {
    
    @Bean
    public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(entityManagerFactory);
        return transactionManager;
    }
    
    @Bean
    public DataSourceTransactionManager dataSourceTransactionManager(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
}

服务层事务应用

@Service
@Transactional(readOnly = true)
public class UserService {
    
    @Autowired
    private UserRepository userRepository;
    
    @Autowired
    private OrderRepository orderRepository;
    
    // 只读事务
    @Transactional(readOnly = true)
    public List<User> findAllActiveUsers() {
        return userRepository.findByStatus(UserStatus.ACTIVE);
    }
    
    // 写事务
    @Transactional(rollbackFor = Exception.class)
    public User createUserWithOrders(UserCreateRequest request) {
        try {
            // 创建用户
            User user = new User();
            user.setUsername(request.getUsername());
            user.setEmail(request.getEmail());
            user.setPassword(encodePassword(request.getPassword()));
            
            User savedUser = userRepository.save(user);
            
            // 创建订单
            if (request.getInitialOrders() != null) {
                for (OrderCreateRequest orderRequest : request.getInitialOrders()) {
                    Order order = new Order();
                    order.setUser(savedUser);
                    order.setOrderNumber(generateOrderNumber());
                    order.setTotalAmount(orderRequest.getTotalAmount());
                    order.setStatus(OrderStatus.PENDING);
                    
                    orderRepository.save(order);
                }
            }
            
            return savedUser;
            
        } catch (Exception e) {
            // 事务会自动回滚
            throw new BusinessException("用户创建失败", e);
        }
    }
    
    // 嵌套事务
    @Transactional
    public User updateUserWithOrders(Long userId, UserUpdateRequest request) {
        User user = userRepository.findById(userId)
            .orElseThrow(() -> new UserNotFoundException(userId));
        
        // 更新用户信息
        updateUserBasicInfo(user, request);
        
        // 处理订单更新(嵌套事务)
        updateUserOrders(user, request.getOrderUpdates());
        
        return userRepository.save(user);
    }
    
    @Transactional(propagation = Propagation.NESTED)
    public void updateUserOrder(User user, OrderUpdateRequest request) {
        Order order = orderRepository.findById(request.getOrderId()))
            .orElseThrow(() -> new OrderNotFoundException(request.getOrderId()));
        
        if (!order.getUser().equals(user)) {
            throw new SecurityException("无权修改此订单");
        }
        
        order.setStatus(request.getStatus());
        orderRepository.save(order);
        
        // 模拟可能失败的操作
        if (request.getStatus() == OrderStatus.CANCELLED) {
            processOrderCancellation(order);
        }
    }
    
    // 分布式事务(XA Transaction)
    @Transactional
    @TransactionalManager("transactionManager")
    public void transferFunds(Long fromUserId, Long toUserId, BigDecimal amount) {
        User fromUser = userRepository.findById(fromUserId)
            .orElseThrow(() -> new UserNotFoundException(fromUserId));
        User toUser = userRepository.findById(toUserId)
            .orElseThrow(() -> new UserNotFoundException(toUserId));
        
        // 扣款
        fromUser.setBalance(fromUser.getBalance().subtract(amount));
        if (fromUser.getBalance().compareTo(BigDecimal.ZERO) < 0) {
            throw new InsufficientFundException("余额不足");
        }
        userRepository.save(fromUser);
        
        // 加款
        toUser.setBalance(toUser.getBalance().add(amount));
        userRepository.save(toUser);
        
        // 记录交易日志
        auditLogService.logTransfer(fromUserId, toUserId, amount);
    }
}

事务传播行为

传播行为示例

@Service
public class OrderProcessingService {
    
    @Autowired
    private OrderRepository orderRepository;
    
    @Autowired
    private PaymentService paymentService;
    
    @Autowired
    private InventoryService inventoryService;
    
    // REQUIRED:如果当前没有事务,创建新事务;如果有事务,加入事务
    @Transactional(propagation = Propagation.REQUIRED)
    public Order processOrder(OrderProcessRequest request) {
        Order order = orderRepository.findById(request.getOrderId())
            .orElseThrow(() -> new OrderNotFoundException(request.getOrderId()));
        
        // 处理支付
        PaymentResult payment = paymentService.processPayment(order);
        
        // 更新库存
        inventoryService.updateInventory(order);
        
        // 更新订单状态
        order.setStatus(OrderStatus.CONFIRMED);
        return orderRepository.save(order);
    }
    
    // REQUIRES_NEW:总是创建新事务,独立于父事务
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void createOrderAuditLog(Order order) {
        OrderAuditLog log = new OrderAuditLog();
        log.setOrderId(order.getId());
        log.setAction("ORDER_CREATED");
        log.setTimestamp(LocalDateTime.now());
        
        // 即使主事务回滚,这个审计日志也会被保存
        auditLogRepository.save(log);
    }
    
    // SUPPORTS:如果当前有事务,加入事务;如果没有事务,以非事务方式执行
    @Transactional(propagation = Propagation.SUPPORTS)
    public PaymentResult checkPaymentStatus(String paymentId) {
        return paymentService.checkPayment(paymentId);
        
        // 这不是关键操作,可以在没有事务的情况下执行
    }
    
    // NOT_SUPPORTED:以非事务方式执行,如果当前有事务则暂停
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void sendNotification(Order order) {
        // 发送通知不应影响主事务
        notificationService.sendOrderConfirmedNotification(order);
        
        // 即使这里抛出异常,也不会影响主事务
    }
    
    // NEVER:以非事务方式执行,如果当前有事务则抛出异常
    @Transactional(propagation = Propagation.NEVER)
    public String generateReport(ReportRequest request) {
        // 生成报告不应该在事务中执行
        return reportService.generateOrderReport(request);
    }
    
    // MANDATORY:必须在事务中执行,如果没有事务则抛出异常
    @Transactional(propagation = Propagation.MANDATORY)
    public void updateCriticalData(CriticalData data) {
        // 关键数据更新必须在事务中进行
        criticalDataRepository.save(data);
    }
}

总结

Spring Data JPA深入应用为企业级数据访问提供了强大的解决方案:

核心技术要点

  1. Repository抽象 - 简化数据访问层的开发
  2. 查询方法生成 - 基于方法名自动生成查询逻辑
  3. 自定义查询 - @Query注解和Specification动态查询
  4. 分页排序 - 内置的分页和排序功能支持
  5. 事务管理 - 灵活的事务控制机制
  6. 性能优化 - N+1问题解决和懒加载控制
  7. 实体关联 - 复杂对象关系的映射和管理

企业级应用价值

  • 开发效率:通过Repository接口减少重复代码
  • 代码质量:类型安全的查询方法定义
  • 性能优化:智能的查询优化和缓存策略
  • 维护性:清晰的数据访问层架构设计

最佳实践建议

  1. 合理使用懒加载:避免不必要的关联查询
  2. 批量操作优化:使用批量插入和更新提高性能
  3. 分页查询:大数据量查询必须使用分页
  4. 事务边界:合理控制事务的范围和传播行为
  5. 查询测试:对复杂查询进行充分的单元测试

继续深入学习Spring MVC的其他组件,将为您的Web应用开发提供更加完整和强大的技术基础!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员小凯

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值