Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

MyBatis Framework: Core Concepts and Getting Started

Tech 1

Core ORM Concepts

Object-Relational Mapping (ORM) is a porgramming technique that converts data between incompatible type systems—specifically between object-oriented programming languages and relational databases. Instead of working with raw SQL queries, developers interact with objects that represent database tables.

Java Persistence API (JPA) is the JavaEE specification defining standard interfaces for ORM implementations. Hibernate serves as a full-featured implementation that abstracts SQL entirely from developers. MyBatis, by contrast, operates as a semi-ORM framework, allowing direct SQL manipulation while providing object mapping capabilities.

Introduction to MyBatis

MyBatis is an open-source data persistence framework that simplifies database operations in Java applications. It fundamentally serves as a JDBC wrapper, eliminating boilerplate code associated with connection management, statement creation, and result mapping.

Originally developed as iBATIS in 2002 under Apache, the project moved to Google Code in 2010 and was rebranded as MyBatis. The version covered here is 3.3.1, though current releases have advanced to 3.4.x.

Key Advantages

  • Reduced Boilerplate: Eliminates repetitive JDBC code for managing connections, statements, and result sets
  • Gentle Learning Curve: SQL-based approach with intuitive APIs makes it accessible to developers
  • Database Portability: Built-in abstractions handle differences between database vendors
  • Ecosystem Support: Extensive third-party integrations including pagination plugins, reverse engineering tools, and caching solutions
  • Spring Integration: First-class support for seamless integrtaion with Spring applications

Project Setup

Required Dependencies

Core MyBatis Library:

  • mybatis-3.3.1.jar

Bytecode Manipulation:

  • asm-3.3.jar
  • javassist-3.15.0.GA.jar
  • cglib-2.2.jar

Logging:

  • commons-logging-1.1.1.jar
  • log4j-1.2.17.jar

Testing:

  • junit-4.11.jar
  • hamcrest-core-1.3.jar

Database Driver:

  • mysql-connector-java-5.0.8-bin.jar

Building Your First Application

Entity Model

package com.example.demo.domain;

import java.io.Serializable;
import java.sql.Timestamp;

public class Account implements Serializable {
    private static final long serialVersionUID = 123456789L;
    
    private Long accountId;
    private String accountName;
    private String username;
    private String pwd;
    private Long departmentId;
    private Timestamp birthDate;
    private Timestamp lastModified;
    
    // Getters and setters
    public Long getAccountId() {
        return accountId;
    }
    
    public void setAccountId(Long accountId) {
        this.accountId = accountId;
    }
    
    public String getAccountName() {
        return accountName;
    }
    
    public void setAccountName(String accountName) {
        this.accountName = accountName;
    }
    
    public String getUsername() {
        return username;
    }
    
    public void setUsername(String username) {
        this.username = username;
    }
    
    public String getPwd() {
        return pwd;
    }
    
    public void setPwd(String pwd) {
        this.pwd = pwd;
    }
    
    public Long getDepartmentId() {
        return departmentId;
    }
    
    public void setDepartmentId(Long departmentId) {
        this.departmentId = departmentId;
    }
    
    public Timestamp getBirthDate() {
        return birthDate;
    }
    
    public void setBirthDate(Timestamp birthDate) {
        this.birthDate = birthDate;
    }
    
    public Timestamp getLastModified() {
        return lastModified;
    }
    
    public void setLastModified(Timestamp lastModified) {
        this.lastModified = lastModified;
    }
    
    @Override
    public String toString() {
        return "Account [accountId=" + accountId + ", accountName=" + accountName 
            + ", username=" + username + ", departmentId=" + departmentId + "]";
    }
}

Data Access Interface

package com.example.demo.repository;

import java.util.List;
import com.example.demo.domain.Account;

public interface IAccountRepository {
    
    Account findById(Long id);
    
    List<Account> findAll();
    
    boolean insert(Account account);
    
    boolean delete(Long id);
    
    boolean modify(Account account);
}

Repository Implementation

package com.example.demo.repository.impl;

import java.util.List;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import com.example.demo.domain.Account;
import com.example.demo.repository.IAccountRepository;

public class AccountRepository implements IAccountRepository {
    private final SqlSessionFactory sessionFactory;
    
    public AccountRepository(SqlSessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }
    
    @Override
    public Account findById(Long id) {
        SqlSession session = sessionFactory.openSession();
        try {
            return session.selectOne("account.findById", id);
        } finally {
            session.close();
        }
    }
    
    @Override
    public List<Account> findAll() {
        SqlSession session = sessionFactory.openSession();
        try {
            return session.selectList("account.findAll");
        } finally {
            session.close();
        }
    }
    
    @Override
    public boolean insert(Account account) {
        SqlSession session = sessionFactory.openSession();
        try {
            int affected = session.insert("account.insert", account);
            session.commit();
            return affected > 0;
        } catch (Exception e) {
            session.rollback();
            return false;
        } finally {
            session.close();
        }
    }
    
