From JDBC to MyBatis: Evolution, Design, and Optimization of a Persistence Layer Framework
This article explains how JDBC evolves into MyBatis, detailing the seven-step JDBC process, the motivations for encapsulating JDBC, the design of MyBatis components such as SqlSession, Executor, and StatementHandler, and various optimization strategies including connection pooling, SQL management, dynamic parameters, and caching.
The article introduces the gradual transformation from raw JDBC usage to the MyBatis persistence framework, emphasizing why JDBC should be encapsulated into a higher‑level data access layer.
1. JDBC Query Process
Typical JDBC querying involves seven steps: loading the driver, obtaining a connection, creating a Statement, setting parameters, executing the SQL, processing the ResultSet, and finally releasing resources.
public static List<Map<String, Object>> queryForList() {
Connection connection = null;
ResultSet rs = null;
PreparedStatement stmt = null;
List<Map<String, Object>> resultList = new ArrayList<>();
try {
// Load driver
Class.forName("oracle.jdbc.driver.OracleDriver").newInstance();
String url = "jdbc:oracle:thin:@localhost:1521:ORACLEDB";
String user = "trainer";
String password = "trainer";
// Get connection
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(); } catch (SQLException ignored) {}
try { if (stmt != null) stmt.close(); } catch (SQLException ignored) {}
try { if (connection != null) connection.close(); } catch (SQLException ignored) {}
}
return resultList;
}2. Motivation for Encapsulation
Frequent opening/closing of connections wastes resources.
SQL statements are scattered across Java classes, hurting readability and maintainability.
Changing SQL requires recompilation and redeployment.
Duplicate SQL fragments increase maintenance cost.
Solutions include using a connection pool (DataSource), centralizing SQL in configuration files or a database, supporting dynamic SQL with placeholders, and modularizing repeated SQL fragments.
3. MyBatis Core Components SqlSession: top‑level API for executing statements. Executor: creates dynamic SQL, handles caching, and delegates to StatementHandler. StatementHandler: prepares PreparedStatement, sets parameters via ParameterHandler, and executes the query. ResultSetHandler: converts ResultSet into List<E> objects.
Other supporting classes: MappedStatement, Configuration, BoundSql, TypeHandler, etc.
Key code snippets illustrate how Executor.query() builds a CacheKey, obtains a MappedStatement, and finally calls StatementHandler.query() which executes the prepared statement and hands the result set to ResultSetHandler.
4. MyBatis Initialization
Initialization follows a Builder pattern:
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
.build(inputStream); // inputStream reads mybatis-config.xmlThe builder creates an XMLConfigBuilder, parses the XML into a Configuration object, and then constructs a DefaultSqlSessionFactory. The Configuration holds settings, type aliases, plugins, environments (including Environment with TransactionFactory and DataSource), mappers, etc.
Environment creation also uses a Builder:
Environment env = new Environment.Builder("development")
.transactionFactory(txFactory)
.dataSource(dataSource)
.build();Thus, MyBatis leverages Builder and Factory patterns to keep configuration flexible and extensible.
5. Design Patterns Highlighted
Builder pattern for SqlSessionFactory and Environment.
Factory pattern for creating TransactionFactory, DataSourceFactory, and SqlSessionFactory.
Proxy (dynamic proxy) for Mapper interfaces.
Strategy pattern via TypeHandler implementations.
The article concludes with practical tips for using MyBatis, such as configuring mappers, leveraging XML or annotation‑based SQL, and optimizing performance through caching and connection pooling.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Top Architect
Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.
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.
