<?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: Rishabh Agarwal</title>
    <description>The latest articles on DEV Community by Rishabh Agarwal (@the_infinity).</description>
    <link>https://dev.to/the_infinity</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%2F1128752%2F91bb81cf-1b0d-4e5f-ae60-ef8f7d8a2ea8.jpeg</url>
      <title>DEV Community: Rishabh Agarwal</title>
      <link>https://dev.to/the_infinity</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/the_infinity"/>
    <language>en</language>
    <item>
      <title>Some VSCode Extensions Were Mining Crypto — Here’s What You Need to Know</title>
      <dc:creator>Rishabh Agarwal</dc:creator>
      <pubDate>Fri, 06 Jun 2025 12:12:55 +0000</pubDate>
      <link>https://dev.to/the_infinity/some-vscode-extensions-were-mining-crypto-heres-what-you-need-to-know-33o5</link>
      <guid>https://dev.to/the_infinity/some-vscode-extensions-were-mining-crypto-heres-what-you-need-to-know-33o5</guid>
      <description>&lt;p&gt;I’m a big fan of customizing my VSCode setup — like most devs, I’ve got a bunch of extensions installed to boost productivity and improve my workflow.&lt;/p&gt;

&lt;p&gt;But a recent report really caught my attention: several extensions that looked completely legit were secretly running &lt;strong&gt;malicious scripts&lt;/strong&gt; behind the scenes.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Happened?
&lt;/h2&gt;

&lt;p&gt;Researchers found 10 extensions on the VSCode Marketplace that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Disabled Windows Defender
&lt;/li&gt;
&lt;li&gt;Gained admin privileges via PowerShell
&lt;/li&gt;
&lt;li&gt;Installed XMRig to mine Monero in the background
&lt;/li&gt;
&lt;li&gt;Faked install numbers to look popular
&lt;/li&gt;
&lt;li&gt;Disguised themselves as trusted tools like Prettier and Discord Presence&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some of these had over &lt;strong&gt;900K installs&lt;/strong&gt; — clearly meant to build false trust.&lt;/p&gt;

&lt;h2&gt;
  
  
  What This Means for Developers
&lt;/h2&gt;

&lt;p&gt;It’s a serious wake-up call for all of us who rely heavily on third-party tools. Even trusted environments like VSCode aren’t immune to abuse.&lt;/p&gt;

&lt;h3&gt;
  
  
  Here’s how to stay safe:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Don’t trust install counts alone&lt;/strong&gt; — they can be manipulated
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verify the publisher&lt;/strong&gt; — check for an established history
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Avoid newly published extensions&lt;/strong&gt; unless vetted
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Keep your system’s security settings enabled&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Microsoft has removed the malicious extensions and blocked the accounts behind them. But this incident highlights a bigger issue: the need for better vetting and more awareness on our end.&lt;/p&gt;

&lt;p&gt;👉 I wrote a full breakdown, including the list of affected extensions and how the attack worked.&lt;br&gt;&lt;br&gt;
&lt;em&gt;Read it &lt;a href="https://medium.com/javarevisited/dont-install-these-10-vscode-extensions-or-you-will-regret-it-later-b79d8d3addff" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>programming</category>
      <category>productivity</category>
      <category>security</category>
      <category>cybersecurity</category>
    </item>
    <item>
      <title>I believe in learning from real-world case studies. In software engineering, we have valuable insights through tech company blogs. Here are 5 of my top picks: Uber, Canva, Pinterest, Airbnb, and Netflix Engineering Blogs. What are Yours?</title>
      <dc:creator>Rishabh Agarwal</dc:creator>
      <pubDate>Tue, 18 Mar 2025 13:49:56 +0000</pubDate>
      <link>https://dev.to/the_infinity/i-believe-in-learning-from-real-world-case-studies-in-software-engineering-we-have-valuable-1651</link>
      <guid>https://dev.to/the_infinity/i-believe-in-learning-from-real-world-case-studies-in-software-engineering-we-have-valuable-1651</guid>
      <description></description>
      <category>learning</category>
      <category>discuss</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>How Pinterest uses Kafka for Long-Term Data Storage</title>
      <dc:creator>Rishabh Agarwal</dc:creator>
      <pubDate>Wed, 15 Jan 2025 07:37:43 +0000</pubDate>
      <link>https://dev.to/the_infinity/how-pinterest-uses-kafka-for-long-term-data-storage-1b18</link>
      <guid>https://dev.to/the_infinity/how-pinterest-uses-kafka-for-long-term-data-storage-1b18</guid>
      <description>&lt;p&gt;I spent hours diving into this so you don’t have to!&lt;/p&gt;

&lt;p&gt;Here is what I learned:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pinterest doesn't store all data on Kafka brokers forever.&lt;/li&gt;
&lt;li&gt;Older data is moved to a remote storage like Amazon S3.&lt;/li&gt;
&lt;li&gt;They built a tool called Segment Uploader to automate this process.&lt;/li&gt;
&lt;li&gt;The Segment Uploader periodically transfers older data from Kafka brokers to remote storage.&lt;/li&gt;
&lt;li&gt;Segment Uploader runs as a sidecar alongside the Kafka broker.&lt;/li&gt;
&lt;li&gt;They also developed a specialized Consumer Library to fetch data intelligently.&lt;/li&gt;
&lt;li&gt;The library fetches old data directly from remote storage and new data from Kafka brokers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By combining Kafka’s real-time capabilities with cost-efficient remote storage, Pinterest ensures scalability, reliability, and efficient long-term data management.&lt;/p&gt;




&lt;p&gt;PS - I recently published an article on my free Newsletter covering this case study in-depth with visuals: &lt;a href="https://designsystemsweekly.substack.com/p/how-pinterest-leverages-kafka-for" rel="noopener noreferrer"&gt;https://designsystemsweekly.substack.com/p/how-pinterest-leverages-kafka-for&lt;/a&gt;&lt;/p&gt;

</description>
      <category>programming</category>
      <category>devops</category>
      <category>career</category>
      <category>learning</category>
    </item>
    <item>
      <title>15 Databases, 15 Use Cases — The Ultimate Guide That No One Asked For (But Everyone Needs)</title>
      <dc:creator>Rishabh Agarwal</dc:creator>
      <pubDate>Sun, 05 Jan 2025 16:14:23 +0000</pubDate>
      <link>https://dev.to/the_infinity/15-databases-15-use-cases-the-ultimate-guide-that-no-one-asked-for-but-everyone-needs-35ai</link>
      <guid>https://dev.to/the_infinity/15-databases-15-use-cases-the-ultimate-guide-that-no-one-asked-for-but-everyone-needs-35ai</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%2Fw9g0aq49j6bjya75blhh.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%2Fw9g0aq49j6bjya75blhh.png" alt="15 Databases" width="800" height="633"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Relational Databases
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Examples&lt;/strong&gt;: Postgres, MySQL, Oracle&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Features&lt;/strong&gt;: Organized into tables with fixed columns; uses foreign keys to establish relationships.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use Cases&lt;/strong&gt;: E-commerce, finance, healthcare, and applications with structured data and well-defined relationships.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. Wide-Column Databases
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Examples&lt;/strong&gt;: Cassandra, ScyllaDB, DynamoDB&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Features&lt;/strong&gt;: NoSQL databases with flexible columns that can vary across rows; optimized for high scalability and low-latency querying.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use Cases&lt;/strong&gt;: Big data, analytics, high-write throughput.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. Time-Series Databases (TSDB)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Examples&lt;/strong&gt;: InfluxDB, Prometheus, Kdb+&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Features&lt;/strong&gt;: Optimized for time-indexed data like metrics and events.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use Cases&lt;/strong&gt;: Financial trading, performance monitoring, IoT sensor data.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4. Ledger Databases
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Examples&lt;/strong&gt;: Amazon Quantum&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Features&lt;/strong&gt;: Designed for financial data with immutability and cryptographic verification; validated by a central authority.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use Cases&lt;/strong&gt;: Financial applications, supply chain management, voting systems.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  5. Graph Databases
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Examples&lt;/strong&gt;: Neo4j, ArangoDB, Amazon Neptune&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Features&lt;/strong&gt;: Store data as nodes, relationships, and properties; ideal for managing interconnected data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use Cases&lt;/strong&gt;: Social networks, knowledge graphs, recommendation systems.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  6. Object-Oriented Databases (ODBMS)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Examples&lt;/strong&gt;: ObjectDB, db4o&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Features&lt;/strong&gt;: Store data as objects, similar to object-oriented programming languages; support inheritance and polymorphism.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use Cases&lt;/strong&gt;: Object-oriented applications, multimedia databases.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  7. Hierarchical Databases
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Examples&lt;/strong&gt;: IBM IMS, Windows Registry&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Features&lt;/strong&gt;: Organize data in a tree-like structure with parent-child relationships.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use Cases&lt;/strong&gt;: File systems, legacy systems.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  8. Document Databases
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Examples&lt;/strong&gt;: MongoDB, CouchDB, ArangoDB&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Features&lt;/strong&gt;: Store semi-structured data as JSON-like documents; flexible and hierarchical.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use Cases&lt;/strong&gt;: Content management systems, e-commerce platforms.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  9. Key-Value Databases
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Examples&lt;/strong&gt;: Redis, Couchbase, DataStax&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Features&lt;/strong&gt;: Store data in key-value pairs; highly scalable and fast.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use Cases&lt;/strong&gt;: Caching, session storage.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  10. Blob Databases
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Examples&lt;/strong&gt;: Amazon S3&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Features&lt;/strong&gt;: Store large unstructured binary data like media files.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use Cases&lt;/strong&gt;: Multimedia storage, content delivery networks.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  11. In-Memory Databases
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Examples&lt;/strong&gt;: Redis, Memcached, Apache Ignite&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Features&lt;/strong&gt;: Store data in memory for ultra-low latency and high throughput.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use Cases&lt;/strong&gt;: Caching, real-time bidding, gaming leaderboards.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  12. Text Search Databases
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Examples&lt;/strong&gt;: Elasticsearch&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Features&lt;/strong&gt;: Optimized for storage, retrieval, and analysis of large volumes of text data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use Cases&lt;/strong&gt;: Web searches, auto-complete, filtering.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  13. Spatial Databases
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Examples&lt;/strong&gt;: PostGIS, Oracle Spatial&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Features&lt;/strong&gt;: Manage spatial data types (e.g., points, polygons) and related relationships.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use Cases&lt;/strong&gt;: GIS, location-based services, spatial analysis.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  14. Vector Databases
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Examples&lt;/strong&gt;: Pinecone, Chroma&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Features&lt;/strong&gt;: Store, index, and search high-dimensional data; optimized for AI and machine learning tasks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use Cases&lt;/strong&gt;: Image and video search, recommendation systems, AI model embeddings.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  15. Embedded Databases
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Examples&lt;/strong&gt;: SQLite, RocksDB, BerkeleyDB&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Features&lt;/strong&gt;: Lightweight databases integrated within applications; offer fast data access with a small footprint.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use Cases&lt;/strong&gt;: Desktop applications, quick proofs of concept, resource-constrained environments.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Checkout the full article on &lt;a href="https://medium.com/gitconnected/15-databases-15-use-cases-the-ultimate-guide-that-no-one-asked-for-but-everyone-needs-47ca4009be78" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>programming</category>
      <category>database</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Conquer Tedious Tasks with These 10 Python Automation Scripts</title>
      <dc:creator>Rishabh Agarwal</dc:creator>
      <pubDate>Tue, 31 Dec 2024 12:57:51 +0000</pubDate>
      <link>https://dev.to/the_infinity/conquer-tedious-tasks-with-these-10-python-automation-scripts-42ea</link>
      <guid>https://dev.to/the_infinity/conquer-tedious-tasks-with-these-10-python-automation-scripts-42ea</guid>
      <description>&lt;p&gt;Juggling repetitive tasks can significantly slow down your development workflow. Thankfully, Python offers a rich ecosystem for crafting clever automation scripts that streamline these processes and free you to focus on more creative coding endeavors.&lt;/p&gt;

