<?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: Shubham Bhati</title>
    <description>The latest articles on DEV Community by Shubham Bhati (@shubham_bhati).</description>
    <link>https://dev.to/shubham_bhati</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3935276%2Fa996911a-6c8f-4d5e-ab58-f46b8c58c670.png</url>
      <title>DEV Community: Shubham Bhati</title>
      <link>https://dev.to/shubham_bhati</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/shubham_bhati"/>
    <language>en</language>
    <item>
      <title>Spring Boot Security: Don't Expose That Sensitive Property</title>
      <dc:creator>Shubham Bhati</dc:creator>
      <pubDate>Tue, 14 Jul 2026 05:53:48 +0000</pubDate>
      <link>https://dev.to/shubham_bhati/spring-boot-security-dont-expose-that-sensitive-property-22lb</link>
      <guid>https://dev.to/shubham_bhati/spring-boot-security-dont-expose-that-sensitive-property-22lb</guid>
      <description>&lt;p&gt;Ever found yourself accidentally committing sensitive keys or passwords to your Git repo? It's a common slip-up. In Spring Boot, the easiest way to avoid this for things like API keys or database credentials is to keep them out of your main &lt;code&gt;application.properties&lt;/code&gt; or &lt;code&gt;application.yml&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Instead, use environment variables. Spring Boot automatically picks them up. For example, if you have a property &lt;code&gt;app.external.api.key&lt;/code&gt;, you can set an environment variable named &lt;code&gt;APP_EXTERNAL_API_KEY&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Your &lt;code&gt;application.properties&lt;/code&gt; would still declare it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;app.external.api.key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;${EXTERNAL_API_KEY:default_fallback_key}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This way, your code is clean, your repo is safe and you can manage your secrets per environment (dev staging prod) without touching the codebase.&lt;/p&gt;

</description>
      <category>springboot</category>
      <category>security</category>
      <category>properties</category>
      <category>configuration</category>
    </item>
    <item>
      <title>Stop Holding DB Connections Hostage</title>
      <dc:creator>Shubham Bhati</dc:creator>
      <pubDate>Mon, 13 Jul 2026 06:39:12 +0000</pubDate>
      <link>https://dev.to/shubham_bhati/stop-holding-db-connections-hostage-3gon</link>
      <guid>https://dev.to/shubham_bhati/stop-holding-db-connections-hostage-3gon</guid>
      <description>&lt;p&gt;We often throw &lt;code&gt;@Transactional&lt;/code&gt; on Spring Boot service methods without thinking. If your method queries PostgreSQL, calls an external API and updates Redis, you hold that HikariCP database connection for the entire API call duration. On cheap servers, this kills performance fast.&lt;/p&gt;

&lt;p&gt;HikariCP defaults to 10 connections. If 10 users hit a slow external API, your app freezes. Keep transactions tight.&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="c1"&gt;// Bad: Connection held during slow API call&lt;/span&gt;
&lt;span class="nd"&gt;@Transactional&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;checkout&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;OrderDto&lt;/span&gt; &lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="n"&gt;paymentService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;charge&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Slow&lt;/span&gt;
    &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setStatus&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;PAID&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;repo&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;order&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Good: Connection held only for DB write&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;checkout&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;OrderDto&lt;/span&gt; &lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="n"&gt;paymentService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;charge&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;updateStatus&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getId&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@Transactional&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;updateStatus&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;updateStatus&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;PAID&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;



</description>
      <category>springboot</category>
      <category>performance</category>
      <category>database</category>
    </item>
    <item>
      <title>Redis as a Spring Boot Session Store: Speed Up Your Apps</title>
      <dc:creator>Shubham Bhati</dc:creator>
      <pubDate>Sun, 12 Jul 2026 06:18:46 +0000</pubDate>
      <link>https://dev.to/shubham_bhati/redis-as-a-spring-boot-session-store-speed-up-your-apps-3n3k</link>
      <guid>https://dev.to/shubham_bhati/redis-as-a-spring-boot-session-store-speed-up-your-apps-3n3k</guid>
      <description>&lt;p&gt;You're building a Spring Boot app and notice session management is a bit sluggish. Why not offload that to Redis? It's incredibly fast and way cheaper than keeping it in-memory or on a relational DB. Here's the quick setup:&lt;/p&gt;

