Deep Dive into Spring Data and MongoDB

MongoBD是最流行的nosql数据库之一:我们如何开始?
本文将探讨面向文档的建模、SpringDataMongoDB框架的特性以及在生产中使用该堆栈所学到的经验。
关于作者
Fabiano Modos
Software Architect/Developer with more than 10 of years experience, developing frameworks, startup projects and critical system for enterprises. So far my biggest learning in the IT area is that there are Black Swan everywhere.

展开查看详情

1. Deep Dive into Spring Data and MongoDB Fabiano Guizellini Modos Software Architect at HBSIS @fmodos

2.I Java and MongoDB

3.Why do I love Java? • Learned Object Oriented Programming • Design Patterns, Clean Code, Unit Test • Saved me from Programming in Delphi

4.Why do I love MongoDB? • Save complex Objects in an easy way • No more relational database commands: Create table, Alter Table, etc.. • Open Source

5. It is not only a Story ...run this in Production in 3 critical systems

6. ~5k Suppliers Invoice Daily Order ~4M Events Daily Validate Suppliers Invoice >10M DB Ops/Daily Invoice Order >100k Sales Invoices Daily Supermarket >500k Events Daily Sales Invoice >10M DB Ops/Daily Invoice Supermarket Transport Invoice ~35k Transport Invoice Daily Deliver ~300k Events Daily >1M DB Ops/Daily

7.Why did we use MongoDB? • Complex documents and events • High Concurrency System

8.Why did we use MongoDB? • Complex documents and events • High Concurrency System

9.Relational Database? SQL? SQL NOSQL

10.“Different databases are designed to solve different problems. Using a single database engine for all of the requirements usually leads to non- performant solutions” ― Pramod J. Sadalage, NoSQL Distilled: A Brief Guide to the Emerging World of Polyglot Persistence “Complex applications combine different types of problems, so picking the right language for each job may be more productive than trying to fit all aspects into a single language.” ― Pramod J. Sadalage, NoSQL Distilled: A Brief Guide to the Emerging World of Polyglot Persistence

11.Case Study – Food Recipe System • Users should be able to create Dish with a name, description and list of ingredientes • Users should be able to add Comments to the Dish. Class Diagram Table Diagram (SQL) Document Diagram (NoSQL)

