<?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>Forem: Wynn TEO</title>
    <description>The latest articles on Forem by Wynn TEO (@wynnt3o).</description>
    <link>https://forem.com/wynnt3o</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%2F622800%2F5d16a564-9d2d-4810-9275-9f5d8437b356.jpeg</url>
      <title>Forem: Wynn TEO</title>
      <link>https://forem.com/wynnt3o</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/wynnt3o"/>
    <language>en</language>
    <item>
      <title>Full-Stack E-Commerce App - Part 1: Project setup</title>
      <dc:creator>Wynn TEO</dc:creator>
      <pubDate>Fri, 03 Apr 2026 06:33:53 +0000</pubDate>
      <link>https://forem.com/wynnt3o/full-stack-e-commerce-app-part-1-project-setup-4pko</link>
      <guid>https://forem.com/wynnt3o/full-stack-e-commerce-app-part-1-project-setup-4pko</guid>
      <description>&lt;p&gt;Hey! Welcome to Part 1 of this series, where we build a complete, production-ready e-commerce app called ShopFlow — from an empty folder all the way to a live site on AWS.&lt;/p&gt;

&lt;p&gt;By the end of this series, ShopFlow will have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  User authentication with JWT tokens&lt;/li&gt;
&lt;li&gt;  A product catalogue with search powered by Elasticsearch&lt;/li&gt;
&lt;li&gt;  A shopping cart (stored in Redis) and a full order system&lt;/li&gt;
&lt;li&gt;  AI features — smart search, a chatbot, and product descriptions generated by AI&lt;/li&gt;
&lt;li&gt;  Real payments via Stripe and PayPal&lt;/li&gt;
&lt;li&gt;  Event-driven order processing with Apache Kafka&lt;/li&gt;
&lt;li&gt;  Deployed on AWS with Kubernetes and a CI/CD pipeline&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That sounds like a lot — and it is! But we are going to build it &lt;strong&gt;one piece at a time&lt;/strong&gt;. Each part of this series focuses on one thing, explains why we are doing it, and by the end, you have working code.&lt;/p&gt;

&lt;p&gt;In this first part, we just focus on getting everything set up. By the end of this post, your backend and frontend will be running, talking to each other, and you'll understand what every piece does.&lt;/p&gt;

&lt;p&gt;This series is aimed at developers who know &lt;strong&gt;some coding&lt;/strong&gt; but maybe haven't built a full-stack app before, or want to see how all these technologies fit together in a real project. If you've followed any beginner tutorials but felt lost when it came to "real-world" apps, this series is for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1 — Install the tools
&lt;/h2&gt;

&lt;p&gt;Let's get your machine ready. We need four things: Java 21, Node.js 20, Docker Desktop, and an IDE.&lt;/p&gt;

&lt;h3&gt;
  
  
  Install Java 25
&lt;/h3&gt;

&lt;p&gt;The best way to install Java is through SDKMAN — a tool that lets you easily switch between Java versions.&lt;/p&gt;

&lt;h4&gt;
  
  
  On macOS or Linux
&lt;/h4&gt;

&lt;p&gt;Open your terminal and run this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Install SDKMAN
curl -s "https://get.sdkman.io" | bash

# Restart your terminal, then install Java 25
sdk install java 25.0.2-tem

# Check it worked
java -version
# You should see: openjdk version "25.0.2"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h4&gt;
  
  
  On Windows
&lt;/h4&gt;

&lt;p&gt;Go to &lt;a href="https://adoptium.net" rel="noopener noreferrer"&gt;https://adoptium.net&lt;/a&gt; and download the "Temurin 25 LTS" Windows installer. Run it, and make sure you tick the option to set JAVA_HOME during setup.&lt;/p&gt;

&lt;p&gt;After installing, open Command Prompt and check:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;java -version
# openjdk version "25.0.2" ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Install Node.js 22
&lt;/h3&gt;

&lt;p&gt;We use Node.js to run our React frontend. The cleanest way to install it is through NVM (Node Version Manager) — it lets you easily switch between Node versions on the same machine.&lt;/p&gt;
&lt;h4&gt;
  
  
  On macOS or Linux
&lt;/h4&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Install NVM
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash

# Restart your terminal, then:
nvm install 22
nvm use 22

# Check
node -v   # v22.x.x
npm -v    # 10.x.x
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h4&gt;
  
  
  On Windows
&lt;/h4&gt;

&lt;p&gt;Download nvm-windows from &lt;a href="https://github.com/coreybutler/nvm-windows/releases" rel="noopener noreferrer"&gt;https://github.com/coreybutler/nvm-windows/releases&lt;/a&gt; (get nvm-setup.exe). Install it, then open a new terminal:&lt;/p&gt;
&lt;h3&gt;
  
  
  Install Docker Desktop
&lt;/h3&gt;

&lt;p&gt;Go to &lt;a href="https://docker.com/products/docker-desktop" rel="noopener noreferrer"&gt;https://docker.com/products/docker-desktop&lt;/a&gt; and download Docker Desktop for your OS. Install it and start it up. You'll know it's running when you see the whale icon in your menu bar or taskbar.&lt;/p&gt;

&lt;p&gt;Check it's working:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker -v
# Docker version 29.x.x

docker compose version
# Docker Compose version v2.x.x
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Install your IDE
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;For the backend (Java / Spring Boot):&lt;/strong&gt; Download IntelliJ IDEA Community Edition for free from &lt;a href="https://jetbrains.com/idea" rel="noopener noreferrer"&gt;https://jetbrains.com/idea&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For the frontend (React):&lt;/strong&gt; Download VS Code for free from &lt;a href="https://code.visualstudio.com" rel="noopener noreferrer"&gt;https://code.visualstudio.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once VS Code is open, install these extensions — they make working with React much nicer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  ES7+ React/Redux/React-Native snippets&lt;/li&gt;
&lt;li&gt;  Prettier — Code formatter&lt;/li&gt;
&lt;li&gt;  Tailwind CSS IntelliSense&lt;/li&gt;
&lt;li&gt;  Thunder Client (a Postman alternative built into VS Code — great for testing APIs)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Step 2 — Run MySQL in Docker
&lt;/h2&gt;

&lt;p&gt;Create a new folder anywhere on your computer — call it &lt;code&gt;shopflow&lt;/code&gt;. Inside it, create a file called &lt;code&gt;docker-compose.yml&lt;/code&gt; and paste this in:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;version: "3.8"