&lt;p&gt;First, add the Spring Data Redis dependency:&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-starter-data-redis&lt;span class="nt"&gt;&amp;lt;/artifactId&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;Then, configure your &lt;code&gt;application.properties&lt;/code&gt; or &lt;code&gt;application.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;spring.redis.host&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;localhost&lt;/span&gt;
&lt;span class="py"&gt;spring.redis.port&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;6379&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, enable RedisHttpSession in your main application class:&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="nd"&gt;@SpringBootApplication&lt;/span&gt;
&lt;span class="nd"&gt;@EnableRedisHttpSession&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;YourAppApplication&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. Spring Boot will automatically use Redis for session storage. Your users will thank you for the snappier experience and you'll save on server resources.&lt;/p&gt;

</description>
      <category>springboot</category>
      <category>redis</category>
      <category>performance</category>
      <category>caching</category>
    </item>
    <item>
      <title>Stop Letting HikariCP Kill Your Cheap VPS</title>
      <dc:creator>Shubham Bhati</dc:creator>
      <pubDate>Sat, 11 Jul 2026 21:24:07 +0000</pubDate>
      <link>https://dev.to/shubham_bhati/stop-letting-hikaricp-kill-your-cheap-vps-fg2</link>
      <guid>https://dev.to/shubham_bhati/stop-letting-hikaricp-kill-your-cheap-vps-fg2</guid>
      <description>&lt;p&gt;If you are running Spring Boot, PostgreSQL and Redis on a 512MB RAM VPS to keep costs under ₹100/month, the default HikariCP connection pool will crash your system. Spring Boot defaults to 10 connections. Add database memory overhead and your tiny server instantly runs out of memory.&lt;/p&gt;

&lt;p&gt;For early-stage apps making money, you don't need 10 active connections. A pool size of 2 or 3 can easily handle dozens of concurrent users because database operations finish in milliseconds.&lt;/p&gt;

&lt;p&gt;Limit your pool size in &lt;code&gt;application.properties&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;spring.datasource.hikari.maximum-pool-size&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;3&lt;/span&gt;
&lt;span class="py"&gt;spring.datasource.hikari.minimum-idle&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;1&lt;/span&gt;
&lt;span class="py"&gt;spring.datasource.hikari.idle-timeout&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;10000&lt;/span&gt;
&lt;span class="py"&gt;spring.datasource.hikari.max-lifetime&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;30000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This simple change keeps your memory footprint low. We scaled a production app to ₹1 Lakh revenue using just 3 connections on a cheap VPS. Stop overpaying for cloud databases when a tiny VPS can do the job.&lt;/p&gt;

</description>
      <category>springboot</category>
      <category>postgres</category>
      <category>performance</category>
      <category>hosting</category>
    </item>
    <item>
      <title>Preventing Database Meltdowns: Caching Strategies That Actually Work</title>
      <dc:creator>Shubham Bhati</dc:creator>
      <pubDate>Sat, 11 Jul 2026 21:16:02 +0000</pubDate>
      <link>https://dev.to/shubham_bhati/preventing-database-meltdowns-caching-strategies-that-actually-work-35i2</link>
      <guid>https://dev.to/shubham_bhati/preventing-database-meltdowns-caching-strategies-that-actually-work-35i2</guid>
      <description>&lt;p&gt;When scaling a high-throughput backend, the database is always your primary bottleneck. Every network roundtrip to fetch static or semi-static data wastes CPU cycles and spikes connection pool latency. &lt;/p&gt;

&lt;p&gt;To prevent database meltdowns, we implement distributed caching using Redis. But simply throwing &lt;code&gt;@Cacheable&lt;/code&gt; on a Spring Boot service method is not enough. You must understand how to manage cache lifecycles.&lt;/p&gt;

&lt;p&gt;Here are three production-tested strategies we use to keep systems highly resilient.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. The Cache-Aside Pattern
&lt;/h3&gt;