12.Create SQL NoSQL INSERT INTO dish (name) db.getCollection(‘Dish’).save({name: “White Rice” VALUES (“White Rice”) ingredients : [“rice”, “garlic”], comments : Array[ INSERT INTO ingredient (name, dish_id) { VALUES (“rice”, 1) text : ‘This rice is really good’ user : { INSERT INTO ingredient (name) nickname : ‘FoodLover’, VALUES (“garlic”, 1) email: ‘fabiano@mail.com’ } INSERT INTO comment (text, user_id, dish_id) ] VALUES (“This rice is really good”, 1, 1) })

13.Read SQL NoSQL SELECT d.name, d.description FROM dish d WHERE id=1 db.getCollection(‘Dish’).find({_id : 1}) SELECT i.name FROM ingredient i WHERE i.dish_id=1 SELECT c.text, u.nickname, u.name FROM comment c, user u WHERE c.user_id = u.id and c.dish_id = 1

14.Update SQL NoSQL UPDATE user SET nickname = ‘Bryan’ WHERE id=1 db.getCollection(‘User’).update({_id : 1}, {$set : {nickname : ‘Bryan’}}) {name: “White Rice” ingredients : [“rice”, “garlic”], comments : Array[ { Data Inconsistency text : ‘This rice is really good’ user : { nickname : ‘FoodLover’, email: ‘fabiano@mail.com’ } ]

15.Delete SQL NoSQL DELETE FROM ingredient WHERE dish_id=1 db.getCollection(‘Dish’).remove({_id : 1}) DELETE FROM comment WHERE dish_id=1 DELETE FROM dish WHERE id=1

16.Java MongoDB Driver

17. Where is the Framework to Map Java Objects and Documents? Spring Data

18.Spring Data “This is an umbrella project which contains many subprojects that are specific to a given database” • MongoDB • Neo4j • Cassandra • JDBC Extensions • Redis • Etc

19.How do we get started? • Add this maven configuration to the pom.xml file <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data- mongodb</artifactId> <version>1.10.6.RELEASE</version> </dependency> • Add the MongoDB config properties to the config file spring.data.mongodb.host=localhost spring.data.mongodb.port=27017 spring.data.mongodb.database=dish-db

20.Application Layers

21.Application Layers DishController DishService DishMongoRepository

22.How to create MongoDB Repository? package com.fmodos.dish.infraestructure.mongodb; import org.springframework.data.mongodb.repository.MongoRepository; import com.fmodos.dish.domain.Dish; public interface DishMongoRepository extends MongoRepository<Dish, String> { }

23. How to use the MongoDB Repository? @Service public class DishService { @Autowired DishMongoRepository dishRepository; public void insert(Dish dish) { Where is the insert dishRepository.insert(dish); method? } public interface DishMongoRepository extends MongoRepository<Dish, String> { }

24.SpringData Repositories Repository CrudRepository <extends> PagingAndSortingRepository MongoRepository DishMongoRepository

25.SpringData Repositories List<Dish> listDish = new ArrayList<Dish>(); <S extends T> S save(S entity); List<Dish> savedList = dishMongoRepository.save(listDish); <S extends T> Iterable<S> save(Iterable<S> entities); long count(); long count = dishMongoRepository.count(); void delete(ID id); dishMongoRepository.delete("id"); void delete(T entity); void delete(Iterable<? extends T> entities); void deleteAll();

26.SpringData Repositories T findOne(ID id); Dish dish = dishRepository.findOne(id) boolean exists(ID id); List<Dish> listDish = dishRepository.findAll() Iterable<T> findAll(); Iterable<T> findAll(Iterable<ID> ids); Page<Dish> pageDish = dishMongoRepository.findAll( Iterable<T> findAll(Sort sort); new PageRequest(1, 10)); Page<T> findAll(Pageable pageable);

27.What about Query Filter? public interface DishMongoRepository extends MongoRepository<Dish, String> { public List<Dish> findByName(String name); public List<Dish> findByNameAndDateCreatedGreaterThan(String name Date dateCreated); } “Methods should have verb or verb phrase names” Clean Code

28.What is the magic? DSL – Dynamic Reception • Handle messages without defining them in the receiving class • Build dynamic queries using the method declaration

29.Spring Data Query Keyword Sample Logical result After findByBirthdateAfter(Date date) {"birthdate" : {"$gt" : date}} GreaterThan findByAgeGreaterThan(int age) {"age" : {"$gt" : age}} GreaterThanEqual findByAgeGreaterThanEqual(int {"age" : {"$gte" : age}} age) Before findByBirthdateBefore(Date date) {"birthdate" : {"$lt" : date}} LessThan findByAgeLessThan(int age) {"age" : {"$lt" : age}} LessThanEqual findByAgeLessThanEqual(int age) {"age" : {"$lte" : age}} Between findByAgeBetween(int from, int to) {"age" : {"$gt" : from, "$lt" : to}} In findByAgeIn(Collection ages) {"age" : {"$in" : [ages…​]}} NotIn findByAgeNotIn(Collection ages) {"age" : {"$nin" : [ages…​]}} IsNotNull, NotNull findByFirstnameNotNull() {"firstname" : {"$ne" : null}} IsNull, Null findByFirstnameNull() {"firstname" : null} Like, StartingWith, EndingWith findByFirstnameLike(String name) {"firstname" : name} (name as regex) NotLike, IsNotLike findByFirstnameNotLike(String {"firstname" : { "$not" : name }} name) (name as regex)