DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Last call! Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • How to Store Text in PostgreSQL: Tips, Tricks, and Traps
  • In-Memory Showdown: Redis vs. Tarantool
  • Manage Hierarchical Data in MongoDB With Spring
  • Spring Data: Data Auditing Using JaVers and MongoDB

Trending

  • Streamlining Event Data in Event-Driven Ansible
  • Mastering Fluent Bit: Installing and Configuring Fluent Bit on Kubernetes (Part 3)
  • Kubeflow: Driving Scalable and Intelligent Machine Learning Systems
  • Mastering Advanced Traffic Management in Multi-Cloud Kubernetes: Scaling With Multiple Istio Ingress Gateways
  1. DZone
  2. Data Engineering
  3. Databases
  4. Can Redis Be Used as a Relational Database?

Can Redis Be Used as a Relational Database?

Explore how easy it is to work with Redis in Java + Spring, and find five differences from a relational database.

By 
Artem Artemev user avatar
Artem Artemev
·
Aug. 11, 23 · Tutorial
Likes (14)
Comment
Save
Tweet
Share
12.9K Views

Join the DZone community and get the full member experience.

Join For Free

Let's start with the question, "How do you use Redis?" I'm sure most use it as a cache for the service. I hope you know that it can do more than just that. Recently, I spoke at a conference with a report on how we moved part of the data to Redis and requests fly to it in the first place. Now I want to tell you not about how we applied it, but about the fact that when working with Spring and its abstractions, you may not immediately notice the substitution.

Let's try to write a small Spring app that will use two PostgreSQL and Redis databases. I want to note that we will store in the databases not some kind of flat object, but a full-fledged object from a relational database with nested fields (inner join). To do this, we need plugins that need to be installed in Redis such as RedisJSON and RediSearch. The first allows us to store our object in JSON format, and the second allows us to search by any field of our object, even nested fields.

To work with a relational database, we will choose Spring Data JPA. And to work with Redis, we will use the excellent Redis OM Spring library, which allows you to work with the database at the abstraction level. This is an analog of Data JPA. Under the hood, Redis OM Spring has all the necessary dependencies for Spring and Jedis to work with the database. We will not dwell on the details, since the article is not about that.

Let's Write Code

So let's write code. Let's say we need to write a certain entity called "downtime" to the database. In this entity, I added other objects such as "place", "reason", and others.

Entity for a relational database:

Java
 
@Entity
@Table(schema = "test", name = "downtime")
public class Downtime {

    @Id
    private String id;
    private LocalDateTime beginDate;
    private LocalDateTime endDate;
    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "area")
    private Place area;
    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "cause")
    private Cause cause;
    ...


This piece of code does not need comments. We need to do the same for Redis.

 Object for Redis:

Java
 
@Document
public class DowntimeDoc {

    @Id
    @Indexed
    private String id;
    @Indexed
    private LocalDateTime beginDate;
    private LocalDateTime endDate;
    @Indexed
    private PlaceDoc area;
    @Indexed
    private CauseDoc cause;
    ....


In this case, instead of @Entity, we use @Document. This annotation indicates that our object is an entity. It will be stored in the database under the key “package path + class name + Idx.”

The @Indexed annotation means that it will be indexed for search. If you do not specify this annotation, then this field will be saved in the database, but searching for it will return an empty result. You can add this annotation as needed. Data that is already in the database will be indexed asynchronously; new data will be indexed synchronously. 

Next, we will make a repository, which basically works to get data from the database.

An example for a relational database:

Java
 
public interface DowntimeRepository extends JpaRepository<Downtime, String> {
}


Example for Redis:

Java
 
public interface DowntimeRedisRepository extends RedisDocumentRepository<DowntimeDoc, String> {
}


The difference is that we extend the current interface from RedisDocumentRepository, which extends the standard CRUD interface for Spring.

Let's add a method to find the first downtime for the reason we specified.

Java
 
public interface DowntimeRepository extends JpaRepository<Downtime, String> {

    Downtime findFirstByCauseIdOrderByBeginDate(String causeId);
}


And the same for Redis:

Java
 
public interface DowntimeRedisRepository extends RedisDocumentRepository<DowntimeDoc, String> {

