Spring ORMの例のチュートリアルへようこそ。今日は、Hibernate JPAトランザクション管理を使用したSpring ORMの例を見ていきます。以下の機能を持つ非常にシンプルなSpringスタンドアロンアプリケーションの例をお見せします。
- 依存性の注入(@Autowiredアノテーション)
- JPA EntityManager(Hibernateによって提供される)
- アノテーション付きのトランザクションメソッド(@Transactionalアノテーション)
Spring ORMの例
Spring ORMの例には、インメモリデータベースを使用しているため、データベースのセットアップは不要です(ただし、spring.xmlのデータソースセクションで他のデータベースに変更することができます)。これはSpring ORMスタンドアロンアプリケーションであり、すべての依存関係を最小限に抑えています(ただし、Springに慣れている場合は簡単にWebプロジェクトに変更できます)。 注意: Spring AOPベースのトランザクション(@Transactional注釈なし)のメソッド解決アプローチについては、このチュートリアルを参照してください: Spring ORM AOPトランザクション管理。以下の画像は、最終的なSpring ORM例プロジェクトを示しています。
それでは、Spring ORMの例プロジェクトの各コンポーネントを1つずつ見ていきましょう。
Spring ORM Maven依存関係
以下は、Spring ORM依存関係を持つ最終的なpom.xmlファイルです。Spring 4とHibernate 4を使用しています。
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>hu.daniel.hari.learn.spring</groupId>
<artifactId>Tutorial-SpringORMwithTX</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<!-- Generic properties -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.7</java.version>
<!-- SPRING & HIBERNATE / JPA -->
<spring.version>4.0.0.RELEASE</spring.version>
<hibernate.version>4.1.9.Final</hibernate.version>
</properties>
<dependencies>
<!-- LOG -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- JPA Vendor -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${hibernate.version}</version>
</dependency>
<!-- IN MEMORY Database and JDBC Driver -->
<dependency>
<groupId>hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>1.8.0.7</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
- 必要なのは、Springの依存関係として
spring-context
とspring-orm
です。 - 私たちは、HibernateのJPA実装として
hibernate-entitymanager
を使用しています。hibernate-entitymanager
はhibernate-core
に依存しているため、pom.xmlに明示的にhibernate-coreを記述する必要はありません。 Mavenのトランジティブ依存関係によって、プロジェクトに引き込まれます。 - データベースアクセスのためにJDBCドライバーも依存関係として必要です。私たちはHSQLDBを使用しており、その中にJDBCドライバーと動作中のインメモリデータベースが含まれています。
Spring ORMモデルクラス
私たちは、HibernateがJPAの実装を提供しているため、モデルビーンのマッピングに標準のJPAアノテーションを使用できます。
package hu.daniel.hari.learn.spring.orm.model;
import javax.persistence.Entity;
import javax.persistence.Id;
@Entity
public class Product {
@Id
private Integer id;
private String name;
public Product() {
}
public Product(Integer id, String name) {
this.id = id;
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Product [id=" + id + ", name=" + name + "]";
}
}
私たちのPOJOをエンティティとして定義し、その主キーを定義するために、@Entity
と@Id
のJPAアノテーションを使用します。
Spring ORM DAOクラス
私たちは、persistとfindALLメソッドを提供する非常にシンプルなDAOクラスを作成します。
package hu.daniel.hari.learn.spring.orm.dao;
import hu.daniel.hari.learn.spring.orm.model.Product;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.stereotype.Component;
@Component
public class ProductDao {
@PersistenceContext
private EntityManager em;
public void persist(Product product) {
em.persist(product);
}
public List<Product> findAll() {
return em.createQuery("SELECT p FROM Product p").getResultList();
}
}
- @Componentは、Springのアノテーションであり、Spring IoC(依存性注入)を介してこのクラスを使用できることをSpringコンテナに伝えます。
- 私たちは、JPAの
@PersistenceContext
アノテーションを使用して、EntityManagerへの依存関係の注入を示しています。Springは、spring.xmlの設定に従って、適切なEntityManagerのインスタンスを注入します。
Spring ORMサービスクラス
私たちのシンプルなサービスクラスには、2つの書き込みメソッド(add、addAll)と1つの読み取りメソッド(listAll)があります。
package hu.daniel.hari.learn.spring.orm.service;
import hu.daniel.hari.learn.spring.orm.dao.ProductDao;
import hu.daniel.hari.learn.spring.orm.model.Product;
import java.util.Collection;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
@Component
public class ProductService {
@Autowired
private ProductDao productDao;
@Transactional
public void add(Product product) {
productDao.persist(product);
}
@Transactional
public void addAll(Collection<Product> products) {
for (Product product : products) {
productDao.persist(product);
}
}
@Transactional(readOnly = true)
public List<Product> listAll() {
return productDao.findAll();
}
}
- 私たちは、サービスクラスにProductDaoを注入するために、Springの@Autowiredアノテーションを使用しています。
- トランザクション管理を使用したいので、メソッドには
@Transactional
のSpringアノテーションが付けられています。listAllメソッドはデータベースの読み取りのみを行うため、最適化のために@Transactionalアノテーションを読み取り専用に設定しています。
Spring ORMの例のBean構成XML
私たちのSpring ORMの例のプロジェクトのJavaクラスが準備できたので、今度はSpringのBean構成ファイルを見てみましょう。spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://www.springframework.org/schema/beans"
xmlns:p="https://www.springframework.org/schema/p"
xmlns:context="https://www.springframework.org/schema/context"
xmlns:tx="https://www.springframework.org/schema/tx"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
https://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans-3.0.xsd
https://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context-3.0.xsd
https://www.springframework.org/schema/tx
https://www.springframework.org/schema/tx/spring-tx.xsd
">
<!-- Scans the classpath for annotated components that will be auto-registered as Spring beans -->
<context:component-scan base-package="hu.daniel.hari.learn.spring" />
<!-- Activates various annotations to be detected in bean classes e.g: @Autowired -->
<context:annotation-config />
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver" />
<property name="url" value="jdbc:hsqldb:mem://productDb" />
<property name="username" value="sa" />
<property name="password" value="" />
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
p:packagesToScan="hu.daniel.hari.learn.spring.orm.model"
p:dataSource-ref="dataSource"
>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="generateDdl" value="true" />
<property name="showSql" value="true" />
</bean>
</property>
</bean>
<!-- Transactions -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<!-- enable the configuration of transactional behavior based on annotations -->
<tx:annotation-driven transaction-manager="transactionManager" />
</beans>
- まず、Springコンポーネント(サービス、DAO)を1つずつ定義するのではなく、クラスパススキャンを使用するようSpringに伝えます。また、Springのアノテーション検出も有効にしています。
- データソースを追加します。現在、HSQLDBインメモリデータベースを使用しています。
- アプリケーションがエンティティマネージャを取得するために使用されるJPA
EntityManagerFactory
を設定しました。Springはこれを行うための3つの異なる方法をサポートしていますが、私たちはフルのJPA機能を持つLocalContainerEntityManagerFactoryBean
を使用しました。次のようにLocalContainerEntityManagerFactoryBean
の属性を設定しました:- モデルクラスのパッケージを指すpackagesToScan属性。
- 前述のデータソースが定義されているSpring構成ファイル。
- HibernateとしてのjpaVendorAdapterといくつかのHibernateプロパティの設定。
- Spring PlatformTransactionManagerインスタンスをJpaTransactionManagerとして作成します。このトランザクションマネージャは、トランザクションデータアクセスに単一のJPA EntityManagerFactoryを使用するアプリケーションに適しています。
- 注釈に基づいたトランザクションの動作の設定を有効にし、作成したトランザクションマネージャを設定します。
Spring ORM Hibernate JPAの例題プログラム
Spring ORM JPA Hibernateの例題プロジェクトが準備されているので、アプリケーションのテストプログラムを作成しましょう。
public class SpringOrmMain {
public static void main(String[] args) {
//Springアプリケーションコンテキストを作成します
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:/spring.xml");
//コンテキストからサービスを取得します。 (サービスの依存関係(ProductDAO)は、ProductServiceにオートワイヤリングされています)
ProductService productService = ctx.getBean(ProductService.class);
//いくつかのデータ操作を行います
productService.add(new Product(1, "Bulb"));
productService.add(new Product(2, "Dijone mustard"));
System.out.println("listAll: " + productService.listAll());
//トランザクションのロールバックをテストします(重複キー)
try {
productService.addAll(Arrays.asList(new Product(3, "Book"), new Product(4, "Soap"), new Product(1, "Computer")));
} catch (DataAccessException dataAccessException) {
}
//ロールバック後の要素リストをテストします
System.out.println("listAll: " + productService.listAll());
ctx.close();
}
}
Springコンテナをメインメソッドから簡単に起動できる方法をご覧ください。最初の依存関係が注入されたエントリポイントであるサービスクラスのインスタンスを取得しています。 springコンテキストが初期化された後、ProductServiceにProductDaoクラスの参照が注入されます。 ProducServiceインスタンスを取得した後、そのメソッドをテストできます。すべてのメソッド呼び出しは、Springのプロキシメカニズムによりトランザクショナルになります。この例では、ロールバックもテストしています。上記のspring ORM例のテストプログラムを実行すると、以下のログが表示されます。
Hibernate: insert into Product (name, id) values (?, ?)
Hibernate: insert into Product (name, id) values (?, ?)
Hibernate: select product0_.id as id0_, product0_.name as name0_ from Product product0_
listAll: [Product [id=1, name=Bulb], Product [id=2, name=Dijone mustard]]
Hibernate: insert into Product (name, id) values (?, ?)
Hibernate: insert into Product (name, id) values (?, ?)
Hibernate: insert into Product (name, id) values (?, ?)
Hibernate: select product0_.id as id0_, product0_.name as name0_ from Product product0_
listAll: [Product [id=1, name=Bulb], Product [id=2, name=Dijone mustard]]
2つ目のトランザクションがロールバックされることに注意してください。これが製品リストが変更されなかった理由です。添付されたソースからlog4j.properties
ファイルを使用すると、裏側で何が起こっているかを確認できます。参考文献:https://docs.spring.io/spring/docs/current/spring-framework-reference/html/orm.html最終的なSpring ORM JPA Hibernateの例プロジェクトを以下のリンクからダウンロードして、さらに学習するためにそれを使って遊んでみてください。
Source:
https://www.digitalocean.com/community/tutorials/spring-orm-example-jpa-hibernate-transaction