iBATIS এর Advanced Features এবং Customization

আইবাটিস (iBATIS) - Java Technologies

436

iBATIS (MyBatis) একটি শক্তিশালী SQL Mapping ফ্রেমওয়ার্ক যা Java objects এবং SQL queries এর মধ্যে সম্পর্ক স্থাপন করে। iBATIS বেশ কয়েকটি advanced features এবং customization options প্রদান করে যা ডেটাবেস ইন্টারঅ্যাকশনে আরও নমনীয়তা, কার্যকারিতা এবং কাস্টমাইজেশন সুবিধা প্রদান করে। এই ফিচারগুলো আপনাকে ডেটাবেসে SQL কুয়েরি চালানোর সময় আরো অধিক কাস্টম লজিক এবং পারফরম্যান্স টিউনিং সক্ষম করে।

এখানে আমরা iBATIS এর কিছু advanced features এবং customization options নিয়ে আলোচনা করব, যেমন: dynamic SQL, result mapping, type handlers, custom SQL statements, caching, এবং interceptors


1. Dynamic SQL in iBATIS

iBATIS-এ dynamic SQL তৈরির জন্য বিভিন্ন ট্যাগ ব্যবহৃত হয়, যা SQL কুয়েরি runtime-এ conditional logic এবং parameterized queries তৈরি করতে সহায়ক।

Dynamic SQL Tags:

  • <if>: শর্ত অনুযায়ী SQL অংশ যোগ বা বাদ করা হয়।
  • <choose>, <when>, <otherwise>: একাধিক শর্তের মধ্যে নির্বাচন করতে ব্যবহৃত হয়।
  • <trim>: SQL স্ট্রিংয়ের মধ্যে অপ্রয়োজনীয় অংশ কেটে ফেলা হয়।
  • <foreach>: লিস্ট বা অ্যারে থেকে একাধিক মানের জন্য SQL তৈরি করে।

Example: Dynamic SQL with <if> and <foreach>

<select id="getEmployees" resultType="com.example.model.Employee">
    SELECT id, name, salary
    FROM employees
    WHERE 1=1
    <if test="minSalary != null">
        AND salary >= #{minSalary}
    </if>
    <if test="maxSalary != null">
        AND salary <= #{maxSalary}
    </if>
    <if test="departments != null">
        AND department_id IN
        <foreach collection="departments" item="department" open="(" close=")" separator=",">
            #{department}
        </foreach>
    </if>
</select>

Explanation:

  • <if> ট্যাগ শর্ত অনুসারে SQL যোগ করে।
  • <foreach> লিস্ট থেকে একাধিক মান নিয়ে SQL এর IN কন্ডিশনে ব্যবহার করা হয়।

2. Result Mapping in iBATIS

iBATIS-এ resultMap ব্যবহার করে SQL কুয়েরির রেজাল্ট এবং Java objects এর মধ্যে সম্পর্ক স্থাপন করা হয়। resultMap ডেটাবেস টেবিলের কলাম এবং JavaBeans এর ফিল্ডগুলির মধ্যে ম্যাপিং নির্ধারণ করে।

Custom Result Mapping

<resultMap id="employeeResultMap" type="com.example.model.Employee">
    <id property="id" column="id"/>
    <result property="name" column="name"/>
    <result property="salary" column="salary"/>
    <association property="department" column="department_id" javaType="com.example.model.Department" select="getDepartmentById"/>
</resultMap>

Explanation:

  • <resultMap>: SQL কুয়েরি থেকে রিটার্ন করা ডেটা JavaBeans এর ফিল্ডগুলির সাথে ম্যাপ করা হয়।
  • <association>: সম্পর্কিত ডেটা (যেমন department) লোড করার জন্য subquery ব্যবহার করা হয়।

3. Type Handlers in iBATIS

iBATIS type handlers ব্যবহার করে custom data types এবং Java types এর মধ্যে কাস্টম ম্যাপিং তৈরি করতে সাহায্য করে। Type Handlers আপনার ডেটাবেসের SQL types এবং Java types এর মধ্যে ট্রান্সলেশন পরিচালনা করে।

Creating Custom Type Handlers

Example: Custom Type Handler

@MappedTypes(Date.class)
public class DateTypeHandler extends BaseTypeHandler<Date> {

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, Date parameter, JdbcType jdbcType) throws SQLException {
        ps.setTimestamp(i, new Timestamp(parameter.getTime()));
    }

    @Override
    public Date getNullableResult(ResultSet rs, String columnName) throws SQLException {
        Timestamp timestamp = rs.getTimestamp(columnName);
        return timestamp != null ? new Date(timestamp.getTime()) : null;
    }

    @Override
    public Date getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        Timestamp timestamp = rs.getTimestamp(columnIndex);
        return timestamp != null ? new Date(timestamp.getTime()) : null;
    }

    @Override
    public Date getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        Timestamp timestamp = cs.getTimestamp(columnIndex);
        return timestamp != null ? new Date(timestamp.getTime()) : null;
    }
}

Explanation:

  • Custom Type Handler: এখানে একটি কাস্টম টাইপ হ্যান্ডলার তৈরি করা হয়েছে যা Date টাইপের মানকে Timestamp এ পরিবর্তন করে ডেটাবেসে সেভ করে এবং রিটার্ন করার সময় Timestamp কে Date তে কনভার্ট করে।
  • @MappedTypes: এই অ্যানোটেশনটি টাইপ হ্যান্ডলারটি Date টাইপের জন্য ব্যবহৃত হবে এমনকি অন্যান্য Java types জন্যও।

4. Caching in iBATIS

iBATIS ক্যাশিং সিস্টেম ব্যবহার করে ডেটাবেস থেকে ডেটা দ্রুত লোড করতে সাহায্য করে, বিশেষ করে যখন একই ডেটা বার বার রিট্রিভ করা হয়। iBATIS first-level cache এবং second-level cache সমর্থন করে।

First-Level Cache (Default)

  • iBATIS সেশন-ভিত্তিক first-level cache সরবরাহ করে, যা SQL কুয়েরি একাধিক বার এক্সিকিউট করার পরিবর্তে একবার লোড করা ডেটা ব্যবহার করে।

Second-Level Cache Configuration

