spring data

23
M.C. Kang

Upload: -

Post on 15-Jan-2015

719 views

Category:

Technology


3 download

DESCRIPTION

spring data repository

TRANSCRIPT

Page 1: Spring data

M.C. Kang

Page 2: Spring data

Overview Spring Data is a high level SpringSource

project whose purpose is to unify and ease

the access to different kinds of persistence

stores, both relational database systems

and NoSQL data stores.

Source http://www.infoq.com/articles/spring-data-intro

Spring Data projects support the followings aspects:

Templating

Object/Datastore mapping

Repository support

Page 3: Spring data

Overview - Templates

The main purpose of a Spring Data template (and all other Spring templates) is resource

allocation and exception translation.

A template offers store specific operations like saving, updating and deleting a single record or

for executing queries or map/reduce jobs. But all these methods work only for the corresponding

underlying datastore.

MongoDb Template Configuration Example

<!-- Connection to MongoDB server -->

<mongo:db-factory host="localhost" port="27017" dbname="test" />

<!-- MongoDB Template -->

<bean id="mongoTemplate“

class="org.springframework.data.mongodb.core.MongoTemplate">

<constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>

</bean>

Page 4: Spring data

Overview - Object/Datastore Mapping

With Spring Data, this support is extended to NoSQL datastores with object-like data

structures. But these data structures can be quite different from each other, so it would be

difficult to make up a common API for object/datastore mapping. Each type of datastore

comes with its own set of annotations to provide the needed meta information for the

mapping.

@Entity

@Table(name="TUSR")

public class User {   

@Id   private String id;

@Column(name="fn")   private String name;   

private Date lastLogin;

...

}

@Document( collection="usr")

public class User {   

@Id   private String id;   

@Field("fn")   private String name;   

private Date lastLogin;

 ...

}

@NodeEntity

public class User {   

@GraphId   Long id;  

 private String name;   

private Date lastLogin;

...

}

JPA MongoDB Neo4j

Page 5: Spring data

Overview - Repository Support

generic support for CRUD and paging , sorting by providing special parameters to the finder

methods for all persistence stores

The main advantages of repository support are:

The developer writes a lot less boilerplate code

Queries can by defined alongside the finder method and its documentation

As a bonus, the JPQL queries are compiled as soon as the Spring context is assembled, not

the first time you use the query, which makes it easier to detect syntax errors

Page 6: Spring data

Data Model

Customer Address

CREATE TABLE customer ( id BIGINT IDENTITY PRIMARY KEY, firstname VARCHAR(255), lastname VARCHAR(255), email_address VARCHAR(255));

CREATE UNIQUE INDEX ix_customer_email ON CUSTOMER (email_address ASC);

CREATE TABLE address ( id BIGINT IDENTITY PRIMARY KEY, customer_id BIGINT CONSTRAINT address_customer_ref REFERENCES customer (id), street VARCHAR(255), city VARCHAR(255), country VARCHAR(255));

Domain Model

<<Entity>>

Customer

<<Entity>>

Address

<<Embeddable>

>

EmailAddress

<<MappedSuperClass>>

AbstractEntity

Step1. “Define Domain Model”

Page 7: Spring data

AbstractEntity@MappedSuperclasspublic class AbstractEntity {

@Id@GeneratedValue(strategy = GenerationType.AUTO)private Long id;

public Long getId() {return id;

}

public boolean equals(Object obj) {if (this == obj) {return true;}

if (this.id == null || obj == null || !(this.getClass().equals(obj.getClass()))) {

return false;}

AbstractEntity that = (AbstractEntity) obj;

return this.id.equals(that.getId());}

public int hashCode() {return id == null ? 0 : id.hashCode();

}}

Customer@Entitypublic class Customer extends AbstractEntity {

private String firstname, lastname;

@Column(unique = true)private EmailAddress emailAddress;

@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)@JoinColumn(name = "customer_id")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;

}

protected Customer() {

}

public void add(Address address) {

Assert.notNull(address);this.addresses.add(address);

}…

Step1. “Define Domain Model”

@MappedSuperclass to express that it is not a managedentity class on its own but rather will be extended by entity classes.

If there were demand to customize the names of the columns to which the properties would be persisted, you could use the @Column annotation.

Page 8: Spring data

