Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Implementing Java Persistence with MyBatis: Core Concepts and Usage

Tech 1

Core Concepts of MyBatis

MyBatis is a persistence framework for Java that enables custom SQL, stored procedures, and advanced object-relational mapping. Unlike full ORM tools like Hibernate, it focuses on flexible SQL control through configuration and ennotations, bridging Java objects and database records.

Configuration File

The central configuration file (mybatis-config.xml) defines database connections, transaction management, and mappers. Example:

<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
  <environments default="prod">
    <environment id="prod">
      <transactionManager type="JDBC"/>
      <dataSource type="POOLED">
        <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/demo_db"/>
        <property name="username" value="admin"/>
        <property name="password" value="secret"/>
      </dataSource>
    </environment>
  </environments>
  <mappers>
    <mapper resource="com/demo/mapper/AppUserMapper.xml"/>
  </mappers>
</configuration>

Mapper Definitions

Mapper XML files map SQL statements to Java methods. Example AppUserMapper.xml:

<?xml version="1.0" encoding="UTF-8" ?>
<mapper namespace="com.demo.mapper.AppUserMapper">
  <select id="fetchUserById" parameterType="int" resultType="com.demo.model.AppUser">
    SELECT * FROM app_users WHERE id = #{userId}
  </select>
  <insert id="addUser" parameterType="com.demo.model.AppUser">
    INSERT INTO app_users (full_name, contact_email) VALUES (#{fullName}, #{contactEmail})
  </insert>
  <update id="modifyUser" parameterType="com.demo.model.AppUser">
    UPDATE app_users SET full_name = #{fullName}, contact_email = #{contactEmail} WHERE id = #{id}
  </update>
  <delete id="removeUser" parameterType="int">
    DELETE FROM app_users WHERE id = #{userId}
  </delete>
</mapper>

Implementation Steps

1. Database Table and Model

Create a table app_users:

CREATE TABLE app_users (
  id INT AUTO_INCREMENT PRIMARY KEY,
  full_name VARCHAR(255) NOT NULL,
  contact_email VARCHAR(255) NOT NULL
);

Corresponding Java model:

package com.demo.model;

public class AppUser {
  private int id;
  private String fullName;
  private String contactEmail;

  // Getters and setters
  public int getId() { return id; }
  public void setId(int id) { this.id = id; }
  public String getFullName() { return fullName; }
  public void setFullName(String fullName) { this.fullName = fullName; }
  public String getContactEmail() { return contactEmail; }
  public void setContactEmail(String contactEmail) { this.contactEmail = contactEmail; }
}

2. Mapper Interface

Define interface matching the XML mapper:

package com.demo.mapper;

import com.demo.model.AppUser;
import java.util.List;

public interface AppUserMapper {
  AppUser fetchUserById(int userId);
  void addUser(AppUser user);
  void modifyUser(AppUser user);
  void removeUser(int userId);
  List<AppUser> queryUsers(AppUser filter);
}

3. Usage Example

Execute operations via SqlSession:

package com.demo;

import com.demo.mapper.AppUserMapper;
import com.demo.model.AppUser;
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;

public class MyBatisDemo {
  public static void main(String[] args) throws Exception {
    try (Reader reader = Resources.getResourceAsReader("mybatis-config.xml")) {
      SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader);
      try (SqlSession session = factory.openSession()) {
        AppUserMapper mapper = session.getMapper(AppUserMapper.class);

        // Add user
        AppUser newUser = new AppUser();
        newUser.setFullName("Alice Smith");
        newUser.setContactEmail("alice@example.com");
        mapper.addUser(newUser);

        // Fetch user
        AppUser fetched = mapper.fetchUserById(newUser.getId());
        System.out.printf("Fetched: %s (%s)\n", fetched.getFullName(), fetched.getContactEmail());

        // Modify user
        fetched.setFullName("Alice Johnson");
        mapper.modifyUser(fetched);

        // Remove user
        mapper.removeUser(fetched.getId());
        session.commit();
      }
    }
  }
}

Advnaced Features

Dynamic SQL

Generate conditional SQL using tags like <if>:

<select id="queryUsers" resultType="com.demo.model.AppUser">
  SELECT * FROM app_users
  <where>
    <if test="fullName != null">AND full_name = #{fullName}</if>
    <if test="contactEmail != null">AND contact_email = #{contactEmail}</if>
  </where>
</select>

Caching Mechanisms

  • First-level cache: Enabled by default, scoped to SqlSession.
  • Second-level cache: Mapper-scoped, enabled via <cache/> in mapper XML:
    <mapper namespace="com.demo.mapper.AppUserMapper">
      <cache/>
      <!-- SQL mappings -->
    </mapper>
    
    Enable globally in mybatis-config.xml:
    <settings>
      <setting name="cacheEnabled" value="true"/>
    </settings>
    

Plugin System

Intercept SQL execution phases. Example logger plugin:

package com.demo.plugin;

import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.plugin.*;

import java.sql.Connection;
import java.util.Properties;

@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
public class SqlExecutionLogger implements Interceptor {
  @Override
  public Object intercept(Invocation invocation) throws Throwable {
    System.out.println("SQL execution started");
    Object result = invocation.proceed();
    System.out.println("SQL execution completed");
    return result;
  }

  @Override
  public Object plugin(Object target) {
    return Plugin.wrap(target, this);
  }

  @Override
  public void setProperties(Properties props) {}
}

Register in mybatis-config.xml:

<plugins>
  <plugin interceptor="com.demo.plugin.SqlExecutionLogger"/>
</plugins>

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.