iBATIS-এ second-level cache সক্ষম করতে, cache এবং cache-ref ব্যবহার করা হয়। এটি ডেটাবেসে একাধিক SQL statements থেকে রিটার্ন করা ডেটা ক্যাশে সংরক্ষণ করতে সাহায্য করে।

Example: Configuring Second-Level Cache

<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
<cache-ref namespace="com.example.mapper.EmployeeMapper"/>

Explanation:

  • <cache>: এখানে EhcacheCache ব্যবহার করে সেকেন্ড-লেভেল ক্যাশে কনফিগার করা হয়েছে।
  • <cache-ref>: একটি namespace এর মাধ্যমে ক্যাশে রেফারেন্স করা হয়েছে যা EmployeeMapper এর জন্য ব্যবহৃত হবে।

5. Interceptors in iBATIS

iBATIS-এ interceptors ব্যবহৃত হয় SQL কুয়েরি বা database interactions এর আগে বা পরে কিছু কাস্টম লজিক সম্পাদন করার জন্য। আপনি ইন্টারসেপ্টর ব্যবহার করে লজিকাল অপারেশন, logging, security, বা transaction management ইত্যাদি কাজ করতে পারেন।

Example: Using an Interceptor

public class MyInterceptor implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // Custom logic before query execution
        System.out.println("Before query execution");

        Object result = invocation.proceed();

        // Custom logic after query execution
        System.out.println("After query execution");

        return result;
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
    }
}

Explanation:

  • Interceptor: এখানে একটি কাস্টম ইন্টারসেপ্টর তৈরি করা হয়েছে যা SQL কুয়েরি এক্সিকিউট হওয়ার আগে এবং পরে কাস্টম লজিক সম্পাদন করে।
  • intercept(): ইন্টারসেপ্টর দ্বারা কাস্টম লজিক সম্পাদিত হবে।
  • plugin(): এটি প্লাগইন তৈরি করার জন্য ব্যবহৃত হয়, যা SQL কুয়েরি প্রসেসিংয়ের উপর কাস্টম লজিক প্রয়োগ করে।

6. Custom SQL Statements in iBATIS

iBATIS-এ আপনি custom SQL statements ডিফাইন করতে পারেন এবং XML Mapper এর মধ্যে বিভিন্ন insert, update, select, এবং delete কুয়েরি কাস্টমাইজ করতে পারেন।

Example: Custom SQL Statement in iBATIS Mapper