&lt;p&gt;This is the most common caching pattern. The application code orchestrates both the cache and the database.&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="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Account&lt;/span&gt; &lt;span class="nf"&gt;getAccountBalance&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;)&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;cacheKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"account:"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nc"&gt;Account&lt;/span&gt; &lt;span class="n"&gt;account&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;redisTemplate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;opsForValue&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="n"&gt;cacheKey&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Cache Hit&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Cache Miss&lt;/span&gt;
    &lt;span class="n"&gt;account&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;accountRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;orElseThrow&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ResourceNotFoundException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Account not found"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;

    &lt;span class="n"&gt;redisTemplate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;opsForValue&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cacheKey&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Duration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofMinutes&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;account&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;ul&gt;
&lt;li&gt;  &lt;strong&gt;The Catch:&lt;/strong&gt; You must ensure cache eviction happens whenever data changes (e.g. during updates) to prevent serving stale data.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Guarding Against Cache Penetration (Bloom Filters)
&lt;/h3&gt;

&lt;p&gt;Cache penetration occurs when requests query keys that do not exist in either the cache or the database. If malicious actors flood your API with random IDs, every single request bypasses the cache and hits the database directly.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;The Solution:&lt;/strong&gt; Use a &lt;strong&gt;Bloom Filter&lt;/strong&gt; in front of your cache. A Bloom Filter is a space-efficient probabilistic data structure that can tell you with 100% certainty if an element is &lt;em&gt;not&lt;/em&gt; present in the system.&lt;/li&gt;
&lt;li&gt;  If the Bloom Filter says the ID does not exist, reject the request immediately without hitting Redis or the database.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Tuning Time-To-Live (TTL) &amp;amp; Jitter
&lt;/h3&gt;

&lt;p&gt;Setting a hard TTL (like exactly 1 hour) on all keys can cause a &lt;strong&gt;Cache Stampede&lt;/strong&gt;. If 10,000 product keys expire at the exact same second, the next wave of concurrent requests will hit the database at the same time, causing a temporary spike in latency.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;The Solution:&lt;/strong&gt; Add a small randomized delay (jitter) to your TTL. Instead of 60 minutes, set the expiration to &lt;code&gt;60 + random(1 to 5) minutes&lt;/code&gt;. This distributes database read operations smoothly over time.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By combining Cache-Aside with Bloom Filters and randomized TTLs, you protect your primary database from unexpected load spikes.&lt;/p&gt;

</description>
      <category>springboot</category>
      <category>redis</category>
      <category>systemdesign</category>
      <category>java</category>
    </item>
    <item>
      <title>Concurrency Control in Financial Ledgers: Pessimistic vs Optimistic Locking</title>
      <dc:creator>Shubham Bhati</dc:creator>
      <pubDate>Sat, 11 Jul 2026 20:37:07 +0000</pubDate>
      <link>https://dev.to/shubham_bhati/concurrency-control-in-financial-ledgers-pessimistic-vs-optimistic-locking-36e9</link>
      <guid>https://dev.to/shubham_bhati/concurrency-control-in-financial-ledgers-pessimistic-vs-optimistic-locking-36e9</guid>
      <description>&lt;p&gt;When building a high-throughput financial ledger like a digital wallet api, concurrency is the biggest silent killer. If two threads attempt to update the same account balance at the exact same millisecond, you risk duplicate spend or inconsistent ledger entries. &lt;/p&gt;