&lt;p&gt;This article highlights 10 such scripts that can significantly enhance your developer experience:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;AFK No More:&lt;/strong&gt; Prevent your computer from going to sleep with a script that keeps your mouse moving, mimicking activity and avoiding those pesky screen locks.&lt;br&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%2Ft6o5t9e4vuj1yqeorry9.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%2Ft6o5t9e4vuj1yqeorry9.png" alt="AFK No More" width="200" height="130"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;News at Your Fingertips:&lt;/strong&gt; Stay informed with a script that delivers news updates directly to your desktop, eliminating the need for constant web browsing.&lt;br&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%2Fhy23zmzmadwz0ij3dagm.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%2Fhy23zmzmadwz0ij3dagm.png" alt="Person reading news" width="400" height="300"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Dictation Dynamo:&lt;/strong&gt; Feeling the typing fatigue? This script empowers you to convert speech to text, allowing you to relax and verbally dictate your code or notes.&lt;br&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%2Fnp67knrdfjm8qxsuqdzf.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%2Fnp67knrdfjm8qxsuqdzf.png" alt="Dictation Dynamo" width="356" height="200"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cartoon Break!&lt;/strong&gt; Take a fun break by transforming photos into cartoon avatars using this script. It's a great way to add a touch of humor or personalize your online presence.&lt;br&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%2Fia6e77d136wlqp9m2a2o.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%2Fia6e77d136wlqp9m2a2o.png" alt="Cartoon Break" width="800" height="1094"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Bulk Email Blaster:&lt;/strong&gt; Streamline email marketing campaigns or mass communication with a script that facilitates sending emails to a large list of recipients efficiently.&lt;br&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%2Frfqrt9eji8omrhwvzf8n.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%2Frfqrt9eji8omrhwvzf8n.png" alt="Bulk Email Blaster" width="400" height="400"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;GIF-tastic Videos:&lt;/strong&gt; Liven up your projects or social media presence by converting video clips into cool GIFs with this easy-to-use script.&lt;br&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%2Fmyznsm0nj0x72osbwakx.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%2Fmyznsm0nj0x72osbwakx.png" alt="GIF-tastic Videos" width="500" height="500"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Voice-Activated Browsing:&lt;/strong&gt; Ditch the keyboard and navigate websites using voice commands! This script lets you speak the URL you want to visit and opens it automatically.&lt;br&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%2F2b9x85e1i8vpmxz6jdcj.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%2F2b9x85e1i8vpmxz6jdcj.png" alt="Voice-Activated Browsing" width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Hydration Hero:&lt;/strong&gt; Never forget to stay hydrated again! This script acts as a personal reminder system, sending notifications throughout the day to nudge you to drink water.&lt;br&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%2Fma823qp0yckkh9rszanw.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%2Fma823qp0yckkh9rszanw.png" alt="Hydration Hero" width="220" height="216"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Stack Overflow Savior:&lt;/strong&gt; Stuck on a coding error? This script comes to the rescue by automatically searching Stack Overflow for relevant solutions based on the error message you're encountering.&lt;br&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%2F36qqz1zg59s0wfewj6iv.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%2F36qqz1zg59s0wfewj6iv.png" alt="Stack Overflow Savior" width="612" height="344"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Screen Recorder on Demand:&lt;/strong&gt; Need to capture your screen for a tutorial or demo? This script allows for quick and easy screen recording, saving the session as a video file.&lt;br&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%2F019or5ap4knyhjggj9vp.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%2F019or5ap4knyhjggj9vp.png" alt="Screen Recorder on Demand" width="544" height="317"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Intrigued? Dive Deeper!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is just a taste of what's possible with Python automation. To explore detailed explanations, code snippets, and practical use cases for these 10 scripts, head over to the full article on &lt;a href="https://medium.com/p/2f93695de8ab" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I hope this summary piques your interest in leveraging Python for automation! By incorporating these scripts into your workflow, you can significantly boost your productivity and free up valuable time for the aspects of development you enjoy most.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>python</category>
      <category>productivity</category>
      <category>automation</category>
    </item>
    <item>
      <title>My Notes on Canva’s Real-Time Mouse Pointer Implementation</title>
      <dc:creator>Rishabh Agarwal</dc:creator>
      <pubDate>Fri, 27 Dec 2024 03:47:32 +0000</pubDate>
      <link>https://dev.to/the_infinity/my-notes-on-canvas-real-time-mouse-pointer-implementation-4g7a</link>
      <guid>https://dev.to/the_infinity/my-notes-on-canvas-real-time-mouse-pointer-implementation-4g7a</guid>
      <description>&lt;p&gt;Canva's engineering team embarked on developing a solution to handle real-time mouse pointer interactions for users working on designs simultaneously. The solution needed to support 3 updates per second per user, for up to 50 users on a single design, while ensuring scalability and performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Short-Term Solution: Backend-Centric Architecture
&lt;/h2&gt;

&lt;p&gt;Initially, Canva's team relied on WebSockets and Redis to facilitate real-time updates. The backend was designed to be stateless, with Redis acting as a message broker. The system scaled horizontally by adding new server instances as load increased, with each instance managing WebSocket connections and communicating through Redis. However, the challenge was to balance communication across these stateless instances.&lt;/p&gt;

&lt;p&gt;To optimize Redis, they used Redis Streams for session control information and PubSub for real-time mouse pointer updates, creating a dedicated Redis instance for PubSub messages. Despite some limitations, this architecture successfully supported up to 100,000 mouse pointer updates per second, with the system handling the load efficiently even at peak usage. Key optimizations included binary encoding of pointer data and batch commits to Redis, reducing backend and Redis CPU load by 30%.&lt;/p&gt;

&lt;p&gt;However, to meet the requirement of 60 updates per second per user, a new solution was necessary.&lt;/p&gt;

&lt;h2&gt;
  
  
  Long-Term Solution: WebRTC Implementation
&lt;/h2&gt;

&lt;p&gt;The long-term vision was to move towards a WebRTC-based solution to reduce backend load and increase scalability. WebRTC enables peer-to-peer communication, eliminating the need for server roundtrips. Canva’s team decided to use WebRTC for sending serialized mouse pointer data directly between clients, using WebSockets for signaling and NAT traversal via STUN/TURN servers.&lt;/p&gt;

&lt;p&gt;The system employed a Mesh topology for WebRTC connections, where each user directly connects with others, reducing backend dependency. About 50% of connections were direct peer-to-peer, while the rest utilized TURN servers when a direct connection wasn’t possible. The WebRTC solution, though complex to implement, provided better scalability and efficiency for handling high-frequency updates.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Insights:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Moving to WebRTC allowed Canva to scale to 60 updates per second per user.&lt;/li&gt;
&lt;li&gt;WebRTC's peer-to-peer connections significantly reduced backend load.&lt;/li&gt;
&lt;li&gt;A hybrid approach, using WebSockets for signaling and TURN servers for connectivity, ensured smooth communication between clients.
Conclusion:&lt;/li&gt;
&lt;li&gt;By combining WebSockets, Redis, and WebRTC, Canva’s engineering team successfully built a scalable solution that can handle real-time mouse pointer interactions at scale, allowing users to work on designs with minimal lag and high responsiveness.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To dive deeper into the technical implementation, challenges, and optimization strategies used by Canva, read the full blog on Medium!&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="https://medium.com/illumination/my-notes-on-canvas-real-time-mouse-pointer-implementation-37b42ebb6321" class="ltag__link__link" rel="noopener noreferrer"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fv2%2Fresize%3Afill%3A88%3A88%2F1%2AyicJmouyplHz2kBSWrnpdg.png" alt="Rishabh Agarwal"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://medium.com/illumination/my-notes-on-canvas-real-time-mouse-pointer-implementation-37b42ebb6321" class="ltag__link__link" rel="noopener noreferrer"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;My Notes on Canva’s Real-Time Mouse Pointer Implementation | by Rishabh Agarwal | ILLUMINATION&lt;/h2&gt;
      &lt;h3&gt;Rishabh Agarwal ・ &lt;time&gt;Dec 27, 2024&lt;/time&gt; ・ 
      &lt;div class="ltag__link__servicename"&gt;
        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fmedium-f709f79cf29704f9f4c2a83f950b2964e95007a3e311b77f686915c71574fef2.svg" alt="Medium Logo"&gt;
        Medium
      &lt;/div&gt;
    &lt;/h3&gt;
&lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>webdev</category>
      <category>programming</category>
      <category>discuss</category>
      <category>coding</category>
    </item>
    <item>
      <title>5 Caching Patterns Every Developer Should Know</title>
      <dc:creator>Rishabh Agarwal</dc:creator>
      <pubDate>Mon, 23 Dec 2024 06:54:40 +0000</pubDate>
      <link>https://dev.to/the_infinity/5-caching-patterns-every-developer-should-know-2p9b</link>
      <guid>https://dev.to/the_infinity/5-caching-patterns-every-developer-should-know-2p9b</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%2Fpb524fbxpi476ffirz72.gif" 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%2Fpb524fbxpi476ffirz72.gif" alt="Image description" width="800" height="576"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Caching is a crucial technique for enhancing the performance of applications by temporarily storing data for quick access. In this post, we'll briefly explore five popular caching patterns: &lt;strong&gt;Read Through&lt;/strong&gt;, &lt;strong&gt;Write Back&lt;/strong&gt;, &lt;strong&gt;Write Around&lt;/strong&gt;, &lt;strong&gt;Write Through&lt;/strong&gt;, and &lt;strong&gt;Cache Aside&lt;/strong&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  1. Read Through
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;Read Through&lt;/strong&gt; caching pattern allows your application to retrieve data directly from the cache. If the data isn't available in the cache, it fetches it from the database and stores it in the cache for future access. This pattern reduces the number of read operations on the database and speeds up data retrieval.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Write Back
&lt;/h2&gt;

&lt;p&gt;With the &lt;strong&gt;Write Back&lt;/strong&gt; pattern, updates to the cached data are written back to the cache first and then asynchronously persisted to the database later. This approach can improve write performance but requires careful handling to ensure data consistency and avoid potential data loss.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Write Around
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;Write Around&lt;/strong&gt; pattern processes writes directly to the database, bypassing the cache. This means that when data is requested afterward, it will be pulled into the cache. This method is beneficial when writes are infrequent compared to reads, minimizing cache pollution with rarely-accessed data.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Write Through
&lt;/h2&gt;

&lt;p&gt;In the &lt;strong&gt;Write Through&lt;/strong&gt; caching pattern, every write operation is performed on both the cache and the database simultaneously. This ensures that the cache always contains the most up-to-date data, providing consistency at the cost of some performance overhead during writes.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Cache Aside
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;Cache Aside&lt;/strong&gt; pattern places the responsibility for managing the cache on the application. When the app requests data, it first checks the cache; if the data isn’t present, it retrieves it from the database and stores it in the cache. This pattern allows fine-grained control over caching but requires more complex logic in the application.&lt;/p&gt;




&lt;p&gt;These caching patterns serve different use cases and have distinct advantages and trade-offs. Understanding them can help you optimize your application for better performance and user experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  Want to dive deeper?
&lt;/h3&gt;

&lt;p&gt;For a detailed discussion on these caching patterns and how to implement them effectively, check out my full blog here: &lt;a href="https://medium.com/p/313911dc2a5a" rel="noopener noreferrer"&gt;5 Caching Strategy Every Developer Keeps in Their Back Pocket&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Happy coding! 🚀&lt;/p&gt;

</description>
      <category>programming</category>
      <category>architecture</category>
      <category>webdev</category>
      <category>backend</category>
    </item>
    <item>
      <title>Relational Databases: PostgreSQL Vs. MariaDB Vs. MySQL Vs. SQLite</title>
      <dc:creator>Rishabh Agarwal</dc:creator>
      <pubDate>Sat, 08 Jun 2024 06:37:54 +0000</pubDate>
      <link>https://dev.to/strapi/relational-databases-postgresql-vs-mariadb-vs-mysql-vs-sqlite-5dn7</link>
      <guid>https://dev.to/strapi/relational-databases-postgresql-vs-mariadb-vs-mysql-vs-sqlite-5dn7</guid>
      <description>&lt;p&gt;Relational databases first appeared in the &lt;a href="https://en.wikipedia.org/wiki/Relational_database" rel="noopener noreferrer"&gt;1970s&lt;/a&gt;—that was more than half a century ago! They have stood what one would call the “test of time” and remained the go-to persistence solution for software applications. Other database technologies like NoSQL have challenged this dominance of RDBMS, but their sheer versatility has kept them at the top.&lt;/p&gt;

&lt;p&gt;In a landscape filled with open-source and commercial relational databases, this article focuses on the four most prominent open-source databases - &lt;a href="https://www.postgresql.org/" rel="noopener noreferrer"&gt;PostgreSQL&lt;/a&gt;, &lt;a href="https://www.mysql.com/" rel="noopener noreferrer"&gt;MySQL&lt;/a&gt;, &lt;a href="https://mariadb.org/" rel="noopener noreferrer"&gt;MariaDB&lt;/a&gt;, and &lt;a href="https://sqlite.org/" rel="noopener noreferrer"&gt;SQLite&lt;/a&gt;. These DBMS are the most preferred databases per the &lt;a href="https://survey.stackoverflow.co/2023/#section-most-popular-technologies-databases" rel="noopener noreferrer"&gt;SO’s 2023 survey&lt;/a&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%2F1yaxmhdrkqbye6xs03u2.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%2F1yaxmhdrkqbye6xs03u2.png" alt="responders-response-top-relational-databases.png" width="800" height="496"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When developers face many database options, it can feel like drowning in a sea of choices. But the real danger lies in the aftermath of a poor database selection. It's not just a ticking time bomb; it's a full-blown explosion in the advanced stages of application development, turning a switch to a more suitable database technology into a living nightmare.&lt;/p&gt;

&lt;p&gt;This article aims to empower developers with enough knowledge to make informed decisions about various popular relational databases.&lt;/p&gt;

&lt;h2&gt;
  
  
  Core Feature Comparison: PostgreSQL Vs. MariaDB Vs. MySQL Vs. SQLite
&lt;/h2&gt;

&lt;p&gt;The core features of a database often emerge as the pivotal factor in your choice of database technology. Whether it's the architecture or the feature set implemented by a database, these properties can significantly sway your decision. Given the importance of these core features, we begin our discussion with an extensive comparison of these across the four databases.&lt;/p&gt;

&lt;h3&gt;
  
  
  1.  Database Architecture
&lt;/h3&gt;

