Spring Boot JOOQ: JPA වෙනුවට Type-Safe SQL Queries | SC Guide

ආයුබෝවන්, හැමෝටම!
අපි software development කරනකොට, විශේෂයෙන්ම Java Spring Boot project එකක් පටන් ගන්නකොට, data persistence layer එකට මුලින්ම මතක් වෙන්නේ මොකක්ද? ගොඩක් වෙලාවට JPA (Java Persistence API) හරි, ඒකේ implementation එකක් වෙන Hibernate හරි නේද? ඒක හොඳයි, මොකද ඒකෙන් boilerplate code ගොඩක් අඩු කරනවා, database operations ලේසි කරනවා. හැබැයි, ටිකක් complex queries ලියන්න ගියාම, හරි database එකේ Performance එක optimize කරන්න ගියාම, JPA 'magic' එක සමහර වෙලාවට අපිට කරදරයක් වෙනවා. "ඇත්තටම මේකෙන් running වෙන්නේ මොන SQL query එකද?" කියලා හොයන්න ඕන වෙනවා. තව Query DSL, Criteria API වගේ දේවල් තිබුණත්, ඒකෙන් SQL වලට තියෙන පාලනය අඩු වෙනවා වගේ හැඟීමක් එනවා.
අද අපි කතා කරන්න යන්නේ ඔය හැමදේටම නියම solution එකක් ගැන – ඒ තමයි JOOQ. JOOQ කියන්නේ SQL වලට ආදරය කරන, ඒ වගේම type-safe programming වලට කැමති අයට කියාපු tool එකක්. මේක ORM එකක් නෙවෙයි, හැබැයි SQL queries type-safe විදියට, compile-time errors අල්ලගන්න පුළුවන් විදියට ලියන්න උදව් කරනවා. මේ guide එකේදී අපි බලමු Spring Boot project එකක JPA වෙනුවට JOOQ කොහොමද පාවිච්චි කරන්නේ කියලා, ඒ වගේම database එකේ schema එකෙන් Java classes generate කරගෙන, ඒ class පාවිච්චි කරලා queries ලියන්නේ කොහොමද කියලත්.
එහෙනම්, අපි පටන් ගමුද?
JPA එක්ක තියෙන පොඩි 'ගැටළු' (JPA's little 'issues')
JPA කියන්නේ Java application එකක object-oriented domain model එක relational database එකකට map කරන්න උදව් කරන powerful framework එකක්. මේකෙන් අපිට Entity classes හදාගෙන, ඒ class වලට annotations දාලා database tables එක්ක map කරන්න පුළුවන්. JpaRepository
වගේ දේවල් නිසා, save()
, findById()
, findAll()
වගේ common database operations කරන්න පුදුමාකාර විදියට ලේසියි.
හැබැයි, හැමදේම හොඳ නැහැ කියලා කතාවක් තියෙනවනේ. JPA වලත් තියෙනවා පොඩි 'ගැටළු' කීපයක්, විශේෂයෙන්ම complex Enterprise level applications වලදී. බලමු මොනවද ඒ කියලා:
- N+1 Problem: මේක JPA වලදී ගොඩක් එන ප්රශ්නයක්. Eagerly fetching associations කරනකොට, database එකට අනවශ්ය queries ගොඩක් යනවා. ඒ වගේම Lazy loading නිසා application logic එක ඇතුලේ unexpected queries run වෙන්නත් පුළුවන්.
- SQL Control එක අඩු වීම: JPA වලදී අපි JPQL හරි Criteria API හරි පාවිච්චි කරනවා. මේවා SQL වගේ පෙනුනත්, database specific features, advanced query optimizations, hints වගේ දේවල් add කරන්න අමාරුයි. Native SQL queries ලියන්න පුළුවන් වුණත්, ඒවට type safety එකක් නැහැ, run-time errors එන්න තියෙන ඉඩකඩ වැඩියි.
- Type Safety නැතිවීම: අපි string-based JPQL queries හරි native SQL queries හරි ලියනකොට, column names, table names වගේ දේවල් ටයිප් කරනකොට පොඩි වැරැද්දක් වුණත් compile-time එකේදී අල්ලගන්න බැහැ. ඒ error එක එළියට එන්නේ application එක run කරලා, ඒ query එක execute වෙනකොට. Database schema එක වෙනස් වුණොත්, අපේ queries update කරන්නත් අමතක වෙන්න පුළුවන්, එතකොටත් run-time error තමයි.
- Debugging Difficulty: JPA වල 'magic' එක නිසා, අපේ application එකෙන් generate වෙන SQL queries මොනවද කියලා හොයන්න ටිකක් අමාරුයි. SQL logs enable කරලා බලන්න පුළුවන් වුණත්, complex operations වලදී ඒක කාලය කා දමන වැඩක්.
මේ ප්රශ්න නිසා තමයි අපිට තව විකල්පයක් ගැන හිතන්න සිද්ධ වෙන්නේ. එතනට තමයි JOOQ එන්නේ.
JOOQ කියන්නේ මොකක්ද? (What is JOOQ?)
JOOQ කියන්නේ JPA වගේ ORM එකක් නෙවෙයි. මේක තනිකරම SQL-centric query builder එකක්. ඒ කියන්නේ JOOQ වල මූලික අරමුණ වෙන්නේ SQL query එකක් Java code එකක් විදියට, type-safe විදියට ලියන්න පුළුවන් කරන එක. සරලවම කිව්වොත්, JOOQ කියන්නේ SQL වලටම හදපු Domain Specific Language (DSL) එකක්.
JOOQ වැඩ කරන්නේ මෙහෙමයි: අපි database schema එක JOOQ code generator එකට දෙනවා. එතකොට ඒකෙන් database tables, columns, constraints, stored procedures වගේ දේවල් වලට අදාළ Java classes generate කරනවා. PRODUCT
table එකක් තියෙනවා නම්, ඒකට අදාළ Product
class එකක් generate වෙනවා. PRODUCT
table එකේ ID
column එකට PRODUCT.ID
වගේ type-safe field එකක් generate වෙනවා.
දැන් අපිට පුළුවන් මේ generate කරපු classes පාවිච්චි කරලා SQL queries ලියන්න. උදාහරණයක් විදියට, SELECT * FROM PRODUCT WHERE ID = 1;
කියන query එක JOOQ වලින් dslContext.selectFrom(PRODUCT).where(PRODUCT.ID.eq(1)).fetch();
කියලා ලියන්න පුළුවන්. මෙතනදී PRODUCT
සහ PRODUCT.ID
කියන දෙකම Java code එකේ තියෙන objects නිසා, අපි වැරදි තැනක PRODUCT_ID
කියලා ටයිප් කළොත් compile-time error එකක් එනවා. මේක තමයි JOOQ වල ලොකුම වාසිය.
JOOQ වල වාසි:
- Type Safety: Database schema එකේ වෙනස්කම් වුණොත්, අපේ queries compile වෙන්නේ නැහැ. ඒ නිසා runtime errors වෙනුවට compile-time errors අල්ලගන්න පුළුවන්.
- Full SQL Power: JOOQ වලින් අපිට complex JOINs, subqueries, window functions, user-defined functions වගේ SQL features අංගසම්පූර්ණව පාවිච්චි කරන්න පුළුවන්. Database specific syntax වුණත් JOOQ support කරනවා.
- Code Generation: Database schema එකෙන් Java classes generate වීම නිසා manual mapping සහ boilerplate code ගොඩක් අඩු වෙනවා.
- Performance: ORMs වලදී වගේ layer එකක් නැති නිසා, සමහර අවස්ථා වලදී JOOQ වලින් execute වෙන queries වල performance එක වඩා හොඳ වෙන්න පුළුවන්.
- Spring Boot Integration: JOOQ Spring Boot එක්ක integrate කරන්න පුළුවන් ඉතාම ලේසියෙන්. Spring Boot starter for JOOQ එකෙන් අවශ්ය configuration බොහොමයක් automacially handle කරනවා.
Project Setup එකයි JOOQ Code Generation එකයි (Project Setup & JOOQ Code Generation)
Spring Boot project එකක JOOQ පාවිච්චි කරන්න නම්, මුලින්ම Project setup එක හදාගන්න ඕනේ. අපි මේකට Maven පාවිච්චි කරනවා. Gradle වුණත් පුළුවන්, හැබැයි මේ example එකේදී අපි Maven එක්ක වැඩ කරමු.
1. Dependencies එකතු කරමු:
ඔයාගේ pom.xml
file එකට පහත dependencies ටික add කරන්න:
<dependencies>
<!-- Spring Boot Starter Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Boot Starter for JOOQ (Includes spring-boot-starter-jdbc) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jooq</artifactId>
</dependency>
<!-- Database Driver (අපි මෙතන H2 database එකක් පාවිච්චි කරමු) -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<!-- Spring Boot Starter Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
2. Database Configuration එක:
application.properties
(හෝ application.yml
) file එකේ database connection details add කරන්න. අපි මෙතන H2 in-memory database එකක් පාවිච්චි කරන නිසා configuration එක පහසුයි:
spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.jooq.sql-dialect=H2
spring.h2.console.enabled=true
spring.jooq.sql-dialect
කියන එක අනිවාර්යයි, මොකද JOOQ එකට කියන්න ඕනේ අපි පාවිච්චි කරන්නේ මොන database එකද කියලා, ඒ අනුව තමයි JOOQ SQL queries generate කරන්නේ.
3. Database Schema එක (Schema.sql):
අපි src/main/resources
folder එකේ schema.sql
කියලා file එකක් හදලා අපේ database schema එක define කරමු. Spring Boot application එක start වෙනකොට මේ SQL file එක automatically run වෙනවා.
CREATE TABLE IF NOT EXISTS PRODUCT (
ID INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(255) NOT NULL,
DESCRIPTION VARCHAR(500),
PRICE DECIMAL(10, 2) NOT NULL
);
INSERT INTO PRODUCT (NAME, DESCRIPTION, PRICE) VALUES ('Laptop', 'High-performance laptop', 1200.00);
INSERT INTO PRODUCT (NAME, DESCRIPTION, PRICE) VALUES ('Mouse', 'Wireless ergonomic mouse', 25.50);
INSERT INTO PRODUCT (NAME, DESCRIPTION, PRICE) VALUES ('Keyboard', 'Mechanical keyboard with RGB', 75.00);
4. JOOQ Code Generation:
මේක තමයි JOOQ වල වැදගත්ම කොටස. අපි මේ සඳහා Maven plugin එකක් පාවිච්චි කරනවා. pom.xml
එකේ <build>
section එකට පහත plugin එක add කරන්න:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<!-- JOOQ Code Generation Plugin -->
<plugin>
<groupId>org.jooq</groupId>
<artifactId>jooq-codegen-maven</artifactId>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
<dependencies>
<!-- Database Driver for JOOQ Code Generation -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>2.2.224</version> <!-- H2 version එක project dependency එකේ වගේම Match වෙන්න ඕනේ -->
</dependency>
</dependencies>
<configuration>
<generator>
<database>
<inputSchema>PUBLIC</inputSchema> <!-- H2 වල default schema එක PUBLIC -->
<includes>.*</includes>
<excludes></excludes>
<forcedTypes>
<forcedType>
<userType>java.math.BigDecimal</userType>
<sqlTypes>DECIMAL</sqlTypes>
</forcedType>
</forcedTypes>
</database>
<generate>
<pojos>true</pojos> <!-- POJOs generate කරන්න -->
<daos>true</daos> <!-- DAOs generate කරන්න (optional) -->
<records>true</records>
<immutablePojos>true</immutablePojos> <!-- Immutable POJOs (optional) -->
<jpaAnnotations>false</jpaAnnotations>
</generate>
<target>
<packageName>com.example.jooqdemo.jooq.generated</packageName> <!-- Generate වෙන classes වල package එක -->
<directory>${project.build.directory}/generated-sources/jooq</directory> <!-- Generated files save වෙන directory එක -->
</target>
</generator>
</configuration>
</plugin>
</plugins>
</build>
මේ configuration එකෙන් කියන්නේ Maven build කරනකොට H2 database එකට connect වෙලා, PUBLIC
schema එකේ තියෙන හැම table එකකින්ම (includes
) Java classes generate කරන්න කියලා. ඒ class com.example.jooqdemo.jooq.generated
package එකට target/generated-sources/jooq
කියන directory එකේ generate වෙනවා.
දැන් ඔයාට පුළුවන් command line එකේ mvn clean install
(හෝ IDE එකෙන් Maven -> Generate Sources) run කරන්න. එතකොට ඔයාගේ project එකේ target/generated-sources/jooq
folder එක ඇතුලේ com.example.jooqdemo.jooq.generated.tables.records.ProductRecord
, com.example.jooqdemo.jooq.generated.tables.Product
වගේ files generate වෙලා තියෙනවා.
com.example.jooqdemo.jooq.generated.tables.Product
කියන class එක තමයි අපිට queries ලියනකොට පාවිච්චි කරන්න පුළුවන් PRODUCT
table එක නියෝජනය කරන object එක.
JPA Repository එක JOOQ වලින් ආදේශ කරමු (Replacing JPA Repository with JOOQ)
දැන් අපි බලමු JPA repository එකක් JOOQ පාවිච්චි කරලා ආදේශ කරන්නේ කොහොමද කියලා. අපි හිතමු අපිට Product
entity එකක් තියෙනවා කියලා:
package com.example.jooqdemo.model;
import java.math.BigDecimal;
public class Product {
private Integer id;
private String name;
private String description;
private BigDecimal price;
// Constructors, Getters, Setters
public Product() {}
public Product(Integer id, String name, String description, BigDecimal price) {
this.id = id;
this.name = name;
this.description = description;
this.price = price;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public BigDecimal getPrice() {
return price;
}
public void setPrice(BigDecimal price) {
this.price = price;
}
}
සාමාන්යයෙන් JPA එක්ක නම් මේකට ProductRepository extends JpaRepository<Product, Integer>
කියලා repo එකක් හදනවනේ. දැන් ඒක වෙනුවට අපි JOOQ පාවිච්චි කරමු. අපිට `ProductRepository` එකක් වෙනුවට ProductService
එකක් වගේ එකක් හදන්න පුළුවන්.
package com.example.jooqdemo.service;
import com.example.jooqdemo.model.Product;
import org.jooq.DSLContext;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
import java.math.BigDecimal;
// Import the generated JOOQ table
import static com.example.jooqdemo.jooq.generated.tables.Product.PRODUCT;
@Service
public class ProductService {
private final DSLContext dslContext; // JOOQ's main entry point
public ProductService(DSLContext dslContext) {
this.dslContext = dslContext;
}
public List<Product> findAllProducts() {
return dslContext.selectFrom(PRODUCT)
.fetchInto(Product.class); // Fetch results and map to Product POJO
}
public Optional<Product> findProductById(Integer id) {
return dslContext.selectFrom(PRODUCT)
.where(PRODUCT.ID.eq(id)) // Type-safe condition
.fetchOptionalInto(Product.class); // Fetch a single optional result
}
public Product saveProduct(Product product) {
if (product.getId() == null) {
// Insert new product
return dslContext.insertInto(PRODUCT)
.columns(PRODUCT.NAME, PRODUCT.DESCRIPTION, PRODUCT.PRICE)
.values(product.getName(), product.getDescription(), product.getPrice())
.returning(PRODUCT.ID) // Get the generated ID back
.fetchOneInto(Product.class);
} else {
// Update existing product
return dslContext.update(PRODUCT)
.set(PRODUCT.NAME, product.getName())
.set(PRODUCT.DESCRIPTION, product.getDescription())
.set(PRODUCT.PRICE, product.getPrice())
.where(PRODUCT.ID.eq(product.getId()))
.returning() // Return updated record (fetchInto might not work with returning() on update for all dbs)
.fetchOneInto(Product.class); // Or fetch into a ProductRecord and convert
}
}
public int deleteProductById(Integer id) {
return dslContext.deleteFrom(PRODUCT)
.where(PRODUCT.ID.eq(id))
.execute(); // Execute the delete statement
}
// Example of a more complex JOOQ query: Find products cheaper than a given price
public List<Product> findProductsCheaperThan(BigDecimal maxPrice) {
return dslContext.selectFrom(PRODUCT)
.where(PRODUCT.PRICE.lessThan(maxPrice))
.orderBy(PRODUCT.PRICE.desc())
.fetchInto(Product.class);
}
}
මේ ProductService
එක දිහා බලන්න. අපි DSLContext
කියන JOOQ object එක Spring dependency injection හරහා inject කරගන්නවා. මේක තමයි JOOQ queries execute කරන්න ප්රධානම object එක. PRODUCT
කියන එක generated class එකෙන් import කරගත්තු type-safe object එකක්. PRODUCT.ID
, PRODUCT.NAME
වගේ දේවල් compile-time එකේදීම check වෙනවා, ඒ නිසා වැරදි කරන්න තියෙන ඉඩකඩක් නැහැ.
saveProduct
method එකේදී බලන්න, අපි insertInto
සහ update
statements පාවිච්චි කරන හැටි. Database එකේ Auto-incrementing ID එකක් තියෙනවා නම්, returning(PRODUCT.ID)
පාවිච්චි කරලා inserted record එකේ ID එක ගන්න පුළුවන්. ඒ වගේම fetchInto(Product.class)
එකෙන් database එකෙන් එන data, අපේ custom Product
POJO එකට map කරනවා.
දැන් අපිට පුළුවන් මේ ProductService
එක අපේ Spring Boot Controller එකක inject කරලා use කරන්න:
package com.example.jooqdemo.controller;
import com.example.jooqdemo.model.Product;
import com.example.jooqdemo.service.ProductService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.math.BigDecimal;
import java.util.List;
@RestController
@RequestMapping("/products")
public class ProductController {
private final ProductService productService;
public ProductController(ProductService productService) {
this.productService = productService;
}
@GetMapping
public List<Product> getAllProducts() {
return productService.findAllProducts();
}
@GetMapping("/{id}")
public ResponseEntity<Product> getProductById(@PathVariable Integer id) {
return productService.findProductById(id)
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
@PostMapping
public Product createProduct(@RequestBody Product product) {
return productService.saveProduct(product);
}
@PutMapping("/{id}")
public ResponseEntity<Product> updateProduct(@PathVariable Integer id, @RequestBody Product product) {
product.setId(id); // Ensure the ID from path is used
Product updatedProduct = productService.saveProduct(product);
return ResponseEntity.ok(updatedProduct);
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteProduct(@PathVariable Integer id) {
int deletedRows = productService.deleteProductById(id);
if (deletedRows > 0) {
return ResponseEntity.noContent().build();
} else {
return ResponseEntity.notFound().build();
}
}
@GetMapping("/cheaperThan/{price}")
public List<Product> getProductsCheaperThan(@PathVariable BigDecimal price) {
return productService.findProductsCheaperThan(price);
}
}
මේ Controller එකත් සාමාන්ය Spring Boot Controller එකක් වගේමයි. හැබැයි මේක database operations වලට JPA repository එකක් වෙනුවට JOOQ-based ProductService
එකක් පාවිච්චි කරනවා.
වාසි සහ සීමාවන් (Advantages and Limitations)
ඕනෑම technology එකක් වගේම JOOQ වලත් තියෙනවා වාසි වගේම සීමාවන්. අපි ඒවා පොඩ්ඩක් බලමු.
වාසි:
- Unmatched Type Safety: මේක තමයි JOOQ වල ප්රධානම වාසිය. Database schema එකේ වෙනස්කම් වුණොත්, අපේ queries compile වෙන්නේ නැහැ. ඒ නිසා runtime errors වෙනුවට compile-time errors අල්ලගන්න පුළුවන්. මේකෙන් Development time එකේදී වැරදි අල්ලගන්න පුළුවන් වීම විශාල වාසියක්.
- Full SQL Power and Control: JOOQ SQL Standard එකට full support එකක් දෙනවා. ඒ වගේම database specific features, advanced query optimizations (e.g., hints), window functions, recursive queries, pivoting, UNNEST වගේ දේවල් පාවිච්චි කරන්න පුළුවන්. JPA වගේ ORMs වලට මේවා හසුරුවන්න අමාරුයි.
- Readability and Maintainability: JOOQ queries Java code වගේ පෙනුනත්, ඒවා SQL queries වලට ගොඩක් සමානයි. ඒ නිසා SQL දන්න developer කෙනෙක්ට මේ queries තේරුම් ගන්නත්, maintain කරන්නත් ලේසියි.
- Performance: ORMs වලදී වගේ entity tracking, dirty checking, caching වගේ දේවල් JOOQ වලට නැහැ. ඒ නිසා complex read operations වලදී JOOQ වලින් execute වෙන queries වල performance එක වඩා හොඳ වෙන්න පුළුවන්. Batch updates/inserts වගේ දේවලටත් JOOQ හරිම effective.
- No N+1 Problem (by design): JOOQ ORM එකක් නොවන නිසා, N+1 problem එකක් එන්නේ නැහැ. අපිට අවශ්ය දත්ත එක query එකකින් fetch කරගන්න පුළුවන්.
සීමාවන්:
- No Automatic Object Tracking/Caching: JPA වගේ ORMs වල තියෙන First-level cache, Second-level cache, object dirty checking, automatic relationship management වගේ දේවල් JOOQ වල නැහැ. මේවා අවශ්ය නම්, අපිට වෙනම implement කරන්න වෙනවා.
- Initial Setup Complexity: JOOQ code generation plugin එක configure කරන එක මුලින් පොඩ්ඩක් අමාරු වෙන්න පුළුවන්. Database schema එකෙන් code generate කරගන්න එක අලුත් concept එකක් වෙන්නත් පුළුවන්.
- Learning Curve: JPA හරි Hibernate හරි විතරක් පාවිච්චි කරපු අයට JOOQ වල SQL-centric approach එකට හුරු වෙන්න ටික කාලයක් යන්න පුළුවන්.
- Boilerplate for Simple CRUD: සරල CRUD operations වලට, JOOQ වලින් ලියන code එක JPA repository එකකින් ලියන code එකට වඩා ටිකක් දිග වැඩි වෙන්න පුළුවන්. (හැබැයි මේක type safety නිසා ලැබෙන trade-off එකක්.)
ඉතින්, JOOQ පාවිච්චි කරන්න ඕනේ ද නැද්ද කියන එක තීරණය වෙන්නේ ඔයාගේ project එකේ requirements මත. ඔයාට complex queries ලියන්න වෙනවා නම්, database specific features ඕනේ නම්, performance optimizations වැදගත් නම්, ඒ වගේම compile-time safety එකට කැමති නම්, JOOQ කියන්නේ නියම තේරීමක්. හැබැයි, සරල CRUD operations විතරක් තියෙන, වේගයෙන් develop කරන්න ඕන project එකකට JPA වඩා සුදුසු වෙන්න පුළුවන්. සමහර project වලදී JPA සහ JOOQ දෙකම එකට පාවිච්චි කරනවා, සරල operations වලට JPAත්, complex operations වලට JOOQත් පාවිච්චි කරනවා.
ඉතින් මොකද හිතන්නේ?
අපි මේ guide එකෙන් Spring Boot project එකක JOOQ කොහොමද integrate කරන්නේ, code generate කරන්නේ, ඒ වගේම JPA repository එකක් JOOQ services වලින් ආදේශ කරන්නේ කොහොමද කියලා බැලුවා. JOOQ කියන්නේ SQL වලට අවුරුදු ගාණක experience එකක් තියෙන senior developersලා අතරේ ගොඩක් ජනප්රිය වෙලා තියෙන tool එකක්. ඒකෙන් SQL වල full power එක Java code එකටම ගෙනත් දෙනවා, ඒ වගේම compile-time safety එකකුත් දෙනවා.
ඔයාට මේ ගැන අදහස් තියෙනවා නම්, පහලින් comment එකක් දාන්න. ඔයා JOOQ පාවිච්චි කරලා තියෙනවාද? නැත්නම් JPA වලටම හුරුද? මේ guide එක ඔයාට ප්රයෝජනවත් වුණා නම්, අනිවාර්යයෙන්ම මේ concepts ඔයාගේ project එකක try කරලා බලන්න. එතකොට තමයි මේකේ නියම වටිනාකම ඔයාට තේරෙන්නේ.
ඊළඟ guide එකෙන් හම්බවෙමු!