Tuesday, June 18, 2013

Основы JPA

JPA (Java Persistence API) - это API, который предоставляет возможность сохранять Java-объекты в базе данных.
Существует несколько реализаций этого интерфейса, одна из самых популярных использует для этого Hibernate.

Создадим простое приложение и разберем, как работает JPA.

Для этого нам понадобятся следующие технологии:
  • Hibernate 4.2.2
  • MySQL 5.6.12
  • Maven 3.0.5

Создадим базу данных jpa_basics_tutorial и таблицу artist с колонками id, name и genre.
Таблица будет хранить информацию о музыкальных исполнителях:
CREATE DATABASE jpa_basics_tutorial;
USE jpa_basics_tutorial;

CREATE TABLE artist (
id INT PRIMARY KEY,
name VARCHAR(30),
genre VARCHAR(20)
);

Добавим в файл pom.xml необходимые зависимости:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>jpa_basics_tutorial</groupId>
    <artifactId>jpa_basics_tutorial</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>4.2.2.Final</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.25</version>
        </dependency>
    </dependencies>
    
</project>

Создадим класс Artist с полями id, name и genre.
Класс, с которым может работать JPA, называется сущностью (entity).
Для того, чтобы класс Artist стал сущностью, добавим аннотацию @Entity.
Сущности типа Artist будут храниться в таблице, имя которой совпадает с именем класса, т.е. artist.
Значения полей сущностей будут храниться в одноименных колонках этой же таблицы.
Сущность должна иметь persistence identity, или идентификатор. Это - ключ, который уникально ее идентифицирует и выделяет среди других сущностей такого же типа. Идентификатор указывается с помощью аннотации @Id. В классе Artist в качестве идентификатора можно использовать поле id, которое соответствует колонке первичного ключа в таблице artist:
package com.jpa.basics.tutorial.domain;

import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class Artist {

    @Id
    private int id;

    private String name;
    private String genre;

    public Artist() {

    }

    public Artist(int id, String name, String genre) {
        this.id = id;
        this.name = name;
        this.genre = genre;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getGenre() {
        return genre;
    }

    public void setGenre(String genre) {
        this.genre = genre;
    }

    @Override
    public String toString() {
        return "Artist{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", genre='" + genre + '\'' +
                '}';
    }
}

Создадим класс ArtistService, который имеет:
  • поле em типа EntityManager. EntityManager реализует API для работы с сущностями. Метод persist() создает новую сущность, find() производит поиск сущности, remove() удаляет сущность, а createQuery() позволяет выполнять JPQL-запросы. Для изменения сущности не нужно вызывать специальный метод EntityManager'а, достаточно изменить значение поля сущности (например, с помощью метода setGenre())
  • CRUD-методы (Create, Read, Update, Delete), которые используют EntityManager для создания, чтения, изменения и удаления сущностей
package com.jpa.basics.tutorial.service;

import com.jpa.basics.tutorial.domain.Artist;

import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import java.util.List;

public class ArtistService {
    
    private EntityManager em;

    public ArtistService(EntityManager em) {
        this.em = em;
    }

    public Artist createArtist(int id, String name, String genre) {
        Artist artist = new Artist(id, name, genre);
        em.persist(artist);
        return artist;
    }

    public void removeArtist(int id) {
        Artist artist = em.find(Artist.class, id);

        if (artist != null) {
            em.remove(artist);
        }
    }

    public Artist changeArtistGenre(int id, String genre) {
        Artist artist = em.find(Artist.class, id);

        if (artist != null) {
            artist.setGenre(genre);
        }

        return artist;
    }

    public Artist findArtist(int id) {
        return em.find(Artist.class, id);
    }

    public List<Artist> findAllArtists() {
        TypedQuery<Artist> query = em.createQuery("SELECT a FROM Artist a", Artist.class);
        return query.getResultList();
    }
}

EntityManager создается с помощью объекта типа EntityManagerFactory.
Каждому объекту EntityManagerFactory соответствует persistence unit, который содержит его настройки (например, для соединения с базой данных) и указывает, какие классы использует EntityManager. Имя persistence unit'а указывается при создании объекта EntityManagerFactory.
Persistence unit описывается в файле persistence.xml, который должен находиться в директории resources/META-INF.
Создадим этот файл:
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
             version="2.0">

    <persistence-unit name="JpaBasicsTutorial" transaction-type="RESOURCE_LOCAL">
        <class>com.jpa.basics.tutorial.domain.Artist</class>
        <properties>
            <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
            <property name="javax.persistence.jdbc.url" 
                      value="jdbc:mysql://localhost:3306/jpa_basics_tutorial"/>
            <property name="javax.persistence.jdbc.user" value="root"/>
            <property name="javax.persistence.jdbc.password" value="root"/>           
        </properties>
    </persistence-unit>

</persistence>

Создадим класс JpaBasicsTutorial для проверки работы приложения.
В методе main() создаются объекты EntityManagerFactory, EntityManager и ArtistService, после чего вызываются CRUD-методы.
Для того, чтобы действия над сущностями сохранялись в базе данных, методы для создания, изменения и удаления сущностей должны вызываться в транзакциях. Для открытия и закрытия транзакций используются методы begin() и commit() объекта EntityTransaction:
package com.jpa.basics.tutorial;

import com.jpa.basics.tutorial.domain.Artist;
import com.jpa.basics.tutorial.service.ArtistService;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import java.util.List;

public class JpaBasicsTutorial {

    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("JpaBasicsTutorial");
        EntityManager em = emf.createEntityManager();
        ArtistService service = new ArtistService(em);

        System.out.println("--- Create and persist artist ---");
        EntityTransaction transaction = em.getTransaction();
        transaction.begin();
        Artist artist = service.createArtist(1, "Franz Ferdinand", "Rock");
        transaction.commit();
        System.out.println(String.format("Persisted: %s\n", artist));

        System.out.println("--- Find artist ---");
        artist = service.findArtist(1);
        System.out.println(String.format("Found: %s\n", artist));

        System.out.println("--- Find all artists ---");
        List<Artist> artists = service.findAllArtists();
        for (Artist foundArtist : artists) {
            System.out.println(String.format("Found: %s\n", foundArtist));
        }

        System.out.println("--- Update artist ---");
        transaction.begin();
        artist = service.changeArtistGenre(1, "Indie Rock");
        transaction.commit();
        System.out.println(String.format("Updated: %s\n", artist));

        System.out.println("--- Remove artist ---");
        transaction.begin();
        service.removeArtist(1);
        transaction.commit();
        artist = service.findArtist(1);
        System.out.println(String.format("Found: %s\n", artist));
    }
}

Запустим метод main():

















Все CRUD-методы отработали верно, а это значит, что мы успешно использовали JPA в приложении.

Структура проекта:




Исходный код созданного приложения доступен по ссылке https://code.google.com/p/jpa-basics-tutorial/.

Рекомендуемые посты:

2 comments:

  1. JPA 1.0 is quite old school.
    JPA 2 provides a lot of new features and approaches. It is more actual API for new applications at the moment.

    ReplyDelete
    Replies
    1. You are right. I've changed xsi:schemaLocation according to JPA 2.0 in persistence.xml.

      Delete