DEV Community

Tejasvi Urkande
Tejasvi Urkande

Posted on

πŸš€ Week 3 – Spring Data JPA & CRUD Operations in Spring Boot

This week, I moved one step ahead from just building REST APIs to connecting them with a real database using Spring Data JPA and H2 Database.
This helped me understand how data actually flows between the backend and the database β€” and how Spring simplifies everything for us.

πŸ”Ή Why Spring Data JPA?

Before using JPA, I tried understanding the evolution:

  • JDBC β†’ Too much code: connection, statements, result sets, closing resources.
  • Spring JDBC β†’ Reduced boilerplate but still SQL-heavy.
  • ORM (Object Relational Mapping) β†’ Maps Java classes to database tables, making data handling object-oriented.
  • JPA (Java Persistence API) β†’ A standard for ORM so we can switch tools like Hibernate easily.
  • Spring Data JPA β†’ Builds on top of JPA and gives ready-made repository methods like save(), findAll(), deleteById() etc.

πŸ’‘ In short:
Spring Data JPA lets you work with objects instead of SQL queries, saving time and effort.

πŸ”Ή Setting Up Spring Data JPA + H2

Added dependencies in pom.xml for:
spring-boot-starter-data-jpa

h2

Configured my H2 in-memory database in application.properties:

spring.datasource.url=jdbc:h2:mem:tejasvi
spring.datasource.driver-class-name=org.h2.Driver
spring.jpa.hibernate.ddl-auto=update
spring.h2.console.enabled=true
spring.jpa.show-sql=true

πŸ’‘ Tip:
jdbc:h2:mem:tejasvi creates an in-memory DB (wiped when app stops).
To persist data even after restart, use jdbc:h2:~/tejasvi.

πŸ”Ή Building Repository Layer

Created an interface for database operations:

public interface ProductRepo extends JpaRepository {}

No need to write SQL queries anymore β€” this gives me all CRUD methods automatically.

πŸ’‘ Bonus:
If I want a custom finder, I can just define:
List findByName(String name);
Spring automatically generates the query!

πŸ”Ή Controller + Service Layer

Controller to handle HTTP requests:

@RestController
@RequestMapping("/products")
public class ProductController {
@Autowired
private ProductService service;

@GetMapping("/{id}")
public Product getProduct(@PathVariable int id) {
    return service.getProductById(id);
}

@PostMapping
public void addProduct(@RequestBody Product product) {
    service.addProduct(product);
}

@PutMapping
public void updateProduct(@RequestBody Product product) {
    service.updateProduct(product);
}

@DeleteMapping("/{id}")
public void deleteProduct(@PathVariable int id) {
    service.deleteProduct(id);
}
Enter fullscreen mode Exit fullscreen mode

}

πŸ’‘ Used annotations:

@RestController β†’ Combines @Controller + @ResponseBody
@RequestBody β†’ To map JSON input from Postman to Java objects
@PathVariable β†’ To read parameters from URL

πŸ”Ή Common Problems & How I Fixed Them

Problem 1: Table not found (or β€œno such table”)

Cause:
I forgot to annotate my model class with @Entity.
Without @Entity, JPA doesn’t recognize it as a table to create in H2.

Solution:
Add these annotations to your class:

@Entity
@Table(name = "products")
public class Product {
@id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
private double price;
}

Also make sure spring.jpa.hibernate.ddl-auto=update is set, so Hibernate creates or updates tables automatically.

Problem 2: β€œFailed to convert value of type 'java.lang.String' to required type 'int'”

Cause:
Sent wrong data format in Postman. For example, ID was sent as a string ("id": "1") instead of a number.

Solution:
Always match data types correctly while sending JSON.
Example valid body:

{
"name": "Laptop",
"price": 55000
}

Problem 3: H2 console not opening

Cause:
Didn’t enable console in properties file.

Solution:
Add:

spring.h2.console.enabled=true
spring.h2.console.path=/h2-console

Then open: http://localhost:8080/h2-console

and make sure JDBC URL matches what’s in your properties file.

Problem 4: Data not visible in H2 after POST request

Cause:
Used an in-memory database (mem:). Once the app restarts, all data is gone.

Solution:
Use persistent database for local testing:

spring.datasource.url=jdbc:h2:~/tejasvi
This creates a file-based DB stored in your system.

Problem 5: β€œDetached entity passed to persist” or duplicate insert errors

Cause:
When calling save() for existing entities, JPA tries to insert instead of update.

Solution:
Always include the correct ID for updates:

product.setId(existingId);
repository.save(product);

Or check first using findById() before updating.

Problem 6: @Autowired NullPointerException

Cause:
Created service/repo object manually using new keyword instead of letting Spring inject it.

Solution:
Never use new for beans. Always annotate:

@Service
public class ProductService { ... }

@Autowired
private ProductService service;

Let Spring handle object creation and dependency injection.

βœ… Week 3 Takeaways

βœ” Understood the evolution from JDBC β†’ JPA β†’ Spring Data JPA
βœ” Configured and used H2 Database successfully
βœ” Built CRUD APIs using JpaRepository
βœ” Tested all endpoints using Postman
βœ” Learned to fix real-time errors like missing @Entity, wrong JSON types, and dependency issues
βœ” Understood how Spring auto-generates queries and handles transactions

πŸ’‘ Why I’m Sharing

Learning backend development is not just about writing code β€” it’s about understanding why errors happen and how to fix them smartly.
By documenting my weekly learnings, I can reflect on my mistakes and also help other beginners avoid the same pitfalls while learning Spring Boot.

SpringBoot #JPA #H2Database #CRUD #BackendDevelopment #JavaDeveloper #100DaysOfCode

Top comments (0)