<insert id="insertEmployee" parameterClass="com.example.model.Employee">
    INSERT INTO employees (name, salary)
    VALUES (#{name}, #{salary})
</insert>

Explanation:

  • <insert>: এই কাস্টম SQL কুয়েরি insertEmployee মেথডের মাধ্যমে employees টেবিলের জন্য নতুন রেকর্ড ইনসার্ট করে।

iBATIS (MyBatis) এর advanced features এবং customization options আপনাকে ডেটাবেস অপারেশনগুলোকে আরও শক্তিশালী, নমনীয় এবং পারফরম্যান্ট করে তুলতে সহায়ক। iBATIS-এ dynamic SQL, result mapping, type handlers, caching, interceptors, এবং custom SQL statements এর সাহায্যে আপনি SQL কুয়েরি এবং Java objects এর মধ্যে সম্পর্কের আরও উন্নত কাস্টমাইজেশন করতে পারবেন।

এই সব ফিচার ব্যবহার করে আপনি ডেটাবেস ইন্টারঅ্যাকশনের পারফরম্যান্স বৃদ্ধি করতে পারেন, কোডের নমনীয়তা বজায় রাখতে পারেন, এবং আরও সুনির্দিষ্ট ডেটাবেস অপারেশন পরিচালনা করতে পারবেন। iBATIS এর caching এবং interceptors এর মতো বৈশিষ্ট্যগুলি আপনার অ্যাপ্লিকেশনকে আরও কার্যকরী এবং স্কেলেবল করতে সাহায্য করবে।

Content added By

iBATIS (বর্তমানে MyBatis নামে পরিচিত) একটি SQL Mapping Framework যা Java objects এবং SQL স্টেটমেন্টগুলির মধ্যে সম্পর্ক তৈরি করে। এটি ডেটাবেসের সাথে Java অ্যাপ্লিকেশনগুলিকে সংযোগ স্থাপন করার জন্য SQL ভিত্তিক একটি টুল। MyBatis আপনাকে dynamic SQL, advanced mapping techniques, এবং complex queries পরিচালনা করতে সহায়তা করে, যা বড় এবং জটিল অ্যাপ্লিকেশনগুলিতে প্রয়োজনীয়।

এখানে আলোচনা করা হবে iBATIS/MyBatis এর কিছু Advanced SQL Mapping Techniques যা ডেটাবেস অপারেশনগুলিকে আরও কার্যকরী, নমনীয় এবং পারফরম্যান্স-বান্ধব করে তোলে।


1. Dynamic SQL

Dynamic SQL হল একটি পদ্ধতি যা SQL কুয়েরি গুলি রানটাইমে তৈরি বা কাস্টমাইজ করতে সক্ষম করে, যেমন যখন আপনি ডেটাবেসের শর্তাবলীর উপর ভিত্তি করে কুয়েরি তৈরি করতে চান। MyBatis এ ডাইনামিক SQL তৈরি করতে XML Mapper ফাইলের মধ্যে <if>, <choose>, <foreach>, <where> ট্যাগ ব্যবহার করা হয়।

Dynamic SQL Example (XML Mapper)

<select id="findEmployees" resultType="com.example.model.Employee">
    SELECT * FROM Employee
    <where>
        <if test="name != null">
            AND name = #{name}
        </if>
        <if test="department != null">
            AND department = #{department}
        </if>
        <if test="salary != null">
            AND salary > #{salary}
        </if>
    </where>
</select>

Explanation:

  • <where>: এটি WHERE ক্লজের জন্য ডাইনামিক শর্ত যোগ করতে ব্যবহৃত হয়। এটি প্রথম শর্তের জন্য WHERE যুক্ত করবে এবং পরবর্তী শর্তগুলির জন্য AND যোগ করবে।
  • <if>: একটি শর্ত ব্যবহার করে SQL অংশ যোগ করা হয় যদি নির্দিষ্ট প্যারামিটার দেওয়া থাকে।
  • <choose>: একাধিক শর্তের মধ্যে যেটি প্রথম সঠিক হবে তা SQL কুয়েরিতে যোগ হবে।
  • <foreach>: ব্যবহারকারী ইনপুটের একটি কালেকশন (যেমন একটি লিস্ট) ব্যবহার করে IN ক্লজ তৈরি করতে।

2. Result Mapping with Complex Types

MyBatis আপনাকে complex types বা nested objects ম্যানেজ করার জন্য একটি শক্তিশালী মেকানিজম প্রদান করে। একাধিক resultMap এর মাধ্যমে আপনি সম্পর্কিত Java objects এর মধ্যে ডেটা মেলাতে পারেন। resultMap ব্যবহার করে, আপনি SQL query এর ফলাফলগুলোকে Java ক্লাসের পলিমর্ফিক বা nested properties এর সাথে যুক্ত করতে পারেন।

Result Map Example for Complex Type Mapping

<resultMap id="employeeResultMap" type="com.example.model.Employee">
    <id property="id" column="id"/>
    <result property="name" column="name"/>
    <result property="department" column="department_id"/>
    <association property="department" column="department_id" javaType="com.example.model.Department"/>
</resultMap>

<select id="getEmployeeWithDepartment" resultMap="employeeResultMap">
    SELECT e.id, e.name, e.department_id, d.name AS department_name
    FROM Employee e
    JOIN Department d ON e.department_id = d.id
</select>

Explanation:

  • <association>: এটি ব্যবহার করা হয় যখন একটি টেবিলের কলাম থেকে সম্পর্কিত একটি অবজেক্টের nested mapping করা হয়।
  • resultMap: MyBatis-এ একাধিক সম্পর্কিত বা complex objects মেলাতে resultMap ব্যবহৃত হয়।
  • SQL Join: দুটি টেবিলের মধ্যে সম্পর্ক তৈরি করতে SQL JOIN ব্যবহার করা হয়েছে।

3. Using @Param for Multiple Parameters

MyBatis ইন্টারফেস মেথডে একাধিক প্যারামিটার পাস করার জন্য @Param অ্যানোটেশন ব্যবহার করা হয়। এটি SQL কুয়েরিতে সঠিকভাবে প্যারামিটার মেলাতে সাহায্য করে এবং dynamic SQL লেখার ক্ষেত্রে সহায়তা করে।

@Param Example

public interface EmployeeMapper {
    @Select("SELECT * FROM Employee WHERE name = #{name} AND salary > #{salary}")
    Employee findEmployeeByNameAndSalary(@Param("name") String name, @Param("salary") double salary);
}

Explanation:

  • @Param("name") এবং @Param("salary"): ইন্টারফেস মেথডের প্যারামিটারগুলিকে SQL কুয়েরিতে সঠিকভাবে পাস করতে এই অ্যানোটেশন ব্যবহার করা হয়।

4. Using foreach for IN Clause

MyBatis এ <foreach> ট্যাগ ব্যবহার করে আপনি একটি collection (যেমন লিস্ট বা অ্যারে) এর জন্য IN কুয়েরি তৈরি করতে পারেন। এটি বিশেষ করে সহায়ক যখন আপনি একাধিক মানের জন্য ডেটা খুঁজে বের করতে চান।

foreach Example for IN Clause

<select id="findEmployeesByIds" resultType="com.example.model.Employee">
    SELECT * FROM Employee
    WHERE id IN
    <foreach collection="ids" item="id" open="(" close=")" separator=",">
        #{id}
    </foreach>
</select>

Explanation:

  • <foreach>: এটি একটি লুপ যা IN কুয়েরির মধ্যে প্যারামিটারগুলি যোগ করতে ব্যবহার করা হয়। collection প্যারামিটারটি একটি লিস্ট বা অ্যারে হতে পারে।
  • open="(" close=")" separator=",": open এবং close ব্যবহার করে আপনি IN ক্লজের মধ্যে প্যারামিটারগুলি আবদ্ধ করতে পারেন, এবং separator দ্বারা কুয়েরির মধ্যে কমা যোগ করতে পারেন।

5. Handling Nested Queries with Subselects

MyBatis তে nested queries বা subselects ব্যবহার করে আপনি একটি কুয়েরির মধ্যে অন্য একটি কুয়েরি কল করতে পারেন। এটি complex reporting এবং aggregations এর জন্য উপকারী।

Subselect Example

<select id="getEmployeeWithSalary" resultType="com.example.model.Employee">
    SELECT id, name, (SELECT AVG(salary) FROM Salary WHERE employee_id = e.id) AS avg_salary
    FROM Employee e
</select>

Explanation:

  • Subselect: এটি একটি কুয়েরির মধ্যে অন্য একটি কুয়েরি চালানোর উদাহরণ, যেখানে Employee টেবিলের প্রতিটি রেকর্ডের জন্য সম্পর্কিত Salary টেবিলের গড় বেতন বের করা হচ্ছে।

6. Use of choose, when, otherwise for Conditional Logic

MyBatis তে <choose>, <when>, এবং <otherwise> ট্যাগ ব্যবহার করে আপনি কন্ডিশনাল SQL তৈরি করতে পারেন। এটি বিশেষভাবে উপকারী যখন আপনি একাধিক শর্তের মধ্যে যেকোনো একটি শর্ত পূর্ণ হলে SQL স্টেটমেন্ট তৈরি করতে চান।

choose, when, otherwise Example

<select id="findEmployeeByIdOrName" resultType="com.example.model.Employee">
    SELECT * FROM Employee
    <where>
        <choose>
            <when test="id != null">
                AND id = #{id}
            </when>
            <when test="name != null">
                AND name = #{name}
            </when>
            <otherwise>
                AND department = 'Unknown'
            </otherwise>
        </choose>
    </where>
</select>

Explanation:

  • <choose>: এটি একাধিক শর্তের মধ্যে যেটি প্রথম সত্য হবে তা অনুসারে SQL কোড তৈরি করবে।
  • <when>: একটি শর্ত যা SQL স্টেটমেন্টে যোগ করা হবে যদি প্যারামিটারটি সত্য হয়।
  • <otherwise>: যদি অন্য কোনো শর্ত পূর্ণ না হয়, তবে এটি একটি ডিফল্ট শর্ত হিসেবে ব্যবহার হবে।

7. Caching with MyBatis

MyBatis ক্যাশিং ব্যবস্থাপনা সমর্থন করে, যা আপনাকে ডেটাবেস অপারেশনগুলি cache করতে সাহায্য করে এবং পারফরম্যান্স উন্নত করতে সহায়তা করে। First-level cache (session scope) এবং Second-level cache (application scope) এর মধ্যে পার্থক্য রয়েছে।

Second-level Cache Example

<cache eviction="LRU" flushInterval="60000" size="512" readOnly="true"/>

Explanation:

  • eviction: ক্যাশের উপাদান সরানোর কৌশল (যেমন LRU - Least Recently Used)।
  • flushInterval: কত সময় পর পর ক্যাশ ফ্লাশ হবে।
  • size: ক্যাশের সর্বোচ্চ আকার।

iBATIS (MyBatis) তে Advanced SQL Mapping Techniques আপনাকে জটিল ডেটাবেস অপারেশন এবং কুয়েরি লেখার ক্ষমতা প্রদান করে। এর মাধ্যমে আপনি dynamic SQL, complex types, conditional logic, nested queries, এবং caching এর মতো শক্তিশালী ফিচারগুলি ব্যবহার করতে পারবেন। MyBatis এর এ ধরনের ফিচারগুলি আপনাকে অধিক কার্যকরী এবং পারফরম্যান্স-বান্ধব অ্যাপ্লিকেশন তৈরি করতে সাহায্য করবে।

  • Dynamic SQL এর মাধ্যমে কুয়েরি গুলিকে কাস্টমাইজ করা।
  • Result Mapping এর মাধ্যমে complex objects এর সাথে ডেটা মেলানো।
  • foreach এবং subselects এর মাধ্যমে ডেটা প্রসেসিংকে আরও নমনীয় করা।
Content added By

iBATIS (MyBatis) একটি শক্তিশালী ORM (Object-Relational Mapping) ফ্রেমওয়ার্ক, যা ডেটাবেসের ডেটা এবং Java অবজেক্টের মধ্যে ম্যাপিং করার জন্য Type Handlers ব্যবহার করে। কখনও কখনও ডেটাবেসে যে ধরনের ডেটা আছে তা Java এ নির্দিষ্টভাবে ম্যাপ করা সম্ভব না হতে পারে, যেমন ডেটাবেসে VARCHAR ফিল্ড যা Java Date অবজেক্টে ম্যাপ করা, বা Boolean ফিল্ড যা Integer হিসেবে চলে আসে। এই ধরনের কাস্টম ট্রান্সফরমেশন পরিচালনা করতে Custom Type Handlers ব্যবহৃত হয়।

এখানে আমরা MyBatis তে কাস্টম টাইপ হ্যান্ডলার তৈরি করার পুরো প্রক্রিয়া দেখাবো।


1. Type Handlers কী?

Type Handlers হল এমন কম্পোনেন্ট যা MyBatis-কে ডেটাবেসের ডেটা এবং Java অবজেক্টের মধ্যে ম্যাপিং করতে সহায়তা করে। সাধারণত, MyBatis অনেক ধরনের ডেটা টাইপ হ্যান্ডল করার জন্য বিল্ট-ইন টাইপ হ্যান্ডলার সরবরাহ করে (যেমন String, Integer, Date, ইত্যাদি), কিন্তু কখনও কখনও আপনাকে কাস্টম ডেটা টাইপের জন্য টাইপ হ্যান্ডলার তৈরি করতে হতে পারে।


2. Custom Type Handler তৈরি করার ধাপসমূহ

Step 1: Type Handler Interface ইমপ্লিমেন্ট করা

MyBatis-এ কাস্টম টাইপ হ্যান্ডলার তৈরি করতে আপনাকে org.apache.ibatis.type.TypeHandler ইন্টারফেস ইমপ্লেমেন্ট করতে হবে। এই ইন্টারফেসে ৪টি মেথড থাকে যা আপনি ইমপ্লিমেন্ট করবেন:

  1. setParameter: Java অবজেক্ট থেকে SQL প্যারামিটার সেট করতে ব্যবহৃত হয়।
  2. getResult: SQL থেকে Java অবজেক্টে ডেটা ম্যাপ করতে ব্যবহৃত হয়।
  3. getResult (আবারও): অন্য কোন ResultSet পদ্ধতিতে ডেটা রিটার্ন করতে ব্যবহৃত হয়।
  4. getResult (আবারও): CallableStatement থেকে ডেটা রিটার্ন করার জন্য ব্যবহৃত হয়।

Step 2: Custom Type Handler Example

ধরা যাক, আপনার ডেটাবেসে একটি BOOLEAN ফিল্ড রয়েছে, কিন্তু আপনি এটি Java-এ String হিসেবে পরিচালনা করতে চান (যেমন 'Y' অথবা 'N')। এই ধরনের কাস্টম টাইপ হ্যান্ডলার তৈরি করার জন্য নিম্নলিখিত কোডটি ব্যবহার করা যেতে পারে।

import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import java.sql.*;

public class BooleanToStringTypeHandler extends BaseTypeHandler<String> {

    @Override
    public void setParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
        if (parameter == null) {
            ps.setNull(i, Types.VARCHAR);
        } else {
            // Convert Boolean to 'Y' or 'N'
            ps.setString(i, parameter.equals("true") ? "Y" : "N");
        }
    }

    @Override
    public String getResult(ResultSet rs, String columnName) throws SQLException {
        String value = rs.getString(columnName);
        return "Y".equals(value) ? "true" : "false";
    }

    @Override
    public String getResult(ResultSet rs, int columnIndex) throws SQLException {
        String value = rs.getString(columnIndex);
        return "Y".equals(value) ? "true" : "false";
    }

    @Override
    public String getResult(CallableStatement cs, int columnIndex) throws SQLException {
        String value = cs.getString(columnIndex);
        return "Y".equals(value) ? "true" : "false";
    }
}

