Introdução ao Spring Data Couchbase
*1. Introdução *
Neste tutorial sobre Spring Data, discutiremos como configurar uma camada de persistência para documentos do Couchbase usando as abstrações de modelo e repositório do Spring Data, bem como as etapas necessárias para preparar o Couchbase para suportar essas abstrações usando visualizações e/ou índices .
===* 2. Dependências do Maven *
Primeiro, adicionamos a seguinte dependência do Maven ao nosso arquivo pom.xml:
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-couchbase</artifactId>
<version>2.0.0.RELEASE</version>
</dependency>
Observe que, ao incluir essa dependência, obtemos automaticamente uma versão compatível do SDK do Couchbase nativo, portanto, não precisamos incluí-la explicitamente.
Para adicionar suporte à validação de bean JSR-303, também incluímos a seguinte dependência:
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.2.4.Final</version>
</dependency>
O Spring Data Couchbase suporta persistência de data e hora através das classes tradicionais Data e Calendário, bem como através da biblioteca Joda Time, que incluímos da seguinte forma:
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.9.2</version>
</dependency>
===* 3. Configuração *
Em seguida, precisaremos configurar o ambiente do Couchbase especificando um ou mais nós do cluster do Couchbase e o nome e a senha do bucket no qual armazenaremos nossos documentos.
====* 3.1 Configuração Java *
Para a configuração da classe Java, simplesmente estendemos a classe AbstractCouchbaseConfiguration:
@Configuration
@EnableCouchbaseRepositories(basePackages={"org..spring.data.couchbase"})
public class MyCouchbaseConfig extends AbstractCouchbaseConfiguration {
@Override
protected List<String> getBootstrapHosts() {
return Arrays.asList("localhost");
}
@Override
protected String getBucketName() {
return "";
}
@Override
protected String getBucketPassword() {
return "";
}
}
Se seu projeto exigir mais personalização do ambiente do Couchbase, você poderá fornecer um substituindo o método _getEnvironment () _:
@Override
protected CouchbaseEnvironment getEnvironment() {
...
}
====* 3.2 Configuração XML *
Aqui está a configuração equivalente em XML:
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/data/couchbase
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/data/couchbase
http://www.springframework.org/schema/data/couchbase/spring-couchbase.xsd">
<couchbase:cluster>
<couchbase:node>localhost</couchbase:node>
</couchbase:cluster>
<couchbase:clusterInfo login="" password=""/>
<couchbase:bucket bucketName="" bucketPassword=""/>
<couchbase:repositories base-package="org..spring.data.couchbase"/>
</beans:beans>
Nota: o nó "clusterInfo" aceita credenciais de cluster ou de bucket e é* obrigatório *para que a biblioteca possa determinar se o cluster do Couchbase suporta ou não o N1QL (um superconjunto de bancos de dados SQL para NoSQL, disponível no Couchbase 4.0 e posterior).
Se o seu projeto exigir um ambiente Couchbase personalizado, você poderá fornecer um usando a tag _ <couchbase: env/> _.
===* 4. Modelo de dados *
Vamos criar uma classe de entidade representando o documento JSON para persistir. Primeiro, anotamos a classe com _ @ Document, _ e, em seguida, anotamos um campo String com _ @ Id_ para representar a chave do documento do Couchbase.
Você pode usar a anotação _ @ Id_ do Spring Data ou a anotação nativa do Couchbase SDK. Lembre-se de que se você usar as duas anotações _ @ Id_ na mesma classe em dois campos diferentes, o campo anotado com a anotação Spring Data _ @ Id_ terá precedência e será usado como a chave do documento.
Para representar os atributos dos documentos JSON, adicionamos variáveis de membro privadas anotadas com _ @ Field_. Usamos a anotação _ @ NotNull_ para marcar determinados campos conforme necessário:
@Document
public class Person {
@Id
private String id;
@Field
@NotNull
private String firstName;
@Field
@NotNull
private String lastName;
@Field
@NotNull
private DateTime created;
@Field
private DateTime updated;
//standard getters and setters
}
Observe que a propriedade anotada com _ @ Id_ representa apenas a chave do documento e não faz necessariamente parte do documento JSON armazenado, a menos que também seja anotada com _ @ Field_ como em:
@Id
@Field
private String id;
Se você deseja nomear um campo na classe de entidade diferente do que deve ser armazenado no documento JSON, simplesmente qualifique sua anotação _ @ Field_, como neste exemplo:
@Field("fname")
private String firstName;
Aqui está um exemplo mostrando como seria um documento Person persistente:
{
"firstName": "John",
"lastName": "Smith",
"created": 1457193705667
"_class": "org..spring.data.couchbase.model.Person"
}
Observe que o Spring Data adiciona automaticamente a cada documento um atributo que contém o nome completo da classe da entidade. Por padrão, esse atributo é denominado _ “_ class” _, embora você possa substituí-lo na sua classe de configuração do Couchbase, substituindo o método _typeKey () _.
Por exemplo, se você deseja designar um campo chamado _ “dataType” _ para conter os nomes das classes, adicione-o à sua classe de configuração do Couchbase:
@Override
public String typeKey() {
return "dataType";
}
Outro motivo popular para substituir _typeKey () _ é se você estiver usando uma versão do Couchbase Mobile que não suporta campos prefixados com o sublinhado. Nesse caso, você pode escolher seu próprio campo de tipo alternativo, como no exemplo anterior, ou usar uma alternativa fornecida pelo Spring:
@Override
public String typeKey() {
//use "javaClass" instead of "_class"
return MappingCouchbaseConverter.TYPEKEY_SYNCGATEWAY_COMPATIBLE;
}
===* 5. Repositório do Couchbase *
O Spring Data Couchbase fornece as mesmas consultas internas e mecanismos de consulta derivados que outros módulos do Spring Data, como o JPA.
Declaramos uma interface de repositório para a classe Person estendendo _CrudRepository <String, Person> _ e adicionando um método de consulta derivável:
public interface PersonRepository extends CrudRepository<Person, String> {
List<Person> findByFirstName(String firstName);
}
===* 6. Suporte ao N1QL via índices *
Se você estiver usando o Couchbase 4.0 ou posterior, por padrão, as consultas personalizadas serão processadas usando o mecanismo N1QL (a menos que seus métodos de repositório correspondentes sejam anotados com _ @ View_ para indicar o uso de visualizações de backup, conforme descrito na próxima seção).
Para adicionar suporte ao N1QL, você deve criar um índice primário no bucket. Você pode criar o índice usando o processador de consulta da linha de comando cbq (consulte a documentação do Couchbase sobre como iniciar a ferramenta cbq para o seu ambiente) e emitindo o seguinte comando:
CREATE PRIMARY INDEX ON USING GSI;
No comando acima, GSI significa global secundário index, que é um tipo de índice particularmente adequado para otimização de consultas N1QL ad hoc no suporte a sistemas OLTP e é o tipo de índice padrão, se não especificado de outra forma.
Diferentemente dos índices baseados em exibição, os índices GSI não são replicados automaticamente em todos os nós de índice em um cluster; portanto, se seu cluster contiver mais de um nó de índice, será necessário criar cada índice GSI em cada nó do cluster e você deverá fornecer um nome de índice diferente em cada nó.
Você também pode criar um ou mais índices secundários. Ao fazê-lo, o Couchbase os utilizará conforme necessário para otimizar o processamento de consultas.
Por exemplo, para adicionar um índice no campo firstName, emita o seguinte comando na ferramenta cbq:
CREATE INDEX idx_firstName ON (firstName) USING GSI;
===* 7. Visualizações de backup *
Para cada interface de repositório, você precisará criar um documento de design do Couchbase e uma ou mais visualizações no bucket de destino. O nome do documento de design deve ser a versão lowerCamelCase do nome da classe da entidade (por exemplo, "pessoa").
Independentemente da versão do Couchbase Server em execução, você deve criar uma exibição de apoio denominada _ “all” _ para suportar o método de repositório interno “findAll” _. Aqui está a função de mapa para a visualização _ "all" _ da nossa classe _Person:
function (doc, meta) {
if(doc._class == "org..spring.data.couchbase.model.Person") {
emit(meta.id, null);
}
}
Cada método de repositório personalizado deve ter uma visualização de backup ao usar uma versão do Couchbase anterior à 4.0 (o uso de visualizações de backup é opcional na 4.0 ou posterior).
Os métodos personalizados com suporte à exibição devem ser anotados com _ @ View_, como no exemplo a seguir:
@View
List<Person> findByFirstName(String firstName);
A convenção de nomenclatura padrão para as visualizações de backup é usar a versão lowerCamelCase dessa parte do nome do método após a palavra-chave "_find" _ (por exemplo, _ “ByFirstName” _).
Aqui está como você escreveria a função map para a visualização _ "byFirstName" _:
function (doc, meta) {
if(doc._class == "org..spring.data.couchbase.model.Person"
&& doc.firstName) {
emit(doc.firstName, null);
}
}
Você pode substituir esta convenção de nomenclatura e usar seus próprios nomes de visualização, qualificando cada anotação _ @ View_ com o nome da visualização de suporte correspondente. Por exemplo:
@View("myCustomView")
List<Person> findByFirstName(String lastName);
===* 8. Camada de serviço *
Para nossa camada de serviço, definimos uma interface e duas implementações: uma usando a abstração do repositório Spring Data e outra usando a abstração do modelo Spring Data. Aqui está nossa interface PersonService:
public interface PersonService {
Person findOne(String id);
List<Person> findAll();
List<Person> findByFirstName(String firstName);
void create(Person person);
void update(Person person);
void delete(Person person);
}
8.1. Serviço de Repositório*
Aqui está uma implementação usando o repositório que definimos acima:
@Service
@Qualifier("PersonRepositoryService")
public class PersonRepositoryService implements PersonService {
@Autowired
private PersonRepository repo;
public Person findOne(String id) {
return repo.findOne(id);
}
public List<Person> findAll() {
List<Person> people = new ArrayList<Person>();
Iterator<Person> it = repo.findAll().iterator();
while(it.hasNext()) {
people.add(it.next());
}
return people;
}
public List<Person> findByFirstName(String firstName) {
return repo.findByFirstName(firstName);
}
public void create(Person person) {
person.setCreated(DateTime.now());
repo.save(person);
}
public void update(Person person) {
person.setUpdated(DateTime.now());
repo.save(person);
}
public void delete(Person person) {
repo.delete(person);
}
}
8.2. Serviço de modelo *
Para a implementação baseada em modelo, devemos criar as visualizações de backup listadas na seção 7 acima. O objeto CouchbaseTemplate está disponível em nosso contexto Spring e pode ser injetado na classe de serviço.
Aqui está a implementação usando a abstração do modelo:
@Service
@Qualifier("PersonTemplateService")
public class PersonTemplateService implements PersonService {
private static final String DESIGN_DOC = "person";
@Autowired
private CouchbaseTemplate template;
public Person findOne(String id) {
return template.findById(id, Person.class);
}
public List<Person> findAll() {
return template.findByView(ViewQuery.from(DESIGN_DOC, "all"), Person.class);
}
public List<Person> findByFirstName(String firstName) {
return template.findByView(ViewQuery.from(DESIGN_DOC, "byFirstName"), Person.class);
}
public void create(Person person) {
person.setCreated(DateTime.now());
template.insert(person);
}
public void update(Person person) {
person.setUpdated(DateTime.now());
template.update(person);
}
public void delete(Person person) {
template.remove(person);
}
}
===* 9. Conclusão*
Mostramos como configurar um projeto para usar o módulo Spring Data Couchbase e como escrever uma classe de entidade simples e sua interface de repositório. Escrevemos uma interface de serviço simples e fornecemos uma implementação usando o repositório e outra implementação usando a API do modelo Spring Data.
Você pode visualizar o código fonte completo deste tutorial em o projeto GitHub.
Para obter mais informações, visite o site do projeto Spring Data Couchbase.