© 2012 SpringSource, A division of VMware. All rights reserved
Spring Data in a Nutshell
Tsuyoshi Miyake (@tsuyokb)
22
背景と動機
§ RDBMS はいまだ重要かつ支配的• ただ “one size fits all” ではなくなってきている
§ Spring はデータアクセスに常に優れたサポートを行ってきた§ Spring Data project のゴールは Spring のデータサポートを “リフレッシュ” すること
• Traditional: JDBC, JPA• New: Grid, Document, Graph, K-V (aka NoSQL or NewSQL)
§ なじみの一貫性のある Springベースのプログラミングモデルを提供• 個々の技術的特徴はいかしながら
§ データアクセス層から boiler-plate code をなくす• 異なるテクノロジーをまたがって利用できる共通のインタフェース
33
Spring Data は “umbrella project”
§ http://www.springframework.org/spring-data§ JPA - Repositories§ JDBC Extensions§ MongoDB – Document Database§ Neo4j – Graphs Database§ Redis – Key Value Database§ Gemfire – Distributed Data Grid§ Commons – shared abstractions
• Repositories• Object Mapping
§ QueryDSL – integration with type-safe query API
44
Spring Data Repositories (1/3)
public interface CrudRepository<T, ID extends Serializable> extendsRepository<T, ID> {
T save(T entity);
Iterable<T> save(Iterable<? extends T> entities);
T findOne(ID id);
boolean exists(ID id);
Iterable<T> findAll();
long count();
void delete(ID id);
void delete(T entity);
void delete(Iterable<? extends T> entities);
void deleteAll();}
public interface Repository<T, ID extends Serializable> {// マーカーインタフェース ex.) Repository<Customer, Long>
}
55
Spring Data Repositories (2/3)
public interface PagingAndSortingRepository<T, ID extends Serializable> extendsCrudRepository<T, ID> {
Iterable<T> findAll(Sort sort);
Page<T> findAll(Pageable pageable);}
§ “naming conventions” によるクエリメソッドの定義
public interface PersonRepository extends CrudRepository<Person,BigInteger> {
// Finder for a single entityPerson findByEmailAddress(String emailAddress);
// Finder for a multiple entitiesList<Person> findByLastnameLike(String lastName);
// Finder with paginationPage<Person> findByFirstnameLike(String firstName, Pageable page);
}
66
Spring Data Repositories (3/3)
@NoRepositoryBeanpublic interface BaseRepository<T, ID extends Serializable> extends
Repository<T, ID> {Iterable<T> findAll(Pageable sort);
<S extends T> S save(S entity);
<S extends T> S save(Iterable<S> entities);}
§ Custom Repository インタフェースの定義• CRUD は便利だが Read のみを提供したい、または Delete は提供したくない etc.
§ 定義方法1. Repository を継承(or @RepositoryDefinition を付与)したインタフェースを定義2. 公開したいメソッドのみをそのインタフェースに定義(ただし、メソッドシグネチャーは Spring Data Repository と同一にする)
3. 出来上がったインタフェースを entity のベースに
77
Spring Data JPA – Entity Mapping
§ インタフェースを定義するだけ:• PersonRepositoryの実装は Spring (Data) が提供
<jpa:repositories base-package="com.acme.repository" />
@Entitypublic class Person {
@Id@GeneratedValue(strategy=GenerationType.AUTO)private BigInteger id;private String firstname, lastname;
@Column(name="email")private String emailAddress;
@OneToManyprivate Set<Person> colleagues;
}
@EnableJpaRepositoriesJavaConfig
XML
88
Spring Data JPA
§ transactional service layer (通常通り)@Servicepublic class DefaultUserManagementService implements UserManagementService {
public PersonRepository personRepository; public ShiftRepository shiftRepository;
@Autowiredpublic DefaultUserManagementService(PersonRepository personRepository,
ShiftRepository shiftRepository) {this.personRepository = personRepository;this.shiftRepository = shiftRepository;
}
@Transactionalpublic void assignToNightShift(String emailAddress) {
Person person = personRepository.findByEmailAddress(emailAddress);
// continue processing
}}
99
Spring Data JPA
§ クエリメソッド(naming conventions ベース)• Query annotation でオーバーライド可能• JPA named query (@NamedQuery) の参照も可.
public interface PersonRepository extends CrudRepository<Person,BigInteger> {
// previous methods omitted…
@Query("select p from Person p where p.emailAddress = ?1")Person findByEmailAddress(String emailAddress);
@Query("select p from Person p where p.firstname = :firstname or p.lastname = :lastname")Person findByLastnameOrFirstname(@Param("lastname") String lastname,
@Param("firstname") String firstname);
}
1010
QueryDSL
§ ”タイプセーフ”な SQL-like なクエリを生成するためのフレームワーク• http://www.querydsl.com/• Open Source, Apache 2.0
§ IDE のコード補完フレンドリー§ 不適切なクエリが構造上不可能(存在しないカラムへのアクセス etc.)§ ドメインのプロパティと型への安全なアクセス(非文字列)
§ Java annotation processor (QueryDSL annotation processor) によるQ<DomainClass> の自動生成
§ Criteria API (JPA 2) より簡潔かつ通常の Java Collection にも使える
private static final QProduct $ = QProduct.product;
macBook = new Product("MacBook Pro", "Apple laptop");iPad = new Product("iPad", "Apple tablet");// …products = Arrays.asList(macBook, iPad, iPod, turntable);
List<Product> result = from($, products).where($.description.contains("Apple")).list($);
1111
QueryDSL - Repositories
§ Repository に QueryDSL interface を拡張(追加)• QueryDSLの Predicate を引数にもつメソッド• JPA, MongoDB
public interface QueryDSLPredicateExecutor<T> {
long count(com.mysema.query.types.Predicate predicate);
T findOne(Predicate predicate);
List<T> findAll(Predicate predicate);
List<T> findAll(Predicate predicate, OrderSpecifier<?>... orders);
Page<T> findAll(Predicate predicate, Pageable pageable);}
public interface CustomerRepository extends Repository<Customer, Long>, QueryDslPredicateExecutor<Customer> {
// Your query methods here}
QCustomer customer = QCustomer.customer;LocalDate today = new LocalDate();BooleanExpression customerHasBirthday = customer.birthday.eq(today);BooleanExpression isLongTermCustomer = customer.createdAt.lt(today.minusYears(2));customerRepository.findAll(customerHasBirthday.and(isLongTermCustomer));
1212
MongoDB
§ ドキュメント・データストア
§ ドキュメント == 構造化されたデータ (e.g. XML, JSON)§ JSON スタイルのドキュメント (BSON)
• 基本的に Map、値にプリミティブ/コレクション/ネストのドキュメント型
§ ドキュメントはコレクションというコンテナ(~テーブル)に格納される§ Index サポート –任意の attribute に§ リッチな query language
… 続きは http://www.mongodb.org/ で
{ firstname : "Dave",lastname : "Matthews",addresses : [ { city : "New York", street : "Broadway" } ]
}
1313
MongoDB Java API を使う (1/2)
public void mongoBasic() throws Exception {Mongo mongo = new Mongo();DB db = mongo.getDB("database");DBCollection customers = db.getCollection("customers");
DBObject address = new BasicDBObject("city", ”Kobe");address.put("street", "Broadway");DBObject addresses = new BasicDBList();((BasicDBList) addresses).add(address);DBObject customer = new BasicDBObject("firstname", "Tsuyoshi");customer.put("lastname", "Miyake");customer.put("addresses", addresses);
customers.insert(customer);
System.out.println(customers.findOne());}
}
1414
MongoDB Java API を使う (2/2)
§ Mongo クラスを使用§ サーバに関する詳細は隠蔽される
§ Insert / Update• (全ての)アプリケーション POJO -> DBObjectにマップする必要あり• mongo.getDatabase(…).getCollection(…).insert(…)
§ クエリ• クエリを組み立て、• mongo.getDatabase(…).getCollection(…).find(…)• カーソルを使って結果を iterate• DBObject -> アプリケーション POJO マップ(手動)
è JDBC よりは抽象化されていそうだけど(繰り返しが多い) …
1515
Spring Data MongoDB
§ MongoTemplate• MongoDB特有のオペレーションへのアクセス: geo, map/reduce etc.• Fluent Query, Criteria, Update APIs
§ Object-Document マッピング§ Repository サポート§ Spring XML namespace (e.g. <mongo:XXX>)§ QueryDSLサポート§ JMX / Logging
1616
Spring Data MongoDB – Entity Mapping (1/3)
@Documentpublic class Customer {
@Idprivate BigInteger id;private String firstname, lastname;
@Field("email")@Indexed(unique = true)private EmailAddress emailAddress;private Set<Address> addresses = new HashSet<Address>();
public Customer(String firstname, String lastname) {Assert.hasText(firstname);Assert.hasText(lastname);
this.firstname = firstname;this.lastname = lastname;
}…}
1717
Spring Data MongoDB – Entity Mapping (2/3)public final class EmailAddress {
private static final String EMAIL_REGEX = “…";private static final Pattern PATTERN = Pattern.compile(EMAIL_REGEX);
@Field("email")private final String value;
public EmailAddress(String emailAddress) {Assert.isTrue(isValid(emailAddress), "Invalid email address!");this.value = emailAddress;
}… }
public class Address {private final String street, city, country;
public Address(String street, String city, String country) {Assert.hasText(street, "Street must not be null or empty!");…
this.street = street;this.city = city;this.country = country;
}… }
1818
Spring Data MongoDB – Entity Mapping (3/3)public void mongoSpring() throws Exception {
MongoMappingContext context = new MongoMappingContext();MongoDbFactory dbFactory = new SimpleMongoDbFactory(new Mongo(),
"database");MappingMongoConverter converter = new MappingMongoConverter(dbFactory,
context);Customer customer = new Customer("Tsuyoshi", "Miyake");customer.setEmailAddress(new EmailAddress("[email protected]"));customer.add(new Address("Minato-ku", "Tokyo", "Japan"));DBObject sink = new BasicDBObject();converter.write(customer, sink);System.out.println(sink.toString());
}
{ "_class" : "com.oreilly.springdata.mongodb.core.Customer”, "_id" : null ,"firstname" : "Tsuyoshi" ,"lastname" : "Miyake" ,"email" : { "email" : "[email protected]"} ,"addresses" : [ { "street" : "Minato-ku" , "city" : "Tokyo" , "country" : "Japan"}]}
1919
Spring Data Mongo – MongoTemplate使用法@AutowiredMongoTemplate template; // in AbstractMongoConfiguration (JavaConfig)
@Testpublic void mongoTemplate() throws Exception {
Customer customer = new Customer("Kirari", "Miyake");customer.setEmailAddress(new EmailAddress("[email protected]"));template.save(customer);
Query query = new Query(new
Criteria("emailAddress").is("[email protected]"));assertThat(template.findOne(query, Customer.class), is(customer));
}@Configuration@ComponentScan@EnableMongoRepositoriesclass ApplicationConfig extends AbstractMongoConfiguration {
@Overrideprotected String getDatabaseName() { return ”database”; }
@Overridepublic Mongo mongo() throws Exception {…}
… }
2020
Spring Data Mongo - Repositories
§ Spring Data Commons の Repository 同様• インタフェースの定義(のみ) & naming convention
2121
Spring Data Mongo – Repository 使用法
or @EnableMongoRepositories in JavaConfig
2222
Neo4j
§ グラフデータベース
§ DB はグラフのノード (nodes) と関連 (relationships) から成る• Nodes と relationships はプロパティーをもつ
§ Cypher Query Language § Indexes on node/relationship プロパティー§ Java で記述されている、アプリケーションへ組み込み可能• Also a REST API (Neo4j Server)
§ Transactional (ACID)
… 続きは http://neo4j.org/ で
2323
Neo4j データモデル
2424
Spring Data Neo4j
§ Neo4jTemplate• Neo4j 特有のオペレーションへのアクセス: get/create Node and Relationship,
query, traverse, fluent query Result handling• トランザクション管理• Exception translation to Spring’s DAO exception hierarchy• Also works via REST with Neo4jServer
§ アノテーションベースの Entity 定義(@NodeEntity/@RelationshipEntity..)§ Repository サポート§ Cypher query language§ Spring XML namespace (<neo4j:XXX>)§ Neo4j Server 統合
<bean id="graphDatabaseService" class="org.springframework.data.neo4j.rest.SpringRestGraphDatabase”
/>
2525
Classic Neo4j – Entity class
public class Person {
private final Node underlyingNode;
public Person(final Node node) {underlyingNode = node;
}
public Node getUnderlyingNode() {return underlyingNode;
}
public final String getName() {return (String) underlyingNode.getProperty(“name”);
}
public void setName(final String name) {underlyingNode.setProperty(“name”, name);
} }
2626
Spring Data Neo4j – Entity class
@NodeEntitypublic class Actor {
@Indexed // Neo4jTemplate.getOrCreateNode() etc. で利用可能private String id;
@Indexed(indexType=IndexType.FULLTEXT , indexName=“people")private String name;
public Person(String id, String name) {this.id = id;this.name = name;
}
public String getId() { return id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; } }
2727
Spring Data Neo4j – Entity class
@NodeEntitypublic class Movie {
@Indexedprivate String id;
@Indexed(indexType=IndexType.FULLTEXT , indexName=“search")private String title;
// Collection of other nodes@RelatedTo(type = "ACTS_IN", direction= INCOMING)private Set<Actor> actors;
// Collection of relationships (actor -> (rating) -> movie)@RelatedToVia(type = “RATED", direction= INCOMING)private Set<Rating> rating;
public Movie(String id, String title) {this.id = id;this.title = title;
}
// Getters and Setters omitted}
2828
Spring Data Neo4j - Repositories
§ Spring Data Commons の Repository 同様• インタフェースの定義(のみ) & naming convention
§ Support for• CRUD• IndexRepository (findAllByPropertyValue, findAllByQuery etc.)• TraversalRepository (findAllByTraversal)
public interface MovieRepository extends GraphRepository<Movie>, NamedIndexRepository<Movie>, RelationshipOperationsRepository<Movie> {
Movie findById(String id);Page<Movie> findByTitleLike(String title, Pageable page);@Query("start user=node({0}) " +
" match user-[r:RATED]->movie<-[r2:RATED]-other-[r3:RATED]->otherMovie " +" where r.stars >= 3 and r2.stars >= 3 and r3.stars >= 3 " +" return otherMovie, avg(r3.stars) " +" order by avg(r3.stars) desc, count(*) desc" +" limit 10")
List<MovieRecommendation> getRecommendations(User user);}
<neo4j:repositories base-package="org.neo4j.cineasts.repository"/>
2929
Spring Data Neo4j – Neo4jTemplate
public void setUp() throws Exception {dave = template.save(new Customer("Dave", "Matthews", "[email protected]"));template.save(new Customer("Carter","Beauford","[email protected]"));template.save(new Customer("Boyd","Tinsley","[email protected]"));final Country usa = template.save(new Country("US", "United States"));template.save(new Address("27 Broadway","New York",usa));iPad = template.save(new Product("iPad", "Apple tablet device")
.withPrice(BigDecimal.valueOf(499D)));mbp = template.save(new Product("MacBook Pro", "Apple notebook").withPrice(BigDecimal.valueOf(1299D)));
final Order order = new Order(dave);order.add(iPad,2);order.add(mbp,1);template.save(order);
}
3030
Redis
§ Advanced key-value store•軽量 & 高パフォーマンス (in-memory)• Values: binary strings, Lists, Sets, Ordered Sets, Hash maps, ..• データタイプごとの操作: e.g. list への追加 ([RL]PUSH), set への追加
(SADD), retrieving a slice of a list (LRANGE key start end), …•各操作がアトミック (e.g. INCR)
§ Very fast: ~100K operations/second on entry-level hardware§ 永続化対応
• Periodic snapshots (point-in-time)• Write コマンドのログファイルへの書き出し (append-based)
§ PUB/SUB§ トランザクション対応 (MULTI <-> EXEC)§ 多言語対応, all separate open source projects
… 続きは http://redis.io/ で
K1
K2
K3
V1
V2
V2
3131
Spring Data Redis
§ Redis ドライバに依存しない統一された API を提供§ RedisTemplate
• Redisの機能実装。各データタイプごとに専用のインタフェース• Value/Hash/Set/Zset/ListOperations• 名前は分かりやすいように変換: SETNX -> putIfAbsent()
• 自動で serialization と型変換を実施• Fluent query API
§ 非同期 Publish-Subscribe サポート with message listener containers§ JDK Atomic counters (AtomicLong etc.) backed by Redis§ Spring 3.1 Cache abstraction provider
3232
Spring Data Redis – RedisTemplate –型変換
<bean id="conFactory“ class="o.s.d.r.connection.jedis.JedisConnectionFactory"/><bean id=“template“ class="o.s.d.redis.core.StringRedisTemplate"
p:connection-factory-ref="conFactory"/>
@Beanpublic RedisTemplate<String, Long> longTemplate() {
RedisTemplate<String, Long> tmpl = new RedisTemplate<String, Long>();tmpl.setConnectionFactory( redisConnectionFactory() );tmpl.setValueSerializer(LongSerializer.INSTANCE);return tmpl;
}
public static enum LongSerializer implements RedisSerializer<Long> {INSTANCE;@Override public byte[] serialize( Long aLong ) throws SerializationException {
if ( null != aLong ) { return aLong.toString().getBytes(); }else { return new byte[0]; }
}
@Override public Long deserialize( byte[] bytes ) throws SerializationException {if ( bytes.length > 0 ) {
return Long.parseLong( new String( bytes ) );} else { return null; }
}}
3333
Spring Data Redis – RedisTemplate – アトミック操作
@Autowired RedisConnectionFactory connectionFactory;
@Test public void testAtomicCounters() {RedisAtomicLong counter = new RedisAtomicLong("spring-data-book:counter-
test:hits", connectionFactory, 0);Long l = counter.incrementAndGet();
assertThat(l, is(greaterThan(0L)));}
3434
Spring Data Redis – RedisTemplate – Pub/Sub
@Configurationpublic class PubSubConfig extends ApplicationConfig {public static final String DUMP_CHANNEL = ”pubsub-test:dump";
@Bean RedisMessageListenerContainer container() {RedisMessageListenerContainer container = new RedisMessageListenerContainer();container.setConnectionFactory(redisConnectionFactory());container.addMessageListener(dumpToConsoleListener(), new ChannelTopic(DUMP_CHANNEL));return container;
}
@Bean MessageListener dumpToConsoleListener() {return new MessageListener() {@Override public void onMessage(Message message, byte[] pattern) {System.out.println("FROM MESSAGE: " + new String(message.getBody()));
}};
}}
@Test public void testPubSubWithoutConversion() {RedisConnection redis = connectionFactory.getConnection();try {redis.publish( PubSubConfig.DUMP_CHANNEL.getBytes(), "Hello World!".getBytes() );
} finally { redis.close(); }}
3535
• 分散/メモリーベースのデータ管理プラットフォーム
• データトランザクションの多いアプリケーションに対し、可用性、高パフォーマンス、スケーラビリティを提供
• データの一貫性を場合に応じて調節可能(分散ロックのレベル)
• イベントドリブンなアーキテクチャ
… 続きはhttp://www.vmware.com/support/pubs/vfabric-gemfire.html で
GemFire – The Enterprise Data Fabric
JavaClient
C#Client
C++Client
3636
GemFire High Level アーキテクチャJavaClient
C#Client
C++Client クライアントは Cache を組
み込み可能 (with disk overflow)
物理的なサーバー群がひとつの
巨大な論理システムとしてみえる (DistributedSystem)
オブジェクトの変更がサブスクライバに伝達される
同期 R/W、非同期Write
データのパーティショニン
グ・レプリケーションはクライアントからは透過的に扱われる。
また、ストレージにメモリデータをバックアップ可能
動的にノードを追加可能
3737
• Cache がインメモリのストレージ、およびデータ管理を提供 (RDBMS でいうところの Database)
• XML (cache.xml) and/or API calls の組合せでCache を構成
• 複数の Regions から構成される
Cache / Region
z
Application
Region
Region
Region
Cache
Cache
• Region class は java.util.Map interface を実装• データの保存方法 (Replicated/Partition)や場所に依らず一貫した API を提供
• Region 内でキーは一意である必要がある Region
java.util.Map
Region
3838
• クライアントが distributed system に接続する方法としてGemFire server に(直接)、または “locator” 経由で接続する方法がある
• クライアントは独自にサーバーからのデータをローカルにコピー(キャッシュ)することが可能
• クライアントはサーバー側の変更に対し register 可能。その場合変更があった際にクライアントに通知されるようになる
Client Cache
Application
Application
Region
Region
Region
Cache
Client Cache
3939
• GemFire distributed system に接続、および Cache を生成するプロセス• Locator• Cacheserver (Cache 保持)• Agent
• 最小構成の GemFire プロセスは組み込みモードで実行される単一のノード
メンバー構成
Application
Region
Region
RegionCache
Application
Region
Region
RegionCache
Application
Region
Region
RegionCache
Application ApplicationApplication
4040
GemFire Topologies
Embedded
Peer-To-Peer
Client/Server
Multi-site/WAN Gateway
Topologies of GemFire
4141
Application
Region
Region
RegionCache
Application
Region
Region
RegionCache
Application
Region
Region
RegionCache
Topologies – Embedded / Peer to Peer
Application
Region
Region
RegionCache
4242
Topologies – Client-Server
ApplicationApplicationApplication
Application
Region
Region
Region
Cache
Application
Region
Region
Region
Cache
Application
Region
Region
Region
Cache
4343
Creating a Cache - XML
Application
Region
Cache
<?xml version="1.0"?><!DOCTYPE cache PUBLIC
"-//GemStone Systems, Inc.//GemFire Declarative Caching 6.6//EN"
"http://www.gemstone.com/dtd/cache6_6.dtd"><cache>
<region name="Customer” refid="REPLICATE" /></cache>
cache.xml
Load XML via JavaCache cache = new CacheFactory()
.set("cache-xml-file", "xml/cache.xml")
.create();Region<Integer, Customer> customers = cache.getRegion("Customer");
4444
Creating a Cache - API
Application
Region
Cache
// Create the cache without using a cache xml fileCache cache = new CacheFactory().create();
// Create a region dynamically using the APIsRegion<Integer, Customer> customers =
(Region<Integer, Customer>)cache.createRegionFactory().create("Customer”);
§ Classes in com.gemstone.gemfire.cache
§ Call cache.close() when done
4545
In gemfire.properties:
Setting startup parameters
log-level=warning
statistic-sampling-enabled=true
statistic-sample-rate=100
statistic-archive-file=/Users/myMac/myApp/stats1007.gfs
locators=localhost[41111],….
mcast-port=0
cache-xml-file=myCache.xml
§ 起動時に読み込まれる構成ファイル§ cache-xml を指定も可能
4646
Spring Data Gemfire
§ Spring namespace (gfe) を用いた Gemfireの構成§ cache.xml との比較
• Import, property placeholder, SpEL etc.
§ Declarative Transaction Management• gfe:transaction-manager -> region 操作が atomic に
§ Exception translation§ GemFireTemplate
• Connection/Transaction 管理の自動化• GemFire native APIにアクセス可能
§ Entity / PDX Mapping§ Repository サポート
4747
Spring Data Gemfire - Configuration
<gfe:cache /> // id=“gemfireCache”
<gfe:replicated-region id="simple" />
<gfe:partitioned-region id="complex" local-max-memory="20"><gfe:cache-listener>
<ref bean="c-listener"/><bean class="org.springframework.data.gemfire.SimpleCacheListener"/>
</gfe:cache-listener><gfe:cache-loader ref="c-loader"/><gfe:cache-writer ref="c-writer"/>
</gfe:partitioned-region>
<bean id="c-listener" class="org.springframework.data.gemfire.SimpleCacheListener"/><bean id="c-loader" class="org.springframework.data.gemfire.SimpleCacheLoader"/><bean id="c-writer" class="org.springframework.data.gemfire.SimpleCacheWriter"/>
§ 標準の Spring 機能 (property replacement, environment) を利用可能
4848
Spring Data Gemfire – Entity Mapping
@Region("myRegion")public class Person {
@Id BigInteger id; // Cache キー@Indexed String firstname;
@Transient String middleName; // persist されない
@PersistenceConstructor // コンストラクタの明示指定public Person(String firstname, String lastname) { … }
}
4949
Spring Data Gemfire - Repositories
interface PersonRepository extends CrudRepository<Person, BigInteger> {
// Finder for a single entityPerson findByEmailAddress(String emailAddress);
// Finder for multiple entitiesList<Person> findByLastnameLike(String lastname);
// Finder with manually defined query@Query("SELECT p FROM /Person p WHERE p.firstname = $1")List<Person> findByFirstname(String firstname);
}
5050
Spring Data Gemfire – Repositories<gf:repositories base-package="com.acme.repositories"/>
@Service
public class MySimpleService {@Autowired PersonRepository personRepository;
@Autowired AccountRepository accountRepository;
@Transactional
public List<Person> doSomething(Integer personId) {Person person = personRepository.findOne(personId);
List<Person> persons = accountRepository.findByPerson(person);}
}
public interface PersonRepository extends CrudRepository<Person, BigInteger> {
// Finder for a single entityPerson findByEmailAddress(String emailAddress);
// Finder for multiple entitiesList<Person> findByLastnameLike(String lastname);
// Finder with manually defined query (OQL)
@Query("SELECT p FROM /Person p WHERE p.firstname = $1")List<Person> findByFirstname(String firstname);
}
5151
Thank you!Q&A
@tsuyokb