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.

Top Architect
Top Architect
Top Architect
MyBatis Introduction, Setup Steps, and Dynamic Proxy Implementation

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"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <!-- Database connection -->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost/user"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <!-- Register mapper files -->
    <mappers>
        <mapper resource="mybatis/User.xml"/>
    </mappers>
</configuration>

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"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xiongxin.mybatis.mapper.UserMapper">
    <select id="queryUser" resultType="com.xiongxin.mybatis.entity.User">
        select * from tbl_user
    </select>
</mapper>

4. 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<User> 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> T getMapper(Class<T> 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> { T convert(ResultSet rs) throws Exception; }
    public static <T> List<T> queryList(String sql, ResultMap<T> mapper) throws Exception {
        Connection conn = getConnH2();
        Statement st = conn.createStatement();
        ResultSet rs = st.executeQuery(sql);
        List<T> list = new ArrayList<>();
        while (rs.next()) {
            list.add(mapper.convert(rs));
        }
        rs.close(); st.close(); conn.close();
        return list;
    }
    public static <T> List<T> queryList(String sql, Class<T> 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.

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.

javasqlbackend-developmentMyBatisORMDynamic Proxy
Top Architect
Written by

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.

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.