    @Override
    public boolean delete(Long id) {
        SqlSession session = sessionFactory.openSession();
        try {
            int affected = session.delete("account.delete", id);
            session.commit();
            return affected > 0;
        } catch (Exception e) {
            session.rollback();
            return false;
        } finally {
            session.close();
        }
    }
    
    @Override
    public boolean modify(Account account) {
        SqlSession session = sessionFactory.openSession();
        try {
            int affected = session.update("account.modify", account);
            session.commit();
            return affected > 0;
        } catch (Exception e) {
            session.rollback();
            return false;
        } finally {
            session.close();
        }
    }
}

Configuration Files

Framework Configuration (mybatis-config.xml):

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <environments default="dev">
        <environment id="dev">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis_demo"/>
                <property name="username" value="root"/>
                <property name="password" value="password"/>
            </dataSource>
        </environment>
    </environments>
    
    <mappers>
        <mapper resource="account-mapper.xml"/>
    </mappers>
</configuration>

SQL Mapping (account-mapper.xml):

<?xml version="1.0" encoding="UTF-8"?>
<mapper namespace="account">
    <select id="findById" parameterType="java.lang.Long"
        resultType="com.example.demo.domain.Account">
        SELECT ACCOUNT_ID AS accountId,
               ACCOUNT_NAME AS accountName,
               USERNAME AS username,
               BIRTH_DATE AS birthDate,
               LAST_MODIFIED AS lastModified
        FROM T_ACCOUNT 
        WHERE ACCOUNT_ID = #{id}
    </select>
    
    <select id="findAll" resultType="com.example.demo.domain.Account">
        SELECT ACCOUNT_ID AS accountId,
               ACCOUNT_NAME AS accountName,
               USERNAME AS username,
               BIRTH_DATE AS birthDate,
               LAST_MODIFIED AS lastModified
        FROM T_ACCOUNT
    </select>
    
    <insert id="insert" parameterType="com.example.demo.domain.Account">
        INSERT INTO T_ACCOUNT(ACCOUNT_NAME, USERNAME, BIRTH_DATE, LAST_MODIFIED)
        VALUES(#{accountName}, #{username}, #{birthDate}, #{lastModified})
    </insert>
    
    <delete id="delete" parameterType="java.lang.Long">
        DELETE FROM T_ACCOUNT WHERE ACCOUNT_ID = #{id}
    </delete>
    
    <update id="modify" parameterType="com.example.demo.domain.Account">
        UPDATE T_ACCOUNT 
        SET ACCOUNT_NAME = #{accountName},
            USERNAME = #{username},
            BIRTH_DATE = #{birthDate}
        WHERE ACCOUNT_ID = #{accountId}
    </update>
</mapper>

Test Suite

package com.example.demo.test;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.InputStream;
import java.sql.Timestamp;
import com.example.demo.domain.Account;
import com.example.demo.repository.IAccountRepository;
import com.example.demo.repository.impl.AccountRepository;

public class AccountRepositoryTest {
    private static final Logger logger = LoggerFactory.getLogger(AccountRepositoryTest.class);
    private SqlSessionFactory sqlSessionFactory;
    
    @Before
    public void setup() throws Exception {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    }
    
    @Test
    public void testFindById() {
        IAccountRepository repository = new AccountRepository(sqlSessionFactory);
        Account account = repository.findById(1L);
        logger.info("Found account: {}", account);
    }
    
    @Test
    public void testFindAll() {
        IAccountRepository repository = new AccountRepository(sqlSessionFactory);
        logger.info("Total accounts: {}", repository.findAll().size());
    }
    
    @Test
    public void testInsert() {
        IAccountRepository repository = new AccountRepository(sqlSessionFactory);
        Account newAccount = new Account();
        newAccount.setAccountName("New User");
        newAccount.setUsername("newuser");
        newAccount.setBirthDate(new Timestamp(System.currentTimeMillis()));
        boolean result = repository.insert(newAccount);
        logger.info("Insert operation: {}", result ? "success" : "failed");
    }
    
    @Test
    public void testModify() {
        IAccountRepository repository = new AccountRepository(sqlSessionFactory);
        Account account = new Account();
        account.setAccountId(2L);
        account.setAccountName("Updated Name");
        account.setUsername("updateduser");
        boolean result = repository.modify(account);
        logger.info("Update operation: {}", result ? "success" : "failed");
    }
    
    @Test
    public void testDelete() {
        IAccountRepository repository = new AccountRepository(sqlSessionFactory);
        boolean result = repository.delete(2L);
        logger.info("Delete operation: {}", result ? "success" : "failed");
    }
}

Execution Workflow

The typical MyBatis workflow follows these steps: load the configuration file, build the SqlSessionFactory, create SqlSession instances, execute mapped statements, and properly release resources. Transaction management requires explicit commits for insert, update, and delete operations to persist changes to the database.

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.