Backend Development 8 min read

MyBatis Q&A: #{} vs ${}, Pagination Techniques, Caching, Lazy Loading, Executors, and Custom Plugin Development

This article explains MyBatis fundamentals including the difference between #{} and ${} placeholders, various pagination approaches, logical versus physical pagination, first‑ and second‑level caching, lazy‑loading mechanisms, executor types, pagination plugin principles, and how to create a custom MyBatis plugin with code examples.

Java Captain
Java Captain
Java Captain
MyBatis Q&A: #{} vs ${}, Pagination Techniques, Caching, Lazy Loading, Executors, and Custom Plugin Development

13. MyBatis

125. What is the difference between #{} and ${} in MyBatis?

#{} is processed as a prepared‑statement placeholder (pre‑compiled) and is replaced with a ? in the SQL, with values set via PreparedStatement , which prevents SQL injection.

${} performs simple string substitution, directly inserting the variable value into the SQL, which can be unsafe.

126. Pagination methods supported by MyBatis

Array pagination

SQL pagination

Interceptor pagination

RowBounds pagination

128. Difference between logical pagination and physical pagination

Physical pagination pushes the paging logic to the database, reducing application‑side load; logical pagination processes the full result set in the application, which may be slower but can be useful in some scenarios.

Physical pagination is generally preferred because it avoids unnecessary pressure on the application layer.

129. Does MyBatis support lazy loading? What is the principle?

MyBatis supports lazy loading for association (one‑to‑one) and collection (one‑to‑many) relationships. It can be enabled with lazyLoadingEnabled=true in the configuration. The mechanism uses CGLIB to create a proxy; when a lazy property is accessed, the proxy triggers a separate SQL query to load the related data and then populates the property.

Other ORM frameworks such as Hibernate use the same principle.

130. First‑level and second‑level cache in MyBatis

First‑level cache: a PerpetualCache based HashMap scoped to a SqlSession . It is enabled by default and cleared when the session is flushed or closed.

Second‑level cache: also uses PerpetualCache but is scoped to a mapper namespace. It is disabled by default and can be enabled by adding a <cache/> element in the mapper XML and providing a serializable cache implementation (e.g., Ehcache). Cache entries are cleared automatically after any C/U/D operation in the same scope.

131. Differences between MyBatis and Hibernate

MyBatis is not a full ORM; developers write raw SQL, giving fine‑grained control over performance but requiring more code and reducing database portability.

Hibernate provides comprehensive object‑relational mapping, database independence, and higher productivity for complex relational models.

132. Executors available in MyBatis

MyBatis defines three core executors:

SimpleExecutor : creates a new Statement for each execution and closes it immediately.

ReuseExecutor : reuses a Statement identified by the SQL key, keeping it in a map for subsequent executions.

BatchExecutor : batches multiple update statements and executes them together using JDBC batch processing.

133. How the MyBatis pagination plugin works

The plugin implements MyBatis’s interceptor interface, intercepts the target SQL, rewrites it according to the database dialect, and appends the appropriate physical pagination clause and parameters.

134. How to write a custom MyBatis plugin

A custom plugin must implement the Interceptor interface and can intercept the four core MyBatis components: Executor , StatementHandler , ParameterHandler , and ResultSetHandler .

public interface Interceptor {
    Object intercept(Invocation invocation) throws Throwable;
    Object plugin(Object target);
    void setProperties(Properties properties);
}

Example plugin implementation:

// ExamplePlugin.java
@Intercepts({@Signature(
    type = Executor.class,
    method = "update",
    args = {MappedStatement.class, Object.class})})
public class ExamplePlugin implements Interceptor {
    public Object intercept(Invocation invocation) throws Throwable {
        Object target = invocation.getTarget(); // proxied object
        Method method = invocation.getMethod(); // method being intercepted
        Object[] args = invocation.getArgs(); // method arguments
        // do something before execution
        Object result = invocation.proceed();
        // do something after execution
        return result;
    }
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }
    public void setProperties(Properties properties) {
        // set plugin properties
    }
}

The @Intercepts annotation can contain multiple @Signature definitions, each specifying the target type, method name, and argument types to intercept.

(End)

SQLbackend-developmentcachingMyBatispaginationlazy loadingCustom Plugin
Java Captain
Written by

Java Captain

Focused on Java technologies: SSM, the Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading; occasionally covers DevOps tools like Jenkins, Nexus, Docker, ELK; shares practical tech insights and is dedicated to full‑stack Java development.

0 followers
Reader feedback

How this landed with the community

login 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.