&lt;p&gt;In Java Spring Boot, we typically choose between two main locking strategies: Optimistic and Pessimistic.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Optimistic Locking (Using &lt;a class="mentioned-user" href="https://dev.to/version"&gt;@version&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;Optimistic locking assumes conflicts are rare. It uses a version column in the database. When a transaction commits, it checks if the version has changed.&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="nd"&gt;@Entity&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Account&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Id&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nd"&gt;@Version&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;version&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;ul&gt;
&lt;li&gt;  &lt;strong&gt;How it works:&lt;/strong&gt; Spring Boot executes &lt;code&gt;UPDATE account SET balance = ?, version = version + 1 WHERE id = ? AND version = ?&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;The Catch:&lt;/strong&gt; If another thread updated it first, the version mismatch throws an &lt;code&gt;OptimisticLockingFailureException&lt;/code&gt;. The application must handle this by retrying the transaction, which adds latency.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Pessimistic Locking (SELECT ... FOR UPDATE)
&lt;/h3&gt;

&lt;p&gt;Pessimistic locking assumes conflicts are highly likely. It explicitly locks the database row at the beginning of the transaction, blocking any other write operations on that row.&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="nd"&gt;@Repository&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;AccountRepository&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;JpaRepository&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Account&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Lock&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;LockModeType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PESSIMISTIC_WRITE&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nd"&gt;@Query&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SELECT a FROM Account a WHERE a.id = :id"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nc"&gt;Optional&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Account&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;findByIdForUpdate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;id&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;ul&gt;
&lt;li&gt;  &lt;strong&gt;How it works:&lt;/strong&gt; Spring Boot translates this to &lt;code&gt;SELECT * FROM account WHERE id = ? FOR UPDATE&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;The Catch:&lt;/strong&gt; Other threads attempting to read or write this row are blocked until the locking transaction commits or rolls back. This prevents optimistic exceptions but requires careful connection pool tuning to avoid thread starvation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For low-latency wallet services where balances are frequently updated, pessimistic locking is the safest default to prevent double spend.&lt;/p&gt;

</description>
      <category>springboot</category>
      <category>postgres</category>
      <category>database</category>
      <category>java</category>
    </item>
    <item>
      <title>Optimize HikariCP for Dirt-Cheap VPS Hosting</title>
      <dc:creator>Shubham Bhati</dc:creator>
      <pubDate>Sat, 11 Jul 2026 20:29:44 +0000</pubDate>
      <link>https://dev.to/shubham_bhati/optimize-hikaricp-for-dirt-cheap-vps-hosting-5gg4</link>
      <guid>https://dev.to/shubham_bhati/optimize-hikaricp-for-dirt-cheap-vps-hosting-5gg4</guid>
      <description>&lt;p&gt;If you are running a Spring Boot app on a tiny ₹100/month VPS with 1GB RAM, the default settings will crash your server. The biggest silent killer is HikariCP. By default, Spring Boot sets the maximum connection pool size to 10. If you run PostgreSQL, Redis and Spring Boot on the same cheap box, you will quickly hit memory limits.&lt;/p&gt;

&lt;p&gt;You don't need 10 connections for low-traffic apps scaling to their first ₹1 Lakh. A pool size of 2 or 3 is more than enough to handle concurrent requests if your queries are indexed properly.&lt;/p&gt;

&lt;p&gt;Add this to your &lt;code&gt;application.properties&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;spring.datasource.hikari.maximum-pool-size&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;3&lt;/span&gt;
&lt;span class="py"&gt;spring.datasource.hikari.minimum-idle&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;2&lt;/span&gt;
&lt;span class="py"&gt;spring.datasource.hikari.idle-timeout&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;30000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This simple tweak slashes RAM usage, prevents database errors and keeps your server alive on tight budgets.&lt;/p&gt;

</description>
      <category>springboot</category>
      <category>postgres</category>
      <category>devops</category>
    </item>
    <item>
      <title>Spring Boot Validation: Don't Reinvent the Wheel</title>
      <dc:creator>Shubham Bhati</dc:creator>
      <pubDate>Sat, 11 Jul 2026 20:29:27 +0000</pubDate>
      <link>https://dev.to/shubham_bhati/spring-boot-validation-dont-reinvent-the-wheel-2h8c</link>
      <guid>https://dev.to/shubham_bhati/spring-boot-validation-dont-reinvent-the-wheel-2h8c</guid>
      <description>&lt;p&gt;You're building a new API endpoint and need to validate incoming request data. Most of us grab a bunch of &lt;code&gt;if&lt;/code&gt; statements. Stop right there. Spring Boot's got your back with JSR 380 (Jakarta Bean Validation).&lt;/p&gt;

&lt;p&gt;Just add the &lt;code&gt;spring-boot-starter-validation&lt;/code&gt; dependency. Then, annotate your DTO with &lt;code&gt;@Valid&lt;/code&gt; and your fields with constraints like &lt;code&gt;@NotNull&lt;/code&gt; &lt;code&gt;@Size(min=2 max=10)&lt;/code&gt; or &lt;code&gt;@Email&lt;/code&gt;. Spring Boot automatically handles validation errors, returning a &lt;code&gt;400 Bad Request&lt;/code&gt; with details. It's way cleaner and more maintainable.&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="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;javax.validation.constraints.Email&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;javax.validation.constraints.NotBlank&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;javax.validation.constraints.Size&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserRequest&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@NotBlank&lt;/span&gt;
    &lt;span class="nd"&gt;@Size&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="n"&gt;max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@NotBlank&lt;/span&gt;
    &lt;span class="nd"&gt;@Email&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Getters and Setters&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then in your controller:&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="nd"&gt;@PostMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/users"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;createUser&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@Valid&lt;/span&gt; &lt;span class="nd"&gt;@RequestBody&lt;/span&gt; &lt;span class="nc"&gt;UserRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ... your logic&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ok&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"User created"&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;



</description>
      <category>springboot</category>
      <category>validation</category>
      <category>java</category>
      <category>backend</category>
    </item>
    <item>
      <title>Stop Manual JSON Parsing in Spring Boot</title>
      <dc:creator>Shubham Bhati</dc:creator>
      <pubDate>Sat, 11 Jul 2026 05:58:20 +0000</pubDate>
      <link>https://dev.to/shubham_bhati/stop-manual-json-parsing-in-spring-boot-11lh</link>
      <guid>https://dev.to/shubham_bhati/stop-manual-json-parsing-in-spring-boot-11lh</guid>
      <description>&lt;p&gt;You're probably still writing boilerplate code to parse JSON requests in your Spring Boot controllers. It's 2024 folks! Spring Boot's &lt;code&gt;@RequestBody&lt;/code&gt; annotation handles this beautifully out of the box. Just define your Java object and let Spring do the heavy lifting.&lt;/p&gt;

&lt;p&gt;Consider this:&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="nd"&gt;@PostMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/users"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&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;createUser&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@RequestBody&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="n"&gt;newUser&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// newUser object is already populated from the JSON request body&lt;/span&gt;
    &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="n"&gt;savedUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;userService&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;newUser&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpStatus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;CREATED&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="n"&gt;savedUser&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 not only cleans up your code but also improves performance slightly by avoiding manual deserialization overhead. Don't reinvent the wheel.&lt;/p&gt;

</description>
      <category>springboot</category>
      <category>java</category>
      <category>performance</category>
      <category>json</category>
    </item>
    <item>
      <title>Spring Boot Database Connection Pooling</title>
      <dc:creator>Shubham Bhati</dc:creator>
      <pubDate>Fri, 10 Jul 2026 07:02:56 +0000</pubDate>
      <link>https://dev.to/shubham_bhati/spring-boot-database-connection-pooling-3cjj</link>
      <guid>https://dev.to/shubham_bhati/spring-boot-database-connection-pooling-3cjj</guid>
      <description>&lt;p&gt;When working with Spring Boot and PostgreSQL, we've found that connection pooling can make a huge difference in performance. We can't afford to create a new connection for every request, so we use a connection pool to reuse existing connections. Spring Boot makes this easy with the HikariCP library. We just need to add the dependency to our pom.xml file and configure the connection pool properties. For example, we can set the minimum and maximum pool size like this: &lt;br&gt;
&lt;a class="mentioned-user" href="https://dev.to/bean"&gt;@bean&lt;/a&gt; &lt;br&gt;
public DataSource dataSource() { &lt;br&gt;
    return DataSourceBuilder.create() &lt;br&gt;
        .driverClassName("org.postgresql.Driver") &lt;br&gt;
        .url("jdbc:postgresql://localhost:5432/mydb") &lt;br&gt;
        .username("myuser") &lt;br&gt;
        .password("mypassword") &lt;br&gt;
        .build(); &lt;br&gt;
} &lt;br&gt;
Then we can configure the pool size in our application.properties file: spring.datasource.hikari.minimumPoolSize=5 and spring.datasource.hikari.maximumPoolSize=15. This way, our application doesn't run out of connections when handling a large number of requests.&lt;/p&gt;

</description>
      <category>springboot</category>
      <category>databaseconnection</category>
      <category>postgres</category>
      <category>java</category>
    </item>
    <item>
      <title>Don't Let Your Spring Boot App Bleed Redis Memory</title>
      <dc:creator>Shubham Bhati</dc:creator>
      <pubDate>Thu, 09 Jul 2026 21:30:50 +0000</pubDate>
      <link>https://dev.to/shubham_bhati/dont-let-your-spring-boot-app-bleed-redis-memory-282n</link>
      <guid>https://dev.to/shubham_bhati/dont-let-your-spring-boot-app-bleed-redis-memory-282n</guid>
      <description>&lt;p&gt;You're probably using Redis for caching in your Spring Boot app, right? Great choice. But I've seen apps absolutely tank because of memory bloat in Redis. Often, it's simple cache expiration issues. You set a TTL (Time To Live) but maybe the underlying data is changing too frequently or your eviction policy isn't aggressive enough.&lt;/p&gt;

&lt;p&gt;Here's a quick check. In your &lt;code&gt;application.properties&lt;/code&gt; or &lt;code&gt;application.yml&lt;/code&gt;, make sure your &lt;code&gt;spring.redis.client-type&lt;/code&gt; is set to &lt;code&gt;lettuce&lt;/code&gt; (it's the default and generally good) and then focus on your eviction policy. If you're using RedisTemplate, ensure your cache configurations are sound. Something like this, for instance, isn't enough on its own if your data churns:&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="c1"&gt;// Example: Without proper eviction policy, this might still cause bloat&lt;/span&gt;
&lt;span class="nd"&gt;@Bean&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;RedisCacheManager&lt;/span&gt; &lt;span class="nf"&gt;cacheManager&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RedisConnectionFactory&lt;/span&gt; &lt;span class="n"&gt;redisConnectionFactory&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;RedisCacheConfiguration&lt;/span&gt; &lt;span class="n"&gt;cacheConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;RedisCacheConfiguration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;defaultCacheConfig&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;entryTtl&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Duration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofMinutes&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// This is just expiration&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;RedisCacheManager&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="n"&gt;redisConnectionFactory&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;cacheWriter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RedisCacheWriter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lockingRedisCacheWriter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;redisConnectionFactory&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withCacheConfiguration&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"myCache"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cacheConfig&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;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead, consider setting an eviction policy like &lt;code&gt;ALLKEYS_LRU&lt;/code&gt; or &lt;code&gt;VOLATILE_LRU&lt;/code&gt; directly in your &lt;code&gt;redis.conf&lt;/code&gt; or via Redis commands. It means Redis will actively kick out less recently used items when it needs space, saving you from those surprise memory bills.&lt;/p&gt;