services:
  mysql:
    image: mysql:8.0
    container_name: shopflow-mysql
    environment:
      MYSQL_ROOT_PASSWORD: shopflow123
      MYSQL_DATABASE: shopflow_db
      MYSQL_USER: shopflow_user
      MYSQL_PASSWORD: shopflow123
    ports:
      - "3306:3306"
    volumes:
      - mysql_data:/var/lib/mysql
    restart: unless-stopped

volumes:
  mysql_data:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now open a terminal in that folder and run:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker compose up -d

# -d means "detached" — runs in the background
# Check it is running:
docker ps

# You should see shopflow-mysql in the list with status "Up"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Let's quickly connect to MySQL to make sure it's working:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker exec -it shopflow-mysql mysql -u shopflow_user -p
# Type the password: shopflow123

# Once connected:
SHOW DATABASES;
# You should see shopflow_db in the list

EXIT;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Step 3 — Create the Spring Boot backend
&lt;/h2&gt;

&lt;p&gt;Now let's create the backend. We'll use &lt;strong&gt;Spring Initializr&lt;/strong&gt; — a free tool at start.spring.io that generates a ready-to-run Spring Boot project for you.&lt;/p&gt;
&lt;h3&gt;
  
  
  Generate the project
&lt;/h3&gt;

&lt;p&gt;Go to &lt;a href="https://start.spring.io" rel="noopener noreferrer"&gt;https://start.spring.io&lt;/a&gt; and fill in the settings like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Project:&lt;/strong&gt; Maven&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Language:&lt;/strong&gt; Java&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Spring Boot version:&lt;/strong&gt; 3.3.x (pick the latest stable, not a SNAPSHOT)&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Group:&lt;/strong&gt; com.shopflow&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Artifact:&lt;/strong&gt; backend&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Java version:&lt;/strong&gt; 25&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then click "ADD DEPENDENCIES" and add these:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Spring Web&lt;/li&gt;
&lt;li&gt;  Spring Data JPA&lt;/li&gt;
&lt;li&gt;  MySQL Driver&lt;/li&gt;
&lt;li&gt;  Spring Security&lt;/li&gt;
&lt;li&gt;  Spring Boot DevTools&lt;/li&gt;
&lt;li&gt;  Lombok&lt;/li&gt;
&lt;li&gt;  Validation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Click &lt;strong&gt;GENERATE&lt;/strong&gt; — it downloads a zip file. Extract it into your &lt;code&gt;shopflow/backend&lt;/code&gt; folder.&lt;/p&gt;
&lt;h3&gt;
  
  
  Open it in IntelliJ
&lt;/h3&gt;

&lt;p&gt;Open IntelliJ IDEA. Go to File → Open and navigate to your &lt;code&gt;shopflow/backend&lt;/code&gt; folder. IntelliJ will detect it's a Maven project and start downloading dependencies automatically. This takes 1–2 minutes the first time.&lt;/p&gt;
&lt;h3&gt;
  
  
  Connect it to the database
&lt;/h3&gt;

&lt;p&gt;Open the file &lt;code&gt;src/main/resources/application.properties&lt;/code&gt; and replace everything in it with:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# App name
spring.application.name=shopflow-backend

# Database connection
spring.datasource.url=jdbc:mysql://localhost:3306/shopflow_db
spring.datasource.username=shopflow_user
spring.datasource.password=shopflow123
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

# JPA settings
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect

# Server port
server.port=8080
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Run the app
&lt;/h3&gt;

&lt;p&gt;Find the file  BackendApplication.java  inside &lt;code&gt;src/main/java/com/shopflow/backend/&lt;/code&gt; and click the green ▶ Run button next to the class name.&lt;/p&gt;

&lt;p&gt;Watch the console at the bottom. After a few seconds, you should see:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Tomcat started on port(s): 8080 (http)
Started BackendApplication in 2.847 seconds
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Open your browser and go to &lt;strong&gt;&lt;a href="http://localhost:8080" rel="noopener noreferrer"&gt;http://localhost:8080&lt;/a&gt;&lt;/strong&gt;. You'll see a login page — that's Spring Security's default. It means the app is running. We'll replace this with our own auth in Part 2.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4 — Create the React frontend
&lt;/h2&gt;

&lt;p&gt;Now let's set up the frontend. We'll use &lt;strong&gt;Vite&lt;/strong&gt; (pronounced "veet") instead of the old Create React App. Vite starts up in under a second and is way faster during development.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create the project
&lt;/h3&gt;

&lt;p&gt;Open a new terminal, go to your &lt;code&gt;shopflow&lt;/code&gt; folder, and run:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm create vite@latest frontend -- --template react
cd frontend
npm install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now let's add the libraries we'll use throughout this series:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Tailwind CSS — for styling without writing tons of CSS
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p

# React Router — for navigation between pages
npm install react-router-dom

# Axios — for making API calls to our backend
npm install axios

# React Query — for managing server data in React
npm install @tanstack/react-query
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Configure Tailwind
&lt;/h3&gt;

