Spring Data JPAの基礎から高度な機能まで

Spring Data JPAは、データベース操作を簡潔かつ効率的に扱うための強力なツールです。この記事では、基本的なCRUD操作から高度な機能まで、Spring Data JPAの利用方法を解説します。

Spring Data JPAとは

Spring Data JPAは、Springフレームワークの一部で、JPA(Java Persistence API)を使用したデータアクセス層の開発を簡素化します。多くのテンプレートコードを自動生成し、開発者が複雑なデータ操作に集中できるように支援します。

クイックスタート

プロジェクト設定

まずは、Spring Bootプロジェクトを作成し、pom.xmlに必要な依存関係を追加します。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
</dependency>

データソースの設定

application.propertiesにデータベース接続情報を記述します。

spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect

エンティティクラスの作成

次に、シンプルなエンティティクラスUserを定義します。

@Entity
public class Person {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String userName;
    private String emailAddress;

    // GetterとSetterメソッド
}

リポジトリインターフェースの作成

JpaRepositoryを継承したリポジトリインターフェースを作ります。

public interface PersonRepository extends JpaRepository<Person, Long> {
    List<Person> findByUserName(String userName);
}

リポジトリの利用

サービスクラスでPersonRepositoryをインジェクションし、データ操作を行います。

@Service
public class PersonService {
    @Autowired
    private PersonRepository personRepository;

    public Person registerUser(String userName, String emailAddress) {
        Person person = new Person();
        person.setUserName(userName);
        person.setEmailAddress(emailAddress);
        return personRepository.save(person);
    }

    public List<Person> findUsersByUserName(String userName) {
        return personRepository.findByUserName(userName);
    }
}

詳細機能

カスタムクエリメソッド

メソッド名からクエリを自動生成する機能があります。

List<Person> findByEmailAddress(String emailAddress);

また、@Queryアノテーションを使用してJPQLクエリを定義できます。

@Query("SELECT p FROM Person p WHERE p.emailAddress = ?1")
Person findUserByEmail(String emailAddress);

ページネーションとソート

Pageableパラメータを使用して、ページネーションを実装します。

Page<Person> findAll(Pageable pageable);

サービスクラスでの使用例:

Page<Person> people = personRepository.findAll(PageRequest.of(0, 10, Sort.by("userName")));

複雑なクエリ

複雑なクエリにはSpecification APIを利用します。

public class PersonSpecification {
    public static Specification<Person> hasUserName(String userName) {
        return (root, query, criteriaBuilder) -> criteriaBuilder.equal(root.get("userName"), userName);
    }
}

サービスクラスでの使用例:

List<Person> people = personRepository.findAll(PersonSpecification.hasUserName("John"));

高度な機能

楽観的ロックと悲観的ロック

楽観的ロックは、@Versionアノテーションを使用して実現します。

@Version
private Integer lockVersion;

悲観的ロックは、クエリ時にロックモードを指定します。

@Lock(LockModeType.PESSIMISTIC_WRITE)
@Query("SELECT p FROM Person p WHERE p.userName = :userName")
List<Person> findByUserNameWithLock(@Param("userName") String userName);

オーディティング機能

オーディティング機能は、@CreatedDate@LastModifiedDateアノテーションで実装します。

@EntityListeners(AuditingEntityListener.class)
public class Person {
    @CreatedDate
    private LocalDateTime createdAt;

    @LastModifiedDate
    private LocalDateTime updatedAt;
}

そして、コンフィグクラスでオーディティングを有効にします。

@Configuration
@EnableJpaAuditing
public class JpaConfiguration {
}

実践例

簡単なブログシステムを例にとって、ユーザー管理、記事管理、コメント管理を実装します。

エンティティクラスの定義

@Entity
public class Post {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long postId;
    private String title;
    private String content;

    @ManyToOne
    @JoinColumn(name = "person_id")
    private Person author;

    // GetterとSetterメソッド
}

@Entity
public class Review {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long reviewId;
    private String content;

    @ManyToOne
    @JoinColumn(name = "person_id")
    private Person reviewer;

    @ManyToOne
    @JoinColumn(name = "post_id")
    private Post post;

    // GetterとSetterメソッド
}

リポジトリインターフェースの作成

public interface PostRepository extends JpaRepository<Post, Long> {
}

public interface ReviewRepository extends JpaRepository<Review, Long> {
}

サービスクラスの実装

@Service
public class BlogService {
    @Autowired
    private PersonRepository personRepository;
    @Autowired
    private PostRepository postRepository;
    @Autowired
    private ReviewRepository reviewRepository;

    public Post writePost(String title, String content, Long authorId) {
        Person author = personRepository.findById(authorId).orElseThrow(() -> new RuntimeException("ユーザーが見つかりません"));
        Post post = new Post();
        post.setTitle(title);
        post.setContent(content);
        post.setAuthor(author);
        return postRepository.save(post);
    }

    public Review addReview(String content, Long postId, Long reviewerId) {
        Person reviewer = personRepository.findById(reviewerId).orElseThrow(() -> new RuntimeException("ユーザーが見つかりません"));
        Post post = postRepository.findById(postId).orElseThrow(() -> new RuntimeException("記事が見つかりません"));
        Review review = new Review();
        review.setContent(content);
        review.setReviewer(reviewer);
        review.setPost(post);
        return reviewRepository.save(review);
    }
}

タグ: SpringDataJPA jpa Hibernate SpringBoot

6月2日 19:52 投稿