Explanation:

  • setParameter: এটি PreparedStatement এ ডেটা সেট করে, যেখানে parameter প্যারামিটারটি Y অথবা N হিসেবে সেট করা হবে।
  • getResult (ResultSet): এটি ResultSet থেকে ডেটা নিয়ে আসবে এবং যদি ডেটা Y হয়, তাহলে এটি true রিটার্ন করবে, অন্যথায় false
  • getResult (CallableStatement): এটি CallableStatement থেকে একই কাজ করবে, অর্থাৎ ডেটা Y বা N চেক করবে এবং তারপরে true অথবা false রিটার্ন করবে।

Step 3: MyBatis Configuration

MyBatis-এ কাস্টম টাইপ হ্যান্ডলার ব্যবহার করার জন্য, আপনাকে mybatis-config.xml ফাইলে TypeHandler কনফিগার করতে হবে।

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

    <!-- Register Custom Type Handler -->
    <typeHandlers>
        <typeHandler handler="com.example.typehandler.BooleanToStringTypeHandler"/>
    </typeHandlers>

    <!-- DataSource Configuration -->
    <dataSource type="POOLED">
        <property name="driver" value="org.h2.Driver"/>
        <property name="url" value="jdbc:h2:mem:test;DB_CLOSE_DELAY=-1"/>
        <property name="username" value="sa"/>
        <property name="password" value=""/>
    </dataSource>

    <!-- Transaction Manager -->
    <transactionManager type="JDBC"/>

    <!-- Mapper Files -->
    <sqlMap resource="com/example/mapper/EmployeeMapper.xml"/>

