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.
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)
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.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.