<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Shashwath S H</title>
    <description>The latest articles on DEV Community by Shashwath S H (@shashwathsh).</description>
    <link>https://dev.to/shashwathsh</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3683066%2F6da5fa96-6222-4159-a698-375535870738.jpeg</url>
      <title>DEV Community: Shashwath S H</title>
      <link>https://dev.to/shashwathsh</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/shashwathsh"/>
    <language>en</language>
    <item>
      <title>🌍 I Stopped Using RestTemplate… Spring Boot RestClient Is Cleaner</title>
      <dc:creator>Shashwath S H</dc:creator>
      <pubDate>Sat, 24 Jan 2026 07:16:34 +0000</pubDate>
      <link>https://dev.to/shashwathsh/i-stopped-using-resttemplate-spring-boot-restclient-is-cleaner-3hg</link>
      <guid>https://dev.to/shashwathsh/i-stopped-using-resttemplate-spring-boot-restclient-is-cleaner-3hg</guid>
      <description>&lt;p&gt;When I started building backend services in Spring Boot, I thought REST APIs were only about creating endpoints.&lt;/p&gt;

&lt;p&gt;But in real-world projects, you often need the opposite too:&lt;/p&gt;

&lt;p&gt;✅ Your service must &lt;strong&gt;call other services&lt;/strong&gt;&lt;br&gt;
✅ Your backend must &lt;strong&gt;consume external APIs&lt;/strong&gt;&lt;br&gt;
✅ Your application must handle &lt;strong&gt;HTTP responses + errors&lt;/strong&gt; properly&lt;/p&gt;

&lt;p&gt;That’s where I discovered &lt;strong&gt;RestClient&lt;/strong&gt; — and honestly, it feels way cleaner.&lt;/p&gt;


&lt;h2&gt;
  
  
  🧠 What is &lt;strong&gt;RestClient&lt;/strong&gt; in Spring Boot?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3gyeoo6w6qmr5gthl0h0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3gyeoo6w6qmr5gthl0h0.png" alt="Rest Client" width="680" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RestClient&lt;/strong&gt; is a &lt;strong&gt;synchronous HTTP client&lt;/strong&gt; with a modern, fluent API.&lt;/p&gt;

&lt;p&gt;It provides a clean abstraction over HTTP libraries and helps you:&lt;/p&gt;

&lt;p&gt;✅ Convert Java objects into HTTP requests&lt;br&gt;
✅ Convert HTTP responses back into Java objects&lt;br&gt;
✅ Write readable and maintainable API-call code&lt;/p&gt;

&lt;p&gt;In simple terms:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;RestClient makes calling APIs from Spring Boot easier and cleaner.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  🏗️ Building a &lt;strong&gt;RestClient&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;You typically create a RestClient using a builder.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;RestClient&lt;/span&gt; &lt;span class="n"&gt;restClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;RestClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;baseUrl&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;BASE_URL&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;defaultHeader&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpHeaders&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;AUTHORIZATION&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;encodeBasic&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;properties&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getUsername&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;properties&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getPassword&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
    &lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What I like here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;baseUrl&lt;/strong&gt; keeps calls consistent&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;defaultHeader&lt;/strong&gt; avoids repeating auth in every request&lt;/li&gt;
&lt;li&gt;The builder feels very readable&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ✅ Using &lt;strong&gt;RestClient&lt;/strong&gt; (GET Example)
&lt;/h2&gt;

&lt;p&gt;Once built, using it feels super fluent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;CustomerResponse&lt;/span&gt; &lt;span class="n"&gt;customer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;restClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/{id}"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;accept&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MediaType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;APPLICATION_JSON&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;retrieve&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;CustomerResponse&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What’s happening here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;.get()&lt;/code&gt; sends a GET request&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.uri("/{id}", 3)&lt;/code&gt; builds dynamic URLs&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.retrieve()&lt;/code&gt; executes the request&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.body(CustomerResponse.class)&lt;/code&gt; maps response into your Java class&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is exactly how a clean backend should consume APIs.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔁 RestClient Supports More Than Just GET
&lt;/h2&gt;

&lt;p&gt;Apart from &lt;strong&gt;get()&lt;/strong&gt;, RestClient supports:&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;post()&lt;/strong&gt;&lt;br&gt;
✅ &lt;strong&gt;put()&lt;/strong&gt;&lt;br&gt;
✅ &lt;strong&gt;patch()&lt;/strong&gt;&lt;br&gt;
✅ &lt;strong&gt;delete()&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So it fits perfectly for full CRUD interactions with external services.&lt;/p&gt;


&lt;h2&gt;
  
  
  🚨 Handling Errors in &lt;strong&gt;RestClient&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Calling external APIs isn’t always smooth.&lt;/p&gt;

&lt;p&gt;Sometimes the response is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;4xx (client errors)&lt;/li&gt;
&lt;li&gt;5xx (server errors)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;RestClient allows handling these cleanly using &lt;strong&gt;onStatus()&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Example (DELETE + error handling):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;ResponseEntity&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;restClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;delete&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;onStatus&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;HttpStatusCode:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;is4xxClientError&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Couldn't delete "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getStatusText&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
    &lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toBodilessEntity&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This makes error handling:&lt;br&gt;
✅ explicit&lt;br&gt;
✅ readable&lt;br&gt;
✅ maintainable&lt;/p&gt;

&lt;p&gt;And most importantly:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It prevents silent failures.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  🧠 Why This Matters in Real Projects
&lt;/h2&gt;

&lt;p&gt;Most real backend projects are not standalone.&lt;/p&gt;

&lt;p&gt;They talk to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;payment services&lt;/li&gt;
&lt;li&gt;authentication servers&lt;/li&gt;
&lt;li&gt;notification APIs&lt;/li&gt;
&lt;li&gt;microservices&lt;/li&gt;
&lt;li&gt;third-party providers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A clean HTTP client is essential, and &lt;strong&gt;RestClient fits perfectly&lt;/strong&gt; into modern Spring Boot development.&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 Final Thoughts
&lt;/h2&gt;

&lt;p&gt;RestClient is one of those tools that feels small…&lt;/p&gt;

&lt;p&gt;…but improves your backend workflow massively.&lt;/p&gt;

&lt;p&gt;If you’re building Spring Boot applications that consume APIs:&lt;br&gt;
✅ try &lt;strong&gt;RestClient&lt;/strong&gt;&lt;br&gt;
✅ set a baseUrl&lt;br&gt;
✅ handle errors properly&lt;br&gt;
✅ keep responses typed&lt;/p&gt;

&lt;p&gt;This post is part of my &lt;strong&gt;learning-in-public&lt;/strong&gt; journey while exploring Spring Boot and real-world backend development.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Do you use RestTemplate, WebClient, or RestClient in your Spring Boot projects?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>springboot</category>
      <category>java</category>
      <category>backend</category>
      <category>restapi</category>
    </item>
    <item>
      <title>⏱️ I Was Manually Setting createdAt &amp; updatedAt… Until I Learned Spring Boot Auditing</title>
      <dc:creator>Shashwath S H</dc:creator>
      <pubDate>Wed, 21 Jan 2026 11:01:04 +0000</pubDate>
      <link>https://dev.to/shashwathsh/i-was-manually-setting-createdat-updatedat-until-i-learned-spring-boot-auditing-414e</link>
      <guid>https://dev.to/shashwathsh/i-was-manually-setting-createdat-updatedat-until-i-learned-spring-boot-auditing-414e</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftcerz8rl2sxtjvulp4n3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftcerz8rl2sxtjvulp4n3.png" alt="Auditing" width="544" height="333"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🔥 Backup options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;“Stop Writing createdAt/updatedAt Manually in Spring Boot”&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;“Spring Boot Auditing: The Feature That Makes Your Backend Look Professional”&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;“How I Automated Entity Timestamps in Spring Data JPA”&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;When I started building CRUD APIs with Spring Boot, everything worked fine.&lt;/p&gt;

&lt;p&gt;But one thing kept bothering me.&lt;/p&gt;

&lt;p&gt;Every entity needed fields like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;createdAt&lt;/li&gt;
&lt;li&gt;updatedAt&lt;/li&gt;
&lt;li&gt;createdBy&lt;/li&gt;
&lt;li&gt;updatedBy&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And I was setting them manually.&lt;/p&gt;

&lt;p&gt;Again and again.&lt;br&gt;
In every service method.&lt;br&gt;
For every entity.&lt;/p&gt;

&lt;p&gt;That’s when I discovered &lt;strong&gt;Auditing in Spring Boot&lt;/strong&gt; — and it instantly made my backend feel more &lt;strong&gt;real-world and production-ready&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧠 What is &lt;strong&gt;Auditing&lt;/strong&gt; in Spring Boot?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Auditing&lt;/strong&gt; in Spring Boot allows you to automatically populate fields such as:&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Creation timestamp&lt;/strong&gt;&lt;br&gt;
✅ &lt;strong&gt;Last modification timestamp&lt;/strong&gt;&lt;br&gt;
✅ &lt;strong&gt;Created by user&lt;/strong&gt;&lt;br&gt;
✅ &lt;strong&gt;Last modified by user&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So instead of manually updating these fields, Spring does it for you automatically.&lt;/p&gt;




&lt;h2&gt;
  
  
  ✅ Why Auditing is Actually Useful
&lt;/h2&gt;

&lt;p&gt;Auditing helps in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;tracking data history&lt;/li&gt;
&lt;li&gt;debugging changes&lt;/li&gt;
&lt;li&gt;maintaining clean records&lt;/li&gt;
&lt;li&gt;building professional enterprise systems&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most real applications require this, especially when multiple users are modifying records.&lt;/p&gt;




&lt;h2&gt;
  
  
  🛠️ Steps to Add &lt;strong&gt;Auditing&lt;/strong&gt; in Spring Boot
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1️⃣ Create an &lt;strong&gt;Auditable Base Entity&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Create a superclass and add:&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;@EntityListeners(AuditingEntityListener.class)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This gives access to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;@CreatedBy&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;@CreatedDate&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;@LastModifiedBy&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;@LastModifiedDate&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  2️⃣ Extend All Entities from the Superclass
&lt;/h3&gt;