</description>
      <category>springboot</category>
      <category>redis</category>
      <category>performance</category>
      <category>caching</category>
    </item>
    <item>
      <title>Simplifying Database Connections with Spring Boot</title>
      <dc:creator>Shubham Bhati</dc:creator>
      <pubDate>Thu, 09 Jul 2026 19:43:51 +0000</pubDate>
      <link>https://dev.to/shubham_bhati/simplifying-database-connections-with-spring-boot-m15</link>
      <guid>https://dev.to/shubham_bhati/simplifying-database-connections-with-spring-boot-m15</guid>
      <description>&lt;p&gt;When building microservices with Spring Boot we often need to connect to multiple databases. To simplify this process we can use the @Configuration annotation to define a separate configuration class for our database connections. For example we can create a class called DatabaseConfig that defines a bean for our PostgreSQL database connection.&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="nd"&gt;@Configuration&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DatabaseConfig&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Bean&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;DataSource&lt;/span&gt; &lt;span class="nf"&gt;dataSource&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;DataSourceBuilder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;driverClassName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"org.postgresql.Driver"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"jdbc:postgresql://localhost:5432/mydb"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"myuser"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"mypassword"&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;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 way we can easily manage our database connections and switch between different databases if needed. We can also use this configuration class to define multiple data sources for different databases.&lt;/p&gt;

</description>
      <category>springboot</category>
      <category>postgres</category>
      <category>java</category>
      <category>microservices</category>
    </item>
  </channel>
</rss>