</configuration>

এখানে:

  • <typeHandlers>: আপনি BooleanToStringTypeHandler কাস্টম টাইপ হ্যান্ডলারটি এখানে রেজিস্টার করছেন।
  • এই কনফিগারেশন দ্বারা MyBatis কাস্টম টাইপ হ্যান্ডলার ব্যবহার করবে।

Step 4: Mapper XML Configuration

এখন, EmployeeMapper.xml ফাইলে আপনি BooleanToStringTypeHandler টাইপ হ্যান্ডলার ব্যবহার করতে পারেন। ধরুন, আপনার Employee ক্লাসে isActive নামে একটি Boolean ফিল্ড রয়েছে, যেটি Y অথবা N হিসেবে স্টোর হবে।

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//iBATIS//DTD Mapper 3.0//EN" "http://ibatis.apache.org/dtd/sql-map-3.dtd">
<mapper namespace="com.example.mapper.EmployeeMapper">

    <resultMap id="EmployeeResultMap" type="com.example.model.Employee">
        <result property="isActive" column="is_active" typeHandler="com.example.typehandler.BooleanToStringTypeHandler"/>
    </resultMap>

    <select id="getEmployeeById" resultMap="EmployeeResultMap">
        SELECT id, name, is_active FROM employee WHERE id = #{id}
    </select>

</mapper>

Explanation:

  • <result>: এখানে isActive প্রপার্টির জন্য কাস্টম টাইপ হ্যান্ডলার BooleanToStringTypeHandler ব্যবহার করা হয়েছে।
  • typeHandler: এটি MyBatis কে জানায় যে is_active কলামের মান Y অথবা N হিসেবে হবে এবং আপনি সেটি Boolean প্রপার্টিতে ম্যাপ করবেন।

Step 5: Testing the Custom Type Handler

এখন, আপনি JUnit বা Basic Java কোড দিয়ে কাস্টম টাইপ হ্যান্ডলার টেস্ট করতে পারেন।

import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class TestApp {

    public static void main(String[] args) {
        SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder()
                .build(TestApp.class.getResourceAsStream("/sql-map-config.xml"));

        try (SqlSession session = sessionFactory.openSession()) {
            // Test retrieving employee with active status
            Employee employee = session.selectOne("com.example.mapper.EmployeeMapper.getEmployeeById", 1);
            System.out.println("Employee Name: " + employee.getName());
            System.out.println("Employee Active Status: " + employee.getIsActive());
        }
    }
}

Explanation:

  • employee.getIsActive(): এটি BooleanToStringTypeHandler ব্যবহার করে Y বা N রিটার্ন হবে এবং Java Boolean হিসেবে ম্যাপ হবে।

Custom Type Handlers ব্যবহার করে আপনি iBATIS (MyBatis)-এ ডেটাবেসে সংরক্ষিত ডেটা এবং Java অবজেক্টের মধ্যে কাস্টম টাইপ ম্যাপিং করতে পারেন। এই প্রক্রিয়ায়:

  • BaseTypeHandler ইন্টারফেস ইমপ্লিমেন্ট করে কাস্টম টাইপ হ্যান্ডলার তৈরি করা হয়।
  • setParameter() এবং getResult() মেথডগুলি ডেটা ট্রান্সফর্ম করতে ব্যবহৃত হয়।
  • mybatis-config.xml ফাইলে টাইপ হ্যান্ডলার রেজিস্টার করা হয়।

এই পদ্ধতি আপনার অ্যাপ্লিকেশনে কাস্টম ডেটা ট্রান্সফর্মেশন, যেমন BOOLEAN কে String বা Integer বা অন্য কোন কাস্টম টাইপে ম্যাপ করার ক্ষেত্রে খুবই কার্যকর।

Content added By

iBATIS (MyBatis) একটি শক্তিশালী SQL Mapping framework যা caching এর মাধ্যমে কর্মক্ষমতা বাড়ানোর জন্য বিভিন্ন কনফিগারেশন বিকল্প প্রদান করে। Caching-এর ব্যবহারের মাধ্যমে, একাধিক কোয়েরি বা ডেটাবেস কল কমিয়ে এনে অ্যাপ্লিকেশনকে আরও দ্রুত এবং কার্যকরী করা যায়। iBATIS (MyBatis)-এ caching দুটি প্রধান স্তরে কাজ করে: session-level cache এবং second-level cache

এখানে Advanced Caching Configuration এর জন্য বিস্তারিত কনফিগারেশন এবং প্র্যাকটিস দেওয়া হয়েছে যা আপনার MyBatis অ্যাপ্লিকেশনের পারফরম্যান্স বাড়াতে সাহায্য করবে।


