NoSQL Endgame
Thodoris Bais
Werner Keil
Otavio Santana
Werner Keil Thodoris Bais
Jakarta EE Specification Committee Member Expert Group Member JSR-385
Let’s meet
@thodorisbais
@wernerkeil
Otavio Santana
Distinguished Software Engineer, Zup Innovation
Let’s meet
@otaviojava
4
5 trends in 2021
New digital trends create new technical
challenges
@thodorisbais
@wernerkeil
What are these challenges?
@thodorisbais
@wernerkeil
• Agile development process
• High performance and availability
• Manage huge data volumes
NoSQL FTW!
Advantages of NoSQL
@thodorisbais
@wernerkeil
• Handles large volumes of data at high-speed
• Stores unstructured, semi-structured, or structured data
• Easy updates to schemas and fields
• Developer-friendly
• Takes advantage of the cloud to deliver zero downtime
Why this talk
Tons of persistence frameworks
Which one performs best for your case?
JVM can cope with heavy loads
Would normally take ages to compare
NoSQL
01 Database
02 Doesn't use (semi)structure
03 No transactions
04 BASE
Four different types
05
Key-Value stores
AmazonS3
Apollo
Ares
Aphrodite
Sun
War
Love Beauty
AmazonDynamo
Hazelcast
Redis
Column-Oriented
Apollo
Aphrodite
Ares
Kratos
Duty
Duty
Duty
Dead Gods
Love, happy
Sun
War
13
Color
weapon
Sword
Row-key Columns
HBase
Scylla
SimpleDB
Cassandra
DynamoDB
Clouddata
Document stores
{
"name":"Diana",
"duty":[
"Hunt",
"Moon",
"Nature"
],
"siblings":{
"Apollo":"brother"
}
}
ApacheCouchDB
MongoDB
Couchbase
Graph databases
Apollo Ares
Kratos
was killed by was killed by
killed killed
Neo4j
InfoGrid
Sones
HyperGraphDB
Multi-Model
01
02
03
04
OrientDB (graph, document)
Couchbase (key value, document)
Elasticsearch (document, graph)
ArangoDB (document, graph, key-value)
SQL vs NoSQL
SQL KEY-VALUE COLUMN DOCUMENTS GRAPH
Table Bucket Column family Collection
Row Key/value pair Column Documents Vertex
Column Key/value pair Key/value pair Vertex and
Edge property
Relationship Link Edge
BASE vs ACID
• Basically Available
• Soft state
• Eventual consistency
• Atomicity
• Consistency
• Isolation
• Durability
CAP
Scalability vs Complexity
Scalability
Complexity
key-value
Column
Document
Graph
Relational Application NoSQL Application
Logic Tier Logic Tier
DAO DAO
JPA
JPA
JPA
JPA
JDBC JDBC
JDBC
JDBC
Data Tier
API
API API
Data Tier
Our comparison model
JPA problem for NoSQL
01
02
03
04
05
06
Saves Async
Async Callback
Time to Live (TTL)
Consistency Level
SQL based
Diversity in NoSQL
Annotated Entities
01
02
03
Mapped Superclass
Entity
Column
@Entity("god")
public class God {
@Column
private String name;
@Column
private long age;
@Column
private Set<String> powers;
}
Template
God artemis = ...;
DocumentTemplate template = …
template.insert(artemis);
template.update(artemis);
DocumentQuery query = ...
List<God> gods = template.select(query);
Repository
interface GodRepository extends MongoRepository<God, String> {
List<God> findByNameAndAge (String name, Integer age);
}
Repository
@Inject
@Database(DatabaseType.COLUMN)
private GodRepository godRepository;
@Inject
@Database(DatabaseType.KEY_VALUE)
private GodRepository godRepository;
Repository with Queries
interface PersonRepository extends Repository<Person, Long> {
@Query("select * from Person")
Optional<Person> findByQuery();
@Query("select * from Person where id = @id")
Optional<Person> findByQuery(@Param("id") String id);
}
List<Movie> movies = documentTemplate.query("select * from Movie
where year > 2012");
List<Person> people = columnTemplate.query("select * from Person
where age = 25");
Optional<God> god = keyValueTemplate.query("get 'Ullr'");
List<City> cities = graphTemplate.query("g.V().hasLabel('City')");
Query by Text
Micronaut Data
NoSQL?
Repository
public class AnimalRepository {
List<Animal> findByType(String type) {…}
public Animal insert(Animal animal) {…}
}
Entity
public class City {
private String name;
public City(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
Query by Text
public void save(City city) {
try (Session s = driver.session()) {
String statement = "MERGE (c:City {id:$name.id}) ON CREATE SET c+=$name";
s.writeTransaction(tx -> tx.run(statement, singletonMap("name" ,city.asMap())));
}
}
public Stream<City> findByName(String name) {
try (Session s = driver.session()) {
String statement = "MATCH (c:City) WHERE c.name contains $name RETURN c";
return s.readTransaction(tx -> tx.run(statement, singletonMap("name", name)))
.list(record -> new City(record.get("c").asMap())).stream();
}
}
GORM
NoSQL?
Entity
@Entity
class User {
ObjectId id
String emailAddress
String password
String fullname
Date dateCreated
Date lastUpdated
static constraints = {
emailAddress email: true
password nullable: true
fullname blank: false
}
}}
@Document(collection = "gods")
public class God { … }
interface GodRepository extends
MongoRepository<God, String> { … }
What about the Controller?
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
spring.data.mongodb.database=mythology
spring.data.mongodb.port=27017
Logistics Domain
Our example
MovieEntity
MovieRepository
PersonEntity
Roles
…
Other reactive dependencies
…
<dependency>
<groupId>org.neo4j.springframework.data</groupId>
<artifactId>spring-data-neo4j-rx-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>
org.neo4j.driver.uri=bolt://localhost:7687
org.neo4j.driver.authentication.username=neo4j
org.neo4j.driver.authentication.password=secret
Logistics Domain
Entities
@Node("Person")
public class PersonEntity {
@Id
private final String name;
private final Integer born;
}
@Node("Movie")
public class MovieEntity {
@Id
private final String title;
@Property("tagline")
private final String description;
@Relationship(type = "ACTED_IN", direction = INCOMING)
private Map<PersonEntity, Roles> actorsAndRoles =
new HashMap<>();
@Relationship(type = "DIRECTED", direction = INCOMING)
private List<PersonEntity> directors = new ArrayList<>();
}
Repository
public interface MovieRepository extends
ReactiveNeo4jRepository<MovieEntity, String> {
Mono<MovieEntity> findOneByTitle(String title);
}
Relationships
@RelationshipProperties
public class Roles {
private final List<String> roles;
public Roles(List<String> roles) {
this.roles = roles;
}
}
What happened to
?
Entity
@Entity
public class Editor {
@Id
@GeneratedValue(generator = "uuid")
@GenericGenerator(name = "uuid", strategy = "uuid2")
private String editorId;
private String editorName;
@OneToMany(mappedBy = "editor", cascade = CascadeType.PERSIST)
private Set<Author> assignedAuthors = new HashSet<>();
// constructors, getters and setters...
}
Operations
private void persistTestData(EntityManagerFactory entityManagerFactory, Editor editor)
throws Exception {
TransactionManager transactionManager =
com.arjuna.ats.jta.TransactionManager.transactionManager();
transactionManager.begin();
EntityManager entityManager = entityManagerFactory.createEntityManager();
entityManager.persist(editor);
entityManager.close();
transactionManager.commit();
}
Warning
“In most cases, multi-document transaction incurs a greater
performance cost over single document writes, and the availability of
multi-document transactions should not be a replacement for
effective schema design. For many scenarios, the denormalized data
model (embedded documents and arrays) will continue to be optimal
for your data and use cases. That is, for many scenarios, modeling
your data appropriately will minimize the need for multi-document
transactions.”
Documentation
Conclusions
NoSQL Endgame
@thodorisbais
@wernerkeil
Conclusions
Still in Progress ❌
Supports a huge number of NoSQL database systems ✅
Loosely coupled code makes switching between
different NoSQL vendors just a matter of configuration
✅
Removes boiler-plate code and provides a cleaner,
more readable DAO
✅
Conclusions
Switching between different NoSQL vendors not so easy ❌
Micronaut Data does not support NoSQL databases yet ❌
Still in Progress ❌
Often faster with a lower footprint and polyglot language
support for Java, Kotlin and Groovy
✅
Conclusions
Provides a cleaner and more readable DAO implementation ✅
Works with Grails, Micronaut or Spring Boot, polyglot
language support for Java and Groovy
✅
Removes a lot of boiler-plate code ✅
Only 3 to 4 of the most popular NoSQL databases are supported
out of the box, others require more effort or won’t work yet ❌
Conclusions
Provides a cleaner and more readable DAO implementation ✅
Loosely coupled code makes switching between
different NoSQL vendors just a matter of configuration
✅
Removes a lot of boiler-plate code ✅
Only a few popular NoSQL databases are supported out of the
box at this moment ❌
Conclusions
Using a mapper for all scenarios is not a
recommended approach
❌
Some JPA concepts are not easily mapped to
the NoSQL world (e.g. transactions)
❌
No error-safe way to run the query language and hydrate DTOs
from the result ❌
Outdated, no release since 2018 ❌
▪ GitHub repositories
▪ https://github.com/JNOSQL/nosql-endgame
▪ Project page
▪ http://jnosql.org
@thodorisbais
@wernerkeil
Links
5
3
• Flaticon.com
• Michael Simons
• Jean Tessier
Credits
@thodorisbais
@wernerkeil
Thank you

EclipseCon 2021 NoSQL Endgame