MyBatis Introduction, Setup Steps, and Dynamic Proxy Implementation
This article provides a comprehensive guide to MyBatis, covering its basic concepts, Maven dependency configuration, XML setup, entity and mapper definitions, execution flow using dynamic proxies, and a custom lightweight framework implementation with full Java code examples.
Hello everyone, I am a senior architect.
1. MyBatis Introduction
MyBatis is an ORM tool that encapsulates JDBC operations and simplifies business programming; it integrates with Spring in web projects to provide database read/write capabilities.
2. Usage Steps
1. Add Dependencies
Use Maven to include the mybatis-3.5.5 dependency and the MySQL driver.
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.5</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.49</version>
</dependency>2. Configuration File
Create an XML configuration that defines the data source, environment, and mapper locations.
<?xml version="1.0" encoding="UTF-8"?>3. Interface Definition
Define the entity class and the mapper interface.
package com.xiongxin.mybatis.entity;
public class User {
private String username;
private String password;
// getters & setters
} package com.xiongxin.mybatis.mapper;
import com.xiongxin.mybatis.entity.User;
import java.util.List;
public interface UserMapper {
List<User> queryUser();
}Create the XML mapper file that maps the SQL query to the method.
<?xml version="1.0" encoding="UTF-8"?>
select * from tbl_user4. Load and Execute
Use MyBatis to build a SqlSessionFactory, obtain the mapper, and execute the query.
package com.xiongxin.mybatis;
import com.alibaba.fastjson.JSON;
import com.xiongxin.mybatis.entity.User;
import com.xiongxin.mybatis.mapper.UserMapper;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.Reader;
import java.util.List;
public class TestMain {
public static void main(String[] args) throws Exception {
String resource = "mybatis-config.xml";
Reader reader = Resources.getResourceAsReader(resource);
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader);
SqlSession session = sessionFactory.openSession();
UserMapper userMapper = session.getMapper(UserMapper.class);
List
users = userMapper.queryUser();
System.out.println(JSON.toJSONString(users));
}
}
// Output example: [{"password":"password","username":"xiongxin"}]At this point the MyBatis usage is complete.
3. Principle Analysis
The framework obtains a dynamic proxy for the mapper interface, leveraging JDK dynamic proxy mechanisms. The proxy intercepts method calls, retrieves the associated SQL via annotations, and executes it through a MethodInvoker, ultimately returning the result set.
4. Handcrafted Framework
Below is a lightweight custom implementation that mimics MyBatis behavior using annotations, reflection, and JDBC.
package com.dbutil.session;
import java.lang.annotation.*;
import java.lang.reflect.*;
import java.sql.*;
import java.util.*;
/**
* Custom annotation for SQL queries
*/
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface QueryList { String value(); }
public class SqlSession {
public static Connection getConnH2() throws Exception {
String url = "jdbc:h2:mem:db_h2;MODE=MYSQL;INIT=RUNSCRIPT FROM './src/main/resources/schema.sql'";
Class.forName("org.h2.Driver");
return DriverManager.getConnection(url, "root", "123456");
}
public static
T getMapper(Class
mapperInterface) {
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[]{mapperInterface}, new MapperInvocationHandler());
}
static class MapperInvocationHandler implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String sql = method.getAnnotation(QueryList.class).value();
Class
returnType = method.getReturnType();
if (returnType == List.class) {
Type generic = method.getGenericReturnType();
String typeName = generic.getTypeName().replace("java.util.List<", "").replace(">", "");
Class
elementClass = Class.forName(typeName);
return queryList(sql, elementClass);
}
return null;
}
}
public interface ResultMap
{ T convert(ResultSet rs) throws Exception; }
public static
List
queryList(String sql, ResultMap
mapper) throws Exception {
Connection conn = getConnH2();
Statement st = conn.createStatement();
ResultSet rs = st.executeQuery(sql);
List
list = new ArrayList<>();
while (rs.next()) {
list.add(mapper.convert(rs));
}
rs.close(); st.close(); conn.close();
return list;
}
public static
List
queryList(String sql, Class
clazz) throws Exception {
return queryList(sql, rs -> {
T obj = clazz.newInstance();
for (Field f : clazz.getDeclaredFields()) {
f.setAccessible(true);
if (f.getType() == String.class) {
f.set(obj, rs.getString(f.getName()));
} else if (f.getType() == Long.class) {
f.set(obj, rs.getLong(f.getName()));
}
}
return obj;
});
}
}Additional resources, promotional links, and community invitations are included throughout the original article but are not part of the technical tutorial.
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.