1. MyBatis Caching Overview

MyBatis caching দুটি স্তরে কাজ করে:

  1. First-level cache (Session-level cache)
    • এটি ডিফল্টভাবে সক্রিয় থাকে এবং একটি SqlSession এর জন্য ব্যবহার করা হয়। অর্থাৎ, একই SqlSession এর মধ্যে করা সব কুয়েরি একই ডেটার জন্য আবার ডেটাবেস থেকে রিটার্ন করবে না। এটি transactional cache এবং প্রতিটি SqlSession এ আলাদা থাকে।
    • প্রথম স্তরের ক্যাশ সাধারণত ডেটাবেস অ্যাক্সেস কমানোর জন্য ব্যবহার করা হয়, তবে এটি শুধুমাত্র সেই সেশনের জন্য প্রযোজ্য।
  2. Second-level cache (Global cache)
    • এটি SqlSession-এর বাইরে আরও বড় পরিসরে কাজ করে এবং multiple SqlSession এবং sessions এর মধ্যে shared থাকে। দ্বিতীয় স্তরের ক্যাশে কনফিগারেশন চালানোর জন্য MyBatis-এর জন্য ক্যাশ ম্যানেজার এবং ক্যাশ পলিসি কনফিগার করতে হয়। এটি ডেটা পুনরায় ব্যবহার করার সময় কর্মক্ষমতা বাড়াতে সাহায্য করে।
    • দ্বিতীয় স্তরের ক্যাশে আরও জটিল কনফিগারেশন এবং ক্যাশ eviction পলিসি ব্যবহৃত হয়।

2. Session-Level Cache (First-level Cache)

Session-level cache হল MyBatis এর ডিফল্ট ক্যাশিং পদ্ধতি, যা কোনও SqlSession এর মধ্যে সমস্ত কুয়েরির ফলাফল ধরে রাখে। এটি একাধিক কুয়েরির জন্য ডেটাবেসে আরও কম অ্যাক্সেস তৈরি করে।

Configuration for First-level Cache

<settings>
    <setting name="cacheEnabled" value="true"/>
</settings>
  • cacheEnabled: true করার মাধ্যমে প্রথম স্তরের ক্যাশিং সক্রিয় করা হয়।

Usage Example for First-level Cache

public class EmployeeService {
    public Employee getEmployeeById(int id) {
        SqlSession session = sqlSessionFactory.openSession();
        try {
            EmployeeMapper mapper = session.getMapper(EmployeeMapper.class);
            Employee employee = mapper.getEmployeeById(id); // First-level cache hit
            Employee employee2 = mapper.getEmployeeById(id); // Cache hit (no DB call)
            return employee;
        } finally {
            session.close();
        }
    }
}

Explanation:

  • যখন একই SqlSession ব্যবহার করা হয়, প্রথম স্তরের ক্যাশে ডেটা একবার লোড হলে পরবর্তী সময়ে সেটি ক্যাশ থেকে রিটার্ন হয়, ডেটাবেসে কল না করে।

3. Second-Level Cache (Global Cache)

Second-level cache সিস্টেমের সমস্ত SqlSession-এর মধ্যে শেয়ার করা হয় এবং এটি ডেটার পুনঃব্যবহার করে। এটি ডেটাবেস অ্যাক্সেস কমিয়ে এবং কর্মক্ষমতা বাড়াতে ব্যবহৃত হয়।

Step 1: Enable Second-level Cache in mybatis-config.xml

<configuration>
    <settings>
        <setting name="cacheEnabled" value="true"/>
    </settings>

    <mappers>
        <mapper resource="com/yourpackage/mapper/EmployeeMapper.xml"/>
    </mappers>
</configuration>

Step 2: Configure Second-level Cache in Mapper XML

<mapper namespace="com.yourpackage.mapper.EmployeeMapper">
    
    <!-- Enable second-level cache -->
    <cache eviction="LRU" flushInterval="60000" size="512" readOnly="true"/>

    <select id="getEmployeeById" resultType="Employee">
        SELECT * FROM employee WHERE id = #{id}
    </select>
</mapper>

Explanation:

  • <cache>: eviction, flushInterval, size, এবং readOnly প্রপার্টিগুলির মাধ্যমে ক্যাশ কনফিগার করা হয়।
    • eviction: ক্যাশের এলআরইউ (Least Recently Used) পলিসি। এটি কম ব্যবহৃত ডেটা সরিয়ে ফেলবে।
    • flushInterval: ক্যাশ ফ্লাশ করার জন্য ইন্টারভ্যাল নির্ধারণ করে (মিলিসেকেন্ডে)।
    • size: ক্যাশে যতটুকু ডেটা থাকবে তা নির্ধারণ করে (512 পৃষ্ঠার জন্য ক্যাশ সাইজ 512 মেগাবাইট)।
    • readOnly: যদি ক্যাশ শুধুমাত্র পড়ার জন্য ব্যবহৃত হয় (ডেটা পরিবর্তন না হয়), তবে এটি true সেট করা যায়।

Step 3: Using the Second-level Cache

public class EmployeeService {
    public Employee getEmployeeById(int id) {
        SqlSession session = sqlSessionFactory.openSession();
        try {
            EmployeeMapper mapper = session.getMapper(EmployeeMapper.class);
            Employee employee = mapper.getEmployeeById(id); // First-level cache hit

            // Second-level cache hit
            session.commit(); // Flush the second-level cache
            return employee;
        } finally {
            session.close();
        }
    }
}
  • session.commit(): ক্যাশে থাকা ডেটা commit হওয়ার পর ডেটাবেসে পরিবর্তন হলে তা সিঙ্ক্রোনাইজ করা হয়।
  • Second-level cache শুধুমাত্র select কুয়েরির জন্য কার্যকরী।

4. Cache Eviction Policy

MyBatis এ ক্যাশ থেকে ডেটা সাফ করার জন্য ক্যাশের eviction policy কনফিগার করা যায়, যেমন LRU (Least Recently Used), FIFO (First In First Out) বা None

Eviction Policy Example (LRU)