&lt;p&gt;While all of the databases we are comparing are relational databases, there are some significant architectural differences among them. Let's explore these differences.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;PostgreSQL:&lt;/strong&gt; PostgreSQL's unique architecture as an Object-Relational DBMS (ORDBMS) is a game-changer. It not only caters to the needs of a relational database but also extends its support to classes, objects, and inheritance. This powerful capability of PostgreSQL effectively bridges the gap between relational databases and object-oriented databases, opening up a world of possibilities for a wide range of applications. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; This object-oriented perspective of PostgreSQL is evident in several places. Every table in PostgreSQL has a corresponding data type created, and each row of a table can be seen as an instance of that data type.&lt;br&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;CREATE TYPE car_type AS &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;id &lt;/span&gt;integer, maker text, model text&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
CREATE TABLE car OF car_type&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also create tables inherited from other tables.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;CREATE TABLE ev_car &lt;span class="o"&gt;(&lt;/span&gt;battery_capacity integer&lt;span class="o"&gt;)&lt;/span&gt; INHERITS &lt;span class="o"&gt;(&lt;/span&gt;car&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Additionally, PostgreSQL is fully ACID-compliant in all of its configurations. This is a desired guarantee for many enterprise-grade applications! Moreover, it is the &lt;a href="https://www.postgresql.org/docs/current/features.html" rel="noopener noreferrer"&gt;closest&lt;/a&gt; database to complete conformance with the SQL standards.&lt;/p&gt;

&lt;p&gt;PostgreSQL's implementation of MVCC (Multi-Version Concurrency Control) is a testament to its efficiency. Unlike other databases that rely on locks or undo logs, PostgreSQL maintains versioned copies of DB objects. This approach is not just efficient, it's highly efficient, particularly when dealing with a large number of concurrent users and long running transactions. This reassures you of its performance in handling your database's needs. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;MySQL:&lt;/strong&gt; This is a pure relational database with an architecture optimized for read-heavy workloads. It uses a single process for multiple users, resulting in better read performance overall compared to other databases!&lt;/p&gt;

&lt;p&gt;MySQL offers a flexible architecture, supporting around 15 DB engines in addition to its default &lt;a href="https://dev.mysql.com/doc/refman/8.3/en/innodb-introduction.html" rel="noopener noreferrer"&gt;InnoDB&lt;/a&gt; engine. MySQL allows you to specify database engines at the table level using the TYPE parameter.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;: Using &lt;strong&gt;ISAM engine&lt;/strong&gt; for a table in MySQL.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;CREATE TABLE car &lt;span class="o"&gt;(&lt;/span&gt;
       &lt;span class="nb"&gt;id &lt;/span&gt;INT NOT NULL AUTO_INCREMENT,
       PRIMARY KEY &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;,
       maker TINYTEXT,
       model TINYTEXT
&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;TYPE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ISAM
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;MariaDB:&lt;/strong&gt; This is a fork of MySQL and thus shares many architectural features with MySQL. The project was initiated by MySQL's developers after its acquisition by Oracle, but since then, both databases have been developed independently. &lt;/p&gt;

&lt;p&gt;MariaDB's architecture offers improved scalability and performance. It has a larger thread pool for better concurrency, only offered in MySQL's enterprise version. It also provides better performance in terms of the number of queries served per second.&lt;/p&gt;

&lt;p&gt;Columnar storages have proven to outperform their row-based counterparts for workloads heavy on analytics. MariaDB sets itself apart by offering a dedicated DB engine for columnar storage, known as &lt;a href="https://mariadb.com/kb/en/mariadb-columnstore/+questions/" rel="noopener noreferrer"&gt;ColumnStore&lt;/a&gt;. This unique feature positions MariaDB as an exceptional choice for OLAP workloads, further enhancing its appeal for specific use cases.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;: Using &lt;strong&gt;ColumnStore&lt;/strong&gt; in MariaDB&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;CREATE TABLE &lt;span class="sb"&gt;`&lt;/span&gt;experiment&lt;span class="sb"&gt;`&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;
  &lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt; datetime NOT NULL,
  &lt;span class="sb"&gt;`&lt;/span&gt;scientist&lt;span class="sb"&gt;`&lt;/span&gt; varchar&lt;span class="o"&gt;(&lt;/span&gt;1024&lt;span class="o"&gt;)&lt;/span&gt; NOT NULL,
  &lt;span class="sb"&gt;`&lt;/span&gt;content&lt;span class="sb"&gt;`&lt;/span&gt; text NOT NULL
&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;ENGINE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Columnstore
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;SQLite:&lt;/strong&gt; Unlike the other three databases, SQLite is a serverless database! A single-file database, it is lightweight, simple, and quickly embeddable. This unique architecture makes it a great choice for embedded applications. &lt;/p&gt;

&lt;p&gt;SQLite, a client-side database, operates on a relational data storage model. However, it does come with some limitations when compared to the other three databases. Its unique architecture, while offering benefits, also means that SQLite has limited transaction and concurrency support.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2.  Data Types &amp;amp; Unique Functionality
&lt;/h3&gt;

&lt;p&gt;All four databases encompass a comprehensive set of basic datatypes, including text, number, boolean, and date, for regular use cases. However, differences start to appear when dealing with advanced data types. Let us compare the support offered by various databases for advanced data types.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;JSON&lt;/strong&gt; - With the increased adaption of JSON in web applications, databases are often required to persist JSON data directly. Both MySQL and PostgreSQL provide support for JSON datatypes. This support is absent for MariaDB and SQLite, and the best we can do is serialise JSON as a string.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Arrays&lt;/strong&gt; - PostgreSQL is the only database among the four that supports storing arrays in database tables. Arrays can be persisted as JSON in MySQL, but there is no support for storing arrays natively. Again, MariaDB and SQLite do not provide support for persisting arrays natively.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Geospatial Data&lt;/strong&gt; - Barring SQLite, all the other databases support Geospatial Data. PostgreSQL's &lt;a href="https://postgis.net/" rel="noopener noreferrer"&gt;PostGIS&lt;/a&gt; extension supports over 600 spatial operators. MySQL, with its &lt;a href="https://www.cmi.ac.in/madhavan/courses/databases10/mysql-5.0-reference-manual/spatial-extensions.html" rel="noopener noreferrer"&gt;Spatial&lt;/a&gt; extension and MariaDB support over 160 operators.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each database offers unique features that may be suitable for specific use cases. Here is a list of popular features provided by each database. &lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Database&lt;/th&gt;
&lt;th&gt;Features&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;PostgreSQL&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://www.postgresql.org/docs/current/rules-materializedviews.html" rel="noopener noreferrer"&gt;Materialized Views&lt;/a&gt;, &lt;a href="https://www.postgresql.org/docs/current/sql-notify.html" rel="noopener noreferrer"&gt;Pub/Sub Notifications&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MySQL/MariaDB&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://dev.mysql.com/doc/refman/8.0/en/invisible-columns.html" rel="noopener noreferrer"&gt;Invisible Columns&lt;/a&gt;, &lt;a href="https://www.notion.so/Exploring-Top-Relational-Databases-PostgreSQL-vs-MariaDB-vs-MySQL-vs-SQLite-930eac3a8a2b4f4085f2737a02cbab0e?pvs=21" rel="noopener noreferrer"&gt;Temporary Tablespaces&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SQLite&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.notion.so/Exploring-Top-Relational-Databases-PostgreSQL-vs-MariaDB-vs-MySQL-vs-SQLite-930eac3a8a2b4f4085f2737a02cbab0e?pvs=21" rel="noopener noreferrer"&gt;Virtual Table&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  3.  Performance &amp;amp; Scalability
&lt;/h3&gt;

&lt;p&gt;The performance of a database depends on several factors, such as data volume, mix of operations, number of concurrent users, and hardware capability. Therefore, a statement like “&lt;strong&gt;&lt;em&gt;Database system X is more performant than database system Y&lt;/em&gt;&lt;/strong&gt;” is incomplete without mentioning all of these variables!&lt;/p&gt;

&lt;p&gt;MySQL/MariaDB have generally been found to provide better performance for a read-heavy workload. On the other hand, when the workload consists of both read and write operations, PostgreSQL outperforms other databases. For very simple queries on small to medium-sized databases, SQLite will be the most efficient since there is no overhead of maintaining a server and heavy concurrency machinery. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: It is very important to characterize your workloads and compare database performance on each workload instead of using a general performance comparison!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Talking about scalability, all databases, except SQLite, offer replication and horizontal scalability. Between MariaDB and MySQL, MariaDB is known to be better scalable. &lt;/p&gt;

&lt;h2&gt;
  
  
  Development Experience
&lt;/h2&gt;

&lt;p&gt;Besides the core features, general development experience is another significant factor when deciding on a database. This section will explore key factors influencing your experience working with each database option.&lt;/p&gt;

&lt;h3&gt;
  
  
  1.  Ease of Use &amp;amp; Learning Curve
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Installation and Setup Complexity
&lt;/h4&gt;

&lt;p&gt;Regarding setup and installation, SQLite wins the race by miles. With its server-less architecture and zero-configuration setup, it is the simplest to spin up and use. Everything needed to use SQLite comes bundled with the application!&lt;/p&gt;

&lt;p&gt;Both MariaDB and MySQL offer a relatively straightforward configuration and usage experience. This ease of installation is a key factor in their popularity for quick Proof of Concept (PoC) and ideation, as it allows developers to focus on their projects rather than the setup process. &lt;/p&gt;

&lt;p&gt;PostgreSQL has the most complex configuration of all four. Installing it can be challenging, especially for beginners. While efforts are being made to simplify its installation, it still lacks MariaDB and MySQL in terms of ease of installation. &lt;/p&gt;

&lt;h4&gt;
  
  
  Learning Curve
&lt;/h4&gt;

&lt;p&gt;Without the complexities of large database systems, SQLite has the gentlest learning curve. With some basic knowledge of SQL and data persistence, anyone can start using and working with SQLite. &lt;/p&gt;

&lt;p&gt;Both MySQL and MariaDB, with their shared architecture, offer a smooth learning curve for beginners. The knowledge you gain from one database can be easily applied to the other, making the learning process even more efficient. &lt;/p&gt;

&lt;p&gt;With its extensive set of features, PostgreSQL has the steepest learning curve. Before they can start using it, users should be familiar with the ORDBMS architecture and several database configurations. &lt;/p&gt;

&lt;h3&gt;
  
  
  2.  Community &amp;amp; Support
&lt;/h3&gt;

&lt;p&gt;All four databases are open-source and highly popular, so they provide good community support. However, MySQL also provides an enterprise version, and some feature requests might be denied in the community version in favor of the enterprise version. &lt;/p&gt;

&lt;h3&gt;
  
  
  3.  Third-Party Tools and Integrations
&lt;/h3&gt;

&lt;p&gt;All four databases enjoy a rich repository of third-party tools and integrations. These tools simplify day-to-day database management and usage. &lt;/p&gt;

&lt;h4&gt;
  
  
  PostgreSQL
&lt;/h4&gt;

&lt;p&gt;PostgreSQL has a large collection of extensions that add a number of features to it. Some of the popular ones are PostGIS, LTree, and HStore. All four databases are open-source and highly popular, so they provide good community support. However, MySQL also provides an enterprise version, and some feature requests might be denied in the community version in favor of the enterprise version. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;Management Tools&lt;/em&gt;&lt;/strong&gt; - &lt;a href="https://www.postgresql.org/docs/7.0/app-psql.htm" rel="noopener noreferrer"&gt;psql&lt;/a&gt; and &lt;a href="https://www.pgadmin.org/" rel="noopener noreferrer"&gt;pgAdmin&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;Backup &amp;amp; Restore&lt;/em&gt;&lt;/strong&gt; - &lt;a href="https://www.postgresql.org/docs/current/app-pgdump.html" rel="noopener noreferrer"&gt;pg_dump&lt;/a&gt; and &lt;a href="https://www.postgresql.org/docs/current/app-pgrestore.html" rel="noopener noreferrer"&gt;pg_restore&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;Monitoring&lt;/em&gt;&lt;/strong&gt; - &lt;a href="https://www.postgresql.org/docs/current/monitoring-stats.html" rel="noopener noreferrer"&gt;pg_stat_activity&lt;/a&gt; and &lt;a href="https://www.postgresql.org/docs/current/monitoring-stats.html" rel="noopener noreferrer"&gt;pg_stat_statement&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  MySQL and MariaDB
&lt;/h4&gt;

&lt;p&gt;MySQL and MariaDB being interoperable shares most of the tools in common. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;Management Tools&lt;/em&gt;&lt;/strong&gt; - mysql and &lt;a href="https://www.phpmyadmin.net/" rel="noopener noreferrer"&gt;phpMyAdmin&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;Backup &amp;amp; Restore&lt;/em&gt;&lt;/strong&gt; - &lt;a href="https://dev.mysql.com/doc/refman/8.4/en/mysqldump.html" rel="noopener noreferrer"&gt;mysqldump&lt;/a&gt; and&lt;a href="https://dev.mysql.com/doc/refman/8.4/en/mysqlimport.html" rel="noopener noreferrer"&gt; mysqlimport&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  SQLite
&lt;/h4&gt;

&lt;p&gt;SQLite too offer tools like &lt;a href="https://docs.python.org/3/library/sqlite3.html" rel="noopener noreferrer"&gt;sqlite3&lt;/a&gt; to manage database from command line.&lt;/p&gt;

&lt;h2&gt;
  
  
  Database Integration with Strapi
&lt;/h2&gt;

&lt;p&gt;Strapi allows you to use either of these four databases for your application development purposes. Once you decide on the most suitable database technology for your application, you can configure Strapi to persist your application data inside that database. Let us understand the configurations required in Strapi for each database. Check out the &lt;a href="https://docs.strapi.io/dev-docs/configurations/database" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; for database configurations in Strapi. &lt;/p&gt;

&lt;h3&gt;
  
  
  SQLite Integration with Strapi
&lt;/h3&gt;

&lt;p&gt;SQLite is the default (&lt;a href="https://docs.strapi.io/dev-docs/quick-start" rel="noopener noreferrer"&gt;quickstart&lt;/a&gt;) and the recommended database to quickly create an app locally. You can use the &lt;code&gt;quickstart&lt;/code&gt; flag to automatically configure the SQLite database.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn create strapi-app my-project &lt;span class="nt"&gt;--quickstart&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should automatically open up the admin page on &lt;code&gt;localhost:1337/admin&lt;/code&gt;. Once logged in, you can create collections and SQLite database will be used to persist all data. &lt;/p&gt;

&lt;p&gt;By default the database file (&lt;code&gt;data.db&lt;/code&gt;) for SQLite will be placed inside &lt;code&gt;.tmp&lt;/code&gt; folder at the root of your Strapi project. This can be configured in the &lt;code&gt;database.js&lt;/code&gt; file inside the &lt;code&gt;config&lt;/code&gt; directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;client&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sqlite&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;..&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DATABASE_FILENAME&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.tmp/data.db&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;useNullAsDefault&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can either set &lt;code&gt;DATABASE_FILENAME&lt;/code&gt; environment variable or explicitly provide database file path in &lt;code&gt;database.js&lt;/code&gt;. As discussed, SQLite is the easiest way to get you started when working on applications.&lt;/p&gt;

&lt;h3&gt;
  
  
  PostgreSQL Integration with Strapi
&lt;/h3&gt;

&lt;p&gt;We can use the custom installation method for creating Strapi projects that uses PostgreSQL. For this to work, you must already have a running PostgreSQL instance on your machine. &lt;/p&gt;

&lt;p&gt;Here is how this can be done. Specify the correct database name, host, port, username, and password for your Postgres database and Strapi will do the rest for you!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-strapi-app strapi-with-postgres           
? Choose your installation &lt;span class="nb"&gt;type &lt;/span&gt;Custom &lt;span class="o"&gt;(&lt;/span&gt;manual settings&lt;span class="o"&gt;)&lt;/span&gt;
? Choose your preferred language JavaScript
? Choose your default database client postgres
? Database name: postgres
? Host: 127.0.0.1
? Port: 5432
? Username: postgres
? Password: &lt;span class="k"&gt;********&lt;/span&gt;
? Enable SSL connection: No

Creating a project with custom database options.
Creating a new Strapi application at /home/strapi-with-postgres.
Creating files.
Dependencies installed successfully.
Initialized a git repository.


Your application was created at /home/strapi-with-postgres.

Available commands &lt;span class="k"&gt;in &lt;/span&gt;your project:

  yarn develop
  Start Strapi &lt;span class="k"&gt;in &lt;/span&gt;watch mode. &lt;span class="o"&gt;(&lt;/span&gt;Changes &lt;span class="k"&gt;in &lt;/span&gt;Strapi project files will trigger a server restart&lt;span class="o"&gt;)&lt;/span&gt;

  yarn start
  Start Strapi without watch mode.

  yarn build
  Build Strapi admin panel.

  yarn strapi
  Display all available commands.

You can start by doing:

  &lt;span class="nb"&gt;cd&lt;/span&gt; /home/strapi-with-postgres
  yarn develop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As suggested in the output of the npx command, we can start the server and our Strapi application will now use the Postgres database. You might see errors like below if the PostgreSQL database is not running or is not configured properly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;┌───────────────────────────────────────────────────────────────────────────┐
│                                                                           │
│   Error: connect ECONNREFUSED 127.0.0.1:5432                              │
│       at TCPConnectWrap.afterConnect &lt;span class="o"&gt;[&lt;/span&gt;as oncomplete] &lt;span class="o"&gt;(&lt;/span&gt;node:net:1195:16&lt;span class="o"&gt;)&lt;/span&gt;   │
│                                                                           │
└───────────────────────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Again, you can find all the database configuration inside the &lt;code&gt;config/database.js&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;postgres&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;connectionString&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DATABASE_HOST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;localhost&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DATABASE_PORT&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5432&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DATABASE_NAME&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;strapi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DATABASE_USERNAME&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;strapi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DATABASE_PASSWORD&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;strapi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;ssl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DATABASE_SSL&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DATABASE_SSL_KEY&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;cert&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DATABASE_SSL_CERT&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;ca&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DATABASE_SSL_CA&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;capath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DATABASE_SSL_CAPATH&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;cipher&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DATABASE_SSL_CIPHER&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;rejectUnauthorized&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DATABASE_SSL_REJECT_UNAUTHORIZED&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="kc"&gt;true&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DATABASE_SCHEMA&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;public&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;min&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DATABASE_POOL_MIN&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;max&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DATABASE_POOL_MAX&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a comprehensive tutorial on setting up Strapi with Postgres, refer to &lt;a href="https://strapi.io/blog/postgre-sql-and-strapi-setup" rel="noopener noreferrer"&gt;this&lt;/a&gt; article.&lt;/p&gt;

&lt;h3&gt;
  
  
  MySQL/MariaDB Integration with Strapi
&lt;/h3&gt;

&lt;p&gt;The configuration process for MySQL/MariaDB is similar to that of PostgreSQL. We can use custom installation method for starting a MySQL/MariaDB based Strapi application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-strapi-app strapi-with-mysql   
? Choose your installation &lt;span class="nb"&gt;type &lt;/span&gt;Custom &lt;span class="o"&gt;(&lt;/span&gt;manual settings&lt;span class="o"&gt;)&lt;/span&gt;
? Choose your preferred language JavaScript
? Choose your default database client mysql
? Database name: strapi-with-mysql
? Host: 127.0.0.1
? Port: 3306
? Username: mysql
? Password: &lt;span class="k"&gt;*****&lt;/span&gt;
? Enable SSL connection: No

Creating a project with custom database options.
Creating a new Strapi application at /home/strapi-with-mysql.
Creating files.
Dependencies installed successfully.
Initialized a git repository.


Your application was created at /home/strapi-with-mysql.

Available commands &lt;span class="k"&gt;in &lt;/span&gt;your project:

  yarn develop
  Start Strapi &lt;span class="k"&gt;in &lt;/span&gt;watch mode. &lt;span class="o"&gt;(&lt;/span&gt;Changes &lt;span class="k"&gt;in &lt;/span&gt;Strapi project files will trigger a server restart&lt;span class="o"&gt;)&lt;/span&gt;

  yarn start
  Start Strapi without watch mode.

  yarn build
  Build Strapi admin panel.

  yarn strapi
  Display all available commands.

You can start by doing:

  &lt;span class="nb"&gt;cd&lt;/span&gt; /home/strapi-with-mysql
  yarn develop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will add the following configuration inside the &lt;code&gt;database.js&lt;/code&gt; file. It lists out the client, host, password, database, and user to be used for connecting.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;mysql&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;connectionString&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DATABASE_HOST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;localhost&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DATABASE_PORT&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3306&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DATABASE_NAME&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;strapi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DATABASE_USERNAME&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;strapi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DATABASE_PASSWORD&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;strapi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;ssl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DATABASE_SSL&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DATABASE_SSL_KEY&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;cert&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DATABASE_SSL_CERT&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;ca&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DATABASE_SSL_CA&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;capath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DATABASE_SSL_CAPATH&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;cipher&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DATABASE_SSL_CIPHER&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;rejectUnauthorized&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DATABASE_SSL_REJECT_UNAUTHORIZED&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="kc"&gt;true&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;min&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DATABASE_POOL_MIN&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;max&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DATABASE_POOL_MAX&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a more comprehensive tutorial on using MySQL/MariaDB with Strapi, refer to &lt;a href="https://strapi.io/blog/configuring-strapi-mysql-database" rel="noopener noreferrer"&gt;this&lt;/a&gt; article!&lt;/p&gt;

&lt;h2&gt;
  
  
  Use Cases &amp;amp; Recommendations
&lt;/h2&gt;

&lt;p&gt;Equipped with the knowledge of core features and development experience for each of the database, it is time for us to identify what scenarios makes one database preferrable over the other. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;SQLite&lt;/strong&gt;: This is most suited for embedded applications. It can also be a viable option if you are working with low volumes of data without much concern for data concurrency. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;MySQL&lt;/strong&gt;: MySQL is a good choice for quick prototyping. Additionally, if your workload consists of bulk reads and a comparatively smaller number of writes, MySQL is a better candidate.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;MariaDB&lt;/strong&gt;: The fact that MariaDB and MySQL share the same architecture implies that both databases are good candidates for many everyday use cases. But if you are looking for a scalable database that offers high query speed, then MariaDB is the way to go. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;PostgreSQL&lt;/strong&gt;: PostgreSQL becomes the best option when building large and complex enterprise-grade applications. Its rich feature set and SQL standard conformance offer everything you need from a relational database. Strapi allows you to use either of these four databases for your application development purposes. Once you decide on the most suitable database technology for your application, you can configure Strapi to persist your application data inside that database. Let us understand the configurations required in Strapi for each database. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Comparison Matrix: PostgreSQL Vs. MariaDB Vs. MySQL Vs. SQLite
&lt;/h2&gt;

&lt;p&gt;The image below shows some summarized differences between the top relational databases discussed so far.&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%2F3y40pd2wkg852tbi6iok.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%2F3y40pd2wkg852tbi6iok.png" alt="top-relational-databases-comparison.png" width="800" height="438"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Each database has its own strengths and weaknesses. While one might be easy to install and use, the other might offer more features. When dealing with large volumes of data requiring complex queries, PostgreSQL is the way to go. For embedded applications or low volume-low concurrency use cases, SQLite offers the best solution. MariaDB/MySQL is a better option for medium data volumes and read-heavy workloads. &lt;/p&gt;

&lt;p&gt;Choosing the correct database for your particular use case is challenging. Finding one that best aligns with your needs takes a lot of research and experimentation. A thorough understanding of core database features facilitates making informed decisions, as explored in this comparison of PostgreSQL, MySQL, MariaDB, and SQLite. While this article covered the four most popular relational databases, a similar exercise can be done for any database.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>database</category>
      <category>coding</category>
      <category>sql</category>
    </item>
    <item>
      <title>What are Content Delivery Networks (CDNs)?</title>
      <dc:creator>Rishabh Agarwal</dc:creator>
      <pubDate>Sat, 25 May 2024 08:23:54 +0000</pubDate>
      <link>https://dev.to/the_infinity/what-is-content-delivery-networks-cdns-3abd</link>
      <guid>https://dev.to/the_infinity/what-is-content-delivery-networks-cdns-3abd</guid>
      <description>&lt;p&gt;Imagine running an application that serve latest news in the form of 100-words articles. News in the form of such short articles allowed your application’s users to consume lot more news in a short time.&lt;/p&gt;

&lt;p&gt;With growing popularity of your application, the load on your application server started growing exponentially. Initially you increased your server’s capability to serve more requests, but you soon realised that this was not sustainable. You dig deep to find a better solution for this problem. You found the following usage pattern for your application ~&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Users that were geographically closer to each other almost consumed the same set of news articles&lt;/li&gt;
&lt;li&gt;While the number of users were large at any point in time, the news articles that they consumed in-together wasn’t that large. In other words, people read almost the same set of articles during a given interval.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All this made you to think of caching news articles. However, this cache needs to be different for different geographical locations. You researched further and found a perfect solution called Content Delivery Networks (CDNs).&lt;/p&gt;

&lt;p&gt;This is how Cloudflare defines CDN ~&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;A content delivery network (CDN) is a geographically distributed group of servers that caches content close to end users. A CDN allows for the quick transfer of assets needed for loading Internet content, including HTML pages, JavaScript files, stylesheets, images, and videos.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So how does CDN works? There are the following three crucial components to it.&lt;/p&gt;

&lt;p&gt;➙ &lt;strong&gt;&lt;em&gt;Origin Server&lt;/em&gt;&lt;/strong&gt;: This is the application server that contains the source of truth. Any updates are made to the contents of the origin server.&lt;/p&gt;

&lt;p&gt;➙ &lt;strong&gt;&lt;em&gt;Edge Servers&lt;/em&gt;&lt;/strong&gt;: These servers are located in multiple geographical locations that are called “&lt;strong&gt;&lt;em&gt;Points-of-Presence&lt;/em&gt;&lt;/strong&gt;” or “&lt;strong&gt;&lt;em&gt;PoP&lt;/em&gt;&lt;/strong&gt;”. Content from the origin server is cached here and is served to the clients. In case of missing data, origin server is used to respond to the client’s query and for simultaneously updating edge server’s cache.&lt;/p&gt;

&lt;p&gt;➙ &lt;strong&gt;&lt;em&gt;DNS Servers&lt;/em&gt;&lt;/strong&gt;: Domain Name Systems (DNS) servers keep track of the origin and edge server. On a DNS lookup, IPs of both the origin and the edge server.&lt;/p&gt;

&lt;p&gt;While caching is one of the biggest advantages of CDNs, it is not the only one. There are several other advantages like decreased server loads, improved site performance, and protection against cyber-attacks. All these benefits are the reason why most of the internet today is being served up by CDNs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Types of CDNs
&lt;/h3&gt;

&lt;p&gt;Based on how the cache in edge servers is updated, two types of CDNs exists: &lt;strong&gt;&lt;em&gt;push&lt;/em&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;em&gt;pull&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Push CDNs&lt;/strong&gt; push contents from origin server to the edge servers. Updated content is pushed periodically which is then served up by the CDNs. The cache data from edge server is not removed until the data is explicitly deleted or overridden by the updated data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pull CDNs&lt;/strong&gt; is the complete opposite of push CDNs. Here, the edge servers are responsible for pulling in data from the origin server. The process works like this: as the website owner, you maintain the content on the origin server and adjust the URLs to point to the CDN. Subsequently, when a request is made for a web page, the CDN fetches the necessary elements and files from the origin server and presents them to the visitor.&lt;/p&gt;

&lt;h3&gt;
  
  
  Popular CDNs
&lt;/h3&gt;

&lt;p&gt;Almost always you would use services of a CDN provider instead of setting up your own CDN. There are some very good options out there, some of them being ~&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Akamai&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Cloudfront&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Azure CDN&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Cloudflare&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;With this we reach the end of this blog. Give yourself a pat on the back if you make it this far!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>beginners</category>
      <category>cloud</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Database Replication Encyclopaedia — Single Leader Replication (1/3)</title>
      <dc:creator>Rishabh Agarwal</dc:creator>
      <pubDate>Fri, 24 May 2024 05:55:42 +0000</pubDate>
      <link>https://dev.to/the_infinity/database-replication-encyclopaedia-single-leader-replication-13-2l5c</link>
      <guid>https://dev.to/the_infinity/database-replication-encyclopaedia-single-leader-replication-13-2l5c</guid>
      <description>&lt;p&gt;Replicated databases are the new reality of data based software applications. Gone are those days when databases were confined to a single machine in a data centre. With the rise of distributed systems, database replication has become one of those topics which every developers should know.&lt;/p&gt;

&lt;p&gt;If you are hearing the term ‘&lt;strong&gt;&lt;em&gt;Database replication&lt;/em&gt;&lt;/strong&gt;’ for the first time, let me summarise it for you in a single line as follows,&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Database replication is the process of maintaining several copies of data across several machines that are interconnected via a network.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Why replicate database you may ask?&lt;/em&gt; There are several reasons to why distributed systems use replication. Some of the important ones are the following —&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;To keep data geographically closer to the users for reduced latency.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;To increase fault tolerance and increase overall availability of the system.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;To be able to scale out the number of machines that can server the read queries.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the replicated data is constant and does not change over time, there is nothing to worry about. Simply replicate your data across nodes and you are done. Almost all of the complexities of database replication arise because of changing data!&lt;/p&gt;

&lt;p&gt;To tackle these difficulties there are three popular approaches to database replications — &lt;strong&gt;&lt;em&gt;Single Leader Replication&lt;/em&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;em&gt;Multi-Leader Replication&lt;/em&gt;&lt;/strong&gt;, and &lt;strong&gt;&lt;em&gt;Leaderless replication&lt;/em&gt;&lt;/strong&gt;. Almost all of the database systems out there use one of these three to achieve database replication. In this blog, we will be discussing the Single Leader Replication method.&lt;/p&gt;

&lt;h2&gt;
  
  
  Single Leader Replication
&lt;/h2&gt;

&lt;p&gt;Each machine that maintains a copy of the data is called a &lt;strong&gt;replica&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In single-leader replication, one of the replica is designated the Leader. The Leader is the one responsible for processing write operations received from the clients. It is also responsible for propagating the write operations to other replicas called follower.&lt;/p&gt;

&lt;p&gt;While writes are only served by the leader, read requests can be served by both the leader and followers.&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%2Fbl3herqwct7hk1bcrx6y.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%2Fbl3herqwct7hk1bcrx6y.png" alt="Single Leader Replication Topology" width="800" height="556"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On receiving a write request from the client, the leader first updates its own local storage. It then sends the update request to followers, which on receiving the message from the leader update their own local storages. In this way, all write operations are ensured across replicas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Synchronous Vs Asynchronous Replication
&lt;/h2&gt;

&lt;p&gt;Depending on how the updates from leader propagates to the follower, the replication is of two types — &lt;strong&gt;Synchronous&lt;/strong&gt; and &lt;strong&gt;Asynchronous&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Under Synchronous replication, leader waits for followers to acknowledge the update. Once the leader ensures that the update has been successfully written to all the synchronous replicas and its own local storage as well, it sends success message in response to the client’s request. This replication method ensures that all of the replicas remain in-sync with the leader. Synchronous replication, however, is slow since all replicas must commit changes before the operation can be deemed successful. It is also susceptible to downtime owing to a single node failure.&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%2Fgfdhn64xemhqviqh90mz.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%2Fgfdhn64xemhqviqh90mz.png" alt="Depiction of Synchronous replication. Follow the numbers written along with the step to understand the relative ordering of operations." width="521" height="371"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Under Asynchronous replication, leader does not wait for followers to process the write operation. Once the leader updates its own local storage, it sends a success message back to the client. In this setting, the system may not be consistent immediately but will be eventually consistent. Since the leader does not wait on followers to complete their work, updates are faster when compared to synchronous replication.&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%2Fnj0tg3h4hi9e7x2lwigd.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%2Fnj0tg3h4hi9e7x2lwigd.png" alt="Depiction of Asynchronous replication. Communication between leader and followers is performed asynchronously." width="521" height="371"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In practice, synchronous replication is characterised by a single follower being replicated synchronously while the other replicas are still replicated asynchronously. This ensures that there is always a follower with up-to-date data that can be made the leader in case the current leader fails. This type of replication is called &lt;strong&gt;&lt;em&gt;semi-synchronous replication&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding new Followers
&lt;/h2&gt;

&lt;p&gt;Adding a new follower replica to the cluster requires some careful considerations. A copy operation on the leader’s database might not give us the correct result since leader is actively accepting write requests and its state is constantly evolving. This could result in corrupted data getting copied. Another option is to take a lock on the leader and then perform the copying operation. This is also not acceptable since it will cause downtime anytime a new follower has to be added.&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%2Fg7crpxt2uq2uw8s7d0wx.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%2Fg7crpxt2uq2uw8s7d0wx.png" alt="Adding new Followers" width="636" height="361"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Instead, we can take a snapshot of the leader’s database. Most database provide this option for the purpose of backup. Restore the snapshot on the new follower’s database. Once the snapshot data is restored, follower can start asking the leader for changes that have occurred since the snapshot was taken. They can use Log Sequence Number (or LSN) to get that data from the leader.&lt;/p&gt;

&lt;p&gt;Once the follower has done the catching-up process, it can continue working like the other followers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handling Node Outages
&lt;/h2&gt;

&lt;p&gt;It is common for nodes to drop out of the cluster. It can be because of network or machine failure, or it could be because of scheduled maintenance. Let us understand how node outages are handled in Single-Leader replication.&lt;/p&gt;

&lt;p&gt;When a follower node goes down, the system can continue to work as usual. Read requests that were earlier served by the impacted node will now be served by other replicas. Later when the follower joins back, it can ask for the updates from the leader and can continue working normally.&lt;/p&gt;

&lt;p&gt;Things become interesting in case of a leader failure. To keep the system in a working state, a new leader has to be elected. There are several algorithm by which the cluster can select the new leader replica. Once the new leader is elected, the client needs to be configured to send all write request to this new leader and all the followers should now accept update requests from this new leader.&lt;/p&gt;

&lt;h2&gt;
  
  
  Issues arising from Replication Lag
&lt;/h2&gt;

&lt;p&gt;Replication lag between the follower and the leader can lead to issues that would otherwise not occur in a single-machine database. These issues require careful considerations, especially when the database does not provide a mechanism to solve them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Read Your Own Writes
&lt;/h3&gt;

&lt;p&gt;Consider the following scenario, a client sends an update request to the leader. As soon as the client receive a success response from the leader, it makes a read request to the cluster and receive a response from an asynchronous follower. Interestingly, the client will see its updates reverted. Therefore we must design applications that provide read-after-write consistency.&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%2Fmzw8he67unqfmweroqs6.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%2Fmzw8he67unqfmweroqs6.png" alt="Read-after-write inconsistency" width="800" height="431"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are several possible ways in which we can provide read-after-write consistency in our application. Some of them are as follows —&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We can always use leader to respond for the data that a client may have updated. This obviously depends on being able to identify all the data that could be updated by a client.&lt;/li&gt;
&lt;li&gt;Another way is to make all reads from the leader until a certain time after a client makes any update. We can also monitor the replication lag on the followers and prevent queries on followers that lags more than a certain amount of time.&lt;/li&gt;
&lt;li&gt;Client may keep the timestamp of the update and this can then be used by the cluster to respond from replicas that are up-to-date until that point in time.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Same user accessing your cluster from different device poses new challenges. In such cases, we want to provide &lt;em&gt;cross-device read-after-write consistency&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Monotonic Reads
&lt;/h3&gt;

&lt;p&gt;With multiple replicas having different replication lags, it is possible that a client, after making request to an up-to-date replica, makes a request to a replica with larger lag. In this situation, client would see an older state and for it the time would appear to go backward.&lt;/p&gt;

&lt;p&gt;Monotonic reads is a guarantee that this kind of anomaly does not happen. One way of achieving it is to ensure that a client always reads from a particular replica. Though this is not the ideal solution since a replica may go down at any point in time.&lt;/p&gt;




&lt;p&gt;Single leader replication is one of the most used replication techniques. When working with read-heavy workloads, single leader replication becomes a good solution since reads are distributes across replicas. This however becomes an issue when working with write heavy-workloads that can cause your leader to bottleneck.&lt;/p&gt;

&lt;p&gt;With this we reach the end of this blog. If you learned something new, then follow me up for more such interesting reads!&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>learning</category>
      <category>database</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Object Sharing in Multi-threaded Environments</title>
      <dc:creator>Rishabh Agarwal</dc:creator>
      <pubDate>Sat, 30 Mar 2024 10:42:50 +0000</pubDate>
      <link>https://dev.to/the_infinity/object-sharing-in-multi-threaded-environments-43l2</link>
      <guid>https://dev.to/the_infinity/object-sharing-in-multi-threaded-environments-43l2</guid>
      <description>&lt;p&gt;All the intricacies of a multi-threaded environment arises from sharing objects across threads. As discussed &lt;a href="https://medium.com/@the_infinity/thread-safety-from-an-object-oriented-perspective-2913b1879d0c" rel="noopener noreferrer"&gt;here&lt;/a&gt;, managing access to shared objects is the base of thread safety. If there are no shared objects, our program is inherently thread-safe!&lt;/p&gt;

&lt;p&gt;But it is not always possible to design a threaded application without making some objects visible across threads. In this article, we will talk about some standard practices for sharing objects. These practices will help us building more resilient and robust multi-threaded systems!&lt;/p&gt;

&lt;h2&gt;
  
  
  Escaped Objects
&lt;/h2&gt;

&lt;p&gt;When we publish an object, we make it available to code outside of its current scope. This can be useful in many situations, but there are also cases where we want our objects to remain unpublished. However, there are times when we may need to publish objects, and it’s important to ensure that this is done in a thread-safe manner using proper synchronisation.&lt;/p&gt;

&lt;p&gt;An accidentally published object is said to have been &lt;strong&gt;&lt;em&gt;escaped&lt;/em&gt;&lt;/strong&gt;. There are several way in which an object may escape!&lt;/p&gt;

&lt;p&gt;➥ &lt;strong&gt;Making objects visible globally&lt;/strong&gt; ~ Storing references to objects such that any executing thread can access it causes objects to ‘&lt;strong&gt;&lt;em&gt;escape&lt;/em&gt;&lt;/strong&gt;’.&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;class&lt;/span&gt; &lt;span class="nc"&gt;Escape1&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&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;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;activeUserIds&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;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;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;In the example above, any thread can access activeUserIds and it is technically escaped!&lt;/p&gt;

&lt;p&gt;➥ &lt;strong&gt;Returning objects from non-private methods&lt;/strong&gt; ~ Returning objects from non-private methods also publishes objects. This is because any executing thread can get hold of internal states of the object.&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;class&lt;/span&gt; &lt;span class="nc"&gt;Escape2&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&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;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;activeUserIds&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;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="kd"&gt;public&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;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getActiveUserIds&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;activeUserIds&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&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;addActiveUser&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;userExists&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;activeUserIds&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;anyMatch&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;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;userId&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;userExists&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;activeUserIds&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userId&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="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above example, the &lt;code&gt;activeUserIds&lt;/code&gt; variable, intended to be private to &lt;code&gt;Escape2&lt;/code&gt; class, has escaped its intended scope due to the accessibility of the &lt;code&gt;getActiveUserIds()&lt;/code&gt; method. This situation poses a risk of breaking the invariant that an ID should only appear once in the &lt;code&gt;activeUserIds&lt;/code&gt; list.&lt;/p&gt;

&lt;p&gt;➥ &lt;strong&gt;Passing object as parameter to alien methods&lt;/strong&gt; ~ When we pass objects as parameter to an alien method, there is a possibility of that method using the object in a way that breaks the bounded invariants. Even worse, that method may store a reference to the object and modify it later from another thread. It therefore causes objects to escape!&lt;/p&gt;

&lt;p&gt;➥ &lt;strong&gt;Publishing inner class instance&lt;/strong&gt; ~ When an object of inner class is published, an implicit reference to the outer class’ object is published. This leads to escaping!&lt;/p&gt;

&lt;h2&gt;
  
  
  Confining Objects to Thread
&lt;/h2&gt;

&lt;p&gt;When objects are used only from a single thread, there is no requirement of extra management to make your code thread safe.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Utilising an object from a single thread is an implementation decision, and although the language provides mechanisms to enforce these constraints, it ultimately falls on the programmer to guarantee that such objects remain within the intended scope of a single thread.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Use of &lt;strong&gt;local variables&lt;/strong&gt; helps us confine objects to thread. This is because each thread maintains its own set of local variables on stack. This stack is inaccessible to other threads. However, we need to take special care of not publishing reference to such local variables.&lt;/p&gt;

&lt;p&gt;Another way of confining object to a thread is to use Java’s ThreadLocal class. Objects of this class hold separate values for separate executing threads.&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="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ThreadLocalTesting&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;ThreadLocal&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;threadLocal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ThreadLocal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withInitial&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&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;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;InterruptedException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Setting threadLocal to 5 from manin thread&lt;/span&gt;
        &lt;span class="n"&gt;threadLocal&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="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Creating a new thread&lt;/span&gt;
        &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Thread&lt;/span&gt; &lt;span class="n"&gt;thread&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;Thread&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"::: Thread =&amp;gt; "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;threadLocal&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="c1"&gt;// Setting threadLocal to 10 from new thread&lt;/span&gt;
            &lt;span class="n"&gt;threadLocal&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="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"::: Thread =&amp;gt; "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;threadLocal&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="n"&gt;thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"::: Main =&amp;gt; "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;threadLocal&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;thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&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;h2&gt;
  
  
  Make your objects Immutable
&lt;/h2&gt;

&lt;p&gt;Need for thread-safety arise when mutable states are shared across threads. We just saw how can we ensure objects are confined to a single thread. Let us consider the other end, objects with &lt;strong&gt;immutable states&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Since an immutable object can always be in a single state, it is inherently thread-safe! But how do you define immutability? An immutable object —&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cannot have its state modified after construction&lt;/li&gt;
&lt;li&gt;All its fields are final&lt;/li&gt;
&lt;li&gt;Properly constructed i.e., &lt;strong&gt;&lt;em&gt;this&lt;/em&gt;&lt;/strong&gt; reference does not escape during construction&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Immutable objects can be safely accessed across threads even when synchronisation is not used!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Note ~ It is considered a best practice to mark all fields as private unless they require greater visibility. Similarly, it is advisable to make all fields final unless there is a specific requirement for them to be mutable.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Safely Publishing Objects
&lt;/h2&gt;

&lt;p&gt;Sometimes, it’s necessary to share objects across threads, but it’s essential to ensure that this is done in a thread-safe manner. When dealing with immutable shared objects, no extra synchronization is required. However, when working with mutable objects, it’s crucial to ensure they're safe publication to avoid concurrency issues.&lt;/p&gt;

&lt;p&gt;To safely publish an object, we can,&lt;/p&gt;

&lt;p&gt;➯ initialise object reference from static initialiser&lt;br&gt;
➯ store object reference in a volatile field or AtomicReference&lt;br&gt;
➯ mark the object with final keyword&lt;br&gt;
➯ use proper locking when accessing the object&lt;/p&gt;

&lt;p&gt;After an object has been safely published and is no longer subject to modification, no additional measures are necessary to guarantee its correctness in a multi-threaded environment. However, if the object can be modified after publication, it’s crucial to either implement proper locking mechanisms or ensure that the object is inherently thread-safe to maintain thread safety.&lt;/p&gt;




&lt;p&gt;A proper understanding of &lt;em&gt;when&lt;/em&gt; and &lt;em&gt;how&lt;/em&gt; to share objects in a multi-threaded environment is really necessary to ensure thread-safety of your application. Avoiding sharing objects or making them immutable wherever possible is a great rule-of-thumb to ensure there are less things to fail!&lt;/p&gt;

&lt;p&gt;With this we reach the end of this blog. If you enjoy reading this blog, consider exploring these other blogs ~&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://medium.com/p/e13119e8d685" rel="noopener noreferrer"&gt;Visibility across Threads&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/p/2913b1879d0c" rel="noopener noreferrer"&gt;Thread Safety from an Object Oriented Perspective&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/@the_infinity/javas-synchronized-collections-07712ae3b2cb" rel="noopener noreferrer"&gt;Java’s Synchronized Collections&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/@the_infinity/a-nice-race-condition-58a560e34cec" rel="noopener noreferrer"&gt;A Nice Race Condition&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/@the_infinity/producer-consumer-pattern-using-javas-blocking-queues-06d147d3c38a" rel="noopener noreferrer"&gt;Producer-Consumer pattern using Java’s Blocking Queue&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>java</category>
      <category>tutorial</category>
      <category>beginners</category>
      <category>programming</category>
    </item>
    <item>
      <title>Java’s Synchronized Collections</title>
      <dc:creator>Rishabh Agarwal</dc:creator>
      <pubDate>Sat, 30 Mar 2024 06:16:14 +0000</pubDate>
      <link>https://dev.to/the_infinity/javas-synchronized-collections-3od2</link>
      <guid>https://dev.to/the_infinity/javas-synchronized-collections-3od2</guid>
      <description>&lt;p&gt;Java’s Collection framework is one of the foundational components of Java platform. Collections in Java represent a group of objects and the framework provides several interfaces and implementations to work with these collections. With such a rich framework at disposal, developers can focus on what matters the most!&lt;/p&gt;

&lt;p&gt;With the advent of multi-threaded programming, the need for thread-safe collections grew. It is when &lt;em&gt;Synchronized Collections&lt;/em&gt; were added to Java’s Collection framework. Let us understand what makes Synchronized Collections thread-safe and what are some things we should keep in-mind while using them.&lt;/p&gt;

&lt;h3&gt;
  
  
  How does Synchronized Collections ensure thread-safety?
&lt;/h3&gt;

&lt;p&gt;Synchronized collections achieves thread-safety by enforcing synchronization on each of its publicly available method. In addition to that, it ensures that its internal state is never published. Thus, the only way to modify a collection is via its public synchronized methods!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Think of synchronized collections as plain unsynchronised collections plus state encapsulation and synchronized public methods.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Since every public method of a synchronized collection is guarded by the same (intrinsic) lock, no two threads can modify/read the collection at once. This ensures that the collection always maintain its variants and hence become thread-safe.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to create Synchronized Collections?
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;Collections&lt;/code&gt; class expose several static methods for creating synchronized collections. These static method are named in the following format — &lt;code&gt;synchronizedXxx&lt;/code&gt;. Here is a list of these methods:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;synchronizedCollection&lt;/strong&gt;(Collection c)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;synchronizedList&lt;/strong&gt;(List list)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;synchronizedMap&lt;/strong&gt;(Map m)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;synchronizedNavigableMap&lt;/strong&gt;(NavigableMap m)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;synchronizedNavigableSet&lt;/strong&gt;(NavigableSet s)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;synchronizedSet&lt;/strong&gt;(Set s)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;synchronizedSortedMap&lt;/strong&gt;(SortedMap m)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;synchronizedSortedSet&lt;/strong&gt;(SortedSet s)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is how you will create a synchronized list using the Collections 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="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;synchronizedIntegerList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Collections&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;synchronizedList&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;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Pitfall of Compound Actions on Synchronized Collections
&lt;/h3&gt;

&lt;p&gt;While methods exposed from synchronized collections are thread-safe, compound actions on client-side still require proper locking. Consider the following method —&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="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;putIfAbsent&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;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;synchronizedList&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;elem&lt;/span&gt;&lt;span class="o"&gt;)&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;synchronizedList&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;contains&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;synchronizedList&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;elem&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 innocent looking method is actually &lt;strong&gt;thread-unsafe&lt;/strong&gt;! Even with thread-safe &lt;code&gt;contains&lt;/code&gt; and &lt;code&gt;add&lt;/code&gt; methods, the &lt;code&gt;putIfAbsent&lt;/code&gt; method does not achieve what it intended to. Between the ‘&lt;em&gt;check&lt;/em&gt;’ and ‘&lt;em&gt;act&lt;/em&gt;’ steps of our method, another thread can add the &lt;code&gt;elem&lt;/code&gt; to the list. Guarding such compound actions is the responsibility of the client.&lt;/p&gt;

&lt;p&gt;Synchronized collections allow client-side locking to ensure that such compound actions are atomic with respect to other operations. Each public method of the synchronized collection is guarded by its own intrinsic lock. It is thus possible for client to create atomic operation by acquiring the same lock.&lt;/p&gt;

&lt;p&gt;Here is how we will fix putIfAbsent using client-side locking.&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="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;putIfAbsent&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;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;synchronizedList&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;elem&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;synchronized&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;synchronizedList&lt;/span&gt;&lt;span class="o"&gt;)&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;synchronizedList&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;contains&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;synchronizedList&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;elem&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="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Pitfalls of Iterating on Synchronized Collections
&lt;/h3&gt;

&lt;p&gt;Some extra care is needed to be taken when iterating over a synchronized collection. When iterating over a synchronized collection using iterators, any concurrent modifications to the collection will cause the iterator to &lt;em&gt;fail-fast&lt;/em&gt;. On detecting any concurrent modification, the iterator will throw a ConcurrentModificationException.&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;final&lt;/span&gt; &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;syncStringSet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Collections&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;synchronizedSet&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;HashSet&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;());&lt;/span&gt;

&lt;span class="c1"&gt;// Might throw ConcurrentModificationException&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nl"&gt;s:&lt;/span&gt; &lt;span class="n"&gt;syncStringSet&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;doSomething&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&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;To avoid getting a &lt;code&gt;ConcurrentModificationException&lt;/code&gt;, we can hold a lock on the synchronized collection for the entire duration of iteration. Clearly this is not the most performant approach since the iteration can take a long time and it will block other executing threads from access to the collection!&lt;/p&gt;




&lt;p&gt;Synchronized classes provides an easy mechanism to make your collection classes thread-safe. A thorough understanding of these would help you avoid common pitfalls associated with it.&lt;/p&gt;

&lt;p&gt;With this we reach the end of this blog. I hope you enjoyed reading this piece.&lt;/p&gt;

&lt;p&gt;If you like reading such articles, here are some other interesting reads from this series —&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&lt;a href="https://medium.com/@the_infinity/object-sharing-in-multi-threaded-environments-d03d2543e210" rel="noopener noreferrer"&gt;Object Sharing in Multi-Threaded environment&lt;/a&gt;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;a href="https://medium.com/@the_infinity/visibility-across-threads-e13119e8d685" rel="noopener noreferrer"&gt;Visibility Across Threads&lt;/a&gt;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;a href="https://medium.com/@the_infinity/thread-safety-from-an-object-oriented-perspective-2913b1879d0c" rel="noopener noreferrer"&gt;Thread Safety from an Object Oriented Perspective&lt;/a&gt;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;a href="https://medium.com/@the_infinity/a-nice-race-condition-58a560e34cec" rel="noopener noreferrer"&gt;A Nice Race Condition&lt;/a&gt;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;a href="https://medium.com/@the_infinity/producer-consumer-pattern-using-javas-blocking-queues-06d147d3c38a" rel="noopener noreferrer"&gt;Producer-Consumer pattern using Java’s Blocking Queue&lt;/a&gt;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>java</category>
      <category>tutorial</category>
      <category>beginners</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
