Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Spring Data in a Nutshell

3,339 views

Published on

Published in: Technology
  • Be the first to comment

Spring Data in a Nutshell

  1. 1. © 2012 SpringSource, A division of VMware. All rights reserved Spring Data in a Nutshell Tsuyoshi Miyake (@tsuyokb)
  2. 2. 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 をなくす • 異なるテクノロジーをまたがって利用できる共通のインタフェース
  3. 3. 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
  4. 4. 44 Spring Data Repositories (1/3) public interface CrudRepository<T, ID extends Serializable> extends Repository<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> }
  5. 5. 55 Spring Data Repositories (2/3) public interface PagingAndSortingRepository<T, ID extends Serializable> extends CrudRepository<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 entity Person findByEmailAddress(String emailAddress); // Finder for a multiple entities List<Person> findByLastnameLike(String lastName); // Finder with pagination Page<Person> findByFirstnameLike(String firstName, Pageable page); }
  6. 6. 66 Spring Data Repositories (3/3) @NoRepositoryBean public 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 のベースに
  7. 7. 77 Spring Data JPA – Entity Mapping § インタフェースを定義するだけ: • PersonRepository の実装は Spring (Data) が提供 <jpa:repositories base-package="com.acme.repository" /> @Entity public class Person { @Id @GeneratedValue(strategy=GenerationType.AUTO) private BigInteger id; private String firstname, lastname; @Column(name="email") private String emailAddress; @OneToMany private Set<Person> colleagues; } @EnableJpaRepositoriesJavaConfig XML
  8. 8. 88 Spring Data JPA § transactional service layer (通常通り) @Service public class DefaultUserManagementService implements UserManagementService { public PersonRepository personRepository; public ShiftRepository shiftRepository; @Autowired public DefaultUserManagementService(PersonRepository personRepository, ShiftRepository shiftRepository) { this.personRepository = personRepository; this.shiftRepository = shiftRepository; } @Transactional public void assignToNightShift(String emailAddress) { Person person = personRepository.findByEmailAddress(emailAddress); // continue processing } }
  9. 9. 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); }
  10. 10. 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($);
  11. 11. 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));
  12. 12. 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" } ] }
  13. 13. 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()); } }
  14. 14. 1414 MongoDB Java API を使う (2/2) § Mongo クラスを使用 § サーバに関する詳細は隠蔽される § Insert / Update • (全ての)アプリケーション POJO -> DBObject にマップする必要あり • mongo.getDatabase(…).getCollection(…).insert(…) § クエリ • クエリを組み立て、 • mongo.getDatabase(…).getCollection(…).find(…) • カーソルを使って結果を iterate • DBObject -> アプリケーション POJO マップ(手動) è JDBC よりは抽象化されていそうだけど(繰り返しが多い) …
  15. 15. 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
  16. 16. 1616 Spring Data MongoDB – Entity Mapping (1/3) @Document public class Customer { @Id private 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; } … }
  17. 17. 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; } … }
  18. 18. 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("tmiyake@vmware.com")); 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" : "tmiyake@vmware.com"} , "addresses" : [ { "street" : "Minato-ku" , "city" : "Tokyo" , "country" : "Japan"}]}
  19. 19. 1919 Spring Data Mongo – MongoTemplate 使用法 @Autowired MongoTemplate template; // in AbstractMongoConfiguration (JavaConfig) @Test public void mongoTemplate() throws Exception { Customer customer = new Customer("Kirari", "Miyake"); customer.setEmailAddress(new EmailAddress("kirari.miyake@gmail.com")); template.save(customer); Query query = new Query( new Criteria("emailAddress").is("kirari.miyake@gmail.com")); assertThat(template.findOne(query, Customer.class), is(customer)); } @Configuration @ComponentScan @EnableMongoRepositories class ApplicationConfig extends AbstractMongoConfiguration { @Override protected String getDatabaseName() { return ”database”; } @Override public Mongo mongo() throws Exception {…} … }
  20. 20. 2020 Spring Data Mongo - Repositories § Spring Data Commons の Repository 同様 • インタフェースの定義(のみ) & naming convention
  21. 21. 2121 Spring Data Mongo – Repository 使用法 or @EnableMongoRepositories in JavaConfig
  22. 22. 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/ で
  23. 23. 2323 Neo4j データモデル
  24. 24. 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” />
  25. 25. 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); } }
  26. 26. 2626 Spring Data Neo4j – Entity class @NodeEntity public 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; } }
  27. 27. 2727 Spring Data Neo4j – Entity class @NodeEntity public class Movie { @Indexed private 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 }
  28. 28. 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"/>
  29. 29. 2929 Spring Data Neo4j – Neo4jTemplate public void setUp() throws Exception { dave = template.save(new Customer("Dave", "Matthews", "dave@dmband.com")); template.save(new Customer("Carter","Beauford","carter@dmband.com")); template.save(new Customer("Boyd","Tinsley","boyd@dmband.com")); 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); }
  30. 30. 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
  31. 31. 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
  32. 32. 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"/> @Bean public 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; } } }
  33. 33. 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))); }
  34. 34. 3434 Spring Data Redis – RedisTemplate – Pub/Sub @Configuration public 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(); } }
  35. 35. 3535 • 分散/メモリーベースのデータ管理プラットフォ ーム • データトランザクションの多いアプリケーション に対し、可用性、高パフォーマンス、スケーラビ リティを提供 • データの一貫性を場合に応じて調節可能(分散 ロックのレベル) • イベントドリブンなアーキテクチャ … 続きは http://www.vmware.com/support/pubs/vfabri c-gemfire.html で GemFire – The Enterprise Data Fabric Java Client C# Client C++ Client
  36. 36. 3636 GemFire High Level アーキテクチャ Java Client C# Client C++ Client クライアントは Cache を組 み込み可能 (with disk overflow) 物理的なサーバー群がひとつの 巨大な論理システムとしてみえ る (DistributedSystem) オブジェクトの変更がサブス クライバに伝達される 同期 R/W、非同期 Write データのパーティショニン グ・レプリケーションはクライ アントからは透過的に扱わ れる。 また、ストレージにメモリデ ータをバックアップ可能 動的にノードを追加可能
  37. 37. 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
  38. 38. 3838 • クライアントが distributed system に接続する方法としてGemFire server に(直接)、 または “locator” 経由で接続する方法がある • クライアントは独自にサーバーからのデータをローカルにコピー(キャッシュ)すること が可能 • クライアントはサーバー側の変更に対し register 可能。その場合変更があった際にク ライアントに通知されるようになる Client Cache Application Application Region Region Region Cache Client Cache
  39. 39. 3939 • GemFire distributed system に接続、および Cache を生成するプロセス • Locator • Cacheserver (Cache 保持) • Agent • 最小構成の GemFire プロセスは組み込みモードで実行される単一のノード メンバー構成 Application Region Region Region Cache Application Region Region Region Cache Application Region Region Region Cache Application ApplicationApplication
  40. 40. 4040 GemFire Topologies Embedded Peer-To-Peer Client/Server Multi-site/WAN Gateway Topologies of GemFire
  41. 41. 4141 Application Region Region Region Cache Application Region Region Region Cache Application Region Region Region Cache Topologies – Embedded / Peer to Peer Application Region Region Region Cache
  42. 42. 4242 Topologies – Client-Server ApplicationApplicationApplication Application Region Region Region Cache Application Region Region Region Cache Application Region Region Region Cache
  43. 43. 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 Java Cache cache = new CacheFactory() .set("cache-xml-file", "xml/cache.xml") .create(); Region<Integer, Customer> customers = cache.getRegion("Customer");
  44. 44. 4444 Creating a Cache - API Application Region Cache // Create the cache without using a cache xml file Cache cache = new CacheFactory().create(); // Create a region dynamically using the APIs Region<Integer, Customer> customers = (Region<Integer, Customer>)cache.createRegionFactory() .create("Customer”); § Classes in com.gemstone.gemfire.cache § Call cache.close() when done
  45. 45. 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 を指定も可能
  46. 46. 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 サポート
  47. 47. 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) を利用可能
  48. 48. 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) { … } }
  49. 49. 4949 Spring Data Gemfire - Repositories interface PersonRepository extends CrudRepository<Person, BigInteger> { // Finder for a single entity Person findByEmailAddress(String emailAddress); // Finder for multiple entities List<Person> findByLastnameLike(String lastname); // Finder with manually defined query @Query("SELECT p FROM /Person p WHERE p.firstname = $1") List<Person> findByFirstname(String firstname); }
  50. 50. 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 entity Person findByEmailAddress(String emailAddress); // Finder for multiple entities List<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); }
  51. 51. 5151 Thank you! Q&A @tsuyokb

×