<cache eviction="LRU" flushInterval="60000" size="512" readOnly="true"/>
  • LRU: এটি সবচেয়ে কম ব্যবহৃত (Least Recently Used) ডেটাকে ক্যাশ থেকে সরিয়ে দেয়।
  • FIFO: এটি প্রথমে সন্নিবেশিত (First In) ডেটাকে সরিয়ে দেয়।

Eviction Example for Specific Query

EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
Employee employee = employeeMapper.getEmployeeById(id);
sqlSession.clearCache();  // Manually clear cache

5. Advanced Caching Configuration Best Practices

  • Use Caching for Frequent Queries: ক্যাশ শুধুমাত্র সেই কুয়েরি বা ডেটার জন্য ব্যবহার করুন যা বেশিরভাগ সময় একই থাকে, যেমন লগইন তথ্য বা স্ট্যাটিক ডেটা।
  • Set Proper Cache Size: ক্যাশের সাইজ উপযুক্তভাবে নির্ধারণ করুন যাতে অতিরিক্ত মেমরি ব্যবহার না হয়।
  • Configure Cache Eviction Properly: LRU eviction পলিসি ব্যবহার করুন যাতে পুরানো ডেটা পরিষ্কার হয়ে যায় এবং ক্যাশে শুধুমাত্র প্রাসঙ্গিক ডেটা থাকে।

iBATIS (MyBatis)-এ Advanced Caching Configuration এর মাধ্যমে আপনি আপনার ডেটাবেসের পারফরম্যান্স উন্নত করতে পারেন। First-level cache এবং Second-level cache এর ব্যবহারে আপনি ডেটাবেস অ্যাক্সেস কমিয়ে, দ্রুত ডেটা রিটার্ন করতে পারবেন।

  • First-level cache: শুধুমাত্র SqlSession এর মধ্যে কাজ করে, এবং এটি ডিফল্টভাবে সক্রিয় থাকে।
  • Second-level cache: সেশনগুলির মধ্যে শেয়ার করা হয় এবং উন্নত ক্যাশ পলিসি কনফিগার করার সুযোগ প্রদান করে।
  • Eviction Policy এবং FlushInterval এর মাধ্যমে ক্যাশ ব্যবস্থাপনাকে আরও উন্নত করা সম্ভব।

এই কনফিগারেশনগুলো সঠিকভাবে ব্যবহার করলে আপনার MyBatis অ্যাপ্লিকেশনটি আরও দ্রুত এবং স্কেলেবল হবে।

Content added By

iBATIS (MyBatis) একটি শক্তিশালী SQL mapping framework যা Java objects এবং SQL queries এর মধ্যে সম্পর্ক তৈরি করতে সাহায্য করে। iBATIS (MyBatis)-এ Complex Data Structure Mapping এবং Nested Queries এর ব্যবহার ডেটাবেস থেকে জটিল ডেটা সংগ্রহ এবং সেগুলি সঠিকভাবে Java objects এ রূপান্তর করার জন্য গুরুত্বপূর্ণ।

এখানে, Complex Data Structure Mapping এবং Nested Queries ব্যবহারের জন্য কিছু বাস্তব জীবন উদাহরণ এবং কৌশল আলোচনা করা হবে।


1. Complex Data Structure Mapping in iBATIS

Complex Data Structure Mapping হল একাধিক সম্পর্কিত টেবিল থেকে ডেটা রিট্রিভ করা এবং সেগুলোকে Java objects-এ ম্যাপ করা। iBATIS (MyBatis) সাধারণত ResultMap এবং <association> বা <collection> ট্যাগের মাধ্যমে এই ধরনের জটিল ডেটা স্ট্রাকচার ম্যাপিং করে।

a) One-to-Many Relationship (Complex Data Structure)

ধরা যাক, একটি Student টেবিল এবং একাধিক Course টেবিল রয়েছে, যেখানে একটি ছাত্রের একাধিক কোর্স হতে পারে। এখানে, iBATIS ব্যবহার করে One-to-Many relationship ম্যাপিং করা হবে।

Example: One-to-Many Relationship Mapping
<select id="getStudentWithCourses" resultMap="studentWithCoursesMap">
    SELECT s.id AS student_id, s.name AS student_name, c.id AS course_id, c.name AS course_name
    FROM student s
    LEFT JOIN course c ON s.id = c.student_id
    WHERE s.id = #{id}
</select>

<resultMap id="studentWithCoursesMap" type="com.example.Student">
    <id property="id" column="student_id"/>
    <result property="name" column="student_name"/>
    <collection property="courses" ofType="com.example.Course">
        <id property="id" column="course_id"/>
        <result property="name" column="course_name"/>
    </collection>
</resultMap>

Explanation:

  • LEFT JOIN: student টেবিলের সাথে সম্পর্কিত course টেবিলের ডেটা একসাথে লোড হচ্ছে।
  • <collection>: Eager Loading এর মাধ্যমে, Student অবজেক্টের সাথে সম্পর্কিত courses একটি list হিসেবে লোড হচ্ছে।

Java Code to Fetch Data Using iBATIS

public class StudentService {

    public Student getStudentWithCourses(int studentId) {
        try (SqlSession session = MyBatisUtil.getSession()) {
            StudentMapper studentMapper = session.getMapper(StudentMapper.class);
            return studentMapper.getStudentWithCourses(studentId);
        }
    }
}

Explanation:

  • getStudentWithCourses মেথডটি iBATIS মেপিংয়ের মাধ্যমে স্টুডেন্ট এবং তার কোর্সগুলো একসাথে রিটার্ন করবে।

b) Many-to-One Relationship (Nested Data Structure)

ধরা যাক, একটি Course টেবিলের সাথে সম্পর্কিত Instructor টেবিলের ডেটা রয়েছে। এখানে, Many-to-One relationship ম্যাপিং করতে iBATIS ব্যবহার করা যেতে পারে।

Example: Many-to-One Relationship Mapping
<select id="getCourseWithInstructor" resultMap="courseWithInstructorMap">
    SELECT c.id AS course_id, c.name AS course_name, i.id AS instructor_id, i.name AS instructor_name
    FROM course c
    LEFT JOIN instructor i ON c.instructor_id = i.id
    WHERE c.id = #{id}
</select>

