Databases 32 min read

From JDBC to MyBatis: Transforming Low‑Level SQL into a Powerful Persistence Layer

This article explains how JDBC evolves into MyBatis, why JDBC should be wrapped into a persistence framework, and examines MyBatis's architecture, initialization process, and design‑pattern usage, providing code examples and optimization steps for developers.

Java High-Performance Architecture
Java High-Performance Architecture
Java High-Performance Architecture
From JDBC to MyBatis: Transforming Low‑Level SQL into a Powerful Persistence Layer

1 Introduction

This article explains how JDBC evolves into MyBatis, why JDBC should be wrapped into a persistence framework, and discusses MyBatis's strengths and shortcomings.

2 JDBC Query Implementation

Typical JDBC query requires seven steps: load driver, obtain connection, create statement, set parameters, execute, process result set, and release resources.

Load JDBC driver; Obtain database connection; Create JDBC Statements object; Set SQL parameters; Execute SQL and obtain result set; Convert result set to desired format; Close resources.

Example code for a simple query is shown below.

public static List<Map<String,Object>> queryForList() {
    Connection connection = null;
    ResultSet rs = null;
    PreparedStatement stmt = null;
    List<Map<String,Object>> resultList = new ArrayList<>();
    try {
        Class.forName("oracle.jdbc.driver.OracleDriver").newInstance();
        String url = "jdbc:oracle:thin:@localhost:1521:ORACLEDB";
        String user = "trainer";
        String password = "trainer";
        connection = DriverManager.getConnection(url,user,password);
        String sql = "select * from userinfo where user_id = ?";
        stmt = connection.prepareStatement(sql);
        stmt.setString(1, "zhangsan");
        rs = stmt.executeQuery();
        ResultSetMetaData rsmd = rs.getMetaData();
        int num = rsmd.getColumnCount();
        while(rs.next()){
            Map<String,Object> map = new HashMap<>();
            for(int i=0;i<num;i++){
                String columnName = rsmd.getColumnName(i+1);
                map.put(columnName, rs.getString(columnName));
            }
            resultList.add(map);
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        try {
            if (rs != null) { rs.close(); rs = null; }
            if (stmt != null) { stmt.close(); stmt = null; }
            if (connection != null) { connection.close(); connection = null; }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    return resultList;
}

3 Evolution from JDBC to MyBatis

Seven‑step JDBC can be encapsulated to reduce boilerplate. The article presents five optimization steps.

3.1 Optimize Connection Acquisition and Release

Frequent opening/closing wastes resources; a connection pool (e.g., DBCP or container JNDI) isolates the DataSource.

3.2 Centralize SQL Management

Scattering SQL across Java classes harms readability, maintenance, and deployment. Storing SQL in configuration files or a database with key‑value mapping solves the problem.

3.3 Parameter Mapping and Dynamic SQL

When parameters are uncertain, dynamic SQL generation (e.g., using #variable# syntax) allows flexible query construction.

3.4 Result Mapping and Caching

Result handling can return raw maps, JavaBeans, or lists, and caching the result set improves performance.

3.5 Eliminate Duplicate SQL

Modularizing common SQL fragments reduces duplication and eases maintenance.

4 MyBatis Limitations

MyBatis still requires explicit SQL for every operation; the article suggests generating SQL automatically from JavaBean metadata.

5 MyBatis Architecture Overview

The architecture consists of interface layer, data‑processing layer, framework support layer, bootstrap layer, and component relationships.

5.1 Interface Layer

Two ways to interact with the database: traditional MyBatis API (statement ID + parameters) and Mapper interfaces.

5.1.1 Traditional API

Creates a SqlSession, passes statement ID and parameters to execute CRUD operations.

5.1.2 Mapper Interface

Each XML node ( , , , ) maps to a method in a Mapper interface; MyBatis generates a proxy implementation.

5.2 Data‑Processing Layer

Core responsibilities: build dynamic SQL from parameters and execute the statement, returning a List.

5.2.1 Parameter Mapping and Dynamic SQL Generation

MyBatis uses OGNL to construct SQL at runtime.

5.2.2 Executing SQL and Wrapping Results

ResultSetHandler converts ResultSet into List, supporting one‑to‑many and many‑to‑one mappings.

5.3 Framework Support Layer

Includes transaction management, connection pooling, caching, and SQL configuration (XML or annotations).

5.4 Bootstrap Layer

Configuration can be loaded from XML or built programmatically via Java API.

5.5 Main Components and Relationships

Key components: SqlSession, Executor, StatementHandler, ParameterHandler, ResultSetHandler, TypeHandler, MappedStatement, SqlSource, BoundSql, Configuration.

6 SqlSession Workflow

Creating a SqlSession, invoking selectList with a statement ID, and the internal steps of Executor, StatementHandler, and ResultSetHandler.

SqlSession sqlSession = factory.openSession();
List<Employee> result = sqlSession.selectList("com.louis.mybatis.dao.EmployeesMapper.selectByMinSalary", params);

Executor obtains MappedStatement, creates a cache key, delegates to StatementHandler, which prepares a PreparedStatement, sets parameters via ParameterHandler, executes the query, and passes the ResultSet to ResultSetHandler for conversion.

7 MyBatis Initialization Mechanism

7.1 What Initialization Does

Loads all configuration information into a Configuration object.

7.2 Building Configuration from XML

SqlSessionFactoryBuilder creates XMLConfigBuilder, which parses the XML, processes nodes (properties, typeAliases, plugins, environments, mappers, etc.), and builds the Configuration.

7.3 Manual Loading via Java API

Developers can instantiate XMLConfigBuilder directly, call parse() to obtain Configuration, and then build a SqlSessionFactory.

7.4 Design Patterns Used

Builder pattern is applied to SqlSessionFactory creation and to the Environment object inside Configuration.

Overall, the article provides a step‑by‑step analysis of how MyBatis abstracts JDBC, its internal architecture, initialization process, and the design patterns that make the framework extensible.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Design PatternsJavaPersistenceMyBatisJDBC
Java High-Performance Architecture
Written by

Java High-Performance Architecture

Sharing Java development articles and resources, including SSM architecture and the Spring ecosystem (Spring Boot, Spring Cloud, MyBatis, Dubbo, Docker), Zookeeper, Redis, architecture design, microservices, message queues, Git, etc.

0 followers
Reader feedback

How this landed with the community

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.