Spring Boot JPA: Database Access ด้วย Hibernate

#java13 เม.ย. 2569

Spring Data JPA คืออะไร

Spring Data JPA ทำให้ database access ง่ายขึ้นมาก ด้วย Repository pattern ที่ generate SQL ให้อัตโนมัติ

Entity

import jakarta.persistence.*;

@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false, length = 100)
    private String name;

    @Column(unique = true, nullable = false)
    private String email;

    @Column(name = "created_at")
    private LocalDateTime createdAt;

    @OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
    private List<Order> orders = new ArrayList<>();

    @PrePersist
    protected void onCreate() {
        createdAt = LocalDateTime.now();
    }

    // constructors, getters, setters
}

Repository

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

public interface UserRepository extends JpaRepository<User, Long> {
    // Spring Data สร้าง SQL ให้อัตโนมัติจากชื่อ method
    Optional<User> findByEmail(String email);
    List<User> findByNameContaining(String name);
    List<User> findByCreatedAtAfter(LocalDateTime date);
    boolean existsByEmail(String email);
    long countByName(String name);

    // Custom JPQL query
    @Query("SELECT u FROM User u WHERE u.email LIKE %:domain")
    List<User> findByEmailDomain(@Param("domain") String domain);

    // Native SQL
    @Query(value = "SELECT * FROM users WHERE YEAR(created_at) = :year",
           nativeQuery = true)
    List<User> findByYear(@Param("year") int year);
}

Pagination และ Sorting

// Controller
@GetMapping
public Page<User> getUsers(
        @RequestParam(defaultValue = "0") int page,
        @RequestParam(defaultValue = "10") int size,
        @RequestParam(defaultValue = "name") String sortBy) {

    Pageable pageable = PageRequest.of(page, size, Sort.by(sortBy));
    return userRepository.findAll(pageable);
}

Relationships

@Entity
public class Order {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_id")
    private User user;

    @OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
    private List<OrderItem> items = new ArrayList<>();
}

Transactions

@Service
@Transactional
public class OrderService {
    public Order createOrder(Long userId, List<OrderItemRequest> items) {
        User user = userRepository.findById(userId)
            .orElseThrow(() -> new UserNotFoundException(userId));

        Order order = new Order(user);
        items.forEach(item -> order.addItem(new OrderItem(item)));

        return orderRepository.save(order);
        // ถ้า exception เกิด transaction จะ rollback อัตโนมัติ
    }
}

สรุป

Spring Data JPA ลด boilerplate code ได้มาก ด้วย Repository pattern ที่ generate SQL จากชื่อ method รองรับ pagination, sorting และ custom queries ครับ