Spring Boot එක්ක MyBatis – Database Operations ලේසි කරන හැටි | SC Guide

හෙලෝ යාලුවනේ! කොහොමද ඉතින් ඔයාලට? අද අපි කතා කරන්න යන්නේ ගොඩක් වැදගත්, ඒ වගේම අපේ Software Development ගමනේදී නිතරම වගේ හම්බවෙන මාතෘකාවක් ගැන. ඒ තමයි Spring Boot එක්ක MyBatis Integrarte කරලා වැඩ කරන්නේ කොහොමද කියන එක. ලංකාවේ IT ෆීල්ඩ් එකේ, විශේෂයෙන් Java Development පැත්තට යන අයට මේක හොඳටම වටිනවා, මොකද ගොඩක් කම්පැනිවල මේ දෙක එකට පාවිච්චි කරනවා දැකලා ඇති.
අපි දන්නවානේ Spring Boot කියන්නේ මොනතරම් පහසු වේදිකාවක්ද කියලා. ඉක්මනට Microservices හදන්න, REST APIs ලියන්න, Web Applications දියුණු කරන්න මේකේ තියෙන Auto-configuration, Starter dependencies වගේ දේවල් නිසා අපේ වැඩ ගොඩක් ලේසි වෙනවා. හැබැයි, Database operations වලදී, සමහරුන්ට JPA/Hibernate වගේ ORM tools ටිකක් සංකීර්ණ වෙන්න පුළුවන්, නැත්තම් තමන්ට ඕන විදිහට SQL queries ලියන්න අවස්ථාවක් නැති වෙනවා කියලා හිතෙන්නත් පුළුවන්.
අන්න ඒ වෙලාවට තමයි MyBatis කියන කෙනා ගේමට එන්නේ. MyBatis කියන්නේ Java ORM එකක් වුණත්, මේක ORM එකකට වැඩිය SQL Mapper එකක් කියන එක තමයි හරියටම ගැලපෙන්නේ. මොකද මේකෙන් අපිට පුළුවන් SQL queries අපිට ඕන විදිහට, Full Control එකක් ඇතුව ලියන්න. ඉතින් මේ දෙක එකතු වුණාම මොන තරම් පවර්ෆුල්ද කියලා අපි අද බලමු.
අපි මේ Post එකේදී Spring Boot Project එකක් හදලා, ඒකට MyBatis Integrate කරලා, පොඩි CRUD (Create, Read, Update, Delete) Application එකක් හදන්නයි හදන්නේ. මේක ඔයාලට ඔයාලගේම Project වලට පාවිච්චි කරන්න හොඳ ආරම්භයක් වෙයි කියලා මම විශ්වාස කරනවා.
මොකක්ද මේ Spring Boot & MyBatis?
Spring Boot
Spring Boot කියන්නේ Spring Framework එකේම Extension එකක්. මේකේ ප්රධානම අරමුණ තමයි Production-ready Spring Applications ඉක්මනට හදන්න පුළුවන් විදිහට සරල කරන එක. මේකේ තියෙන විශේෂාංග කිහිපයක් මෙන්න:
- Auto-configuration: ඔයාලා Project එකට Add කරන Dependencies අනුව, Spring Boot එකෙන් අවශ්ය Configuration ටික Auto generate කරනවා. අතින් XML files ලියන්න, Complex configurations කරන්න ඕනේ නැහැ.
- Starter Dependencies: Common functionalities (e.g., Web, Data JPA, Security) වලට අදාළව group කරපු Dependencies set එකක් මේකෙන් දෙනවා. උදාහරණයක් විදිහට,
spring-boot-starter-web
කියන්නේ Web Applications වලට ඕන හැම dependency එකක්ම එකට දාපු එකක්. - Embedded Servers: Tomcat, Jetty, Undertow වගේ Servers, JAR file එක ඇතුලෙන්ම Run කරන්න පුළුවන්. වෙනම Server එකක් Install කරලා Deploy කරන්න ඕනේ නැහැ.
- Actuator: Production-ready features (Monitoring, Health checks, Metrics) වගේ දේවල් මේකෙන් දෙනවා.
MyBatis
MyBatis කියන්නේ SQL, stored procedures, සහ advanced mappings භාවිතයෙන් relational databases එක්ක වැඩ කරන්න පුළුවන් Persistence Framework එකක්. මේක JPA/Hibernate වගේ Full-fledged ORM එකක් නෙවෙයි. මේක Database Abstraction එකක් දෙනවා, ඒත් SQL queries ලියන්න තියෙන නිදහස සම්පූර්ණයෙන්ම අපිට දෙනවා.
MyBatis වල ප්රධානම විශේෂාංග:
- SQL Flexibility: ඔබට අවශ්ය පරිදි SQL queries ලියන්න පුළුවන්. Complex joins, stored procedures, database-specific functions වගේ දේවල් පහසුවෙන් භාවිත කරන්න පුළුවන්.
- Mapping XMLs or Annotations: SQL queries Mapper Interfaces වලම Annotations විදිහට හෝ වෙනම XML files වල ලියන්න පුළුවන්. Large projects වලට XML files භාවිත කරන එක වඩා හොඳයි, මොකද SQL වෙනම තියෙන නිසා Code එක Maintain කරන්න ලේසියි.
- Dynamic SQL: Conditions, loops, foreach වගේ දේවල් පාවිච්චි කරලා Dynamic SQL queries හදන්න පුළුවන්. (e.g.,
<if>
,<where>
,<foreach>
). - Caching: Performance වැඩි කරගන්න First-level සහ Second-level Caching support කරනවා.
ඇයි Spring Boot එක්ක MyBatis?
අපි දන්නවා Spring Data JPA කියන්නේ Spring Boot එක්ක Data Access Layer එක Handle කරන්න තියෙන ජනප්රියම විකල්පය කියලා. හැබැයි සමහර වෙලාවට අපිට JPA වලින් Handle කරන්න අමාරු වෙන Complex SQL queries හෝ Database-specific functions පාවිච්චි කරන්න වෙනවා. ඒ වගේම, සමහර developersලා JPA වල auto-generated queries වලට වඩා තමන්ටම SQL queries ලියලා Database operations වල Full control එකක් ගන්න කැමතියි.
අන්න ඒ වගේ අවස්ථාවලට MyBatis තමයි හොඳම විසඳුම. Spring Boot එකේ Simplicity එකයි, MyBatis වල SQL Flexibility එකයි එකතු වුණාම, වේගයෙන් Development කරන්න පුළුවන්, ඒ වගේම Performance Optimized Database operations තියෙන Applications හදන්න පුළුවන් වෙනවා. මේ සංකලනය (Combination) ගොඩක් Enterprises වල ජනප්රියයි, විශේෂයෙන්ම දැනටමත් Existing Databases එක්ක වැඩ කරන Projects වලදී. ඒ වගේම Microservices Architecture වලදී, Microservice එකකට තමන්ටම Specific Data Access Strategy එකක් තෝරාගන්න පුළුවන් නිසා, Spring Boot එක්ක MyBatis කියන Combination එක හොඳටම ගැලපෙනවා.
CRUD App එකක් ගහමු! (Building a CRUD App)
හරි, දැන් අපි theoretical පැත්ත ඇති තරම් කතා කරා. දැන් අපි practical පැත්තට යමු. අපි හදමු Product Management System එකක්. මේකෙන් Product එකක් Add කරන්න, View කරන්න, Update කරන්න, Delete කරන්න පුළුවන් වෙන්න ඕනේ.
Step 1: Project Setup
මුලින්ම අපි Spring Initializr (start.spring.io) එකට ගිහින් අපිට ඕන Project එක හදාගමු. මේකේදී මේ Dependencies ටික තෝරගන්න:
- Spring Web
- Spring Data JDBC (මේකෙන් Database Connection, Transaction Management වගේ දේවල් වලට අවශ්ය Infrastructure හදලා දෙනවා)
- MyBatis Spring Boot Starter
- H2 Database (අපි Simple Project එකක් හදන නිසා In-memory Database එකක් විදිහට H2 පාවිච්චි කරමු. ඔයාලට MySQL, PostgreSQL වගේ ඒවා වුණත් පාවිච්චි කරන්න පුළුවන්.)
Project එක Generate කරලා, Download කරලා, ඔයාලගේ IDE (IntelliJ IDEA, VS Code, Eclipse) එකෙන් Open කරගන්න.
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId&n> <artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
Step 2: Database Configuration & Schema
src/main/resources/application.properties
file එකට H2 Database එකට අදාළ Configuration ටික දාගමු.
spring.datasource.url=jdbc:h2:mem:productsdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.h2.console.enabled=true
# MyBatis configuration
mybatis.mapper-locations=classpath*:mapper/*.xml
mybatis.configuration.map-underscore-to-camel-case=true
දැන් අපි Database Schema එකක් හදමු. src/main/resources/schema.sql
කියන file එක හදලා මේ ටික දාගන්න:
CREATE TABLE IF NOT EXISTS products (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
price DECIMAL(10, 2) NOT NULL
);
Step 3: Model Class
අපි Product එකක් Represent කරන්න Java Class එකක් හදමු. com.example.springbootmybatis.model.Product
විදිහට file එක හදලා මේ code එක දාගන්න:
package com.example.springbootmybatis.model;
public class Product {
private Long id;
private String name;
private double price;
// Constructors
public Product() {
}
public Product(Long id, String name, double price) {
this.id = id;
this.name = name;
this.price = price;
}
// Getters and Setters
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
@Override
public String toString() {
return "Product{" +
"id=" + id +
", name='" + name + '\'' +
", price=" + price +
'}';
}
}
Step 4: MyBatis Mapper Interface
MyBatis වලදී Database operations handle කරන්න Mapper Interfaces පාවිච්චි කරනවා. අපි com.example.springbootmybatis.mapper.ProductMapper
කියන Interface එක හදලා, ඒකේ අපිට ඕන methods define කරමු.
package com.example.springbootmybatis.mapper;
import com.example.springbootmybatis.model.Product;
import org.apache.ibatis.annotations.*;
import java.util.List;
@Mapper // This annotation tells Spring to create a bean for this interface
public interface ProductMapper {
@Select("SELECT id, name, price FROM products WHERE id = #{id}")
Product findById(Long id);
@Select("SELECT id, name, price FROM products")
List<Product> findAll();
@Insert("INSERT INTO products(name, price) VALUES(#{name}, #{price})")
@Options(useGeneratedKeys = true, keyProperty = "id") // For auto-generated ID
int insert(Product product);
@Update("UPDATE products SET name = #{name}, price = #{price} WHERE id = #{id}")
int update(Product product);
@Delete("DELETE FROM products WHERE id = #{id}")
int delete(Long id);
}
මෙහිදී, අපි `@Mapper` annotation එක පාවිච්චි කරලා තියෙනවා Spring Boot එකට මේ Interface එක MyBatis Mapper එකක් විදිහට recognize කරන්න කියලා. ඊට අමතරව, `@Select`, `@Insert`, `@Update`, `@Delete` වගේ Annotations පාවිච්චි කරලා Direct SQL queries ලියන්න පුළුවන්. Simple queries වලට මේක ගොඩක් පහසුයි.
සටහන: Complex SQL queries වලට සහ Dynamic SQL වලට XML Mappers පාවිච්චි කරන එක වඩා හොඳයි. අපි දැන් XML Mapper එකක් හදමු.
Step 5: MyBatis XML Mapper (Alternative to Annotations)
XML Mapper එකක් හදන්න, src/main/resources
Folder එක ඇතුලේ mapper
කියලා අලුත් Folder එකක් හදලා, ඒක ඇතුලේ ProductMapper.xml
කියන file එක හදන්න.
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.springbootmybatis.mapper.ProductMapper">
<resultMap id="productResultMap" type="com.example.springbootmybatis.model.Product">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="price" column="price"/>
</resultMap>
<select id="findById" parameterType="Long" resultMap="productResultMap">
SELECT id, name, price FROM products WHERE id = #{id}
</select>
<select id="findAll" resultMap="productResultMap">
SELECT id, name, price FROM products
</select>
<insert id="insert" parameterType="com.example.springbootmybatis.model.Product" useGeneratedKeys="true" keyProperty="id">
INSERT INTO products(name, price) VALUES(#{name}, #{price})
</insert>
<update id="update" parameterType="com.example.springbootmybatis.model.Product">
UPDATE products SET name = #{name}, price = #{price} WHERE id = #{id}
</update>
<delete id="delete" parameterType="Long">
DELETE FROM products WHERE id = #{id}
</delete>
</mapper>
මේ XML file එකේ namespace
එක අපේ ProductMapper Interface එකට Match වෙන්න ඕනේ. id
attribute එක Interface එකේ Method නමට Match වෙන්න ඕනේ. resultMap
එකෙන් කියන්නේ Database Column Name එක Java Object එකේ Property Name එකට Map කරන්නේ කොහොමද කියලා. #{id}
, #{name}
වගේ දේවල් වලින් කියන්නේ Prepared Statement එකකට Parameter එකක් Pass කරන හැටි.
Tip: ඔයාලා XML Mappers පාවිච්චි කරනවා නම්, ProductMapper.java
Interface එකේ Annotations අයින් කරන්න පුළුවන්. MyBatis Spring Boot Starter එකෙන් Auto-scan කරලා XML එකේ SQL ටික Interface එකේ Methods වලට බඳිනවා. හැබැයි, @Mapper
annotation එක නම් තියෙන්න ඕනේ.
Step 6: Service Layer
දැන් අපි Service Layer එක හදමු. මේකෙන් Business Logic ටික Handle කරනවා. com.example.springbootmybatis.service.ProductService
කියන Class එක හදලා මේ code එක දාගන්න:
package com.example.springbootmybatis.service;
import com.example.springbootmybatis.mapper.ProductMapper;
import com.example.springbootmybatis.model.Product;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class ProductService {
private final ProductMapper productMapper;
public ProductService(ProductMapper productMapper) {
this.productMapper = productMapper;
}
public List<Product> getAllProducts() {
return productMapper.findAll();
}
public Product getProductById(Long id) {
return productMapper.findById(id);
}
public int addProduct(Product product) {
return productMapper.insert(product);
}
public int updateProduct(Product product) {
return productMapper.update(product);
}
public int deleteProduct(Long id) {
return productMapper.delete(id);
}
}
Step 7: Controller Layer
අවසානයට, අපි REST API Endpoints ටික හදමු. com.example.springbootmybatis.controller.ProductController
කියන Class එක හදලා මේ code එක දාගන්න:
package com.example.springbootmybatis.controller;
import com.example.springbootmybatis.model.Product;
import com.example.springbootmybatis.service.ProductService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/products")
public class ProductController {
private final ProductService productService;
public ProductController(ProductService productService) {
this.productService = productService;
}
@GetMapping
public ResponseEntity<List<Product>> getAllProducts() {
List<Product> products = productService.getAllProducts();
return new ResponseEntity<>(products, HttpStatus.OK);
}
@GetMapping("/{id}")
public ResponseEntity<Product> getProductById(@PathVariable Long id) {
Product product = productService.getProductById(id);
if (product != null) {
return new ResponseEntity<>(product, HttpStatus.OK);
} else {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
}
@PostMapping
public ResponseEntity<String> addProduct(@RequestBody Product product) {
int result = productService.addProduct(product);
if (result > 0) {
return new ResponseEntity<>("Product added successfully! ID: " + product.getId(), HttpStatus.CREATED);
} else {
return new ResponseEntity<>("Failed to add product.", HttpStatus.INTERNAL_SERVER_ERROR);
}
}
@PutMapping("/{id}")
public ResponseEntity<String> updateProduct(@PathVariable Long id, @RequestBody Product product) {
Product existingProduct = productService.getProductById(id);
if (existingProduct != null) {
product.setId(id); // Ensure the ID from path variable is used
int result = productService.updateProduct(product);
if (result > 0) {
return new ResponseEntity<>("Product updated successfully!", HttpStatus.OK);
} else {
return new ResponseEntity<>("Failed to update product.", HttpStatus.INTERNAL_SERVER_ERROR);
}
} else {
return new ResponseEntity<>("Product not found.", HttpStatus.NOT_FOUND);
}
}
@DeleteMapping("/{id}")
public ResponseEntity<String> deleteProduct(@PathVariable Long id) {
int result = productService.deleteProduct(id);
if (result > 0) {
return new ResponseEntity<>("Product deleted successfully!", HttpStatus.OK);
} else {
return new ResponseEntity<>("Product not found or failed to delete.", HttpStatus.NOT_FOUND);
}
}
}
Step 8: Enable MyBatis Mapper Scanning
අවසානයට, අපේ Main Application Class එකේ @MapperScan
annotation එකෙන් MyBatis Mappers තියෙන Package එක Scan කරන්න කියලා Spring Boot එකට කියන්න ඕනේ. SpringBootMybatisApplication.java
file එකට මේක Add කරගන්න:
package com.example.springbootmybatis;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.example.springbootmybatis.mapper") // Scan for MyBatis Mappers
public class SpringBootMybatisApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootMybatisApplication.class, args);
}
}
දැන් Project එක Run කරලා බලන්න. ඔයාලට Postman, Insomnia වගේ tool එකක් පාවිච්චි කරලා මේ APIs ටෙස්ට් කරන්න පුළුවන්. H2 Console එක http://localhost:8080/h2-console
එකෙන් access කරන්න පුළුවන් (Username: sa, Password: <empty>). Database එකේ data ටික check කරන්නත් පුළුවන්.
උදාහරණ REST API Calls:
- Add Product:
POST http://localhost:8080/api/products
(Body:{"name":"Laptop", "price":1200.00}
) - Get All Products:
GET http://localhost:8080/api/products
- Get Product by ID:
GET http://localhost:8080/api/products/1
- Update Product:
PUT http://localhost:8080/api/products/1
(Body:{"id":1, "name":"Gaming Laptop", "price":1500.00}
) - Delete Product:
DELETE http://localhost:8080/api/products/1
Tipස් ටිකක්! (A Few Tips!)
- Dynamic SQL: MyBatis වල තියෙන
<if>
,<where>
,<set>
,<trim>
,<foreach>
වගේ Elements පාවිච්චි කරලා Complex, Dynamic SQL queries ලියන්න පුළුවන්. මේවා හරිම වැදගත්, විශේෂයෙන් Search functions වගේ දේවල් හදනකොට. - Result Mapping:
<resultMap>
කියන Element එකෙන් Database Column names සහ Java Object Property names අතර mapping එක customize කරන්න පුළුවන්. මේකෙන් DB column names camelCase නැතිව underscore_case වගේ ඒවා වුණත් Java object එකට හරියට map කරගන්න පුළුවන්. (අපි application.properties එකේmybatis.configuration.map-underscore-to-camel-case=true
දැම්මම ඕක automatically කරනවා, නමුත් Complex scenarios වලට resultMap එක අවශ්ය වෙනවා). - Transactions: Spring Boot වල Default Transaction Management එක MyBatis එක්ක හොඳට වැඩ කරනවා. Service Layer එකේ Methods වලට
@Transactional
annotation එක දාන්න පුළුවන්. - Caching: MyBatis First-level Cache (SqlSession scope) සහ Second-level Cache (Mapper namespace scope) support කරනවා. Performance වැඩි කරගන්න මේවා පාවිච්චි කරන්න පුළුවන්.
- Type Handlers: Custom Java types (e.g., Enum types) Database types වලට Map කරන්න Type Handlers හදන්න පුළුවන්.
අවසන් වශයෙන්
ඉතින් යාලුවනේ, ඔයාලට දැන් හොඳ අවබෝධයක් තියෙනවා ඇති Spring Boot Application එකකට MyBatis Integrate කරලා Database operations කොහොමද Handle කරන්නේ කියලා. අපි හදපු මේ CRUD Application එක ඔයාලට ඔයාලගේම Project වලට modify කරලා පාවිච්චි කරන්න පුළුවන්. MyBatis වල තියෙන SQL Control එකයි, Spring Boot වල තියෙන Rapid Development පහසුකමයි එකතු වුණාම, ගොඩක් Effective Applications හදන්න පුළුවන් කියන එක ඔයාලට දැන් තේරෙනවා ඇති.
මේ වගේ තව Tech Tutorials බලන්න, අලුත් දේවල් ඉගෙන ගන්න අපේ Site එකත් එක්කම රැඳී සිටින්න. මේ Post එක ගැන ඔයාලගේ අදහස්, ප්රශ්න, යෝජනා පහළ Comment Section එකේ දාන්න අමතක කරන්න එපා. අපි ලබන Post එකෙන් හම්බවෙමු!
Happy Coding!