&lt;p&gt;Instead of repeating auditing fields in every entity, simply extend the base class.&lt;/p&gt;

&lt;p&gt;This keeps the code:&lt;br&gt;
✅ clean&lt;br&gt;
✅ reusable&lt;br&gt;
✅ consistent&lt;/p&gt;




&lt;h3&gt;
  
  
  3️⃣ Implement &lt;strong&gt;AuditorAware&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Create a class that implements &lt;strong&gt;AuditorAware&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Its job is to provide:&lt;br&gt;
✅ the current authenticated user (usually from Spring Security)&lt;/p&gt;

&lt;p&gt;This is how Spring knows &lt;em&gt;who&lt;/em&gt; created/modified the entity.&lt;/p&gt;




&lt;h3&gt;
  
  
  4️⃣ Enable JPA Auditing
&lt;/h3&gt;

&lt;p&gt;Enable auditing using:&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;@EnableJpaAuditing&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is usually added in a configuration class.&lt;/p&gt;




&lt;h3&gt;
  
  
  5️⃣ Pass the &lt;strong&gt;AuditorAware Bean Reference&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Connect your auditor provider to auditing configuration so Spring can use it globally.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔍 Internal Working of Auditing (Simple Explanation)
&lt;/h2&gt;

&lt;p&gt;Auditing works using an entity listener called &lt;strong&gt;AuditingEntityListener&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Whenever an entity is saved or updated, Spring triggers:&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;PrePersist&lt;/strong&gt; (before insert)&lt;br&gt;
✅ &lt;strong&gt;PreUpdate&lt;/strong&gt; (before update)&lt;/p&gt;

&lt;p&gt;So when an entity is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;created → created fields are filled automatically&lt;/li&gt;
&lt;li&gt;updated → last modified fields are updated automatically&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The user information comes from &lt;strong&gt;AuditorAware&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Spring Boot Auditing is one of those features that quietly improves your backend quality.&lt;/p&gt;

&lt;p&gt;If you’re still:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;manually setting timestamps&lt;/li&gt;
&lt;li&gt;repeating createdAt/updatedAt logic everywhere&lt;/li&gt;
&lt;li&gt;struggling to track modifications&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Start using &lt;strong&gt;Auditing&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It makes your project look &lt;strong&gt;professional and enterprise-ready&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This post is part of my &lt;strong&gt;learning-in-public&lt;/strong&gt; journey while exploring Spring Boot and real-world backend development.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Do you handle createdAt/updatedAt manually or are you using Spring Boot Auditing?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>springboot</category>
      <category>java</category>
      <category>backend</category>
      <category>performance</category>
    </item>
    <item>
      <title>⚡ I Was Restarting Spring Boot Again and Again… Until I Found DevTools</title>
      <dc:creator>Shashwath S H</dc:creator>
      <pubDate>Tue, 20 Jan 2026 05:26:15 +0000</pubDate>
      <link>https://dev.to/shashwathsh/i-was-restarting-spring-boot-again-and-again-until-i-found-devtools-4nng</link>
      <guid>https://dev.to/shashwathsh/i-was-restarting-spring-boot-again-and-again-until-i-found-devtools-4nng</guid>
      <description>&lt;p&gt;When I started learning Spring Boot, I thought restarting the server was normal.&lt;/p&gt;

&lt;p&gt;Change code ✅&lt;br&gt;
Stop server ❌&lt;br&gt;
Start again ✅&lt;br&gt;
Wait… 😴&lt;br&gt;
Repeat 🔁&lt;/p&gt;

&lt;p&gt;At first it was fine.&lt;br&gt;
But once the project grew, restarting again and again became painful.&lt;/p&gt;

&lt;p&gt;That’s when I discovered &lt;strong&gt;Spring Boot DevTools&lt;/strong&gt; — and it instantly made development faster.&lt;/p&gt;


&lt;h2&gt;
  
  
  🧠 What is &lt;strong&gt;Spring Boot DevTools&lt;/strong&gt;?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Spring Boot DevTools&lt;/strong&gt; is a development-time dependency that improves productivity by enabling features like:&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Automatic restart&lt;/strong&gt;&lt;br&gt;
✅ Faster feedback loop&lt;br&gt;
✅ Better developer experience&lt;/p&gt;

&lt;p&gt;It’s meant only for development, not production.&lt;/p&gt;


&lt;h2&gt;
  
  
  ✅ Step 1: Add the &lt;strong&gt;DevTools Dependency&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;In Maven (&lt;code&gt;pom.xml&lt;/code&gt;), add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-boot-devtools&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;optional&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/optional&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After adding this, Spring Boot can detect classpath changes and restart automatically.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔄 The Best Feature: &lt;strong&gt;Automatic Restart&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;DevTools automatically restarts your application when files on the classpath change.&lt;/p&gt;

&lt;p&gt;Why this is useful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It’s faster than a full restart&lt;/li&gt;
&lt;li&gt;Only changed parts get reloaded&lt;/li&gt;
&lt;li&gt;Development becomes smoother&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🧩 How DevTools Restart Works Internally (Simple Explanation)
&lt;/h2&gt;

&lt;p&gt;DevTools uses &lt;strong&gt;two class loaders&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;✅ One for &lt;strong&gt;base classes that don’t change&lt;/strong&gt; (libraries, dependencies)&lt;br&gt;
✅ One for &lt;strong&gt;application classes that change&lt;/strong&gt; (your code)&lt;/p&gt;

&lt;p&gt;So when you change your code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Only your application class loader reloads&lt;/li&gt;
&lt;li&gt;Restart happens faster&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is why it feels quick and lightweight.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ IntelliJ Setting (Important)
&lt;/h2&gt;

&lt;p&gt;After adding DevTools, you may need to update IntelliJ settings to allow restart properly during development.&lt;/p&gt;

&lt;p&gt;This step matters because sometimes IntelliJ doesn’t trigger automatic reload unless configured.&lt;/p&gt;




