Apache MyBatis
Introduction
- MyBatis is a persistence framework that simplifies the interaction between Java programs and databases. Compared to traditional JDBC (Java Database Connectivity), MyBatis configures and maps SQL statements via XML or annotations, greatly reducing boilerplate code.
- MyBatis was originally an Apache open-source project named iBatis. In 2010 the project moved from Apache to Google Code and was renamed MyBatis. In November 2013 it migrated to GitHub.
JDBC (Java DataBase Connectivity)
JDBC is the Java API for database connectivity, released in 1997 by Sun Microsystems (now part of Oracle Corporation). JDBC defines a standard that allows Java programs to interact with many relational databases. It provides a set of interfaces and classes for sending SQL statements and processing results. A JDBC driver is a Java class library implementing the JDBC interfaces for a specific DBMS; Java programs communicate with the DBMS through the driver.
Persistence Framework
In computing a persistence framework is middleware that assists in the storage and retrieval of information between applications and databases, especially relational databases. It acts as a layer of abstraction for persisted data, bridging conceptual and technical differences between storage and utilisation.
Many persistence frameworks are also object-relational mapping (ORM) tools (e.g. Hibernate, MyBatis SQL Maps, Apache Cayenne, Entity Framework, Slick, and Java Ultra-Lite Persistence). Such frameworks map the objects in the application domain to data that needs to be persisted in a database. The mappings can be defined using either XML files or metadata annotations.Object-Relational Mapping (ORM, or O/RM, or O/R mapping) is a programming technique for converting data between incompatible type systems in object-oriented programming languages. Object orientation grew out of software engineering principles (coupling, aggregation, encapsulation), while relational databases grew out of mathematical theory. The two theories differ significantly, and ORM emerged to resolve this mismatch.
Comparison with other persistence-layer technologies
- JDBC
- SQL mixed into Java code creates tight coupling and hard-coding problems;
- Hard to maintain; in real projects SQL changes often and must be modified frequently;
- Verbose code, low development efficiency;
- Hibernate and JPA
- Easy to use, high development efficiency;
- Long, complex SQL in a program has to bypass the framework;
- The internally generated SQL is hard to optimize for special cases;
- As fully mapped, fully automatic frameworks, partial mapping of POJOs with many fields is difficult;
- Heavy use of reflection hurts database performance;
- MyBatis
- Lightweight, with excellent performance;
- SQL and Java code are separated, with clear boundaries: Java code focuses on business logic, SQL focuses on data;
- Development efficiency is slightly behind Hibernate, but entirely acceptable;
Development efficiency:
Hibernate > Mybatis > JDBC;
Runtime efficiency:JDBC > Mybatis > Hibernate;Why is MyBatis called a semi-automatic ORM tool? How does it differ from fully automatic ones?
Hibernate is a fully automatic ORM tool: when querying associated objects or associated collections with Hibernate, you can fetch them directly through the object-relational model, hence “fully automatic”. MyBatis, in contrast, offers a flexible, semi-automatic way to handle database operations. Unlike fully automatic ORM frameworks, MyBatis emphasizes SQL control: developers write the SQL themselves and gain better performance and flexibility in return.
The core strengths of MyBatis:
- SQL Control: you fully control how SQL statements are written and executed, avoiding the complexity of ORM frameworks, especially when you need to optimize queries.
- Dynamic SQL Support: MyBatis provides very powerful dynamic SQL. Developers can flexibly generate different SQL statements based on business logic, without the pain of concatenating SQL strings.
- Lightweight: MyBatis is lightweight and easy to integrate, without pulling in as many dependencies as some heavier ORM frameworks.
- Simplified Mapping: through XML configuration or annotations, you can easily map database table columns to Java object properties.
MyBatis Core Concepts
SqlSessionFactoryis the core entry point of MyBatis; every MyBatis application is built around a SqlSessionFactory instance. It is created by reading a configuration file. From the SqlSessionFactory you obtain a SqlSession to perform database operations.SqlSessionis similar to JDBC’sStatementobject and provides the methods for interacting with the database. Through a SqlSession you can run CRUD operations, commit transactions, close connections, and so on. Each session is isolated from the others.Mapper Interfaceis another convenient way MyBatis offers to operate on database tables. You define an interface for the operations on a table, with each method mapped to a SQL statement. For example, a UserMapper interface might have a methodgetUserById()corresponding to the SQLSELECT * FROM user WHERE id = ?.Dynamic SQLis a powerful MyBatis feature that lets you use conditional statements (such asif, choose, where) and loops (foreach) in SQL. Dynamic SQL improves flexibility, especially for complex query conditions, generating SQL statements dynamically based on the conditions.Result Mappingmaps database columns in a query result to the properties of a Java object. The mapping can be defined via XML configuration or annotations.
CRUD Demo
Suppose we have a In this project structure, we use Spring Boot’s typical layered architecture to organize the MyBatis CRUD operations:User table with columns id, name, and age.CREATE TABLE user ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50), age INT);Model Layer: defines the User entity class.
Mapper Layer: defines database operations through the UserMapper interface, with SQL configured in UserMapper.xml.
Service Layer: wraps business logic in the UserService class.
Controller Layer: UserController receives HTTP requests and calls UserService to run the corresponding database operations.src/ └── main/ ├── java/ │ └── com/ │ └── example/ │ └── mybatisdemo/ │ ├── controller/ │ │ └── UserController.java │ ├── mapper/ │ │ └── UserMapper.java │ ├── model/ │ │ └── User.java │ └── service/ │ └── UserService.java └── resources/ ├── application.yml └── mapper/ └── UserMapper.xml# application.ymlspring: datasource: url: jdbc:mysql://localhost:3306/mybatis_demo username: root password: root_password driver-class-name: com.mysql.cj.jdbc.Drivermybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.example.mybatisdemo.modelpackage com.example.mybatisdemo.model;public class User { private int id; private String name; private int age; // Getters and Setters public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; }}package com.example.mybatisdemo.service;import com.example.mybatisdemo.mapper.UserMapper;import com.example.mybatisdemo.model.User;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;@Servicepublic class UserService { @Autowired private UserMapper userMapper; public int createUser(User user) { return userMapper.insertUser(user); } public User getUserById(int id) { return userMapper.getUserById(id); } public int updateUser(User user) { return userMapper.updateUser(user); } public int deleteUser(int id) { return userMapper.deleteUser(id); }}package com.example.mybatisdemo.mapper;import com.example.mybatisdemo.model.User;import org.apache.ibatis.annotations.Mapper;@Mapperpublic interface UserMapper { // Insert a user record int insertUser(User user); // Query by user ID // In the `xml` file, write the corresponding SQL statement, e.g. // <select id = "getUserById" resultType = "User"> // select * from user where id = #{id} // </select> User getUserById(int id); // Update user info int updateUser(User user); // Delete by user ID int deleteUser(int id);}package com.example.mybatisdemo.controller;import com.example.mybatisdemo.model.User;import com.example.mybatisdemo.service.UserService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.*;@RestController@RequestMapping("/users")public class UserController { @Autowired private UserService userService; // Create a user @PostMapping public String createUser(@RequestBody User user) { userService.createUser(user); return "User created successfully"; } // Query a user by ID @GetMapping("/{id}") public User getUserById(@PathVariable int id) { return userService.getUserById(id); } // Update a user @PutMapping("/{id}") public String updateUser(@PathVariable int id, @RequestBody User user) { user.setId(id); userService.updateUser(user); return "User updated successfully"; } // Delete a user @DeleteMapping("/{id}") public String deleteUser(@PathVariable int id) { userService.deleteUser(id); return "User deleted successfully"; }}
More
MyBatis Interview Questions Summary
Object-Relational Mapping