    DowntimeDoc findTopByCause_IdOrderByBeginDateAsc(String causeId);
}


As you noticed, if you write code working with the database through abstractions, then the difference is almost not noticeable. In addition, Redis OM Spring allows you to write queries yourself using the @Query annotation, as in Spring Data JPA.

Here is an example of an HQL query:

Java
 
@Query("SELECT d FROM Downtime d" +
        " JOIN FETCH d.area " +
        " JOIN FETCH d.cause" +
        " JOIN FETCH d.fixer" +
        " JOIN FETCH d.area.level " +
        " WHERE d.area IN ?1 AND (d.beginDate BETWEEN ?2 AND ?3 OR d.cause IN ?4) ")
List<Downtime> findAllByParams(List<Place> workPlace, LocalDateTime start, LocalDateTime end, List<Cause> causes);


Same for Redis:

Java
 
@Query("(@area_id:{$areas} ) & (@beginDate:[$start $end] | @cause_id:{$causes})")
Page<DowntimeDoc> findByParams(@Param("areas") List<String> areas,
                               @Param("start") long start,
                               @Param("end") long end,
                               @Param("causes") List<String> causes, Pageable pageable);


In the case of Redis, we simply specify the conditions for the “WHERE” section. It is not necessary to indicate which fields need to be attached since they are always pulled from the database. However, we can not pull up all the fields but specify with the additional “returnFields” parameter what exactly we need. You can also specify sorting, limit, and offset - the latter, by the way, is impossible in HQL. In this example, I passed Pageable to the method, and it will work at the database level, not pull all the data into the service, and trim it in it (as would be the case with Hibernate).

Also, Redis OM Spring allows you to write queries using EntityStream, which is analogous to Stream API.

Here is an example of the above queries using EntityStream.

Java
 
…
entityStream
        .of(DowntimeDoc.class)
        .filter(DowntimeDoc$.AREA_ID.in(filter.getWorkPlace().toArray(String[]::new)))
        .filter(between + " | " + causes)
        .map(mapper::toEntity)
        .collect(Collectors.toList());


In this example, I'm using one filter using the metamodel, passing the parameters as a string to the second filter to show that both options are valid. You guessed it: EntityStream accepts a set of intermediate operations and executes this set when calling a terminal operation.

Nuances of Redis OM Spring

Let me tell you about some of the nuances of using Redis OM Spring:

  • You will not be able to use a UUID as a primary key. You can specify it as a string and it will be indexed. But when searching, you will need to escape spaces @id:
 
{2e5af82m\-02af\-553b\-7961\-168878aa521е}


And one more thing: if you search through the RedisDocumentRepository repository, nothing will work, because there is such an expression in the code that will remove all screens:

 
String regex = "(\\$" + key + ")(\\W+|\\*|\\+)(.*)";


Therefore, in order to search by such fields, you will have to write a query directly in RediSearch. I have an example of how to do this in the demo project.

  • When searching through the RedisDocumentRepository methods, if you expect a collection, then you must pass a Pageable indicating the size of the expected rows or specifying the size in @Query; otherwise, you will receive a maximum of 10 records.
  • The FT.SEARCH (@Query) method supports only one parameter for sorting. This is solved by writing a query through FT.AGGREGATE (@Aggregation).

The above list is not exhaustive. While working with these libraries, I found many different things, but this is all just a specificity of the database implementation. Finally, I did not put information about Redis plugins in this article and did not talk about all the features of Redis OM Spring; otherwise, this article will be huge and not readable.

Conclusion

I showed that currently, Redis allows you to store an object with a large nesting and allows you to search through the fields of this object. If you are working with data through abstractions in the repository, then some may not see any difference from Spring Data JPA, especially if you use some simple queries like Save, delete, findAllBy, etc., as well as queries through the name of the method.

Examples can be found on GitHub.

All success.

Relational database Data (computing) Redis (company) Java Persistence API Spring Data

Opinions expressed by DZone contributors are their own.

Related

  • How to Store Text in PostgreSQL: Tips, Tricks, and Traps
  • In-Memory Showdown: Redis vs. Tarantool
  • Manage Hierarchical Data in MongoDB With Spring
  • Spring Data: Data Auditing Using JaVers and MongoDB

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!