SpringBoot + JPA/Hibernate: Zero XML, Zero SQL – Fast Data Layer Setup

This tutorial walks through integrating SpringBoot with JPA (Hibernate) from adding dependencies to configuring the datasource, defining entities, using JpaRepository, building service and controller layers, applying method‑naming rules, writing custom queries, comparing JPA with MyBatis and JdbcTemplate, and highlighting key pitfalls for rapid, low‑boilerplate data‑access development.

Java Tech Workshop
Java Tech Workshop
Java Tech Workshop
SpringBoot + JPA/Hibernate: Zero XML, Zero SQL – Fast Data Layer Setup

SpringBoot + JPA (Hibernate) eliminates XML, hand‑written SQL and CRUD code; defining a repository interface is enough to perform data operations.

When to use JPA

Heavy single‑table CRUD

Rapid prototyping

Lightweight microservice modules

Object‑oriented DB access without manual SQL

Advantages

Extremely concise, almost no boilerplate

Automatic table creation and schema updates

Built‑in pagination, sorting and complex query support

Native integration with the Spring ecosystem and transaction management

Dependencies

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>

application.yml configuration

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/testdb?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver

  jpa:
    hibernate:
      ddl-auto: update   # auto‑update schema (none, create, create-drop also available)
    show-sql: true
    properties:
      hibernate:
        format_sql: true
    database-platform: org.hibernate.dialect.MySQL8Dialect

Common ddl-auto values: none – no automatic schema management update – update schema without data loss create – recreate tables on each start create-drop – create on start, drop on shutdown

Entity class

package com.demo.entity;

import jakarta.persistence.*;
import lombok.Data;
import java.time.LocalDateTime;

@Data
@Entity
@Table(name = "user")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false, length = 50)
    private String username;

    @Column(length = 100)
    private String password;

    private Integer age;

    @Column(unique = true)
    private String email;

    private LocalDateTime createTime;
    private LocalDateTime updateTime;
}

Common annotations: @Entity – marks the class as a JPA entity @Table(name = "user") – specifies the table name @Id – primary key @GeneratedValue – auto‑increment strategy @Column – column constraints (nullable, length, unique, etc.)

Repository layer

package com.demo.repository;

import com.demo.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    // Method names automatically generate SQL
    List<User> findByUsername(String username);
    List<User> findByAgeGreaterThan(Integer age);
    List<User> findByUsernameContaining(String username);
}

JpaRepository provides the following methods out of the box: save() – insert or update findById() – query by primary key findAll() – retrieve all records findAll(Pageable) – pagination query deleteById() – delete by primary key count() – count rows

Service layer

package com.demo.service;

import com.demo.entity.User;
import com.demo.repository.UserRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Optional;

@Service
@RequiredArgsConstructor
public class UserService {
    private final UserRepository userRepository;

    @Transactional(rollbackFor = Exception.class)
    public User save(User user) {
        return userRepository.save(user);
    }

    @Transactional
    public void delete(Long id) {
        userRepository.deleteById(id);
    }

    public User findById(Long id) {
        Optional<User> optional = userRepository.findById(id);
        return optional.orElse(null);
    }

    public List<User> findAll() {
        return userRepository.findAll();
    }

    public Page<User> page(Integer pageNum, Integer pageSize) {
        Pageable pageable = PageRequest.of(pageNum - 1, pageSize, Sort.by(Sort.Direction.DESC, "id"));
        return userRepository.findAll(pageable);
    }

    public List<User> findByUsername(String username) {
        return userRepository.findByUsernameContaining(username);
    }
}

Controller interface

package com.demo.controller;

import com.demo.common.Result;
import com.demo.entity.User;
import com.demo.service.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.web.bind.annotation.*;
import java.util.List;

@RestController
@RequestMapping("/user")
@RequiredArgsConstructor
public class UserController {
    private final UserService userService;

    @PostMapping("/save")
    public Result save(@RequestBody User user) {
        return Result.success(userService.save(user));
    }

    @DeleteMapping("/delete/{id}")
    public Result delete(@PathVariable Long id) {
        userService.delete(id);
        return Result.success("删除成功");
    }

    @GetMapping("/{id}")
    public Result findById(@PathVariable Long id) {
        return Result.success(userService.findById(id));
    }

    @GetMapping("/list")
    public Result list() {
        return Result.success(userService.findAll());
    }

    @GetMapping("/page")
    public Result page(@RequestParam(defaultValue = "1") Integer pageNum,
                       @RequestParam(defaultValue = "10") Integer pageSize) {
        Page<User> page = userService.page(pageNum, pageSize);
        return Result.success(page);
    }

    @GetMapping("/search")
    public Result search(@RequestParam String username) {
        return Result.success(userService.findByUsername(username));
    }
}

JPA method naming rules

findByXxx

– exact match findByXxxLike – fuzzy match findByXxxContaining – contains findByXxxGreaterThan – greater than findByXxxAndYyy – multiple conditions (AND) findByXxxOrYyy – multiple conditions (OR) findByXxxOrderByZzzDesc – sorting

Spring Data JPA automatically generates SQL based on method names.

Custom SQL (complex queries)

@Query(value = "select * from user where age > ?1", nativeQuery = true)
List<User> findUserByAge(Integer age);

Choosing JPA, MyBatis, or JdbcTemplate

Extreme simplicity, many single‑table operations → JPA

Complex queries, need fine‑grained SQL control → MyBatis

Ultra‑lightweight, write native SQL directly → JdbcTemplate

Precautions

Primary key not auto‑increment – verify @GeneratedValue(strategy = GenerationType.IDENTITY) Table not auto‑created – verify jpa.hibernate.ddl-auto setting

Pagination page index starts at 0 – subtract 1 from front‑end page number

Query returning no data throws error – handle with Optional Field name conflicts – avoid using SQL reserved keywords

Summary

SpringBoot + JPA provides the fastest path to a functional data layer: add dependencies, configure the datasource, write entity classes, extend JpaRepository, and use the repository directly. The approach removes XML, eliminates repetitive CRUD code, and auto‑creates tables, maximizing development efficiency for rapid iteration and lightweight business needs.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Backend DevelopmentSpringBootCRUDHibernateJPASpring Data JPA
Java Tech Workshop
Written by

Java Tech Workshop

Focused on Java backend technologies, sharing fundamentals, multithreading, JVM, the Spring ecosystem, microservices, distributed systems, high concurrency, source‑code analysis, and practical experience. Continuously delivers high‑quality original content, interview guides, and learning roadmaps to help Java developers progress from beginner to advanced, enhancing technical skills and core competitiveness.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.