Persistence Best Practices for Java Applications by Otàvio Santana & Karina Varela

Persistence Best Practices for Java Applications by Otàvio Santana & Karina Varela

Author:Otàvio Santana & Karina Varela
Language: eng
Format: epub
Publisher: Packt
Published: 2023-11-15T00:00:00+00:00


Column databases

The following database type is the wide-column type, which follows the same principles as key-value, but instead of a unique blob, you can split the information into small columns.

This NoSQL database is also known as a two-dimensional key-value store. The most popular implementation is Apache Cassandra; this section will cover an integration between Java and Apache Cassandra.

As mentioned, we won’t cover tips for running in production; for now, we’ll run a single instance for test purposes:

docker run -d --name cassandra-instance -p 9042:9042 cassandra

Tip

When running a Cassandra instance with Docker, please don’t run it this way in production. This configuration is best for your test environment. For production use, go to the Apache Cassandra documentation on the Apache website.

We’ll follow the same idea of configuration, so we’ll use Java and Maven projects. The first step on the Java side is to add dependencies to the Maven project:

<dependency> <groupId>org.eclipse.jnosql.mapping</groupId> <artifactId>jnosql-cassandra-extension</artifactId> <version>${jnosql.version}</version> </dependency>

This dependency seems different because it is a Cassandra extension; it is the column API plus behavior specific to Cassandra, such as CQL. If you wish, you can use it as we did with Redis, but you cannot use Cassandra-specific behavior easily:

<dependency> <groupId>org.eclipse.jnosql.communication</groupId> <artifactId>jnosql-cassandra-driver</artifactId> <version>${jnosql.version}</version> </dependency> <dependency> <groupId>org.eclipse.jnosql.mapping</groupId> <artifactId>jnosql-mapping-column</artifactId> <version>${project.version}</version> </dependency>

This NoSQL database works differently from SQL. Indeed, denormalization is your best friend.

First, visualize the model. Then, create it. We want to track and view the rental records of a user with a particular ID who rents books:

@Entity("rental")public class RentalBook { @Id("id") private UUID id; @Column private LocalDate date; @Column @UDT("user") private User user; @Column @UDT("book") private Set<Book> books = new HashSet<>(); } @Entity public class User { @Column private String username; @Column private String name; } @Entity public class Book { @Column private UUID id; @Column private String title; }

That’s it for the model; from the ID, we can return the track record of a book rental. We’re replicating information such as the book’s title and the user’s name to avoid any joins or more processes, but once a field has been updated, we need to run an event in the background to update it.

The User and Book entities are user-defined types, where we can add multiple values to a single column.

Despite JPA, JNoSQL must define each field to be stored using either a Column or Id annotation.

Let’s execute the code, as essentially we can use the same principles and behavior that we did with key-value. We can also select the fields to return in a query instead of always returning everything:

try(SeContainer container = SeContainerInitializer.newInstance().initialize()) { RentalBook otavio = RentalBook.builder() .id(UUID.randomUUID()) .date(LocalDate.now()) .user(User.of("otaviojava", "Otavio Santana")) .book(Book.of(UUID.randomUUID(), "Clean Code")) .book(Book.of(UUID.randomUUID(), "Effective Java")) .build(); RentalBook karina = RentalBook.builder() .id(UUID.randomUUID()) .date(LocalDate.now()) .user(User.of("kvarel4", "Karina Varela")) .book(Book.of(UUID.randomUUID(), "Clean Arch")) .build(); ColumnTemplate template = container .select(CassandraTemplate.class).get(); template.insert(List.of(otavio, karina), Duration.ofDays(600L)); ColumnQuery query = ColumnQuery.select("id", "date").from("rental") .where("id").eq(karina.getId()).build(); System.out.println("Executing query using API: "); template.select(query).forEach(System.out::println); System.out.println("Executing query using text: "); template.query("select * from rental") .forEach(System.out::println); }

Cassandra is not schemaless, although you need to create the schema before using it. Running the query locally is OK, but don’t use it in production.



Download



Copyright Disclaimer:
This site does not store any files on its server. We only index and link to content provided by other sites. Please contact the content providers to delete copyright contents if any and email us, we'll remove relevant links or contents immediately.