<resultMap id="courseWithInstructorMap" type="com.example.Course">
    <id property="id" column="course_id"/>
    <result property="name" column="course_name"/>
    <association property="instructor" javaType="com.example.Instructor">
        <id property="id" column="instructor_id"/>
        <result property="name" column="instructor_name"/>
    </association>
</resultMap>

Explanation:

  • <association>: এটি Eager Loading এর মাধ্যমে Course অবজেক্টের সাথে সম্পর্কিত Instructor অবজেক্ট লোড করবে।
  • LEFT JOIN: কোর্স এবং ইনস্ট্রাক্টরের সম্পর্কিত তথ্য একসাথে রিট্রিভ করা হচ্ছে।

2. Nested Queries in iBATIS

Nested Queries হল এমন SQL কুয়েরি, যেখানে একটি কুয়েরি আরেকটি কুয়েরির মধ্যে অন্তর্ভুক্ত থাকে। iBATIS (MyBatis)-এ, আপনি subqueries বা nested queries ব্যবহার করতে পারেন, যা ডেটাবেসের মধ্যে জটিল সম্পর্ক তৈরি করতে সাহায্য করে।

a) Example of Using Nested Queries

ধরা যাক, আপনি একটি কুয়েরি লিখছেন যেখানে প্রথমে গ্রাহক অনুযায়ী total_order_value বের করা হচ্ছে এবং তারপর সেই গ্রাহকের last_order_date রিটার্ন করা হচ্ছে।

Example: Nested Query for Total Order and Last Order Date
<select id="getCustomerOrderDetails" resultMap="customerOrderDetailsMap">
    SELECT c.id AS customer_id, c.name AS customer_name,
           (SELECT SUM(o.amount) FROM orders o WHERE o.customer_id = c.id) AS total_order_value,
           (SELECT MAX(o.order_date) FROM orders o WHERE o.customer_id = c.id) AS last_order_date
    FROM customer c
    WHERE c.id = #{customerId}
</select>

<resultMap id="customerOrderDetailsMap" type="com.example.Customer">
    <id property="id" column="customer_id"/>
    <result property="name" column="customer_name"/>
    <result property="totalOrderValue" column="total_order_value"/>
    <result property="lastOrderDate" column="last_order_date"/>
</resultMap>

Explanation:

  • Nested Query: প্রথমে total_order_value গণনা করা হচ্ছে একটি subquery দিয়ে, তারপর last_order_date বের করা হচ্ছে আরেকটি subquery দিয়ে।
  • <resultMap>: iBATIS-এ, total_order_value এবং last_order_date এর ফলাফলগুলি Java object প্রপার্টিতে ম্যাপ করা হচ্ছে।

3. Handling Complex Data with Multiple Nested Queries

মনে করুন, আপনার একটি অ্যাপ্লিকেশন রয়েছে যেখানে orders এবং products সম্পর্কিত ডেটা রিট্রিভ করতে হবে, যেখানে order একাধিক products এর সাথে সম্পর্কিত। iBATIS-এ আপনি একাধিক nested queries ব্যবহার করে এই ধরনের সম্পর্কিত ডেটা একত্রে রিট্রিভ করতে পারেন।

Example: Nested Query for Orders and Products
<select id="getOrderWithProducts" resultMap="orderWithProductsMap">
    SELECT o.id AS order_id, o.customer_id, o.order_date,
           (SELECT GROUP_CONCAT(p.name) FROM product p WHERE p.order_id = o.id) AS product_names
    FROM orders o
    WHERE o.id = #{orderId}
</select>

<resultMap id="orderWithProductsMap" type="com.example.Order">
    <id property="id" column="order_id"/>
    <result property="customerId" column="customer_id"/>
    <result property="orderDate" column="order_date"/>
    <result property="productNames" column="product_names"/>
</resultMap>

Explanation:

  • GROUP_CONCAT(p.name): এখানে একাধিক পণ্য নামের তালিকা GROUP_CONCAT ব্যবহার করে subquery এর মাধ্যমে সংগ্রহ করা হচ্ছে।
  • Nested Query: Order টেবিল থেকে ডেটা রিট্রিভ করা হচ্ছে, এবং সম্পর্কিত পণ্যসমূহের নাম subquery এর মাধ্যমে product_names কলামে রিটার্ন করা হচ্ছে।

4. Performance Considerations for Complex Data Mapping and Nested Queries

  • Database Indexing: একাধিক JOIN বা subqueries ব্যবহার করলে database indexing নিশ্চিত করতে হবে, যাতে পারফরম্যান্সের সমস্যা না হয়।
  • Optimize Queries: nested queries বা complex data mapping ব্যবহারের সময়ে SQL কোয়েরিগুলোর কার্যকারিতা নিশ্চিত করতে তাদের অপটিমাইজ করা প্রয়োজন। উদাহরণস্বরূপ, LIMIT, OFFSET, এবং pagination কৌশলগুলি ব্যবহার করা যেতে পারে।
  • Lazy vs. Eager Loading: Eager loading করার সময় অনেক ডেটা একসাথে লোড হতে পারে, যেটি পারফরম্যান্স সমস্যা সৃষ্টি করতে পারে, বিশেষ করে যখন সম্পর্কিত টেবিলের ডেটার পরিমাণ অনেক বেশি থাকে। তাই, Lazy loading ব্যবহারের সময় সতর্ক হতে হবে।

iBATIS (MyBatis) একটি শক্তিশালী টুল যা Complex Data Structure Mapping এবং Nested Queries হ্যান্ডল করতে সক্ষম। ResultMap এবং <association> বা <collection> ট্যাগ ব্যবহার করে আপনি একাধিক সম্পর্কিত টেবিল থেকে ডেটা রিট্রিভ এবং সেগুলোকে Java objects-এ ম্যাপ করতে পারেন। Nested Queries এর মাধ্যমে, আপনি একাধিক সাবকুয়েরি ব্যবহার করে জটিল ডেটা সংগ্রহ এবং সংযোগ করতে পারবেন। তবে, পারফরম্যান্স এবং ডেটাবেস অপটিমাইজেশন নিশ্চিত করা গুরুত্বপূর্ণ, বিশেষ করে যখন আপনি একাধিক JOIN বা subqueries ব্যবহার করেন।

Content added By
Promotion

Are you sure to start over?

Loading...