diff --git a/spring-boot-modules/spring-boot-3/pom.xml b/spring-boot-modules/spring-boot-3/pom.xml
index cc8e7e1426..685df233ba 100644
--- a/spring-boot-modules/spring-boot-3/pom.xml
+++ b/spring-boot-modules/spring-boot-3/pom.xml
@@ -124,6 +124,8 @@
1.5.2.Final
2.0.0
3.0.0-M7
+ com.baeldung.sample.TodoApplication
+
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/QueryService.java b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/QueryService.java
new file mode 100644
index 0000000000..4c1e73e530
--- /dev/null
+++ b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/QueryService.java
@@ -0,0 +1,42 @@
+package com.baeldung.recordswithjpa;
+
+import com.baeldung.recordswithjpa.entity.Book;
+import com.baeldung.recordswithjpa.records.BookRecord;
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.PersistenceContext;
+import jakarta.persistence.Query;
+import jakarta.persistence.TypedQuery;
+import jakarta.persistence.criteria.CriteriaBuilder;
+import jakarta.persistence.criteria.CriteriaQuery;
+import jakarta.persistence.criteria.Root;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+public class QueryService {
+ @PersistenceContext
+ private EntityManager entityManager;
+
+ public List findAllBooks() {
+ CriteriaBuilder cb = entityManager.getCriteriaBuilder();
+ CriteriaQuery query = cb.createQuery(BookRecord.class);
+ Root root = query.from(Book.class);
+ query.select(cb
+ .construct(BookRecord.class, root.get("id"), root.get("title"), root.get("author"), root.get("isbn")));
+ return entityManager.createQuery(query).getResultList();
+ }
+
+ public BookRecord findBookById(Long id) {
+ TypedQuery query = entityManager
+ .createQuery("SELECT new com.baeldung.recordswithjpa.records.BookRecord(b.id, b.title, b.author, b.isbn) " +
+ "FROM Book b WHERE b.id = :id", BookRecord.class);
+ query.setParameter("id", id);
+ return query.getSingleResult();
+ }
+
+ public List findAllBooksUsingMapping() {
+ Query query = entityManager.createNativeQuery("SELECT * FROM book", "BookRecordMapping");
+ return query.getResultList();
+ }
+}
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/RecordsAsJpaApplication.java b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/RecordsAsJpaApplication.java
new file mode 100644
index 0000000000..d6eb1edec1
--- /dev/null
+++ b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/RecordsAsJpaApplication.java
@@ -0,0 +1,13 @@
+package com.baeldung.recordswithjpa;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class RecordsAsJpaApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(RecordsAsJpaApplication.class, args);
+ }
+
+}
diff --git a/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/entity/Book.java b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/entity/Book.java
new file mode 100644
index 0000000000..9ea982e323
--- /dev/null
+++ b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/entity/Book.java
@@ -0,0 +1,70 @@
+package com.baeldung.recordswithjpa.entity;
+
+import com.baeldung.recordswithjpa.records.BookRecord;
+import jakarta.persistence.*;
+
+@SqlResultSetMapping(
+ name = "BookRecordMapping",
+ classes = @ConstructorResult(
+ targetClass = BookRecord.class,
+ columns = {
+ @ColumnResult(name = "id", type = Long.class),
+ @ColumnResult(name = "title", type = String.class),
+ @ColumnResult(name = "author", type = String.class),
+ @ColumnResult(name = "isbn", type = String.class)
+ }
+ )
+)
+@Entity
+@Table(name = "book")
+public class Book {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Long id;
+ private String title;
+ private String author;
+ private String isbn;
+
+ public Book() {
+ }
+
+ public Book(Long id, String title, String author, String isbn) {
+ this.id = id;
+ this.title = title;
+ this.author = author;
+ this.isbn = isbn;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public String getAuthor() {
+ return author;
+ }
+
+ public void setAuthor(String author) {
+ this.author = author;
+ }
+
+ public String getIsbn() {
+ return isbn;
+ }
+
+ public void setIsbn(String isbn) {
+ this.isbn = isbn;
+ }
+
+}
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/records/BookRecord.java b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/records/BookRecord.java
new file mode 100644
index 0000000000..96968575d9
--- /dev/null
+++ b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/records/BookRecord.java
@@ -0,0 +1,4 @@
+package com.baeldung.recordswithjpa.records;
+
+public record BookRecord(Long id, String title, String author, String isbn) {
+}
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/records/CustomBookRecord.java b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/records/CustomBookRecord.java
new file mode 100644
index 0000000000..35e9be9513
--- /dev/null
+++ b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/records/CustomBookRecord.java
@@ -0,0 +1,4 @@
+package com.baeldung.recordswithjpa.records;
+
+public record CustomBookRecord(Long id, String title) {
+}
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/repository/BookRepository.java b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/repository/BookRepository.java
new file mode 100644
index 0000000000..4ef5f17296
--- /dev/null
+++ b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/repository/BookRepository.java
@@ -0,0 +1,17 @@
+package com.baeldung.recordswithjpa.repository;
+
+import com.baeldung.recordswithjpa.entity.Book;
+import com.baeldung.recordswithjpa.records.BookRecord;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.CrudRepository;
+import org.springframework.data.repository.query.Param;
+
+import java.util.List;
+
+public interface BookRepository extends CrudRepository {
+ List findBookByAuthor(String author);
+
+ @Query("SELECT new com.baeldung.recordswithjpa.records.BookRecord(b.id, b.title, b.author, b.isbn) " +
+ "FROM Book b WHERE b.id = :id")
+ BookRecord findBookById(@Param("id") Long id);
+}
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/repository/CustomBookRepository.java b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/repository/CustomBookRepository.java
new file mode 100644
index 0000000000..bb8002d70d
--- /dev/null
+++ b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/repository/CustomBookRepository.java
@@ -0,0 +1,9 @@
+package com.baeldung.recordswithjpa.repository;
+
+import com.baeldung.recordswithjpa.records.CustomBookRecord;
+
+import java.util.List;
+
+public interface CustomBookRepository {
+ List findAllBooks();
+}
diff --git a/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/repository/CustomBookRepositoryImpl.java b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/repository/CustomBookRepositoryImpl.java
new file mode 100644
index 0000000000..8d420a9874
--- /dev/null
+++ b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/repository/CustomBookRepositoryImpl.java
@@ -0,0 +1,20 @@
+package com.baeldung.recordswithjpa.repository;
+
+import com.baeldung.recordswithjpa.records.CustomBookRecord;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+@Repository
+public class CustomBookRepositoryImpl implements CustomBookRepository {
+ private final JdbcTemplate jdbcTemplate;
+
+ public CustomBookRepositoryImpl(JdbcTemplate jdbcTemplate) {
+ this.jdbcTemplate = jdbcTemplate;
+ }
+
+ public List findAllBooks() {
+ return jdbcTemplate.query("SELECT id, title FROM book", (rs, rowNum) -> new CustomBookRecord(rs.getLong("id"), rs.getString("title")));
+ }
+}
diff --git a/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/recordswithjpa/QueryServiceIntegrationTest.java b/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/recordswithjpa/QueryServiceIntegrationTest.java
new file mode 100644
index 0000000000..011895e7fa
--- /dev/null
+++ b/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/recordswithjpa/QueryServiceIntegrationTest.java
@@ -0,0 +1,39 @@
+package com.baeldung.recordswithjpa;
+
+import com.baeldung.recordswithjpa.entity.Book;
+import com.baeldung.recordswithjpa.records.BookRecord;
+import com.baeldung.recordswithjpa.repository.BookRepository;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+public class QueryServiceIntegrationTest extends RecordsAsJpaIntegrationTest {
+
+ @Autowired
+ private QueryService queryService;
+
+
+ @Test
+ void findAllBooks() {
+ List allBooks = queryService.findAllBooks();
+ assertEquals(3, allBooks.size());
+ }
+
+ @Test
+ void findBookById() {
+ BookRecord bookById = queryService.findBookById(1L);
+ assertEquals("The Lord of the Rings", bookById.title());
+ }
+
+ @Test
+ void findAllBooksUsingMapping() {
+ List allBooksUsingMapping = queryService.findAllBooksUsingMapping();
+ assertEquals(3, allBooksUsingMapping.size());
+ }
+}
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/recordswithjpa/RecordsAsJpaIntegrationTest.java b/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/recordswithjpa/RecordsAsJpaIntegrationTest.java
new file mode 100644
index 0000000000..f0869dad48
--- /dev/null
+++ b/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/recordswithjpa/RecordsAsJpaIntegrationTest.java
@@ -0,0 +1,30 @@
+package com.baeldung.recordswithjpa;
+
+import com.baeldung.recordswithjpa.entity.Book;
+import com.baeldung.recordswithjpa.repository.BookRepository;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+public class RecordsAsJpaIntegrationTest {
+ @Autowired
+ protected BookRepository bookRepository;
+
+ @BeforeEach
+ void setUp() {
+ Book book = new Book(1L,"The Lord of the Rings", "J.R.R. Tolkien", "978-0544003415");
+ Book book2 = new Book(2L,"The Hobbit", "J.R.R. Tolkien", "978-0547928227");
+ Book book3 = new Book(3L,"Harry Potter and the Philosopher's Stone", "J.K. Rowling", "978-0747532699");
+
+ bookRepository.save(book);
+ bookRepository.save(book2);
+ bookRepository.save(book3);
+ }
+
+ @AfterEach
+ void tearDown() {
+ bookRepository.deleteAll();
+ }
+}
diff --git a/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/recordswithjpa/repository/BookRepositoryIntegrationTest.java b/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/recordswithjpa/repository/BookRepositoryIntegrationTest.java
new file mode 100644
index 0000000000..9173fea269
--- /dev/null
+++ b/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/recordswithjpa/repository/BookRepositoryIntegrationTest.java
@@ -0,0 +1,19 @@
+package com.baeldung.recordswithjpa.repository;
+
+import com.baeldung.recordswithjpa.RecordsAsJpaIntegrationTest;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class BookRepositoryIntegrationTest extends RecordsAsJpaIntegrationTest {
+
+ @Test
+ void findBookByAuthor() {
+ assertEquals(2, bookRepository.findBookByAuthor("J.R.R. Tolkien").size());
+ }
+
+ @Test
+ void findBookById() {
+ assertEquals("The Lord of the Rings", bookRepository.findBookById(1L).title());
+ }
+}
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/recordswithjpa/repository/CustomBookRepositoryIntegrationTest.java b/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/recordswithjpa/repository/CustomBookRepositoryIntegrationTest.java
new file mode 100644
index 0000000000..866645429a
--- /dev/null
+++ b/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/recordswithjpa/repository/CustomBookRepositoryIntegrationTest.java
@@ -0,0 +1,23 @@
+package com.baeldung.recordswithjpa.repository;
+
+import com.baeldung.recordswithjpa.RecordsAsJpaIntegrationTest;
+import com.baeldung.recordswithjpa.records.CustomBookRecord;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class CustomBookRepositoryIntegrationTest extends RecordsAsJpaIntegrationTest {
+
+ @Autowired
+ private CustomBookRepository customBookRepository;
+
+ @Test
+ void findAllBooks() {
+ List allBooks = customBookRepository.findAllBooks();
+ assertEquals(3, allBooks.size());
+ }
+}
\ No newline at end of file