&lt;h2&gt;
  
  
  🛠️ Useful &lt;strong&gt;DevTools Configurations&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;You can control DevTools behavior using &lt;code&gt;application.properties&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ Disable restart (if needed)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;spring.devtools.restart.enabled&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  ✅ Exclude folders from restart
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;spring.devtools.restart.exclude&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;static/**,public/**&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Useful when you don’t want restart triggers for static content.&lt;/p&gt;




&lt;h3&gt;
  
  
  ✅ Poll interval
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;spring.devtools.restart.pollInterval&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;20&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Defines how often DevTools checks for changes.&lt;/p&gt;




&lt;h3&gt;
  
  
  ✅ Quiet period
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;spring.devtools.restart.quietPeriod&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wait time before restarting after changes are detected.&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Spring Boot DevTools is one of those small features that makes a huge difference.&lt;/p&gt;

&lt;p&gt;If you're tired of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;restarting again and again&lt;/li&gt;
&lt;li&gt;losing time during development&lt;/li&gt;
&lt;li&gt;slow feedback while learning&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;DevTools is a must-have for Spring Boot development.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This post is part of my &lt;strong&gt;learning-in-public&lt;/strong&gt; journey while exploring Spring Boot and real-world backend development.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Do you still restart Spring Boot manually or are you using DevTools?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>springboot</category>
      <category>java</category>
      <category>backend</category>
      <category>productivity</category>
    </item>
    <item>
      <title>🚀 My Spring Boot Project Finally Felt Real After Adding Web MVC + JPA</title>
      <dc:creator>Shashwath S H</dc:creator>
      <pubDate>Mon, 19 Jan 2026 09:59:13 +0000</pubDate>
      <link>https://dev.to/shashwathsh/my-spring-boot-project-finally-felt-real-after-adding-web-mvc-jpa-1k4m</link>
      <guid>https://dev.to/shashwathsh/my-spring-boot-project-finally-felt-real-after-adding-web-mvc-jpa-1k4m</guid>
      <description>&lt;p&gt;When I started learning Spring Boot, I built small demos.&lt;/p&gt;

&lt;p&gt;A controller here.&lt;br&gt;
A GET API there.&lt;br&gt;
Everything looked fine…&lt;/p&gt;

&lt;p&gt;But it didn’t feel like a &lt;strong&gt;real backend project&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A real project needs:&lt;br&gt;
✅ REST APIs&lt;br&gt;
✅ Database integration&lt;br&gt;
✅ Clean layered structure&lt;br&gt;
✅ Proper dependencies and configuration&lt;/p&gt;

&lt;p&gt;So today I’m documenting how I set up a &lt;strong&gt;Spring Boot project with Web MVC + Spring Data JPA&lt;/strong&gt; the right way.&lt;/p&gt;


&lt;h2&gt;
  
  
  ✅ What We Are Setting Up
&lt;/h2&gt;

&lt;p&gt;This project will include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Spring Boot Web MVC&lt;/strong&gt; → for building REST APIs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Spring Data JPA&lt;/strong&gt; → for database operations&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A clean layered structure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;controller&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;service&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;repository&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dto&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;entity&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxrrd4oyasrslgvggh0xv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxrrd4oyasrslgvggh0xv.png" alt="str" width="800" height="335"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the most common structure used in real-world Spring Boot apps.&lt;/p&gt;


&lt;h2&gt;
  
  
  🧱 Step 1: Create a Spring Boot Project
&lt;/h2&gt;

&lt;p&gt;You can create the project using &lt;strong&gt;Spring Initializr&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Choose:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Project:&lt;/strong&gt; Maven&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Language:&lt;/strong&gt; Java&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Packaging:&lt;/strong&gt; Jar&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Java Version:&lt;/strong&gt; (your installed version)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  ✅ Add Dependencies
&lt;/h3&gt;

&lt;p&gt;Add these:&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Spring Web&lt;/strong&gt;&lt;br&gt;
✅ &lt;strong&gt;Spring Data JPA&lt;/strong&gt;&lt;br&gt;
✅ &lt;strong&gt;H2 Database / MySQL Driver&lt;/strong&gt; (optional but recommended)&lt;/p&gt;


&lt;h2&gt;
  
  
  📦 Step 2: Understand Your Dependencies
&lt;/h2&gt;

&lt;p&gt;Once dependencies are added, Spring Boot handles most setup automatically.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Spring Web&lt;/strong&gt; gives you:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Controllers&lt;/li&gt;
&lt;li&gt;REST APIs&lt;/li&gt;
&lt;li&gt;JSON support (via Jackson)&lt;/li&gt;
&lt;li&gt;Embedded server (Tomcat)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Spring Data JPA&lt;/strong&gt; gives you:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Repositories&lt;/li&gt;
&lt;li&gt;CRUD operations&lt;/li&gt;
&lt;li&gt;Query methods&lt;/li&gt;
&lt;li&gt;ORM support (Hibernate under the hood)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This combination = &lt;strong&gt;production-ready backend base&lt;/strong&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  🗂️ Step 3: Follow a Clean Project Structure
&lt;/h2&gt;

&lt;p&gt;Here’s the structure I use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;com.yourapp.project
 ├── controller
 ├── service
 ├── repository
 ├── dto
 ├── entity
 └── Application.java
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why this matters
&lt;/h3&gt;

&lt;p&gt;Without structure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Controllers become huge&lt;/li&gt;
&lt;li&gt;Logic becomes messy&lt;/li&gt;
&lt;li&gt;Debugging becomes painful&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With structure:&lt;br&gt;
✅ separation of concerns&lt;br&gt;
✅ maintainability&lt;br&gt;
✅ scalability&lt;/p&gt;




&lt;h2&gt;
  
  
  🌐 Step 4: Web MVC Setup (Controller Layer)
&lt;/h2&gt;

&lt;p&gt;To expose APIs, we use &lt;strong&gt;@RestController&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This layer should:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Handle request mappings&lt;/li&gt;
&lt;li&gt;Accept input&lt;/li&gt;
&lt;li&gt;Return response&lt;/li&gt;
&lt;li&gt;Call service layer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Rule:&lt;br&gt;
👉 &lt;strong&gt;Controller should NOT talk to database directly.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🗄️ Step 5: JPA Setup (Entity + Repository)
&lt;/h2&gt;

&lt;p&gt;To connect your backend to the database, you need:&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Entity&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Represents table in DB&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;✅ &lt;strong&gt;Repository&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Handles database operations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Spring Data JPA makes database work simple because you can use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;JpaRepository&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Dynamic query methods like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;findByName()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;findByEmail()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;No need to write boilerplate DAO code.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Step 6: Configure Database in &lt;code&gt;application.properties&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Your project needs DB configuration.&lt;/p&gt;

&lt;p&gt;In general, you set:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;datasource URL&lt;/li&gt;
&lt;li&gt;username/password (if needed)&lt;/li&gt;
&lt;li&gt;JPA behavior like ddl-auto&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is where you control:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;table creation/update&lt;/li&gt;
&lt;li&gt;SQL logging&lt;/li&gt;
&lt;li&gt;dialect settings&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🧠 Step 7: Add Service Layer (Business Logic)
&lt;/h2&gt;

&lt;p&gt;This is the layer that makes your backend “real”.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Service Layer&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;encapsulates business logic&lt;/li&gt;
&lt;li&gt;connects controller and repository&lt;/li&gt;
&lt;li&gt;keeps architecture clean&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Rule:&lt;br&gt;
👉 &lt;strong&gt;Controller → Service → Repository → DB&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  ✅ Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Setting up Spring Boot with &lt;strong&gt;Web MVC + Spring Data JPA&lt;/strong&gt; is the moment where projects start feeling like actual backend systems — not demos.&lt;/p&gt;

&lt;p&gt;Once this setup is done, you’re ready to build:&lt;br&gt;
✅ CRUD APIs&lt;br&gt;
✅ validations&lt;br&gt;
✅ exception handling&lt;br&gt;
✅ pagination&lt;br&gt;
✅ relationships&lt;/p&gt;

&lt;p&gt;This post is part of my &lt;strong&gt;learning-in-public&lt;/strong&gt; journey while exploring Spring Boot and real-world backend development.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What was the most confusing part when you set up your first Spring Boot + JPA project?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>springboot</category>
      <category>java</category>
      <category>backend</category>
      <category>webdev</category>
    </item>
    <item>
      <title>🐌 My Spring Boot API Was Fast… Until Relationships Caused N+1 Queries</title>
      <dc:creator>Shashwath S H</dc:creator>
      <pubDate>Sat, 17 Jan 2026 18:51:18 +0000</pubDate>
      <link>https://dev.to/shashwathsh/my-spring-boot-api-was-fast-until-relationships-caused-n1-queries-18fn</link>
      <guid>https://dev.to/shashwathsh/my-spring-boot-api-was-fast-until-relationships-caused-n1-queries-18fn</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6m7fdu78sdpszi7p4h1u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6m7fdu78sdpszi7p4h1u.png" alt="FetchType and Orphan Removal in Relational Queries, N+1 Query Optimization" width="800" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When I first built relational APIs using Spring Data JPA, everything worked fine.&lt;/p&gt;

&lt;p&gt;Entities saved properly ✅&lt;br&gt;
Relationships mapped correctly ✅&lt;br&gt;
Responses returned clean JSON ✅&lt;/p&gt;

&lt;p&gt;But then I noticed something scary:&lt;/p&gt;

&lt;p&gt;The API got slower &lt;strong&gt;as the data increased&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;No code changes.&lt;br&gt;
No heavy computation.&lt;br&gt;
Just… slower.&lt;/p&gt;

&lt;p&gt;That’s when I discovered the hidden performance killers:&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;FetchType&lt;/strong&gt;&lt;br&gt;
✅ &lt;strong&gt;orphanRemoval&lt;/strong&gt;&lt;br&gt;
✅ &lt;strong&gt;N+1 Query problem&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🧠 FetchType: The Silent Decision Maker
&lt;/h2&gt;

&lt;p&gt;Whenever you map a relationship like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;@OneToMany&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;@ManyToOne&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;@OneToOne&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;@ManyToMany&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hibernate has to decide:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Should I load related data now… or later?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That decision is controlled using &lt;strong&gt;FetchType&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔥 Two Fetch Strategies in JPA
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ✅ &lt;strong&gt;FetchType.EAGER&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Hibernate loads related data &lt;strong&gt;immediately&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Parent loads ✅&lt;/li&gt;
&lt;li&gt;Child loads ✅&lt;/li&gt;
&lt;li&gt;Even if you don’t need child data ❌&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This can lead to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Heavy queries&lt;/li&gt;
&lt;li&gt;Bigger payloads&lt;/li&gt;
&lt;li&gt;Slower APIs&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  ✅ &lt;strong&gt;FetchType.LAZY&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Hibernate loads related data &lt;strong&gt;only when needed&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Parent loads ✅&lt;/li&gt;
&lt;li&gt;Child loads only when accessed ✅&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is usually better for performance…&lt;/p&gt;

&lt;p&gt;But it introduces real-world issues if you're not careful.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚠️ The Real Problem: &lt;strong&gt;N+1 Queries&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This is where performance gets destroyed quietly.&lt;/p&gt;

&lt;h3&gt;
  
  
  What happens in N+1?
&lt;/h3&gt;

&lt;p&gt;You fetch:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1 query for parent list ✅
Then for each parent:&lt;/li&gt;
&lt;li&gt;1 query for its children ❌ ❌ ❌&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So if you have 10 parents:&lt;/p&gt;

&lt;p&gt;👉 1 (parent query) + 10 (child queries) = &lt;strong&gt;11 total queries&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you have 100 parents:&lt;br&gt;
👉 &lt;strong&gt;101 queries&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That’s why it’s called &lt;strong&gt;N+1&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  💥 Why N+1 Happens So Often
&lt;/h2&gt;

&lt;p&gt;Because with &lt;strong&gt;LAZY loading&lt;/strong&gt;, Hibernate doesn’t fetch children in the first query.&lt;/p&gt;

&lt;p&gt;So when you loop through results and access relations, Hibernate keeps firing extra SELECT queries.&lt;/p&gt;

&lt;p&gt;And the scary part?&lt;/p&gt;

&lt;p&gt;✅ Your code looks clean&lt;br&gt;
❌ Your database gets abused&lt;/p&gt;




&lt;h2&gt;
  
  
  🛠️ How to Fix / Optimize N+1 Queries
&lt;/h2&gt;

&lt;p&gt;N+1 is not “a small issue”.&lt;br&gt;
It’s a &lt;strong&gt;performance bug&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Common ways to fix it include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fetching required relations efficiently (instead of triggering lazy loads repeatedly)&lt;/li&gt;
&lt;li&gt;Using optimized fetch strategies in queries&lt;/li&gt;
&lt;li&gt;Designing API responses properly (DTOs / projections)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The key is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Fetch what you need — not everything, and not one-by-one.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  🧹 Orphan Removal: Helpful… and Dangerous
&lt;/h2&gt;

&lt;p&gt;When I saw &lt;code&gt;orphanRemoval = true&lt;/code&gt;, I thought it was just cleanup.&lt;/p&gt;

&lt;p&gt;But orphan removal means:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When a child is removed from the parent’s collection, it gets deleted from the DB automatically.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Example idea:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Patient has appointments&lt;/li&gt;
&lt;li&gt;Remove an appointment from list&lt;/li&gt;
&lt;li&gt;Hibernate deletes that appointment record ✅&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is useful when:&lt;br&gt;
✅ Child cannot exist without parent&lt;/p&gt;

&lt;p&gt;But it can also cause unexpected deletions if used blindly.&lt;/p&gt;




&lt;h2&gt;
  
  
  ✅ orphanRemoval vs Cascade REMOVE (Quick Clarity)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;CascadeType.REMOVE&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Child gets deleted when &lt;strong&gt;parent is deleted&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;orphanRemoval = true&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Child gets deleted when it is &lt;strong&gt;no longer referenced by parent&lt;/strong&gt;&lt;br&gt;
(even when parent still exists)&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚠️ The Mistakes I Made
&lt;/h2&gt;

&lt;p&gt;I used to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;strong&gt;EAGER&lt;/strong&gt; without thinking&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;LAZY&lt;/strong&gt; and accidentally trigger N+1 queries&lt;/li&gt;
&lt;li&gt;Enable &lt;strong&gt;orphanRemoval&lt;/strong&gt; and forget about it&lt;/li&gt;
&lt;li&gt;Wonder why performance dropped randomly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once I understood FetchType + N+1:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;APIs became faster&lt;/li&gt;
&lt;li&gt;Queries became predictable&lt;/li&gt;
&lt;li&gt;Debugging got easier&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🚀 Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Relationships in Spring Data JPA are easy to write…&lt;/p&gt;

&lt;p&gt;…but hard to scale if you ignore performance.&lt;/p&gt;

&lt;p&gt;If your Spring Boot API is slow and you don’t know why:&lt;/p&gt;

&lt;p&gt;Check:&lt;br&gt;
✅ &lt;strong&gt;FetchType&lt;/strong&gt;&lt;br&gt;
✅ &lt;strong&gt;N+1 queries&lt;/strong&gt;&lt;br&gt;
✅ &lt;strong&gt;orphanRemoval behavior&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This post is part of my &lt;strong&gt;learning-in-public&lt;/strong&gt; journey as I explore Spring Boot and real-world backend optimization.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Have you ever noticed your API getting slower after adding relationships?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>springboot</category>
      <category>java</category>
      <category>backend</category>
      <category>performance</category>
    </item>
    <item>
      <title>💀 I Deleted a Parent Entity… and Hibernate Deleted Everything (Cascades Explained)</title>
      <dc:creator>Shashwath S H</dc:creator>
      <pubDate>Sat, 17 Jan 2026 12:48:10 +0000</pubDate>
      <link>https://dev.to/shashwathsh/i-deleted-a-parent-entity-and-hibernate-deleted-everything-cascades-explained-27gp</link>
      <guid>https://dev.to/shashwathsh/i-deleted-a-parent-entity-and-hibernate-deleted-everything-cascades-explained-27gp</guid>
      <description>&lt;p&gt;When I started working with Spring Data JPA relationships, I thought saving and deleting was simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;delete&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then I tried it with relationships like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Patient → Appointments&lt;/li&gt;
&lt;li&gt;User → Orders&lt;/li&gt;
&lt;li&gt;Department → Employees&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And suddenly…&lt;/p&gt;

&lt;p&gt;✅ Saving one object saved many&lt;br&gt;
💀 Deleting one object deleted many&lt;br&gt;
❌ Updates didn’t behave how I expected&lt;/p&gt;

&lt;p&gt;That’s when I learned the two concepts that control everything:&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Cascade Types&lt;/strong&gt;&lt;br&gt;
✅ &lt;strong&gt;@Transactional&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🧠 What is &lt;strong&gt;Cascading&lt;/strong&gt; in JPA?
&lt;/h2&gt;

&lt;p&gt;In JPA, &lt;strong&gt;cascading&lt;/strong&gt; tells Hibernate:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“When I perform an operation on the parent, automatically apply it to the child entities too.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So instead of manually doing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;save parent&lt;/li&gt;
&lt;li&gt;save child&lt;/li&gt;
&lt;li&gt;save child&lt;/li&gt;
&lt;li&gt;save child&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hibernate can do it for you.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔁 Common &lt;strong&gt;Cascade Types&lt;/strong&gt; (and what they really mean)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ✅ &lt;strong&gt;CascadeType.PERSIST&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;When you save the parent, child entities are saved automatically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use case:&lt;/strong&gt; parent creation should create children too.&lt;/p&gt;




&lt;h3&gt;
  
  
  ✅ &lt;strong&gt;CascadeType.MERGE&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;When you update the parent, related child updates propagate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use case:&lt;/strong&gt; parent update should sync children.&lt;/p&gt;




&lt;h3&gt;
  
  
  💀 &lt;strong&gt;CascadeType.REMOVE&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;When you delete the parent, child entities are deleted too.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use case:&lt;/strong&gt; child has no meaning without parent (like appointments without patient).&lt;/p&gt;

&lt;p&gt;⚠️ This is the one that can wipe data if used blindly.&lt;/p&gt;




&lt;h3&gt;
  
  
  ✅ &lt;strong&gt;CascadeType.REFRESH&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Reloads child entities when parent is refreshed.&lt;/p&gt;




&lt;h3&gt;
  
  
  ✅ &lt;strong&gt;CascadeType.DETACH&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Detaches child entities when parent is detached from persistence context.&lt;/p&gt;




&lt;h3&gt;
  
  
  ✅ &lt;strong&gt;CascadeType.ALL&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Applies all cascade operations:&lt;br&gt;
&lt;strong&gt;PERSIST, MERGE, REMOVE, REFRESH, DETACH&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This feels convenient — but it can be dangerous if you don’t understand it.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧹 The Hidden Killer: &lt;strong&gt;orphanRemoval = true&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This is not a cascade type, but it changes deletion behavior massively.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;orphanRemoval = true&lt;/strong&gt; means:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If a child is removed from the parent collection, Hibernate deletes it from the database automatically.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Parent remains in DB ✅&lt;/li&gt;
&lt;li&gt;Child removed from list ❌ → deleted from DB 💀&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ✅ Cascade REMOVE vs orphanRemoval (Important Difference)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;CascadeType.REMOVE&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Child is deleted only when &lt;strong&gt;parent is deleted&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;orphanRemoval = true&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Child is deleted when it is &lt;strong&gt;no longer referenced by parent&lt;/strong&gt;, even if parent is still alive.&lt;/p&gt;

&lt;p&gt;This is perfect for true parent-child lifecycle relationships.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔥 Why &lt;strong&gt;@Transactional&lt;/strong&gt; Becomes Important in Relational Queries
&lt;/h2&gt;

&lt;p&gt;At first I thought transactions are only for big systems.&lt;/p&gt;

&lt;p&gt;But relational operations break easily without a transaction because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;multiple DB operations happen in one flow&lt;/li&gt;
&lt;li&gt;entity states change during execution&lt;/li&gt;
&lt;li&gt;lazy loading may fail outside a session&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s why Spring provides &lt;strong&gt;@Transactional&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧠 What does &lt;strong&gt;@Transactional&lt;/strong&gt; do?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;@Transactional&lt;/strong&gt; ensures that all operations inside a method run in &lt;strong&gt;one transaction&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Either everything succeeds ✅&lt;/li&gt;
&lt;li&gt;Or everything rolls back ❌&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This makes database operations &lt;strong&gt;safe and consistent&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚠️ What Happens Without @Transactional?
&lt;/h2&gt;

&lt;p&gt;This is where people get errors like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;partial save (half data inserted, half failed)&lt;/li&gt;
&lt;li&gt;inconsistent state&lt;/li&gt;
&lt;li&gt;lazy-loading issues (accessing relations after session closes)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even if your code looks correct, database behavior becomes unpredictable.&lt;/p&gt;




&lt;h2&gt;
  
  
  ✅ Real-World Scenario: Saving Parent + Children
&lt;/h2&gt;

&lt;p&gt;If you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Patient has many Appointments&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and you set:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;cascade = &lt;strong&gt;PERSIST&lt;/strong&gt; or &lt;strong&gt;ALL&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then:&lt;br&gt;
✅ Saving Patient automatically saves Appointments&lt;br&gt;
✅ No need to explicitly save Appointment records&lt;/p&gt;

&lt;p&gt;This keeps code clean and avoids repeated repository calls.&lt;/p&gt;




&lt;h2&gt;
  
  
  ✅ Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Cascading and transactions are not “extra JPA features”.&lt;/p&gt;

&lt;p&gt;They decide whether your application is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;clean ✅&lt;/li&gt;
&lt;li&gt;scalable ✅&lt;/li&gt;
&lt;li&gt;safe ✅
or&lt;/li&gt;
&lt;li&gt;unpredictable ❌&lt;/li&gt;
&lt;li&gt;dangerous ❌&lt;/li&gt;
&lt;li&gt;bug-prone ❌&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you’re using Spring Data JPA relationships, you can’t ignore:&lt;br&gt;
✅ &lt;strong&gt;Cascade Types&lt;/strong&gt;&lt;br&gt;
✅ &lt;strong&gt;orphanRemoval&lt;/strong&gt;&lt;br&gt;
✅ &lt;strong&gt;@Transactional&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This post is part of my &lt;strong&gt;learning-in-public&lt;/strong&gt; journey while exploring Spring Boot and real-world backend behavior.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Have you ever deleted a parent entity and lost child data by mistake? 😅&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>springboot</category>
      <category>java</category>
      <category>backend</category>
      <category>jpa</category>
    </item>
    <item>
      <title>🔗 JPA Relationships Finally Made Sense When I Stopped Memorizing Them</title>
      <dc:creator>Shashwath S H</dc:creator>
      <pubDate>Fri, 16 Jan 2026 05:59:54 +0000</pubDate>
      <link>https://dev.to/shashwathsh/jpa-relationships-finally-made-sense-when-i-stopped-memorizing-them-1h81</link>
      <guid>https://dev.to/shashwathsh/jpa-relationships-finally-made-sense-when-i-stopped-memorizing-them-1h81</guid>
      <description>&lt;p&gt;When I started Spring Data JPA, I thought relationships would be easy.&lt;/p&gt;

&lt;p&gt;Just add:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;@OneToOne&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;@OneToMany&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;@ManyToOne&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;@ManyToMany&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Done ✅&lt;/p&gt;

&lt;p&gt;But then I hit real problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Foreign keys didn’t update&lt;/li&gt;
&lt;li&gt;Extra tables appeared&lt;/li&gt;
&lt;li&gt;Deletes didn’t behave correctly&lt;/li&gt;
&lt;li&gt;Infinite JSON recursion happened&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s when I realized:&lt;br&gt;
&lt;strong&gt;JPA relationships are not about annotations… they’re about ownership and data modeling.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🧠 The Real Meaning of JPA Relationships
&lt;/h2&gt;

&lt;p&gt;JPA mappings are basically answering one question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;How do two tables relate to each other in the database?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Spring Data JPA only makes it easier — the relationship rules still come from SQL fundamentals.&lt;/p&gt;




&lt;h2&gt;
  
  
  1️⃣ &lt;strong&gt;@OneToOne&lt;/strong&gt; — One record links to one record
&lt;/h2&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One &lt;strong&gt;User&lt;/strong&gt; has one &lt;strong&gt;Profile&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;One &lt;strong&gt;Employee&lt;/strong&gt; has one &lt;strong&gt;IDCard&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;✅ Best used when the child record has meaning only with the parent.&lt;/p&gt;

&lt;p&gt;💡 Tip:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Usually implemented using a &lt;strong&gt;foreign key&lt;/strong&gt; with a &lt;strong&gt;unique constraint&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  2️⃣ &lt;strong&gt;@ManyToOne&lt;/strong&gt; — Many children belong to one parent
&lt;/h2&gt;

&lt;p&gt;This is one of the most common relationships in real applications.&lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Many &lt;strong&gt;Employees&lt;/strong&gt; belong to one &lt;strong&gt;Department&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Many &lt;strong&gt;Orders&lt;/strong&gt; belong to one &lt;strong&gt;Customer&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Important point:&lt;br&gt;
👉 The &lt;strong&gt;Many side holds the foreign key&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That’s why &lt;strong&gt;@ManyToOne is usually the owning side&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  3️⃣ &lt;strong&gt;@OneToMany&lt;/strong&gt; — One parent has many children
&lt;/h2&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One &lt;strong&gt;Department&lt;/strong&gt; has many &lt;strong&gt;Employees&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;One &lt;strong&gt;Customer&lt;/strong&gt; has many &lt;strong&gt;Orders&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This relationship is basically the reverse of &lt;strong&gt;ManyToOne&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;But here’s what confused me initially:&lt;/p&gt;

&lt;p&gt;⚠️ &lt;strong&gt;The OneToMany side is often NOT the owning side&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Meaning:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Changing the parent collection alone may not update the foreign key&lt;/li&gt;
&lt;li&gt;Ownership decides what actually updates in the database&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  4️⃣ &lt;strong&gt;@ManyToMany&lt;/strong&gt; — The most confusing one (at first)
&lt;/h2&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Many &lt;strong&gt;Students&lt;/strong&gt; can enroll in many &lt;strong&gt;Courses&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Many &lt;strong&gt;Users&lt;/strong&gt; can have many &lt;strong&gt;Roles&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This mapping creates a &lt;strong&gt;join table&lt;/strong&gt; in the database automatically.&lt;/p&gt;

&lt;p&gt;That join table stores:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;student_id&lt;/li&gt;
&lt;li&gt;course_id&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This works great… but in real-world apps:&lt;/p&gt;

&lt;p&gt;⚠️ &lt;strong&gt;ManyToMany can become messy quickly&lt;/strong&gt;&lt;br&gt;
Because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You often need extra fields (like createdAt, status, etc.)&lt;/li&gt;
&lt;li&gt;Join tables become actual entities later&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ⚠️ The Biggest Mistake I Made
&lt;/h2&gt;

&lt;p&gt;I thought relationships were just:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Pick an annotation and done.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But the real key is:&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Owning Side vs Inverse Side&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;owning side controls foreign key updates&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;The inverse side only reflects the relationship&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you don’t understand ownership:&lt;br&gt;
your mapping will “work sometimes” — and break later.&lt;/p&gt;




&lt;h2&gt;
  
  
  ✅ Final Thoughts
&lt;/h2&gt;

&lt;p&gt;JPA relationships became easy when I stopped memorizing definitions and started thinking like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Where is the &lt;strong&gt;foreign key&lt;/strong&gt; stored?&lt;/li&gt;
&lt;li&gt;Who is the &lt;strong&gt;parent&lt;/strong&gt;?&lt;/li&gt;
&lt;li&gt;Who controls the relationship updates?&lt;/li&gt;
&lt;li&gt;Do I need a &lt;strong&gt;join table&lt;/strong&gt;?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you’re learning Spring Boot and struggling with mappings…&lt;/p&gt;

&lt;p&gt;You’re not alone 😅&lt;br&gt;
This topic is confusing at first — but once it clicks, backend development becomes 10x easier.&lt;/p&gt;

&lt;p&gt;This post is part of my &lt;strong&gt;learning-in-public&lt;/strong&gt; journey while exploring Spring Boot and real-world backend design.&lt;/p&gt;

</description>
      <category>springboot</category>
      <category>java</category>
      <category>backend</category>
      <category>hibernate</category>
    </item>
    <item>
      <title>🧠 Hibernate Felt Like Magic… Until I Understood Entity Lifecycle &amp; Cascading</title>
      <dc:creator>Shashwath S H</dc:creator>
      <pubDate>Thu, 15 Jan 2026 06:27:23 +0000</pubDate>
      <link>https://dev.to/shashwathsh/hibernate-felt-like-magic-until-i-understood-entity-lifecycle-cascading-1d0d</link>
      <guid>https://dev.to/shashwathsh/hibernate-felt-like-magic-until-i-understood-entity-lifecycle-cascading-1d0d</guid>
      <description>&lt;p&gt;At first, Spring Data JPA felt amazing.&lt;/p&gt;

&lt;p&gt;I wrote:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Data magically appeared in the database.&lt;/p&gt;

&lt;p&gt;But then strange things started happening.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Updates didn’t persist&lt;/li&gt;
&lt;li&gt;Deletes didn’t behave as expected&lt;/li&gt;
&lt;li&gt;Child records disappeared (or didn’t)&lt;/li&gt;
&lt;li&gt;Entities acted… alive&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s when I realized:&lt;/p&gt;

&lt;p&gt;👉 I didn’t understand &lt;strong&gt;what Hibernate was actually doing&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  🏗️ The Big Stack (Clear Mental Model)
&lt;/h2&gt;

&lt;p&gt;Before diving deep, here’s the &lt;strong&gt;actual hierarchy&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;Spring Data JPA&lt;/strong&gt; → abstraction (repositories)&lt;br&gt;
👉 &lt;strong&gt;JPA&lt;/strong&gt; → specification (rules)&lt;br&gt;
👉 &lt;strong&gt;Hibernate&lt;/strong&gt; → implementation (ORM engine)&lt;br&gt;
👉 &lt;strong&gt;JDBC&lt;/strong&gt; → executes SQL&lt;br&gt;
👉 &lt;strong&gt;Database&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyaj2udyzrk8u7ctorfew.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyaj2udyzrk8u7ctorfew.png" alt="Spring JPA" width="800" height="424"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Spring Data JPA reduces boilerplate.&lt;br&gt;
Hibernate does the heavy lifting.&lt;br&gt;
JDBC talks to the database.&lt;/p&gt;


&lt;h2&gt;
  
  
  🧬 Hibernate &lt;strong&gt;Entity Lifecycle&lt;/strong&gt; (The Missing Piece)
&lt;/h2&gt;

&lt;p&gt;Every JPA entity lives in &lt;strong&gt;one of these states&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Understanding this changed everything for me.&lt;/p&gt;


&lt;h3&gt;
  
  
  🟡 &lt;strong&gt;Transient&lt;/strong&gt;
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Patient&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Patient&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Just a Java object&lt;/li&gt;
&lt;li&gt;Not tracked by Hibernate&lt;/li&gt;
&lt;li&gt;Not stored in DB&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If garbage collected → gone forever.&lt;/p&gt;


&lt;h3&gt;
  
  
  🟢 &lt;strong&gt;Persistent&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Triggered by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;persist()&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;save()&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;find()&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;get() / load()&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Entity is managed&lt;/li&gt;
&lt;li&gt;Tracked inside &lt;strong&gt;Persistence Context&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Changes are auto-synced to DB&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 This is where &lt;strong&gt;Hibernate magic happens&lt;/strong&gt;.&lt;/p&gt;


&lt;h3&gt;
  
  
  🔵 &lt;strong&gt;Detached&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Triggered by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;detach()&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;clear()&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;close()&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Entity:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Exists in DB&lt;/li&gt;
&lt;li&gt;Exists in memory&lt;/li&gt;
&lt;li&gt;But Hibernate stops tracking it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Changes won’t be saved unless you &lt;strong&gt;merge()&lt;/strong&gt;.&lt;/p&gt;


&lt;h3&gt;
  
  
  🔴 &lt;strong&gt;Removed&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Triggered by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;remove()&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;delete()&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Entity:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Marked for deletion&lt;/li&gt;
&lt;li&gt;Deleted during transaction commit&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj9uqpk5ie3szhu6dg908.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj9uqpk5ie3szhu6dg908.png" alt="Entity Lifecycle" width="800" height="424"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  🧠 EntityManager &amp;amp; Persistence Context (VERY IMPORTANT)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm7mm8bdgian47r3yvix0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm7mm8bdgian47r3yvix0.png" alt="VERY IMPORTANT" width="800" height="476"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hibernate doesn’t hit the DB immediately.&lt;/p&gt;

&lt;p&gt;It first checks the &lt;strong&gt;Persistence Context&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Flow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;find()&lt;/code&gt; → checks Persistence Context&lt;/li&gt;
&lt;li&gt;If found → return object&lt;/li&gt;
&lt;li&gt;If not → DB SELECT&lt;/li&gt;
&lt;li&gt;Store entity in Persistence Context&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;👉 This is why &lt;strong&gt;multiple finds don’t always hit the DB&lt;/strong&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  🔗 Relationships: &lt;strong&gt;Owning Side vs Inverse Side&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This is where many bugs are born.&lt;/p&gt;
&lt;h3&gt;
  
  
  🔑 Owning Side
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Controls the &lt;strong&gt;foreign key&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Updates actually affect DB&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  🔄 Inverse Side
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Only reflects relationship&lt;/li&gt;
&lt;li&gt;Cannot update foreign key&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 Updating inverse side alone does &lt;strong&gt;nothing&lt;/strong&gt; in DB.&lt;/p&gt;


&lt;h2&gt;
  
  
  🏥 One-to-Many Example (Patient &amp;amp; Appointments)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Patient&lt;/strong&gt; = Parent&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Appointment&lt;/strong&gt; = Child&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If Patient is deleted → Appointments should also go.&lt;/p&gt;

&lt;p&gt;That’s why:&lt;br&gt;
👉 &lt;strong&gt;Patient is the owning lifecycle controller&lt;/strong&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  🔁 Cascading: Let Hibernate Do the Work
&lt;/h2&gt;

&lt;p&gt;Cascading tells Hibernate:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“When I do something to the parent, do the same to children.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Common Cascade Types:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;PERSIST&lt;/strong&gt; → save child automatically&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MERGE&lt;/strong&gt; → update child&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;REMOVE&lt;/strong&gt; → delete child&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;REFRESH&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DETACH&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ALL&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Save Patient → Appointments saved automatically&lt;/li&gt;
&lt;li&gt;Delete Patient → Appointments deleted automatically&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No manual repository calls needed.&lt;/p&gt;


&lt;h2&gt;
  
  
  🧹 orphanRemoval = true (POWERFUL &amp;amp; DANGEROUS)
&lt;/h2&gt;

&lt;p&gt;This one surprised me.&lt;/p&gt;
&lt;h3&gt;
  
  
  What it does:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Deletes child entity when it’s &lt;strong&gt;removed from parent collection&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Parent still exists&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;patient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAppointments&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;remove&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;appointment&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;👉 Appointment gets deleted from DB automatically.&lt;/p&gt;




&lt;h3&gt;
  
  
  orphanRemoval vs CascadeType.REMOVE
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;CascadeType.REMOVE&lt;/th&gt;
&lt;th&gt;orphanRemoval&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Parent deleted&lt;/td&gt;
&lt;td&gt;✅ Child deleted&lt;/td&gt;
&lt;td&gt;✅ Child deleted&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Child removed from collection&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Parent still exists&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  🎯 When to Use orphanRemoval
&lt;/h2&gt;

&lt;p&gt;Perfect when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Child has &lt;strong&gt;no meaning without parent&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Appointment without Patient&lt;/li&gt;
&lt;li&gt;Insurance without User&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;⚠️ Use carefully — deletions are automatic.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚠️ The Mistakes I Was Making
&lt;/h2&gt;

&lt;p&gt;I used to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Call save() everywhere&lt;/li&gt;
&lt;li&gt;Ignore entity states&lt;/li&gt;
&lt;li&gt;Manually delete children&lt;/li&gt;
&lt;li&gt;Get confused by unexpected deletes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once I understood:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Entity lifecycle&lt;/li&gt;
&lt;li&gt;Persistence Context&lt;/li&gt;
&lt;li&gt;Cascades &amp;amp; orphanRemoval&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 Hibernate stopped feeling random.&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Hibernate is not magic.&lt;/p&gt;

&lt;p&gt;It’s &lt;strong&gt;state + rules + lifecycle&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If JPA ever feels:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unpredictable&lt;/li&gt;
&lt;li&gt;Dangerous&lt;/li&gt;
&lt;li&gt;Confusing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You’re missing this layer of understanding.&lt;/p&gt;

&lt;p&gt;This post is part of my &lt;strong&gt;learning-in-public&lt;/strong&gt; journey while exploring Spring Boot, JPA, and real-world backend behavior.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Did Hibernate ever delete or update something you didn’t expect?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>springboot</category>
      <category>java</category>
      <category>backend</category>
      <category>hibernate</category>
    </item>
    <item>
      <title>🎯 I Was Fetching Entire Entities… Until I Learned About Projections</title>
      <dc:creator>Shashwath S H</dc:creator>
      <pubDate>Wed, 14 Jan 2026 04:43:21 +0000</pubDate>
      <link>https://dev.to/shashwathsh/i-was-fetching-entire-entities-until-i-learned-about-projections-ja9</link>
      <guid>https://dev.to/shashwathsh/i-was-fetching-entire-entities-until-i-learned-about-projections-ja9</guid>
      <description>&lt;p&gt;When I started using Spring Data JPA, my approach was simple:&lt;/p&gt;

&lt;p&gt;Need data?&lt;br&gt;
Fetch the entity.&lt;/p&gt;

&lt;p&gt;Every time.&lt;/p&gt;

&lt;p&gt;It worked.&lt;br&gt;
But something felt wrong.&lt;/p&gt;

&lt;p&gt;APIs returned &lt;strong&gt;too much data&lt;/strong&gt;.&lt;br&gt;
Performance started degrading.&lt;br&gt;
Clients received fields they never asked for.&lt;/p&gt;

&lt;p&gt;That’s when I discovered &lt;strong&gt;Spring Data JPA Projections&lt;/strong&gt; — and everything changed.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧠 What Are &lt;strong&gt;Projections&lt;/strong&gt; in Spring Data JPA?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Projections&lt;/strong&gt; allow you to fetch &lt;strong&gt;only the data you actually need&lt;/strong&gt; from the database.&lt;/p&gt;

&lt;p&gt;Instead of loading the entire entity:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You select specific fields&lt;/li&gt;
&lt;li&gt;You reduce query overhead&lt;/li&gt;
&lt;li&gt;You return lighter responses&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In short:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Projections help you avoid over-fetching data.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  ⚠️ The Problem with Fetching Full Entities
&lt;/h2&gt;

&lt;p&gt;Fetching full entities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Loads unnecessary columns&lt;/li&gt;
&lt;li&gt;Increases memory usage&lt;/li&gt;
&lt;li&gt;Makes APIs slower&lt;/li&gt;
&lt;li&gt;Exposes more data than required&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This may be fine for small apps — but it doesn’t scale.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧩 Types of &lt;strong&gt;Projections&lt;/strong&gt; in Spring Data JPA
&lt;/h2&gt;

&lt;p&gt;Spring Data JPA supports &lt;strong&gt;three main types of projections&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Each one solves a slightly different problem.&lt;/p&gt;




&lt;h2&gt;
  
  
  1️⃣ &lt;strong&gt;Interface-Based Projections&lt;/strong&gt; (Most Common)
&lt;/h2&gt;

&lt;p&gt;This is the most popular and cleanest way to use projections.&lt;/p&gt;

&lt;p&gt;You define an &lt;strong&gt;interface&lt;/strong&gt; with getter methods for required fields.&lt;/p&gt;

&lt;p&gt;Spring Data JPA automatically maps query results to it.&lt;/p&gt;

&lt;p&gt;Why this is powerful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No implementation needed&lt;/li&gt;
&lt;li&gt;Clean and readable&lt;/li&gt;
&lt;li&gt;Works seamlessly with repositories&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Perfect when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You want partial data&lt;/li&gt;
&lt;li&gt;You don’t want extra objects&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  2️⃣ &lt;strong&gt;Class-Based (DTO) Projections&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Here, you define a &lt;strong&gt;DTO class&lt;/strong&gt; and use a constructor to map values.&lt;/p&gt;

&lt;p&gt;This is useful when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You want custom logic&lt;/li&gt;
&lt;li&gt;You want computed fields&lt;/li&gt;
&lt;li&gt;You need strong control over response structure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Slightly more verbose — but very flexible.&lt;/p&gt;




&lt;h2&gt;
  
  
  3️⃣ &lt;strong&gt;Open Projections&lt;/strong&gt; (Advanced but Dangerous)
&lt;/h2&gt;

&lt;p&gt;Open projections allow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Derived values&lt;/li&gt;
&lt;li&gt;Expression-based fields&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They look powerful — but there’s a catch.&lt;/p&gt;

&lt;p&gt;⚠️ &lt;strong&gt;They may trigger additional queries&lt;/strong&gt;, impacting performance.&lt;/p&gt;

&lt;p&gt;Use them carefully and only when needed.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔍 How Spring Data JPA Makes This Work
&lt;/h2&gt;

&lt;p&gt;Under the hood:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Spring analyzes your repository method return type&lt;/li&gt;
&lt;li&gt;Detects projection usage&lt;/li&gt;
&lt;li&gt;Generates optimized queries&lt;/li&gt;
&lt;li&gt;Maps results automatically&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You don’t write SQL.&lt;br&gt;
You don’t write mapping code.&lt;/p&gt;

&lt;p&gt;This is &lt;strong&gt;convention over configuration&lt;/strong&gt; done right.&lt;/p&gt;




&lt;h2&gt;
  
  
  🛠️ Projections with Repository Methods
&lt;/h2&gt;

&lt;p&gt;Projections work naturally with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Query methods&lt;/li&gt;
&lt;li&gt;Derived queries&lt;/li&gt;
&lt;li&gt;Sorting&lt;/li&gt;
&lt;li&gt;Pagination&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Which means:&lt;br&gt;
👉 You can combine &lt;strong&gt;Projections + Pageable + Sort&lt;/strong&gt; for production-ready APIs.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚠️ The Mistake I Was Making
&lt;/h2&gt;

&lt;p&gt;I used to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Always return entities&lt;/li&gt;
&lt;li&gt;Let Jackson decide response shape&lt;/li&gt;
&lt;li&gt;Ignore payload size&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It worked… until APIs slowed down.&lt;/p&gt;

&lt;p&gt;After switching to projections:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Responses became lighter&lt;/li&gt;
&lt;li&gt;Performance improved&lt;/li&gt;
&lt;li&gt;APIs felt cleaner and safer&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🚀 Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Spring Data JPA Projections are not a micro-optimization.&lt;/p&gt;

&lt;p&gt;They are a &lt;strong&gt;design decision&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If your Spring Boot APIs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Return too much data&lt;/li&gt;
&lt;li&gt;Feel slow&lt;/li&gt;
&lt;li&gt;Expose unnecessary fields&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Start with &lt;strong&gt;Projections&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This post is part of my &lt;strong&gt;learning-in-public&lt;/strong&gt; journey while exploring Spring Boot and real-world backend optimization.&lt;/p&gt;

</description>
      <category>springboot</category>
      <category>java</category>
      <category>backend</category>
      <category>performance</category>
    </item>
    <item>
      <title>🐌 “My Spring Boot API Became Slow… Until I Learned Pagination &amp; Sorting”</title>
      <dc:creator>Shashwath S H</dc:creator>
      <pubDate>Tue, 13 Jan 2026 05:18:06 +0000</pubDate>
      <link>https://dev.to/shashwathsh/my-spring-boot-api-became-slow-until-i-learned-pagination-sorting-20md</link>
      <guid>https://dev.to/shashwathsh/my-spring-boot-api-became-slow-until-i-learned-pagination-sorting-20md</guid>
      <description>&lt;p&gt;At first, my Spring Boot APIs worked perfectly.&lt;/p&gt;

&lt;p&gt;Data was returned.&lt;br&gt;
UI was happy.&lt;br&gt;
Everything looked fine.&lt;/p&gt;

&lt;p&gt;Then the database grew.&lt;/p&gt;

&lt;p&gt;Hundreds of records became thousands.&lt;br&gt;
Responses slowed down.&lt;br&gt;
Memory usage increased.&lt;/p&gt;

&lt;p&gt;That’s when I realized I was missing something critical:&lt;br&gt;
&lt;strong&gt;Sorting and Pagination&lt;/strong&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  🧠 Why &lt;strong&gt;Sorting &amp;amp; Pagination&lt;/strong&gt; Matter
&lt;/h2&gt;

&lt;p&gt;In real applications:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Databases grow fast&lt;/li&gt;
&lt;li&gt;Fetching everything at once is expensive&lt;/li&gt;
&lt;li&gt;Clients rarely need &lt;em&gt;all&lt;/em&gt; data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sorting and pagination help you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Improve performance&lt;/li&gt;
&lt;li&gt;Reduce memory usage&lt;/li&gt;
&lt;li&gt;Deliver faster APIs&lt;/li&gt;
&lt;li&gt;Build scalable systems&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is &lt;strong&gt;not optional&lt;/strong&gt; in production backends.&lt;/p&gt;


&lt;h2&gt;
  
  
  🔀 Sorting Using &lt;strong&gt;Method Query Names&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Spring Data JPA allows sorting directly in method names.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Employee&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;findAllByOrderByNameAsc&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Employee&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;findAllByOrderByNameDesc&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works well when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sorting logic is fixed&lt;/li&gt;
&lt;li&gt;Requirements are simple&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But real applications need &lt;strong&gt;dynamic sorting&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧭 Dynamic Sorting with the &lt;strong&gt;Sort&lt;/strong&gt; Class
&lt;/h2&gt;

&lt;p&gt;Spring Data JPA provides the &lt;strong&gt;Sort&lt;/strong&gt; class for flexible sorting.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sorting with repository methods
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Employee&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;findByDepartment&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;department&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Sort&lt;/span&gt; &lt;span class="n"&gt;sort&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allows clients to decide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which field to sort&lt;/li&gt;
&lt;li&gt;Ascending or descending order&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ⚙️ Creating &lt;strong&gt;Sort&lt;/strong&gt; Objects
&lt;/h2&gt;

&lt;p&gt;Examples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Sort&lt;/span&gt; &lt;span class="n"&gt;sort&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Sort&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;by&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Sort&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Direction&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ASC&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sortField&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Multiple sorting fields:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Sort&lt;/span&gt; &lt;span class="n"&gt;sort&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Sort&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;by&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="nc"&gt;Sort&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Order&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asc&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
    &lt;span class="nc"&gt;Sort&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Order&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;desc&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"salary"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This gives full control without complex queries.&lt;/p&gt;




&lt;h2&gt;
  
  
  📚 Why Sorting Alone Is Not Enough
&lt;/h2&gt;

&lt;p&gt;Even with sorting:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Returning thousands of rows is inefficient&lt;/li&gt;
&lt;li&gt;APIs become slower&lt;/li&gt;
&lt;li&gt;Clients struggle to handle large responses&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s where &lt;strong&gt;Pagination&lt;/strong&gt; comes in.&lt;/p&gt;




&lt;h2&gt;
  
  
  📄 Understanding &lt;strong&gt;Pagination&lt;/strong&gt; (Simple Terms)
&lt;/h2&gt;

&lt;p&gt;Pagination breaks large datasets into &lt;strong&gt;smaller chunks&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Pagination Concepts
&lt;/h3&gt;

&lt;h3&gt;
  
  
  🔹 &lt;strong&gt;Page&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Represents a single chunk of data.&lt;br&gt;
It also contains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Total elements&lt;/li&gt;
&lt;li&gt;Total pages&lt;/li&gt;
&lt;li&gt;Current page data&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;
  
  
  🔹 &lt;strong&gt;Pageable&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Defines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Page number&lt;/li&gt;
&lt;li&gt;Page size&lt;/li&gt;
&lt;li&gt;Sorting rules&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;
  
  
  🔹 &lt;strong&gt;PageRequest&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;A concrete implementation of &lt;strong&gt;Pageable&lt;/strong&gt; used to create pagination objects.&lt;/p&gt;


&lt;h2&gt;
  
  
  🧩 Using &lt;strong&gt;Pageable&lt;/strong&gt; in Repositories
&lt;/h2&gt;

&lt;p&gt;Spring Data JPA makes pagination extremely simple.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Page&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;findAll&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Pageable&lt;/span&gt; &lt;span class="n"&gt;pageable&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;Page&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;findByLastName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;lastName&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Pageable&lt;/span&gt; &lt;span class="n"&gt;pageable&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No SQL.&lt;br&gt;
No complex logic.&lt;br&gt;
Just clean method signatures.&lt;/p&gt;




&lt;h2&gt;
  
  
  🛠️ Creating a &lt;strong&gt;Pageable&lt;/strong&gt; Instance
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Pageable&lt;/span&gt; &lt;span class="n"&gt;pageable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PageRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;pageNumber&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="nc"&gt;Sort&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;by&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"lastName"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;ascending&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You control page size&lt;/li&gt;
&lt;li&gt;You control page number&lt;/li&gt;
&lt;li&gt;You control sorting&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All in one object.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚠️ The Mistake I Was Making
&lt;/h2&gt;

&lt;p&gt;I used to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fetch all records&lt;/li&gt;
&lt;li&gt;Sort in memory&lt;/li&gt;
&lt;li&gt;Ignore scalability&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It worked… until data increased.&lt;/p&gt;

&lt;p&gt;After using pagination and sorting:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;APIs became faster&lt;/li&gt;
&lt;li&gt;Memory usage dropped&lt;/li&gt;
&lt;li&gt;Backend felt production-ready&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🚀 Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Sorting and Pagination are not “extra features”.&lt;/p&gt;

&lt;p&gt;They are &lt;strong&gt;core backend fundamentals&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If your Spring Boot APIs feel:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Slow&lt;/li&gt;
&lt;li&gt;Heavy&lt;/li&gt;
&lt;li&gt;Hard to scale&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Start here.&lt;/p&gt;

&lt;p&gt;This post is part of my &lt;strong&gt;learning-in-public&lt;/strong&gt; journey while exploring Spring Boot and real-world backend development.&lt;/p&gt;

</description>
      <category>springboot</category>
      <category>backend</category>
      <category>java</category>
      <category>sorting</category>
    </item>
    <item>
      <title>✨I Didn’t Write a Single SQL Query… Yet Spring Data JPA Queried My Database</title>
      <dc:creator>Shashwath S H</dc:creator>
      <pubDate>Sun, 11 Jan 2026 19:41:34 +0000</pubDate>
      <link>https://dev.to/shashwathsh/i-didnt-write-a-single-sql-query-yet-spring-data-jpa-queried-my-database-2bla</link>
      <guid>https://dev.to/shashwathsh/i-didnt-write-a-single-sql-query-yet-spring-data-jpa-queried-my-database-2bla</guid>
      <description>&lt;p&gt;When I started using Spring Data JPA, something felt unreal.&lt;/p&gt;

&lt;p&gt;I wrote a method like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;findByEmail()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No SQL.&lt;br&gt;
No JPQL.&lt;br&gt;
No query annotations.&lt;/p&gt;

&lt;p&gt;Yet… it worked.&lt;/p&gt;

&lt;p&gt;At first, it felt like magic.&lt;br&gt;
Later, it felt confusing.&lt;br&gt;
Finally, it clicked.&lt;/p&gt;


&lt;h2&gt;
  
  
  🧠 Where &lt;strong&gt;Spring Data JPA&lt;/strong&gt; Fits in the Big Picture
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgog2cedaxzhrmp5jfx4l.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgog2cedaxzhrmp5jfx4l.jpeg" alt="Spring data jpa" width="800" height="434"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before diving in, here’s the clear hierarchy:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;Spring Data JPA&lt;/strong&gt; sits on top of &lt;strong&gt;JPA&lt;/strong&gt;&lt;br&gt;
👉 &lt;strong&gt;JPA&lt;/strong&gt; is implemented by &lt;strong&gt;Hibernate&lt;/strong&gt;&lt;br&gt;
👉 &lt;strong&gt;Hibernate&lt;/strong&gt; executes SQL using &lt;strong&gt;JDBC&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Spring Data JPA’s job is simple but powerful:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Make data access easier by removing boilerplate code.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  📦 What is &lt;strong&gt;Spring Data JPA&lt;/strong&gt;?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Spring Data JPA&lt;/strong&gt; is part of the larger &lt;strong&gt;Spring Data&lt;/strong&gt; family.&lt;/p&gt;

&lt;p&gt;It provides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Repository abstractions&lt;/li&gt;
&lt;li&gt;Ready-made CRUD operations&lt;/li&gt;
&lt;li&gt;Dynamic query generation&lt;/li&gt;
&lt;li&gt;Pagination and sorting support&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of writing DAO classes manually, you just define &lt;strong&gt;Repository interfaces&lt;/strong&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  🗄️ Repositories: Where the Magic Starts
&lt;/h2&gt;

&lt;p&gt;Spring Data JPA provides repository interfaces like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CrudRepository&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;JpaRepository&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By extending them, you instantly get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;save()&lt;/li&gt;
&lt;li&gt;findById()&lt;/li&gt;
&lt;li&gt;findAll()&lt;/li&gt;
&lt;li&gt;delete()&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No implementation needed.&lt;/p&gt;

&lt;p&gt;This alone saves &lt;strong&gt;a huge amount of code&lt;/strong&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  🔮 Dynamic Query Methods (The Cool Part)
&lt;/h2&gt;

&lt;p&gt;Dynamic query methods allow Spring Data JPA to &lt;strong&gt;generate queries from method names&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Yes — your method name defines the query.&lt;/p&gt;

&lt;p&gt;This is called &lt;strong&gt;Query Derivation&lt;/strong&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  🧩 Anatomy of a Query Method Name
&lt;/h2&gt;

&lt;p&gt;A query method has four parts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ReturnType + QueryPrefix + Subject + Predicate + Parameters
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once I understood this structure, everything became predictable.&lt;/p&gt;




&lt;h2&gt;
  
  
  🏷️ Rules for Creating Query Methods
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🔹 1️⃣ Method Name Prefix
&lt;/h3&gt;

&lt;p&gt;Query methods must start with one of these:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;find…By&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;read…By&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;query…By&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;get…By&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;findByName&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;readByEmail&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;queryByStatus&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;getByUsername&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  🔹 2️⃣ Limiting Results with &lt;strong&gt;First&lt;/strong&gt; or &lt;strong&gt;Top&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;To limit results, add &lt;strong&gt;First&lt;/strong&gt; or &lt;strong&gt;Top&lt;/strong&gt; before &lt;code&gt;By&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;findFirstByName&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;findTop10ByStatus&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;readFirst2ByCategory&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This avoids unnecessary data fetching.&lt;/p&gt;




&lt;h3&gt;
  
  
  🔹 3️⃣ Fetching Unique Results with &lt;strong&gt;Distinct&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;To return unique results, use &lt;strong&gt;Distinct&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;findDistinctByName&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;findNameDistinctBy&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This helps when duplicates exist in data.&lt;/p&gt;




&lt;h3&gt;
  
  
  🔹 4️⃣ Combining Conditions with &lt;strong&gt;AND / OR&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;You can combine conditions directly in method names.&lt;/p&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;findByNameAndDepartment&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;findByStatusOrRole&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Spring automatically builds the correct query.&lt;/p&gt;




&lt;h2&gt;
  
  
  📄 Pagination &amp;amp; Sorting (Real-World Requirement)
&lt;/h2&gt;

&lt;p&gt;Spring Data JPA provides &lt;strong&gt;built-in support&lt;/strong&gt; for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pagination&lt;/li&gt;
&lt;li&gt;Sorting&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is essential for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Large datasets&lt;/li&gt;
&lt;li&gt;Performance optimization&lt;/li&gt;
&lt;li&gt;API scalability&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And the best part — no complex query writing.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚠️ The Mistake I Was Making
&lt;/h2&gt;

&lt;p&gt;Initially, I:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Thought method names were arbitrary&lt;/li&gt;
&lt;li&gt;Memorized examples without understanding rules&lt;/li&gt;
&lt;li&gt;Got confused when queries failed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once I learned the &lt;strong&gt;naming rules&lt;/strong&gt;, dynamic queries stopped feeling magical — they became logical.&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Spring Data JPA dynamic query methods are not magic.&lt;/p&gt;

&lt;p&gt;They are &lt;strong&gt;well-designed conventions&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you understand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Method name structure&lt;/li&gt;
&lt;li&gt;Query keywords&lt;/li&gt;
&lt;li&gt;Naming rules&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can build powerful data access layers &lt;strong&gt;without writing SQL&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This post is part of my &lt;strong&gt;learning-in-public&lt;/strong&gt; journey while exploring Spring Boot and backend development.&lt;/p&gt;

</description>
      <category>springboot</category>
      <category>java</category>
      <category>backend</category>
      <category>springdatajpa</category>
    </item>
    <item>
      <title>🔍 JPA, Hibernate, JDBC… I Was Confused Until This Finally Clicked</title>
      <dc:creator>Shashwath S H</dc:creator>
      <pubDate>Sun, 11 Jan 2026 05:37:45 +0000</pubDate>
      <link>https://dev.to/shashwathsh/jpa-hibernate-jdbc-i-was-confused-until-this-finally-clicked-e99</link>
      <guid>https://dev.to/shashwathsh/jpa-hibernate-jdbc-i-was-confused-until-this-finally-clicked-e99</guid>
      <description>&lt;p&gt;When I started backend development with Spring Boot, these terms kept showing up everywhere:&lt;/p&gt;

&lt;p&gt;JPA&lt;br&gt;
Hibernate&lt;br&gt;
JDBC&lt;/p&gt;

&lt;p&gt;Everyone explained them — yet I was still confused.&lt;/p&gt;

&lt;p&gt;Who does what?&lt;br&gt;
Why do we need all three?&lt;br&gt;
Are they competitors or teammates?&lt;/p&gt;

&lt;p&gt;It finally made sense when I stopped memorizing definitions and understood &lt;strong&gt;how they work together&lt;/strong&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  🧠 The Big Picture (Before Details)
&lt;/h2&gt;

&lt;p&gt;Here’s the simplest mental model:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;Your code talks to JPA&lt;/strong&gt;&lt;br&gt;
👉 &lt;strong&gt;JPA uses Hibernate&lt;/strong&gt;&lt;br&gt;
👉 &lt;strong&gt;Hibernate uses JDBC&lt;/strong&gt;&lt;br&gt;
👉 &lt;strong&gt;JDBC talks to the database&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Once I understood this chain, everything clicked.&lt;/p&gt;


&lt;h2&gt;
  
  
  📜 What is &lt;strong&gt;JPA (Java Persistence API)&lt;/strong&gt;?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;JPA&lt;/strong&gt; is &lt;strong&gt;NOT a framework&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It is a &lt;strong&gt;specification&lt;/strong&gt; — a set of rules and guidelines that define:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How Java objects map to database tables&lt;/li&gt;
&lt;li&gt;How relationships should work&lt;/li&gt;
&lt;li&gt;How queries and transactions are handled&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Important point:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;JPA itself does not execute anything.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It only defines &lt;em&gt;how things should behave&lt;/em&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  ⚙️ What is &lt;strong&gt;Hibernate&lt;/strong&gt;?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Hibernate&lt;/strong&gt; is a &lt;strong&gt;powerful ORM framework&lt;/strong&gt; and a &lt;strong&gt;JPA implementation&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhc84lmsv89s6nte1x8ta.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhc84lmsv89s6nte1x8ta.png" alt="Hibernate ORM" width="800" height="410"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hibernate follows JPA rules&lt;/li&gt;
&lt;li&gt;Hibernate provides the actual logic&lt;/li&gt;
&lt;li&gt;Hibernate converts Java objects into SQL queries&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In short:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Hibernate is the engine that makes JPA work.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It also provides extra features beyond JPA, which is why it’s so popular.&lt;/p&gt;


&lt;h2&gt;
  
  
  🔌 Where Does &lt;strong&gt;JDBC&lt;/strong&gt; Fit In?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;JDBC&lt;/strong&gt; is the &lt;strong&gt;lowest-level database API&lt;/strong&gt; in Java.&lt;/p&gt;

&lt;p&gt;Hibernate does not talk to the database directly.&lt;br&gt;
Instead:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;Hibernate generates SQL&lt;/strong&gt;&lt;br&gt;
👉 &lt;strong&gt;JDBC executes that SQL&lt;/strong&gt;&lt;br&gt;
👉 &lt;strong&gt;Database returns results&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So even if you never write JDBC code:&lt;br&gt;
&lt;strong&gt;JDBC is still working behind the scenes&lt;/strong&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  🧱 Spring Data JPA: The Final Layer
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Spring Data JPA&lt;/strong&gt; sits on top of JPA and Hibernate.&lt;/p&gt;

&lt;p&gt;Its job:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reduce boilerplate&lt;/li&gt;
&lt;li&gt;Help you build DAO methods easily&lt;/li&gt;
&lt;li&gt;Provide repositories like &lt;strong&gt;JpaRepository&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s why you can write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;findByEmail&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;…and it magically works.&lt;/p&gt;




&lt;h2&gt;
  
  
  🏗️ Common &lt;strong&gt;Hibernate Configurations&lt;/strong&gt; (That Actually Matter)
&lt;/h2&gt;

&lt;p&gt;These are the ones I see in almost every real project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;spring.jpa.hibernate.ddl-auto&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;update / create / validate / create-drop / none&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;spring.jpa.show-sql&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Shows generated SQL in logs&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;hibernate.format_sql&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Makes SQL readable&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;hibernate.dialect&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Helps Hibernate generate database-specific SQL&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Understanding these made debugging MUCH easier.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧩 Entity Mapping: Where Magic Begins
&lt;/h2&gt;

&lt;p&gt;Hibernate maps Java classes to database tables using annotations like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a class="mentioned-user" href="https://dev.to/entity"&gt;@entity&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;@Table&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a class="mentioned-user" href="https://dev.to/id"&gt;@id&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;@GeneratedValue&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a class="mentioned-user" href="https://dev.to/column"&gt;@column&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;@CreationTimestamp&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;@UpdateTimestamp&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This mapping is what makes ORM possible.&lt;/p&gt;

&lt;p&gt;Once entities are correct, everything else becomes smoother.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔑 Key Features of &lt;strong&gt;JPA&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;JPA provides powerful abstractions for:&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ &lt;strong&gt;Entity Management&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Defines how objects are persisted.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ &lt;strong&gt;JPQL&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;A query language that works on entities, not tables.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ &lt;strong&gt;Transactions&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Handles commit and rollback cleanly.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ &lt;strong&gt;Entity Relationships&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Supports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One-to-One&lt;/li&gt;
&lt;li&gt;One-to-Many&lt;/li&gt;
&lt;li&gt;Many-to-One&lt;/li&gt;
&lt;li&gt;Many-to-Many&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is where real-world data modeling happens.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚠️ The Mistake I Was Making
&lt;/h2&gt;

&lt;p&gt;I used to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Treat JPA and Hibernate as the same thing&lt;/li&gt;
&lt;li&gt;Ignore JDBC completely&lt;/li&gt;
&lt;li&gt;Memorize annotations without understanding flow&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once I understood the &lt;strong&gt;layered responsibility&lt;/strong&gt;, my learning speed doubled.&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 Final Thoughts
&lt;/h2&gt;

&lt;p&gt;If you’re learning Spring Boot and feel confused by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JPA&lt;/li&gt;
&lt;li&gt;Hibernate&lt;/li&gt;
&lt;li&gt;JDBC&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You’re not alone.&lt;/p&gt;

&lt;p&gt;The clarity comes when you understand &lt;strong&gt;who does what&lt;/strong&gt; — not when you memorize definitions.&lt;/p&gt;

&lt;p&gt;This post is part of my &lt;strong&gt;learning-in-public&lt;/strong&gt; journey while exploring Spring Boot and backend development.&lt;/p&gt;

</description>
      <category>springboot</category>
      <category>java</category>
      <category>backend</category>
      <category>hibernate</category>
    </item>
  </channel>
</rss>