Address@Entitypublic class Address extends AbstractEntity {

private String street, city, country;

public Address(String street, String city, String country) {

Assert.hasText(street, "Street must not be null or empty!");Assert.hasText(city, "City must not be null or empty!");Assert.hasText(country, "Country must not be null or empty!");

this.street = street;this.city = city;this.country = country;

}

protected Address() {

} …

EmailAddress@Embeddablepublic class EmailAddress {

@Column(name = "email_address")private String value;

public EmailAddress(String emailAddress) {Assert.isTrue(isValid(emailAddress), "Invalid email address!");this.value = emailAddress;

}

protected EmailAddress() {

}…

public interface CustomerRepository extends CrudRepository<Customer, Long> {

Customer findByEmailAddress(EmailAddress emailAddress);Customer findById(Long id);List<Customer> findAll();

}

CustomerRepository

Step1. “Define Domain Model”

Step2. “Define Repository Interface”

-Just only interface

the EmailAddress class is an @Embeddable, which will cause the persistence provider to flatten out all properties of it into the table of the surrounding class.

Page 9: Spring data

@Configuration@EnableTransactionManagement@ComponentScan@EnableJpaRepositoriespublic class InfrastructureConfig {

@Beanpublic DataSource dataSource() {

return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.HSQL).addScript("classpath:sql/schema.sql").addScript("classpath:sql/test-data.sql").build();

}

@Beanpublic LocalContainerEntityManagerFactoryBean entityManagerFactory() {

HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();vendorAdapter.setDatabase(Database.HSQL);//vendorAdapter.setGenerateDdl(true);vendorAdapter.setShowSql(true);LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();factory.setJpaVendorAdapter(vendorAdapter);factory.setPackagesToScan(getClass().getPackage().getName());factory.setDataSource(dataSource());return factory;

}

@Beanpublic PlatformTransactionManager transactionManager() {

JpaTransactionManager txManager = new JpaTransactionManager();txManager.setEntityManagerFactory(entityManagerFactory().getObject());return txManager;

}}

SpringConfig

Step3. “Configure Spring Beans”

Page 10: Spring data

@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(classes = { TestConfig.class })@Transactional@DirtiesContextpublic class TestMain {

@AutowiredCustomerRepository repository;

@AutowiredDataSource dataSource;

@Testpublic void testFindAll() {List<Customer> results = repository.findAll();assertThat(results, is(notNullValue()));assertThat(results, hasSize(3));assertThat(results.get(0), notNullValue());assertThat(results.get(1), notNullValue());assertThat(results.get(2), notNullValue());}

@Testpublic void testFindById() {Customer result = repository.findOne(100L);assertThat(result, is(notNullValue()));assertThat(result.getFirstname(), is("John"));}

@Testpublic void testFindByEmail() {Customer result = repository.findByEmailAddress(new EmailAddress("[email protected]"));assertThat(result, is(notNullValue()));assertThat(result.getFirstname(), is("Bob"));}

TestCase@Testpublic void saveNewCustomer() {Customer c = new Customer();//c.setFirstname("Sven");c.setLastname("Svensson");c.setEmailAddress(new EmailAddress("[email protected]"));Address a = new Address("Storgaten 6", "Trosa", "Sweden");c.add(a);repository.save(c);System.out.println(repository.findAll());Customer result = repository.findOne(c.getId());assertThat(result, is(notNullValue()));//assertThat(result.getFirstName(), is("Sven"));assertThat(result.getEmailAddress().toString(), is(notNullValue()));}

@Test(expected = DataIntegrityViolationException.class)public void saveNewCustomerWithDuplicateEmail() {Customer c = new Customer("Bob","Doe");c.setEmailAddress(new EmailAddress("[email protected]"));Address a = new Address("66 Main St", "Middletown", "USA");c.add(a);repository.save(c);}

@Testpublic void deleteCustomer() {Customer c = repository.findOne(100L);repository.delete(c);Customer result = repository.findOne(100L);assertThat(result, is(nullValue()));}

}

Step4. “Test it…”

Page 11: Spring data

Document Model

Customer

(*)Address

{ firstname : "Dave", lastname : "Matthews", email : { email : "[email protected]" }, addresses : [ { street : "Broadway", city : "New York", country : "United States" } ]}

Domain Model

<<Document>

>

Customer

<<Entity>>

Address

<<Embeddable>

>

EmailAddress

AbstractDocument

Step1. “Define Domain Model”

Email

Page 12: Spring data

AbstractDocumentpublic class AbstractDocument {

@Idprivate BigInteger id;

public BigInteger getId() {return id;

}

public boolean equals(Object obj) {

if (this == obj) {return true;}

if (this.id == null || obj == null || !(this.getClass().equals(obj.getClass()))) {return false;}

AbstractDocument that = (AbstractDocument) obj;

return this.id.equals(that.getId());}

public int hashCode() {return id == null ? 0 : id.hashCode();

}}

Customer@Documentpublic class Customer extends AbstractDocument {

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;}

protected Customer() {

}…

Step1. “Define Domain Model”

Page 13: Spring data

Addresspublic 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!");Assert.hasText(city, "City must not be null or empty!");Assert.hasText(country, "Country must not be null or empty!");

this.street = street;this.city = city;this.country = country;

} …

EmailAddresspublic class EmailAddress {

@Field("email")private final String value;

public EmailAddress(String emailAddress) {Assert.isTrue(isValid(emailAddress), "Invalid email address!");this.value = emailAddress;

}

protected EmailAddress() {

}…

public interface CustomerRepository extends CrudRepository<Customer, Long> {

Customer findByEmailAddress(EmailAddress emailAddress);Customer findById(Long id);List<Customer> findAll();

}

CustomerRepository

Step1. “Define Domain Model”

Step2. “Define Repository Interface”

-Just only interface

Page 14: Spring data

@Configuration@ComponentScan@EnableMongoRepositories(basePackages="com.mckang.springdata.mongo")class ApplicationConfig extends AbstractMongoConfiguration {

@Autowiredprivate List<Converter<?, ?>> converters;

protected String getDatabaseName() {return "e-store";

}

public Mongo mongo() throws Exception {

Mongo mongo = new Mongo("127.0.0.1");mongo.setWriteConcern(WriteConcern.FSYNC_SAFE);

return mongo;}

public CustomConversions customConversions() {return new CustomConversions(converters);

}

protected String getMappingBasePackage() {return "com.mckang.springdata.mongo";

}}

SpringConfig

Step3. “Configure Spring Beans”

Page 15: Spring data

@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(classes = { TestConfig.class })@Transactional@DirtiesContextpublic class TestMain {

@AutowiredCustomerRepository repository;

@AutowiredDataSource dataSource;

@Testpublic void testFindAll() {

List<Customer> results = repository.findAll();assertThat(results, is(notNullValue()));assertThat(results, hasSize(3));assertThat(results.get(0), notNullValue());assertThat(results.get(1), notNullValue());assertThat(results.get(2), notNullValue());

}

@Testpublic void testFindById() {

Customer result = repository.findOne(100L);assertThat(result, is(notNullValue()));assertThat(result.getFirstname(), is("John"));

}

@Testpublic void testFindByEmail() { Customer result = repository.findByEmailAddress(new EmailAddress("[email protected]"));}

TestCase@Testpublic void saveNewCustomer() {

Customer c = new Customer();//c.setFirstname("Sven");c.setLastname("Svensson");c.setEmailAddress(new EmailAddress("[email protected]"));Address a = new Address("Storgaten 6", "Trosa", "Sweden");c.add(a);repository.save(c);

}

@Test(expected = DataIntegrityViolationException.class)public void saveNewCustomerWithDuplicateEmail() {

Customer c = new Customer("Bob","Doe");c.setEmailAddress(new EmailAddress("[email protected]"));Address a = new Address("66 Main St", "Middletown", "USA");c.add(a);repository.save(c);

}

@Testpublic void deleteCustomer() {

Customer c = repository.findOne(100L);repository.delete(c);

}

}

Step4. “Test it…”(Need Fixture…)

Page 16: Spring data

Graph Database

Neo4j is the leading implementation of a property graph database. It is written predominantly in

Java and leverages a custom storage format and the facilities of the Java Transaction Architecture

(JTA) to provide XA transactions.

Neo4j integrates a transactional, pluggable indexing subsystem that uses Lucene as the

default. The index is used primarily to locate starting points for traversals. Its second use is to

support unique entity creation.

Page 17: Spring data

Cypher statement

With the declarative Cypher query language, Neo4j makes it easier to get started for everyone

who knows SQL from working with relational databases.

enabling users to define sophisticated queries like “find me all the customers who have friends

who have recently bought similar products.”

Like other query languages, it supports filtering, grouping, and paging. Cypher allows easy

creation, deletion, update, and graph construction.

Page 18: Spring data
Page 19: Spring data

Graph Model Domain Model

<<NodeEntity>

>

Customer

<<NodeEntity>

>

Address

EmailAddress

AbstractEntity

Step1. “Define Domain Model”

Customer

Address

Address

Page 20: Spring data

AbstractDocumentpublic abstract class AbstractEntity {

@GraphIdprivate Long id;

public Long getId() {return id;

}

@Overridepublic boolean equals(Object obj) {

if (this == obj) {return true;

}

if (id == null || obj == null || !getClass().equals(obj.getClass())) { return false;} return id.equals(((AbstractEntity) obj).id);

}

@Overridepublic int hashCode() {

return id == null ? 0 : id.hashCode();}

}

Customer@NodeEntitypublic class Customer extends AbstractEntity {

private String firstName, lastName;

@Indexed(unique = true)private String emailAddress;

@RelatedTo(type = "ADDRESS")private Set<Address> addresses = new HashSet<Address>();

public Customer(String firstName, String lastName, String emailAddress) {

Assert.hasText(firstName); Assert.hasText(lastName); Assert.hasText(emailAddress);

this.firstName = firstName; this.lastName = lastName; this.emailAddress = emailAddress;}

protected Customer() {

} …

Step1. “Define Domain Model”

Page 21: Spring data

Address@NodeEntitypublic class Address extends AbstractEntity {

private String street, city;

public Address(String street, String city) {this.street = street;this.city = city;

}

public Address() {

} …

EmailAddresspublic class EmailAddress {

private final String value;

public EmailAddress(String emailAddress) {Assert.isTrue(isValid(emailAddress), "Invalid email address!");this.value = emailAddress;

}

protected EmailAddress() {

}…

public interface CustomerRepository extends GraphRepository<Customer> {

Customer findOne(Long id);

<C extends Customer> C save(C customer);

Customer findByEmailAddress(String emailAddress);}

CustomerRepository

Step1. “Define Domain Model”

Step2. “Define Repository Interface”

-Just only interface

Page 22: Spring data

@Configuration@ComponentScan@ImportResource("classpath:META-INF/spring/spring-data-context.xml")@EnableTransactionManagementclass ApplicationConfig {

@Bean(destroyMethod = "shutdown")public GraphDatabaseService graphDatabaseService() {

//return new EmbeddedGraphDatabase("target/graph.db");return new SpringRestGraphDatabase("http://localhost:7474/db/data");

}}

SpringConfig

Step3. “Configure Spring Beans”

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:neo4j="http://www.springframework.org/schema/data/neo4j" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/data/neo4j http://www.springframework.org/schema/data/neo4j/spring-neo4j-2.0.xsd">

<!--neo4j:config storeDirectory="target/graph.db" /--><neo4j:config graphDatabaseService="graphDatabaseService" /><neo4j:repositories base-package="com.mckang.springdata.neo4j" />

</beans>

Page 23: Spring data

@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(classes = { TestConfig.class })public class TestMain {

@AutowiredCustomerRepository repository;

@AutowiredDataSource dataSource;

@Testpublic void savesCustomerCorrectly() {

EmailAddress email = new EmailAddress("[email protected]");Customer alicia = new Customer("Alicia", "Keys",email.getEmail()); // todoalicia.add(new Address("27 Broadway", "New York"));Customer result = repository.save(alicia);assertThat(result.getId(), is(notNullValue()));}

@Testpublic void readsCustomerByEmail() {

EmailAddress email = new EmailAddress("[email protected]");Customer alicia = new Customer("Alicia", "Keys",email.getEmail());repository.save(alicia);Customer result = repository.findByEmailAddress(email.getEmail());assertThat(result, is(alicia));}

TestCase

@Testpublic void preventsDuplicateEmail() {

final EmailAddress email = new EmailAddress("[email protected]"); Customer dave = repository.findByEmailAddress(email.getEmail()); Customer anotherDave = new Customer("Dave", "Matthews",dave.getEmailAddress()); repository.save(anotherDave);}

}

Step4. “Test it…”(Need Fixture…)