&lt;p&gt;Open &lt;code&gt;tailwind.config.js&lt;/code&gt; and update the content section:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export default {
  content: [
    "./index.html",
    "./src/**/*.{js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Then open &lt;code&gt;src/index.css&lt;/code&gt; and replace everything with just these three lines:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@tailwind base;
@tailwind components;
@tailwind utilities;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Start the React dev server
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm run dev

# You will see:
#   VITE v5.x.x  ready in 300ms
#   ➜  Local:   http://localhost:5173/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Open &lt;strong&gt;&lt;a href="http://localhost:5173" rel="noopener noreferrer"&gt;http://localhost:5173&lt;/a&gt;&lt;/strong&gt; in your browser. You should see the Vite + React welcome page. That means your frontend is running.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5 — Make the frontend talk to the backend
&lt;/h2&gt;

&lt;p&gt;This is the moment things get real. We're going to make a simple API endpoint in Spring Boot and call it from React.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create a health check endpoint
&lt;/h3&gt;

&lt;p&gt;In IntelliJ, create a new file: &lt;code&gt;src/main/java/com/shopflow/backend/controller/HealthController.java&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.shopflow.backend.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;

@RestController
@RequestMapping("/api")
public class HealthController {

    @GetMapping("/health")
    public Map&amp;lt;String, String&amp;gt; health() {
        return Map.of(
            "status", "ok",
            "message", "ShopFlow backend is running!"
        );
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Let's break down what this does:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;   &lt;code&gt;@RestController&lt;/code&gt;  — tells Spring this class handles HTTP requests and returns data (not HTML pages)&lt;/li&gt;
&lt;li&gt;   &lt;code&gt;@RequestMapping("/api")&lt;/code&gt;  — all endpoints in this class start with &lt;code&gt;/api&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;   &lt;code&gt;@GetMapping("/health")&lt;/code&gt;  — when someone calls GET &lt;code&gt;/api/health&lt;/code&gt;, run this method&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Restart Spring Boot, then open &lt;strong&gt;&lt;a href="http://localhost:8080/api/health" rel="noopener noreferrer"&gt;http://localhost:8080/api/health&lt;/a&gt;&lt;/strong&gt; in your browser. You should see:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "status": "ok",
  "message": "ShopFlow backend is running!"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Fix CORS so React can call the backend
&lt;/h3&gt;

&lt;p&gt;Right now, if React tries to call the backend, the browser will block it with a &lt;strong&gt;CORS error&lt;/strong&gt;. CORS is a browser security rule that blocks requests from different origins. Our frontend is on port 5173, our backend is on port 8080 — different origins.&lt;/p&gt;

&lt;p&gt;Create a new file: &lt;code&gt;src/main/java/com/shopflow/backend/config/CorsConfig.java&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.shopflow.backend.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

@Configuration
public class CorsConfig {

    @Bean
    public CorsFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        config.addAllowedOrigin("http://localhost:5173");
        config.addAllowedMethod("*");
        config.addAllowedHeader("*");
        config.setAllowCredentials(true);

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/api/**", config);
        return new CorsFilter(source);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Call the API from React
&lt;/h3&gt;

&lt;p&gt;Open &lt;code&gt;src/App.jsx&lt;/code&gt; and replace everything with:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useState, useEffect } from "react"
import axios from "axios"

function App() {
  const [status, setStatus] = useState("Checking...")

  useEffect(() =&amp;gt; {
    axios.get("http://localhost:8080/api/health")
      .then(response =&amp;gt; setStatus(response.data.message))
      .catch(() =&amp;gt; setStatus("Backend is not running!"))
  }, [])

  return (
    &amp;lt;div className="min-h-screen bg-gray-50 flex items-center justify-center"&amp;gt;
      &amp;lt;div className="bg-white rounded-xl shadow-sm border border-gray-100 p-10 text-center"&amp;gt;
        &amp;lt;h1 className="text-4xl font-bold text-gray-900 mb-2"&amp;gt;ShopFlow&amp;lt;/h1&amp;gt;
        &amp;lt;p className="text-gray-400 text-sm mb-4"&amp;gt;Full-stack e-commerce app&amp;lt;/p&amp;gt;
        &amp;lt;p className="text-gray-500"&amp;gt;Backend status:&amp;lt;/p&amp;gt;
        &amp;lt;p className="text-green-600 font-semibold mt-1 text-lg"&amp;gt;{status}&amp;lt;/p&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}

export default App
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Restart Spring Boot (to pick up the CORS config), then open &lt;strong&gt;&lt;a href="http://localhost:5173" rel="noopener noreferrer"&gt;http://localhost:5173&lt;/a&gt;&lt;/strong&gt;. You should see the ShopFlow card with:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"ShopFlow backend is running!"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;That's it — your frontend and backend are talking to each other.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6 — Folder structure and Git
&lt;/h2&gt;

&lt;p&gt;Before we go any further, let's organise the project and save our work in Git.&lt;/p&gt;

&lt;h3&gt;
  
  
  Backend folder structure
&lt;/h3&gt;

&lt;p&gt;This is the structure we'll follow for the whole course. Create these empty folders inside your backend project now so they're ready:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;backend/src/main/java/com/shopflow/backend/
├── config/       ← Spring configuration (CORS, Security, etc.)
├── controller/   ← API endpoints
├── service/      ← Business logic
├── repository/   ← Database access
├── model/        ← Entity classes (map to database tables)
│   └── dto/      ← Data Transfer Objects (request/response shapes)
├── security/     ← Auth and JWT
├── exception/    ← Error handling
└── util/         ← Helper utilities
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This follows a &lt;strong&gt;layered architecture&lt;/strong&gt; pattern: the request comes in through the Controller, the Controller calls the Service, the Service calls the Repository, the Repository talks to the database. Each layer only talks to the one below it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Frontend folder structure
&lt;/h3&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;frontend/src/
├── api/          ← API call functions (axios)
├── components/   ← Reusable UI pieces (buttons, cards, etc.)
├── pages/        ← Full page components
├── context/      ← React Context (auth state, cart state)
├── hooks/        ← Custom React hooks
└── utils/        ← Helper functions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Set up Git
&lt;/h3&gt;

&lt;p&gt;In your &lt;code&gt;shopflow&lt;/code&gt; root folder (the one that contains both backend and frontend), run:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git init
git add .
git commit -m "feat: initial project setup"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Create a &lt;code&gt;.gitignore&lt;/code&gt; file in the root:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="c"&gt;# Java / Maven
&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;/
*.&lt;span class="n"&gt;class&lt;/span&gt;
*.&lt;span class="n"&gt;jar&lt;/span&gt;

&lt;span class="c"&gt;# IntelliJ
&lt;/span&gt;.&lt;span class="n"&gt;idea&lt;/span&gt;/
*.&lt;span class="n"&gt;iml&lt;/span&gt;

&lt;span class="c"&gt;# Node
&lt;/span&gt;&lt;span class="n"&gt;node_modules&lt;/span&gt;/
&lt;span class="n"&gt;dist&lt;/span&gt;/

&lt;span class="c"&gt;# Environment files — NEVER commit these
&lt;/span&gt;.&lt;span class="n"&gt;env&lt;/span&gt;
.&lt;span class="n"&gt;env&lt;/span&gt;.&lt;span class="n"&gt;local&lt;/span&gt;

&lt;span class="c"&gt;# OS
&lt;/span&gt;.&lt;span class="n"&gt;DS_Store&lt;/span&gt;
&lt;span class="n"&gt;Thumbs&lt;/span&gt;.&lt;span class="n"&gt;db&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What's next?
&lt;/h2&gt;

&lt;p&gt;In Part 2 of this series, we build the authentication system. That means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Designing the user and roles database tables&lt;/li&gt;
&lt;li&gt;  Building register and login endpoints&lt;/li&gt;
&lt;li&gt;  Generating JWT tokens so users stay logged in&lt;/li&gt;
&lt;li&gt;  Protecting routes so only logged-in users can access them&lt;/li&gt;
&lt;li&gt;  Building the React login page and keeping auth state globally&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Authentication is the foundation of the whole app — every other feature depends on it. &lt;strong&gt;See you in Part 2.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>softwaredevelopment</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Top Asynchronous JavaScript Interview Questions (2025)</title>
      <dc:creator>Wynn TEO</dc:creator>
      <pubDate>Thu, 10 Jul 2025 02:12:52 +0000</pubDate>
      <link>https://forem.com/wynnt3o/top-asynchronous-javascript-interview-questions-2025-16ak</link>
      <guid>https://forem.com/wynnt3o/top-asynchronous-javascript-interview-questions-2025-16ak</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Getting ready for a JavaScript interview? Asynchronous JavaScript interview questions are everywhere in technical interviews. Don’t worry – this guide covers everything you need to know about asynchronous JavaScript, from basic concepts to tricky interview scenarios.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Makes JavaScript Asynchronous?
&lt;/h2&gt;

&lt;p&gt;Here’s something that confuses many developers: JavaScript is single-threaded, but it can handle multiple tasks at once. How does this work?&lt;/p&gt;

&lt;p&gt;The secret lies in how JavaScript engines work with browsers. While JavaScript itself runs on one thread, browsers provide extra tools that make async operations possible.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Call Stack Explained
&lt;/h2&gt;

&lt;p&gt;Think of the call stack as a stack of plates. When we call a function, it goes on top of the stack. When the function finishes, it gets removed from the top.&lt;/p&gt;

&lt;p&gt;Basically call stack is where JavaScript keeps track of function calls. Functions are pushed onto the stack when called and popped off when they return. It’s synchronous — one task at a time.&lt;/p&gt;

&lt;p&gt;Let’s see this in action:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function add(a, b) {
    console.log("add function called");
    return a + b;
}

function calculate(a, b) {
    console.log("calculate function called");
    return add(a, b);
}

function printTotal(a, b) {
    let total = calculate(a, b);
    console.log(total);
}

printTotal(4, 5);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When this code runs:&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%2Fucclfif5qwr10ovdss4s.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%2Fucclfif5qwr10ovdss4s.png" alt="https://cloudfullstack.dev/asynchronous-javascript-interview-questions/" width="720" height="263"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;printTotal(4, 5) goes on the call stack&lt;/li&gt;
&lt;li&gt;Inside printTotal, calculate(4, 5) goes on top&lt;/li&gt;
&lt;li&gt;Inside calculate, console goes on top, followed by add(4, 5)&lt;/li&gt;
&lt;li&gt;console finishes and gets removed&lt;/li&gt;
&lt;li&gt;add finishes and gets removed&lt;/li&gt;
&lt;li&gt;calculate finishes and gets removed&lt;/li&gt;
&lt;li&gt;console inside printTotal goes on top&lt;/li&gt;
&lt;li&gt;printTotal finishes and gets removed&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This happens very fast, but it’s still one thing at a time. This step-by-step process ensures that functions are executed in the correct order, maintaining an organised and predictable flow of execution.&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%2Fa2xwz4ljkkul45yapnps.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%2Fa2xwz4ljkkul45yapnps.png" alt="https://cloudfullstack.dev/asynchronous-javascript-interview-questions/" width="800" height="753"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem with Synchronous Code
&lt;/h2&gt;

&lt;p&gt;Let’s understand why asynchronous JavaScript exists in the first place.&lt;/p&gt;

&lt;p&gt;Imagine we’re building a web app that needs to fetch user data from an API. If JavaScript worked only synchronously, our code might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;console.log("Starting app...");
let userData = fetchUserData(); // This takes 3 seconds
console.log("User data:", userData);
console.log("App ready!");
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The problem? The entire webpage would freeze for 3 seconds while waiting for the API response. Users couldn’t click buttons, scroll, or do anything. This creates a terrible user experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Asynchronous Callbacks – The Solution
&lt;/h2&gt;

&lt;p&gt;Asynchronous callbacks allow us to handle time-consuming tasks without freezing the browser. Instead of waiting for an operation to complete, we tell JavaScript: “Start this task, and when it’s done, call this function.”&lt;/p&gt;

&lt;p&gt;Here’s how the same API call would work with async callbacks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;console.log("Starting app...");

fetchUserData((userData) =&amp;gt; {
    console.log("User data:", userData);
});

console.log("App ready!");
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the output would be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Starting app...
App ready!
User data: [object Object]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice how “App ready!” appears before the user data? That’s because the app doesn’t wait for the API call to finish.&lt;/p&gt;

&lt;h2&gt;
  
  
  1: How Does setTimeout Work?
&lt;/h2&gt;

&lt;p&gt;This is probably the most asked question about asynchronous JavaScript. Let’s break it down:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;console.log("Number 1");

setTimeout(() =&amp;gt; {
    console.log("Number 2");
}, 2000);

console.log("Number 3");

Output:
Number 1
Number 3
Number 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why doesn’t “Number 2” come after “Number 1”? Here’s what happens:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;console.log("Number 1") runs immediately&lt;/li&gt;
&lt;li&gt;setTimeout starts a timer but doesn’t block the code&lt;/li&gt;
&lt;li&gt;console.log("Number 3") runs immediately&lt;/li&gt;
&lt;li&gt;After 2 seconds, “Number 2” finally prints&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The key insight: setTimeout doesn’t pause your code. It schedules something to happen later.&lt;/p&gt;

&lt;h2&gt;
  
  
  2: What Happens with setTimeout(fn, 0)?
&lt;/h2&gt;

&lt;p&gt;This question trips up many developers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;console.log("Start");

setTimeout(() =&amp;gt; {
    console.log("Timeout");
}, 0);

console.log("End");
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even with 0 milliseconds, you get:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Start
End
Timeout
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why? Because setTimeout always puts callbacks in the queue, even with 0 delay. The callback must wait for the call stack to be empty.&lt;/p&gt;

&lt;h2&gt;
  
  
  3: Multiple setTimeout Calls
&lt;/h2&gt;

&lt;p&gt;If you have multiple setTimeout(fn, 0) calls in a row, how will they be executed in relation to other synchronous code?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;console.log("Start");

setTimeout(() =&amp;gt; console.log("Timer 1"), 0);
setTimeout(() =&amp;gt; console.log("Timer 2"), 0);
setTimeout(() =&amp;gt; console.log("Timer 3"), 0);

console.log("End");
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Start
End
Timer 1
Timer 2
Timer 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All timers go to the same callback queue and execute in order, but only after all synchronous code finishes.&lt;/p&gt;

&lt;h2&gt;
  
  
  4: What About Nested Promises?
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;console.log("Start");

Promise.resolve()
    .then(() =&amp;gt; {
        console.log("Promise 1");
        return Promise.resolve();
    })
    .then(() =&amp;gt; {
        console.log("Promise 2");
    });

setTimeout(() =&amp;gt; {
    console.log("Timeout");
}, 0);

console.log("End");
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Start
End
Promise 1
Promise 2
Timeout
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each .then() creates a new microtask, but they all run before any macrotasks.&lt;/p&gt;

&lt;h2&gt;
  
  
  5: Error Handling in Async Code
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;console.log("Start");

setTimeout(() =&amp;gt; {
    console.log("Timeout");
}, 0);

Promise.reject("Error!")
    .catch(() =&amp;gt; {
        console.log("Caught error");
    });

console.log("End");
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Error handling with .catch() also uses the microtask queue.&lt;/p&gt;

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

&lt;p&gt;Asynchronous JavaScript might seem complex, but it follows predictable rules. The event loop, queues, and Web APIs work together to keep your applications responsive.&lt;/p&gt;

&lt;p&gt;Remember the key principle: JavaScript runs one thing at a time, but browsers provide tools to handle multiple operations without blocking your code.&lt;/p&gt;

&lt;p&gt;For a more detailed explanation, you can visit the following &lt;a href="https://cloudfullstack.dev/asynchronous-javascript-interview-questions/" rel="noopener noreferrer"&gt;link&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>javascript</category>
      <category>interview</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Essential Java Producer-Consumer Interview Questions</title>
      <dc:creator>Wynn TEO</dc:creator>
      <pubDate>Wed, 09 Jul 2025 09:23:09 +0000</pubDate>
      <link>https://forem.com/wynnt3o/essential-java-producer-consumer-interview-questions-5ccc</link>
      <guid>https://forem.com/wynnt3o/essential-java-producer-consumer-interview-questions-5ccc</guid>
      <description>&lt;p&gt;In concurrent programming, the Producer-Consumer problem is a classic synchronisation scenario where two entities share a common resource, typically a buffer or queue. The Producer creates data and adds it to the queue, while the Consumer retrieves and processes that data.&lt;/p&gt;

&lt;p&gt;In this guide, we’ll:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Implement a thread-safe Producer-Consumer solution in Java.&lt;/li&gt;
&lt;li&gt;Fix common pitfalls (race conditions, deadlocks).&lt;/li&gt;
&lt;li&gt;Answer the top Java Producer Consumer interview questions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Problem Overview
&lt;/h2&gt;

&lt;p&gt;In our scenario, the Producer may try to add an item to a full buffer, while the Consumer might attempt to remove an item from an empty buffer. This can lead to synchronisation issues that need to be handled effectively.&lt;/p&gt;

&lt;h2&gt;
  
  
  Initial Implementation of Shared Buffer (Non-Thread-Safe)
&lt;/h2&gt;

&lt;p&gt;We’ll start by implementing a simple shared buffer using a Queue.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class SharedBuffer {
    private final Queue&amp;lt;Integer&amp;gt; queue = new LinkedList&amp;lt;&amp;gt;();
    private final int capacity;

    public SharedBuffer(int capacity) {
        this.capacity = capacity;
    }

    public void produce(int item) {
        queue.add(item); //Problem: No capacity check
        System.out.println("Produced: " + item);
    }

    public Integer consume() {
        if (queue.isEmpty()) {
            System.out.println("Buffer is empty! Consumer cannot consume.");
            return null;
        } else {
            Integer item = queue.poll();
            System.out.println("Consumed: " + item);
            return item;
        }
    }

    public int size() {
        return queue.size();
    }

    public int getCapacity() {
        return capacity;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we’ll create a Producer class that implements the Runnable interface.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Producer implements Runnable {
    private final SharedBuffer sharedBuffer;

    public Producer(SharedBuffer sharedBuffer) {
        this.sharedBuffer = sharedBuffer;
    }

    @Override
    public void run() {
        for (int i = 0; i &amp;lt; 15; i++) {
            sharedBuffer.produce(i);
            try {
                Thread.sleep(100); // Simulate production time
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            if (sharedBuffer.size() &amp;gt; sharedBuffer.getCapacity()) {
                System.out.println("ERROR: Buffer exceeded capacity! Current size: " + sharedBuffer.size());
            }
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we’ll implement the Consumer class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Consumer implements Runnable {
    private final SharedBuffer sharedBuffer;

    public Consumer(SharedBuffer sharedBuffer) {
        this.sharedBuffer = sharedBuffer;
    }

    @Override
    public void run() {
        for (int i = 0; i &amp;lt; 15; i++) {
            sharedBuffer.consume();
            try {
                Thread.sleep(150); // Simulate consumption time
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, we will create the main method to run our simulation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class ProducerConsumerSimulation {
    public static void main(String[] args) {
        SharedBuffer sharedBuffer = new SharedBuffer(5); // Buffer size of 5
        Thread producerThread = new Thread(new Producer(sharedBuffer));
        Thread consumerThread = new Thread(new Consumer(sharedBuffer));

        producerThread.start();
        consumerThread.start();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the ProducerConsumerSimulation class. You should see the Producer producing items and the Consumer consuming them. Watch for error messages indicating when the Producer exceeds the buffer capacity.&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%2F26jt9ae0wtut45c1jjy1.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%2F26jt9ae0wtut45c1jjy1.png" alt="https://cloudfullstack.dev/top-java-producer-consumer-interview-questions" width="800" height="416"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If we add in one more Consumer thread, we may encounter the same item being consumed twice:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
Consumed: 2
Consumed: 2
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without synchronisation, both the Producer and Consumer can perform actions that lead to inconsistencies in the shared buffer’s state.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fixed Implementation (Thread-Safe)
&lt;/h2&gt;

&lt;p&gt;To address these issues, we will implement synchronisation techniques using synchronized, wait(), and notify(). This will help us manage access to the shared buffer properly and ensure that the Producer and Consumer operate in harmony.&lt;/p&gt;

&lt;h3&gt;
  
  
  Revised SharedBuffer Class
&lt;/h3&gt;

&lt;p&gt;Here’s how we can implement synchronisation in the SharedBuffer class and ensure proper communication between the Producer and Consumers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class SharedBuffer {
    private final Queue&amp;lt;Integer&amp;gt; queue = new LinkedList&amp;lt;&amp;gt;();
    private final int capacity;

    public SharedBuffer(int capacity) {
        this.capacity = capacity;
    }

    // Thread-safe produce()
    public synchronized void produce(int item) throws InterruptedException {
        while (queue.size() == capacity) {
            System.out.println("Buffer is full! Producer waiting...");
            wait(); // Releases lock, waits for consumer to notify
        }
        queue.add(item);
        System.out.println("Produced: " + item);
        notifyAll(); // Wakes up all waiting consumers
    }

    public synchronized Integer consume() throws InterruptedException {
        while (queue.isEmpty()) {
            System.out.println("Buffer is empty! Consumer waiting...");
            wait(); // Releases lock, waits for producer to notify
        }
        Integer item = queue.poll();
        System.out.println(Thread.currentThread().getName() + " consumed item " +item+ ".");
        notifyAll(); // Wakes up all waiting producers
        return item;
    }

    public synchronized int size() {
        return queue.size();
    }

    public int getCapacity() {
        return capacity;
    }
}

class Producer implements Runnable {
    private final SharedBuffer sharedBuffer;

    public Producer(SharedBuffer sharedBuffer) {
        this.sharedBuffer = sharedBuffer;
    }

    @Override
    public void run() {
        for (int i = 0; i &amp;lt; 10; i++) {
            try {
                sharedBuffer.produce(i);
                Thread.sleep(100); // Simulate production time
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }
}

class Consumer implements Runnable {
    private final SharedBuffer sharedBuffer;

    public Consumer(SharedBuffer sharedBuffer) {
        this.sharedBuffer = sharedBuffer;
    }

    @Override
    public void run() {
        for (int i = 0; i &amp;lt; 10; i++) {
            try {
                sharedBuffer.consume();
                Thread.sleep(200); // Simulate consumption time
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }
}

public class Main {
    public static void main(String[] args) {
        SharedBuffer sharedBuffer = new SharedBuffer(5); // Buffer size of 5
        Thread producerThread = new Thread(new Producer(sharedBuffer));
        Thread consumerThread = new Thread(new Consumer(sharedBuffer));
        Thread consumer2Thread = new Thread(new Consumer(sharedBuffer));

        producerThread.start();
        consumerThread.start();
        consumer2Thread.start();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this implementation, you will see output that includes the names of the Consumer threads, like this:&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%2Flapl14d9j3z11ejw6dsd.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%2Flapl14d9j3z11ejw6dsd.png" alt="https://cloudfullstack.dev/top-java-producer-consumer-interview-questions/" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Interview Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Why should we check the waiting conditions on the while loop instead of the if block?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Condition Re-evaluation:&lt;/strong&gt;&lt;br&gt;
When a thread wakes up from waiting (after a notify()), it does not automatically mean the condition it was waiting for has changed. Using while ensures the thread checks the condition again.&lt;br&gt;
If we use if, there’s a risk that the thread proceeds without re-checking the condition, leading to potential errors.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Spurious Wakeups:&lt;/strong&gt;&lt;br&gt;
Threads can wake up from waiting due to reasons other than a notify(), known as “spurious wakeups.” Using while helps protect against this by forcing the thread to re-evaluate the condition. Always use a loop (while) to check the condition after waking up.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Why should we use the notifyAll() rather than the notify() method?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Waking Up All Waiting Threads:&lt;/strong&gt;&lt;br&gt;
notifyAll() wakes up all threads that are waiting on the object’s monitor, while notify() only wakes one. This is particularly important in scenarios with multiple producers and consumers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Avoiding Deadlocks:&lt;/strong&gt;&lt;br&gt;
Using notifyAll() can help prevent situations where a single notify() might not wake the right thread, potentially leading to deadlocks or threads waiting indefinitely.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fairness:&lt;/strong&gt;&lt;br&gt;
In a multi-threaded environment, using notifyAll() ensures that all waiting threads get a chance to proceed when the condition changes, promoting fairness.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Complex Conditions:&lt;/strong&gt;&lt;br&gt;
If multiple threads are waiting for different conditions (e.g., multiple consumers waiting for items and multiple producers waiting for space), notifyAll() ensures that all threads can recheck their conditions after being woken up.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Why wait() method should be called from a synchronized method or block?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Intrinsic Lock Requirement:&lt;/strong&gt;&lt;br&gt;
The wait(), notify(), and notifyAll() methods are designed to be used with the intrinsic lock (or monitor) of the object on which they are called. When a thread calls wait(), it must own the lock on that object.&lt;br&gt;
Releasing the Lock:&lt;/p&gt;

&lt;p&gt;When a thread calls wait(), it releases the lock on the object and enters the waiting state. This allows other threads to acquire the lock and make progress. If wait() were called without holding the lock, there would be no lock to release, leading to IllegalMonitorStateException exceptions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ensuring Atomicity:&lt;/strong&gt;&lt;br&gt;
The synchronized keyword ensures that the thread calling wait() holds the intrinsic lock of the object. By calling wait() within a synchronized block, you ensure that the state check and the call to wait() are performed atomically. This prevents race conditions where the state might change between the check and the wait call.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Why wait() and notify() methods are defined in java.lang.Object class instead of Thread?
&lt;/h3&gt;

&lt;p&gt;Threads need to acquire a lock (or monitor) on an object to enter a synchronized block or method. Threads do not need to know which specific thread currently holds the lock. They only care whether the lock is available. If the lock is not available (held by another thread), the thread will wait until the lock is released.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Coordination with wait() and notify():&lt;/strong&gt;&lt;br&gt;
A thread that calls wait() on an object releases the lock and waits until another thread calls notify() or notifyAll() on the same object.&lt;br&gt;
This allows threads to coordinate without knowing the details of other threads.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Intrinsic Lock Mechanism:&lt;/strong&gt;&lt;br&gt;
Every Java object has an intrinsic lock associated with it, also known as a monitor. The wait(), notify(), and notifyAll() methods are used to coordinate thread activity based on this monitor.&lt;br&gt;
By defining these methods in the Object class, Java allows any object to be used as a lock for synchronisation purposes, not just threads.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Object-Level Synchronisation:&lt;/strong&gt;&lt;br&gt;
Synchronisation in Java is based on object-level locks. When a thread enters a synchronized block, it acquires the lock of the object that is used to synchronise the block. The wait() method releases this lock and puts the thread into a waiting state. The notify() and notifyAll() methods wake up threads that are waiting on this lock.&lt;/p&gt;

&lt;p&gt;These methods need to be in the Object class so that any object can be the target of synchronisation.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. What happens if a thread throws Exception inside a synchronized block?
&lt;/h3&gt;

&lt;p&gt;When a thread enters a synchronized block or method, it acquires the lock on the synchronized object. If an exception is thrown inside the synchronized block, the thread exits the block. Exiting the block, whether normally or due to an exception, causes the lock to be released. Once the lock is released, other threads waiting for the lock can acquire it and proceed with their execution.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. What is the difference between wait() and sleep()?
&lt;/h3&gt;

&lt;p&gt;wait(): Releases the lock and allows other threads to acquire it; should be called from a synchronized context.&lt;br&gt;
sleep(): Does not release the lock and simply pauses the current thread for a specified duration.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. What is the purpose of the volatile keyword in Java?
&lt;/h3&gt;

&lt;p&gt;Definition: Indicates that a variable’s value will be modified by different threads.&lt;br&gt;
Usage: Ensures visibility of changes to variables across threads, preventing caching issues.&lt;/p&gt;

&lt;p&gt;For a more detailed explanation and full source code, you can visit the following &lt;a href="https://cloudfullstack.dev/top-java-producer-consumer-interview-questions/" rel="noopener noreferrer"&gt;link&lt;/a&gt;&lt;/p&gt;

</description>
      <category>programming</category>
      <category>java</category>
      <category>multithreading</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Spring @Transactional Rollback Handling</title>
      <dc:creator>Wynn TEO</dc:creator>
      <pubDate>Thu, 03 Aug 2023 12:43:53 +0000</pubDate>
      <link>https://forem.com/wynnt3o/spring-transactional-rollback-handling-hc8</link>
      <guid>https://forem.com/wynnt3o/spring-transactional-rollback-handling-hc8</guid>
      <description>&lt;h2&gt;
  
  
  Spring @Transactional Rollback Handling
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2A0MiR7DOGFKcFByxAwgETGg.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2A0MiR7DOGFKcFByxAwgETGg.jpeg" alt="Photo by [James Harrison](https://unsplash.com/@jstrippa?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/programming?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText)" width="640" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By default, the spring boot transaction is &lt;strong&gt;auto-commit&lt;/strong&gt;. Every single SQL statement is in its own transaction and will commit after execution. Take a look at the below example, the product is inserted into the database even though an exception has been raised.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public void createProduct() {  
    System.out.println("------ createProduct ------");
    Product prod = new Product();
    prod.setDescription("This is an example with runtime exception but no rollback.");
    prod.setPrice(10);
    prod.setTitle("First Product");
    productRepository.save(prod);
    System.out.println("First Product inserted.");

throw new RuntimeException();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fh9z2nt4ml730ingfh8fr.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%2Fh9z2nt4ml730ingfh8fr.png" width="800" height="53"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This shouldn’t be the case. In some scenarios, multiple transactions are run in a logical unit of code. All the transactions should only commit when there is no exception occurring in between.&lt;/p&gt;

&lt;p&gt;In Spring Boot, when &lt;strong&gt;@Transactional&lt;/strong&gt; annotation is used, Spring Boot implicitly creates a proxy that will be creating a connection to the database. A transaction will be started and committed after the code has been executed errorless. Otherwise, it will roll back the changes if an exception occurred.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;**import** **java.sql.Connection**;

**Connection** conn = dataSource.getConnection(); 

**try** (connection) {

 *   // execute some SQL statements...*

 *   *// commit transaction
    conn.commit();

} **catch** (**SQLException** e) {
    conn.rollback();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Example 1
&lt;/h2&gt;

&lt;p&gt;In this example, we added &lt;strong&gt;@Transactional&lt;/strong&gt; annotation to roll back the transaction if the exception occurred.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;**@Transactional**
public void createProduct() {  
    System.out.println("------ createProduct ------");
    Product prod = new Product();
    prod.setDescription("This is an example with runtime exception and transactional annotation.");
    prod.setPrice(10);
    prod.setTitle("Second Product");
    productRepository.save(prod);
    System.out.println("Second Product inserted.");

    throw new RuntimeException();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fh9z2nt4ml730ingfh8fr.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%2Fh9z2nt4ml730ingfh8fr.png" width="800" height="53"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The above example proves that the &lt;strong&gt;&lt;em&gt;@Transactional&lt;/em&gt;&lt;/strong&gt; annotation can roll back the transaction if the exception occurs. Take note, Spring only rolled back on &lt;strong&gt;&lt;em&gt;unchecked&lt;/em&gt;&lt;/strong&gt; exceptions by default.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example 2a
&lt;/h2&gt;

&lt;p&gt;This example shows that the &lt;strong&gt;&lt;em&gt;checked&lt;/em&gt;&lt;/strong&gt; exception will not be rolled back even though we have specified the **@Transactional **annotation.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Transactional
public void createProduct() throws Exception{  
    System.out.println("------ createProduct ------");
    Product prod = new Product();
    prod.setDescription("This is an example with checked exception and transactional annotation.");
    prod.setPrice(10);
    prod.setTitle("Second Product");
    productRepository.save(prod);
    System.out.println("Second Product inserted.");
    throw new SQLException();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fs3l364t5zhilbw4hmg7w.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%2Fs3l364t5zhilbw4hmg7w.png" width="800" height="85"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Example 2b
&lt;/h2&gt;

&lt;p&gt;To roll back &lt;strong&gt;checked&lt;/strong&gt; exceptions, we need to specify the &lt;strong&gt;&lt;em&gt;rollbackFor&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Transactional( **rollbackFor** = SQLException.class)
public void createProduct() throws Exception{  
    System.out.println("------ createProduct ------");
    Product prod = new Product();
    prod.setDescription("This is an example with checked exception and transactional annotation with rollbackFor.");
    prod.setPrice(10);
    prod.setTitle("Example 2b Product");
    productRepository.save(prod);
    System.out.println("Example 2b inserted.");
    throw new SQLException();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fs3l364t5zhilbw4hmg7w.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%2Fs3l364t5zhilbw4hmg7w.png" width="800" height="85"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We see that the transaction has rolled back successfully.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example 3
&lt;/h2&gt;

&lt;p&gt;In this example, we added the try-catch block to see if the rollback still working.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Transactional
public void createProduct() {
    try {
        System.out.println("------ createProduct ------");
        Product prod = new Product();
        prod.setDescription("This is an example with runtime exception, transactional annotation and try catch.");
        prod.setPrice(10);
        prod.setTitle("Example 3 Product");
        productRepository.save(prod);
        System.out.println("Example 3 Product inserted.");
        throw new RuntimeException();
    }catch (Exception e){
        System.out.println("Here we catch the exception.");
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fbwxxbq2vz5qgs2uz6h79.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%2Fbwxxbq2vz5qgs2uz6h79.png" width="800" height="114"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It won’t work. This happened because we manually caught the exception and handle it. Therefore the current transaction is being executed normally and committed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example 4
&lt;/h2&gt;

&lt;p&gt;What about a &lt;strong&gt;nested transaction&lt;/strong&gt;? From the example below, the &lt;em&gt;createProduct()*and *createOrder()&lt;/em&gt; methods will insert a record into the database. The &lt;em&gt;createOrder()&lt;/em&gt; method has thrown a runtime exception. Both methods have been annotated with the **@Transactional **annotation.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//ProductController.java
@Transactional
public void createProduct() {
    System.out.println("------ createProduct ------");
    Product prod = new Product();
    prod.setDescription("This is createProduct method.");
    prod.setPrice(10);
    prod.setTitle("Create Product");
    productRepository.save(prod);
    orderController.createOrder();
}

//OrderController.java
@Transactional
public void createOrder() {
    System.out.println("------ createOrder ------");
    Order order = new Order();
    order.setTitle("Create Order");
    order.setDescription("This is createOrder method with runtime exception");
    orderRepository.save(order);  
    throw new RuntimeException("Create Order RuntimeException");
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fbwxxbq2vz5qgs2uz6h79.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%2Fbwxxbq2vz5qgs2uz6h79.png" width="800" height="114"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;createProduct()*and *createOrder()&lt;/em&gt; transactions were rolled back. Even though the runtime exception has happened in the &lt;em&gt;createOrder()&lt;/em&gt; method. However, because it doesn’t handle the exception, this led to the &lt;em&gt;createProduct()&lt;/em&gt; transaction also rollback.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example 5
&lt;/h2&gt;

&lt;p&gt;Let’s add in the try-and-catch block to handle the runtime exception in the &lt;em&gt;createProduct()&lt;/em&gt; method.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//ProductController.java
@Transactional
public void createProduct() {
    System.out.println("------ createProduct ------");
    Product prod = new Product();
    prod.setDescription("This is createProduct method.");
    prod.setPrice(10);
    prod.setTitle("Create Product");
    productRepository.save(prod);
    try{
        orderController.createOrder();
    }catch (RuntimeException e){
        System.out.println("Handle " + e.getMessage());
    }
}

//OrderController.java
@Transactional
public void createOrder() {
    System.out.println("------ createOrder ------");
    Order order = new Order();
    order.setTitle("Create Order");
    order.setDescription("This is createOrder method with runtime exception");
    orderRepository.save(order);  
    throw new RuntimeException("Create Order RuntimeException");
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Arg? Both records have been rollback. Why? At the same time, we also noticed the exception error.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;org.springframework.transaction.UnexpectedRollbackException: Transaction silently rolled back because it has been marked as rollback-only
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;@Transactional&lt;/strong&gt; has a parameter called **Propagation. **Propagation will define the transaction boundary. Spring will start and end the transaction according to the propagation setting. By default, propagation is set to **REQUIRED. **So, if there is an active transaction, Spring will consume it instead of creating a new transaction. Therefore, in the above scenario, even though we have caught the exception on the outer method, the transaction was still rolling back.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example 6
&lt;/h2&gt;

&lt;p&gt;Use Propagation **REQUIRES_NEW, **this will force spring to create a subtransaction.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Transactional
public void createProduct() {
    System.out.println("------ createProduct ------");
    Product prod = new Product();
    prod.setDescription("This is createProduct method.");
    prod.setPrice(10);
    prod.setTitle("Create Product");
    productRepository.save(prod);
    try{
        orderController.createOrder();
    }catch (RuntimeException e){
        System.out.println("Handle " + e.getMessage());
    }
}

@Transactional(propagation=Propagation.REQUIRES_NEW)
public void createOrder() {
    System.out.println("------ createOrder ------");
    Order order = new Order();
    order.setTitle("Create Order");
    order.setDescription("This is createOrder method with runtime exception");
    orderRepository.save(order);  
    throw new RuntimeException("Create Order RuntimeException");
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fveknyfuvgrnzcmses8iq.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%2Fveknyfuvgrnzcmses8iq.png" width="800" height="141"&gt;&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%2F6fd2va10dzjtt8rx0f7g.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%2F6fd2va10dzjtt8rx0f7g.png" width="800" height="46"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The product record was written into the database, and the order record was rolled back.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example 7
&lt;/h2&gt;

&lt;p&gt;What if we never use try and catch block in the outer method, and an exception has happened in the inner method? Will the outer transaction still commit?&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Transactional
public void createProduct() {
    System.out.println("------ createProduct ------");
    Product prod = new Product();
    prod.setDescription("This is createProduct method.");
    prod.setPrice(10);
    prod.setTitle("Create Product");
    productRepository.save(prod);
    orderController.createOrder();
}

@Transactional(propagation=Propagation.REQUIRES_NEW)
public void createOrder() {
    System.out.println("------ createOrder ------");
    Order order = new Order();
    order.setTitle("Create Order");
    order.setDescription("This is createOrder method with runtime exception");
    orderRepository.save(order);  
    throw new RuntimeException("Create Order RuntimeException");
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We see that both transactions have been rolled back. Because the inner transaction threw an exception, the outer transaction detected the exception and it hasn’t been handled. Therefore, the outer transaction has been rolled back.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Example 8&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Let’s see if the exception has happened in the outer method instead.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Transactional
public void createProduct() {
    System.out.println("------ createProduct ------");
    Product prod = new Product();
    prod.setDescription("This is createProduct method.");
    prod.setPrice(10);
    prod.setTitle("Create Product with runtime");
    productRepository.save(prod);
    orderController.createOrder();
    throw new RuntimeException("Create Product RuntimeException");
}

@Transactional(propagation=Propagation.REQUIRES_NEW)
public void createOrder() {
    System.out.println("------ createOrder ------");
    Order order = new Order();
    order.setTitle("Create Order with propagation required_new");
    order.setDescription("This is createOrder method.");
    orderRepository.save(order);  
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2F2aprjlbwz2t0phqzr2uy.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%2F2aprjlbwz2t0phqzr2uy.png" width="800" height="146"&gt;&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%2Fgnyc8eu4jn8qj2cw6qa2.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%2Fgnyc8eu4jn8qj2cw6qa2.png" width="800" height="48"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We see that the inner transaction has been committed successfully due to the &lt;strong&gt;Propagation.REQUIRES_NEW&lt;/strong&gt;. This forces the Spring to handle the query in subtransaction. Once it is completed the outer transaction resumed, and an exception happened at this moment, so it rolled back.&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional Notes
&lt;/h2&gt;

&lt;p&gt;To take note, if both methods are in the same class, the &lt;strong&gt;@Transactional&lt;/strong&gt; annotation will not take place. It will always be treated as one transaction, so even if we specified the &lt;strong&gt;Propagation.REQUIRES_NEW&lt;/strong&gt;, it won’t work. At the very beginning, we talked about Spring creating a proxy when seeing annotation @Transactional. When you are calling the internal method, it will bypass the proxy.&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
