Interview ‐ Spring Data (JpaRepository, MongoRepository) - Yash-777/MyWorld GitHub Wiki
Download and install Rancher Desktop : https://rancherdesktop.io/
After installation, verify Docker: Portable console emulator for Windows λcmder
λ docker --version
Docker version 29.1.4-rd, build 3c6914c
🐳 MSSQL Setup using Docker (Rancher Desktop)
🚀 Step 1 — Run Microsoft SQL Server Container
docker run -e "ACCEPT_EULA=Y" ^
-e "MSSQL_SA_PASSWORD=Strong@123" ^
-p 1433:1433 ^
--name mssql ^
-d mcr.microsoft.com/mssql/server:2019-latest→ If image is not present locally:
λ docker run -e "ACCEPT_EULA=Y" -e "MSSQL_SA_PASSWORD=Strong@123" -p 1433:1433 --name mssql -d mcr.microsoft.com/mssql/server:2019-latest
Unable to find image 'mcr.microsoft.com/mssql/server:2019-latest' locally
2019-latest: Pulling from mssql/server
8e76b0919436: Pull complete
e012aedd45a6: Pull complete
306fbe3b6736: Pull complete
Digest: sha256:e7ef04aca478b8aa8dd6380297bdae4969c9ae03cf39de3af94bb6ce3273ca53
Status: Downloaded newer image for mcr.microsoft.com/mssql/server:2019-latest
acc164ea3b4205b6ff5988f0276756ff7d216ca2be9e05fdb6008bae93331fe0
→ ⚠ Container Name Already Exists Error
If you see: Conflict. The container name "/mssql" is already in use. It means container already exists.
docker: Error response from daemon: Conflict.
The container name "/mssql" is already in use by container "acc164ea3b4205b6f...".
You have to remove (or rename) that container to be able to reuse that name.
Run 'docker run --help' for more information
🔎 Step 2 — Check SQL Server Container Name, Verify Container is Running. (RUN: docker ps)
Example output:
λ docker ps
CONTAINER ID IMAGE PORTS NAMES
71912fdfc7a0 mcr.microsoft.com/mssql/server:2019-latest 0.0.0.0:1433->1433/tcp mssql
✅ Confirm port mapping: 1433 -> 1433 (TCP)
🧪 Step 3 — Test SQL Server Connection
Run SQL command using mssql-tools container:
docker run -it --rm mcr.microsoft.com/mssql-tools \
/opt/mssql-tools/bin/sqlcmd \
-S host.docker.internal,1433 \
-U sa \
-P "Strong@123" \
-Q "SELECT 1"
Expected Output:
λ docker run -it --rm mcr.microsoft.com/mssql-tools /opt/mssql-tools/bin/sqlcmd -S host.docker.internal,1433 -U sa -P "Strong@123" -Q "SELECT 1"
-----------
1
(1 rows affected)
🗄 Step 4 — Create Database (One-Line Command)
docker run -it --rm mcr.microsoft.com/mssql-tools \
/opt/mssql-tools/bin/sqlcmd \
-S host.docker.internal,1433 \
-U sa \
-P "Strong@123" \
-Q "CREATE DATABASE finance"
----> 🚀 One-Line Shortcut (Without Entering Shell) (Using mssql-tools Container)
C:\Users\ymerugu>docker run -it --rm mcr.microsoft.com/mssql-tools /opt/mssql-tools/bin/sqlcmd -S host.docker.internal,1433 -U sa -P "Strong@123" -Q "CREATE DATABASE finance"
---> ✅ Verify Database Exists
C:\Users\ymerugu>docker run -it --rm mcr.microsoft.com/mssql-tools /opt/mssql-tools/bin/sqlcmd -S host.docker.internal,1433 -U sa -P "Strong@123" -Q "SELECT name FROM sys.databases"
name
--------------------------------------------------------------------------------------------------------------------------------
master
tempdb
model
msdb
finance
(5 rows affected)
🛑 Step 5 — Stop and Remove Container
C:\Users\ymerugu>docker.exe stop mssql
mssql
C:\Users\ymerugu>docker.exe rm mssql
mssql
🧰 Step 6 — Install MSSQL GUI Client (SSMS): Download SQL Server Management Studio (SSMS)
Installer: https://aka.ms/ssms/22/release/vs_SSMS.exe
Documentation: https://learn.microsoft.com/en-us/ssms/install/install
SSMS Connection Settings
Connection String
Data Source=localhost,1433;
Persist Security Info=True;
User ID=sa;
Password=Strong@123;
Pooling=False;
MultipleActiveResultSets=False;
Encrypt=false;
TrustServerCertificate=False;
Application Name="SQL Server Management Studio";
Command Timeout=0
⚠ Important: Encrypt=false Required for local Docker SQL Server.
🍃 MongoDB Setup using Docker (Rancher Desktop)
🚀 Step 1 — Run MongoDB Container
docker run -d --name mongodb -p 27017:27017 mongo:latest
If image is not available locally:
Unable to find image 'mongo:latest' locally
Pulling from library/mongo
Status: Downloaded newer image for mongo:latest
Container will start automatically after download.
🔎 Step 2 — Verify MongoDB Container docker ps
Example output: ✅ MongoDB default port: TCP 27017
CONTAINER ID IMAGE PORTS NAMES
77ca86c14ee8 mongo:latest 0.0.0.0:27017->27017/tcp mongodb
🧰 Step 3 — Install MongoDB GUI Client
MongoDB Compass (Official GUI Tool) for MongoDB data exploration and management.
Download
Product Page: https://www.mongodb.com/products/tools/compass
Direct Download: https://downloads.mongodb.com/compass/mongodb-compass-1.49.2-win32-x64.exe
🔌 Step 4 — Connect MongoDB using Compass
Open MongoDB Compass → New Connection
Connection String
mongodb://localhost:27017
Click: Connect
| Relationship | Default Fetch Type | Explanation |
|---|---|---|
| @OneToOne | EAGER | Associated entity loaded immediately |
| @ManyToOne | EAGER | Parent entity loaded immediately |
| @OneToMany | LAZY | Child entities loaded when accessed |
| @ManyToMany | LAZY | Associated collection loaded when accessed |
jakarta.persistence-api-2.2.3.jar<.code> - source code of Relationship's
javax.persistence.FetchType.EAGER |
javax.persistence.FetchType.LAZY; |
|---|---|
@Target({METHOD, FIELD}) @Retention(RUNTIME)
public @interface OneToOne {
/**
* (Optional) Whether the association should be lazily
* loaded or must be eagerly fetched. The EAGER
* strategy is a requirement on the persistence provider runtime that
* the associated entity must be eagerly fetched. The LAZY
* strategy is a hint to the persistence provider runtime.
*/
FetchType fetch() default EAGER;
// ...
}@Target({METHOD, FIELD}) @Retention(RUNTIME)
public @interface ManyToOne {
/**
* (Optional) Whether the association should be lazily
* loaded or must be eagerly fetched. The EAGER
* strategy is a requirement on the persistence provider runtime that
* the associated entity must be eagerly fetched. The LAZY
* strategy is a hint to the persistence provider runtime.
*/
FetchType fetch() default EAGER;
} |
@Target({METHOD, FIELD}) @Retention(RUNTIME)
public @interface OneToMany {
/** (Optional) Whether the association should be lazily loaded or
* must be eagerly fetched. The EAGER strategy is a requirement on
* the persistence provider runtime that the associated entities
* must be eagerly fetched. The LAZY strategy is a hint to the
* persistence provider runtime.
*/
FetchType fetch() default LAZY;
}@Target({METHOD, FIELD})
@Retention(RUNTIME)
public @interface ManyToMany {
/** (Optional) Whether the association should be lazily loaded or
* must be eagerly fetched. The EAGER strategy is a requirement on
* the persistence provider runtime that the associated entities
* must be eagerly fetched. The LAZY strategy is a hint to the
* persistence provider runtime.
*/
FetchType fetch() default LAZY;
} |
⭐ Golden Rule
- Lazy loading works only within an active transactional persistence context.
-
❌ LazyInitializationExceptionhappens when a LAZY field is accessed outside an active Persistence Context (Hibernate Session / Transaction).
Repository Hierarchy
Repository<T, ID> ← Marker interface (no methods)
└── CrudRepository<T, ID> ← Basic CRUD operations
└── PagingAndSortingRepository<T, ID> ← + Sorting & Pagination
├── JpaRepository<T, ID> ← + JPA-specific (flush, batch delete, getOne)
└── MongoRepository<T, ID> ← + Mongo-specific (insert)
Both JpaRepository and MongoRepository also extend QueryByExampleExecutor<T>.
JpaRepository |
MongoRepository |
|---|---|
package org.springframework.data.jpa.repository;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.repository.query.QueryByExampleExecutor;
@org.springframework.data.repository.NoRepositoryBean
public interface JpaRepository<T, ID> extends
PagingAndSortingRepository<T, ID>,
QueryByExampleExecutor<T> {
@Override
List<T> findAll();
@Override
List<T> findAll(Sort sort);
@Override
List<T> findAllById(Iterable<ID> ids);
@Override
<S extends T> List<S> saveAll(Iterable<S> entities);
// Flushes all pending changes to the database.
void flush();
// Saves an entity and flushes changes instantly.
<S extends T> S saveAndFlush(S entity);
void deleteInBatch(Iterable<T> entities);
void deleteAllInBatch();
T getOne(ID id);
@Override
<S extends T> List<S> findAll(Example<S> example);
@Override
<S extends T> List<S> findAll(Example<S> example, Sort sort);
} |
package org.springframework.data.mongodb.repository;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.repository.query.QueryByExampleExecutor;
@org.springframework.data.repository.NoRepositoryBean
public interface MongoRepository<T, ID> extends
PagingAndSortingRepository<T, ID>,
QueryByExampleExecutor<T> {
@Override
<S extends T> List<S> saveAll(Iterable<S> entities);
@Override
List<T> findAll();
@Override
List<T> findAll(Sort sort);
<S extends T> S insert(S entity);
<S extends T> List<S> insert(Iterable<S> entities);
@Override
<S extends T> List<S> findAll(Example<S> example);
@Override
<S extends T> List<S> findAll(Example<S> example, Sort sort);
} |
package org.springframework.data.repository;
// ── Paging & Sorting ──────────────────────────────────────────────────────────
@NoRepositoryBean
public interface PagingAndSortingRepository<T, ID> extends CrudRepository<T, ID> {
Iterable<T> findAll(org.springframework.data.domain.Sort sort); // All records, sorted
Page<T> findAll(org.springframework.data.domain.Pageable pageable); // Paginated + sorted result
}
// ── Basic CRUD ────────────────────────────────────────────────────────────────
@NoRepositoryBean
public interface CrudRepository<T, ID> extends Repository<T, ID> {
<S extends T> S save(S entity); // Insert or Update (upsert)
<S extends T> Iterable<S> saveAll(Iterable<S> entities); // Bulk upsert
Optional<T> findById(ID id); // Find by PK → Optional (never null)
boolean existsById(ID id); // Check existence by PK
Iterable<T> findAll(); // Fetch all records
Iterable<T> findAllById(Iterable<ID> ids); // Fetch by list of PKs
long count(); // Total row/document count
void deleteById(ID id); // Delete by PK
void delete(T entity); // Delete given entity
void deleteAll(Iterable<? extends T> entities); // Delete given list
void deleteAll(); // Delete everything — USE WITH CAUTION
}
// ── Marker interface ──────────────────────────────────────────────────────────
@Indexed
public interface Repository<T, ID> { } |
|
Maven Dependency,
application.properties
spring-boot-starter-data-jpa |
spring-boot-starter-data-mongodb |
|---|---|
Maven Dependency
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<exclusions>
<!-- Exclude HikariCP if using Tomcat JDBC pool instead -->
<exclusion>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- SQL Server JDBC driver -->
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<scope>runtime</scope>
</dependency>
<!-- Tomcat JDBC Connection Pool (if replacing HikariCP) -->
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId>
</dependency>application.properties
#-----------------------------------------
# SQL Server DataBase Properties
#-----------------------------------------
spring.datasource.url=jdbc:sqlserver://localhost:1433;databaseName=finance
spring.datasource.username=sa
spring.datasource.password=Strong@123
spring.datasource.driver-class-name=com.microsoft.sqlserver.jdbc.SQLServerDriver
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.SQLServerDialect
#-----------------------------------------
# DataBase Connection Pool (Tomcat JDBC)
#-----------------------------------------
spring.datasource.type=org.apache.tomcat.jdbc.pool.DataSource
spring.datasource.tomcat.test-on-borrow=true
spring.datasource.tomcat.test-while-idle=true
spring.datasource.tomcat.test-on-return=false
spring.datasource.tomcat.validation-query=select 1
spring.datasource.tomcat.initial-size=15
spring.datasource.tomcat.max-wait=20000
spring.datasource.tomcat.max-active=50
spring.datasource.tomcat.max-idle=15
spring.datasource.tomcat.min-idle=8
spring.datasource.tomcat.default-auto-commit=true
spring.datasource.tomcat.log-validation-errors=true
spring.datasource.log-abandoned=true
#-----------------------------------------
# JPA / Hibernate Properties
#-----------------------------------------
# none | validate | update | create | create-drop
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=false
# Preserve column names as declared in @Column(name="...")
spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
# Required for @CreatedDate / @LastModifiedDate to work
spring.jpa.properties.javax.persistence.validation.mode=none |
Maven Dependency
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>#-----------------------------------------
# MongoDB Properties
#-----------------------------------------
spring.data.mongodb.uri=mongodb://localhost:27017/local?authSource=admin&ssl=false&maxPoolSize=1000
# Alternative: individual properties
# spring.data.mongodb.host=localhost
# spring.data.mongodb.port=27017
# spring.data.mongodb.database=local
# spring.data.mongodb.username=admin
# spring.data.mongodb.password=secret |
JpaRepository vs MongoRepository
Note
@Data on JPA @Entity classes — @EqualsAndHashCode and @ToString can trigger lazy-load exceptions and cause infinite loops with bidirectional relationships. Use @Getter + @Setter + @NoArgsConstructor + @AllArgsConstructor + @Builder separately instead.
🗄️ JPA Side — Product (SQL Entity)
|
🍃 MongoDB Side — Order (NoSQL Document)
|
|---|---|
BaseEntity.java — Abstract JPA base class
package com.example.shop.entity;
/**
* Abstract base for all JPA entities.
*
* @MappedSuperclass — Fields are inherited into child entity tables (no separate table created).
* @EntityListeners — Activates Spring's JPA auditing for @CreatedDate / @LastModifiedDate.
*/
@Getter @Setter
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class BaseEntity implements Serializable {
private static final long serialVersionUID = 1L;
@org.springframework.data.annotation.Id
@GeneratedValue(strategy = GenerationType.IDENTITY) // Auto-increment PK (Long)
private Long id;
@Column(name = "active_status", nullable = false)
private boolean activeStatus = true;
@org.springframework.data.annotation.CreatedDate
@Column(name = "created_at", nullable = false, updatable = false)
private LocalDateTime createdAt;
@org.springframework.data.annotation.LastModifiedDate
@Column(name = "updated_at", nullable = false)
private LocalDateTime updatedAt;
} |
BaseDocument.java — Abstract MongoDB base class
package com.example.shop.document;
/**
* Abstract base for all MongoDB documents.
*
* @Id — Maps to MongoDB's _id field. Spring stores the ObjectId as a String.
* Unlike JPA, there is no @GeneratedValue — MongoDB generates ObjectId automatically.
*
* No @MappedSuperclass needed — MongoDB has no schema inheritance constraint.
* No @EntityListeners needed — @EnableMongoAuditing handles @CreatedDate / @LastModifiedDate.
* @Getter / @Setter — Lombok: generates all getters and setters automatically.
*/
@Getter @Setter
public abstract class BaseDocument implements Serializable {
private static final long serialVersionUID = 1L;
@org.springframework.data.annotation.Id
private String id; // MongoDB ObjectId (auto-generated as 24-char hex string)
private boolean active = true;
@org.springframework.data.annotation.CreatedDate
private LocalDateTime createdAt;
@org.springframework.data.annotation.LastModifiedDate
private LocalDateTime updatedAt;
} |
ProductEntity.java — Concrete JPA Entity
package com.example.shop.entity;
import javax.persistence.*;
/**
* Maps to the "products" table in the SQL database.
*
* @Entity — Marks this class as a JPA-managed table.
* @Table — Specifies the exact table name in the DB.
* @Getter / @Setter — Lombok: all getters & setters.
* @NoArgsConstructor — Lombok: no-arg constructor (required by JPA).
* @AllArgsConstructor — Lombok: constructor with all fields.
* @Builder — Lombok: fluent builder pattern e.g. ProductEntity.builder().name("X").build()
* @ToString — Lombok: generates toString() (excludes BaseEntity fields via callSuper=false)
*/
@Getter @Setter @NoArgsConstructor @AllArgsConstructor @Builder @ToString @Entity
@Table(name = "products")
public class ProductEntity extends BaseEntity {
private static final long serialVersionUID = 2L;
@Column(name = "product_name", nullable = false)
private String name;
@Column(name = "category")
private String category;
@Column(name = "price", nullable = false)
private double price;
@Column(name = "stock_quantity")
private int stockQuantity;
@Column(name = "sku", unique = true)
private String sku; // Stock Keeping Unit — unique product code
} |
package com.example.shop.document;
public enum OrderStatus {
PENDING, CONFIRMED, SHIPPED, DELIVERED, CANCELLED
}
/**
* Embedded object stored inside OrderDocument as a nested BSON field.
* NOT a separate MongoDB collection — no @Document annotation.
*
* @Data = @Getter + @Setter + @ToString + @EqualsAndHashCode + @RequiredArgsConstructor
*/
@Data @NoArgsConstructor @AllArgsConstructor @Builder
public class OrderItem {
private String sku;
private String productName;
private int quantity;
private double unitPrice;
// Derived field — not stored in DB, computed on read
public double getTotalPrice() {
return quantity * unitPrice;
}
}
/**
* Maps to the "orders" collection in MongoDB.
*
* @org.springframework.data.mongodb.core.mapping.Document(collection = "orders")
* Equivalent of @Entity + @Table in JPA.
* Specifies the MongoDB collection name explicitly.
*
* @com.fasterxml.jackson.annotation.JsonIgnoreProperties({"createdAt","updatedAt"})
* Excludes audit fields from JSON REST responses.
*
* @Indexed — Creates a MongoDB index on the annotated field for faster queries.
*/
@Data @NoArgsConstructor @AllArgsConstructor @Builder
@org.springframework.data.mongodb.core.mapping.Document(collection = "orders")
@JsonIgnoreProperties({ "createdAt", "updatedAt" })
public class OrderDocument extends BaseDocument {
private static final long serialVersionUID = 2L;
@org.springframework.data.mongodb.core.index.Indexed // MongoDB index — speeds up queries by customerId
private String customerId;
private String customerName;
private List<OrderItem> items; // Embedded list of sub-documents (no separate collection)
private OrderStatus status;
private double totalAmount;
private String deliveryAddress;
private String remarks;
} |
package com.example.shop.repository;
import com.example.shop.entity.BaseEntity;
import org.springframework.data.jpa.repository.JpaRepository;
/**
* @NoRepositoryBean — Spring will NOT instantiate this interface as a bean.
* Only concrete child interfaces get Spring-managed beans.
*
* Generic bound ensures only proper entities extend this.
*/
@org.springframework.data.repository.NoRepositoryBean
public interface BaseRepository<E extends BaseEntity>
extends JpaRepository<E, Long> {
// Shared custom query methods go here (e.g. findAllByActiveStatus)
}
import com.example.shop.entity.ProductEntity;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
/**
* Spring creates a bean for this interface (it is concrete, not @NoRepositoryBean).
* All CRUD + paging + sorting methods are inherited automatically.
*/
@Repository
public interface ProductRepository extends BaseRepository<ProductEntity> {
// Derived query — Spring generates: WHERE category = ? AND active_status = ?
List<ProductEntity> findByCategoryAndActiveStatus(
@Param("category") String category,
@Param("activeStatus") boolean activeStatus);
// Derived query — Spring generates: WHERE sku = ?
Optional<ProductEntity> findBySku(@Param("sku") String sku);
// Derived count — Spring generates: SELECT COUNT(*) WHERE category = ?
long countByCategory(@Param("category") String category);
// Derived exists — Spring generates: SELECT CASE WHEN COUNT(*) > 0 WHERE sku = ?
boolean existsBySku(@Param("sku") String sku);
} |
package com.example.shop.repository;
import com.example.shop.document.BaseDocument;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.repository.NoRepositoryBean;
/**
* @NoRepositoryBean — Spring will NOT create a bean for this interface.
*
* ID is String because MongoDB ObjectId is serialized as a 24-char hex String.
*/
@NoRepositoryBean
public interface BaseDocumentRepository<D extends BaseDocument>
extends MongoRepository<D, String> {
// Shared Mongo query methods can go here
}
import com.example.shop.document.OrderDocument;
import com.example.shop.document.OrderStatus;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
@Repository
public interface OrderRepository extends BaseDocumentRepository<OrderDocument> {
// Derived query — WHERE customerId = ?
List<OrderDocument> findByCustomerId(@Param("customerId") String customerId);
// Derived query — WHERE customerId = ? AND status = ?
List<OrderDocument> findByCustomerIdAndStatus(
@Param("customerId") String customerId,
@Param("status") OrderStatus status);
// Derived count — SELECT COUNT(*) WHERE status = ?
long countByStatus(@Param("status") OrderStatus status);
// Derived exists — WHERE customerId = ?
boolean existsByCustomerId(@Param("customerId") String customerId);
} |
package com.example.shop;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.data.mongodb.config.EnableMongoAuditing;
@SpringBootApplication
@EnableJpaAuditing // Activates @CreatedDate / @LastModifiedDate for JPA entities
@EnableMongoAuditing // Activates @CreatedDate / @LastModifiedDate for Mongo documents
public class ShopApplication {
public static void main(String[] args) {
SpringApplication.run(ShopApplication.class, args);
}
} |
|