MyBatis Persistence Framework with Mapper Interface and Maven Integration
Understanding MyBatis
MyBatis is a powerful persistence framework designed to simplify JDBC development. It operates within the three-tier architecture model:
- Presentation Layer (UI)
- Business Layer (Logic)
- Persistence Layer (Database Operations)
The framework addresses common JDBC challenges:
- Hardcoding Issues: Database drivers, connection details, and SQL statements are moved to configuration files
- Complex Operations: Manual parameter setting and result set mapping are automated
Getting Started with MyBatis
Basic Query Example: Steps to Retrieve All Data from User Table
- Prepare the user table in your database
- Create a project module and add necessary dependencies
- Configure the MyBatis core configuration file to replace hardcoded connection information
- Create a SQL mapping file to centralize SQL statements
- Implement the code:
- Define a POJO (Plain Old Java Object) class representing the entity
- Load the core configuration file to obtain a SqlSessionFactory object
- Get a SqlSession object and execute SQL queries
- Release resources properly
Practical Implementation with Maven and MyBatis
POM.xml Dependency Configuration
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>mybatis-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<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.46</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.20</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.2.3</version>
</dependency>
</dependencies>
Logback Configuration File
<configuration>
<appender name="Console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>[%level] %blue(%d{HH:mm:ss.SSS})%cyan([%thread]) %boldGreen(%logger{15}) - %msg %n</pattern>
</encoder>
</appender>
<logger name="com.example" level="DEBUG" additivity="false">
</logger>
</configuration>
Entity Class Definition
package com.example.entity;
public class User {
private int userId;
private String userName;
private String userPassword;
private String userGender;
private String userAddress;
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserPassword() {
return userPassword;
}
public void setUserPassword(String userPassword) {
this.userPassword = userPassword;
}
public String getUserGender() {
return userGender;
}
public void setUserGender(String userGender) {
this.userGender = userGender;
}
public String getUserAddress() {
return userAddress;
}
public void setUserAddress(String userAddress) {
this.userAddress = userAddress;
}
@Override
public String toString() {
return "User{" +
"userId=" + userId +
", userName='" + userName + '\'' +
", userPassword='" + userPassword + '\'' +
", userGender='" + userGender + '\'' +
", userAddress='" + userAddress + '\'' +
'}';
}
}
MyBatis Core Configuration File
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///mydb?useSSL=false"/>
<property name="username" value="admin"/>
<property name="password" value="securepassword"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/example/mapper/UserMapper.xml"/>
</mappers>
</configuration>
UserMapper XML Mapping File
<mapper namespace="com.example.mapper.UserMapper">
<select id="fetchAllUsers" resultType="com.example.entity.User">
SELECT user_id, user_name, user_password, user_gender, user_address
FROM users;
</select>
</mapper>
MyBatis Demo Test Class
package com.example;
import com.example.entity.User;
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.IOException;
import java.io.InputStream;
import java.util.List;
public class MyBatisDemo {
public static void main(String[] args) throws IOException {
// 1. Load MyBatis core configuration file and get SqlSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 2. Get SqlSession object
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3. Execute SQL query
List<User> users = sqlSession.selectList("com.example.mapper.UserMapper.fetchAllUsers");
System.out.println(users);
// 4. Release resources
sqlSession.close();
}
}
Mapper Interface Development
Steps for Mapper Interface Development
- Define a Mapper interface with the same name as the SQL mapping file, placing both in the same directory
- Set the namespace attribute in the SQL mapping file to the fully qualified name of the Mapper interface
- Define methods in the Mapper interface where method names match SQL statement IDs in the mapping file, with consistent parameter and return types
- Implementation:
- Obtain a proxy object of the Mapper interface using SqlSession's getMapper method
- Call the corresponding method to execute SQL
Continued Implementation with Maven, MyBatis, and Mapper
Updated MyBatis Configuration
<mappers>
<package name="com.example.mapper"/>
</mappers>
Updated UserMapper XML Namespace
<mapper namespace="com.example.mapper.UserMapper">
<select id="fetchAllUsers" resultType="com.example.entity.User">
SELECT user_id, user_name, user_password, user_gender, user_address
FROM users;
</select>
</mapper>
UserMapper Interface
package com.example.mapper;
import com.example.entity.User;
import java.util.List;
public interface UserMapper {
// Returns a List containing multiple User entities
List<User> fetchAllUsers();
}
Updated MyBatis Demo Test Class
package com.example;
import com.example.entity.User;
import com.example.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.IOException;
import java.io.InputStream;
import java.util.List;
public class MyBatisMapperDemo {
public static void main(String[] args) throws IOException {
// 1. Load MyBatis core configuration file and get SqlSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 2. Get SqlSession object
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3. Get proxy object of UserMapper interface
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<User> users = userMapper.fetchAllUsers();
System.out.println(users);
// 4. Release resources
sqlSession.close();
}
}
MyBatis Core Configuration
For comprehensive configuration options, refer to the official MyBatis documentation.
Practical Implementation Examples
Configuration-Based Development Approach
Entity Class
package com.example.entity;
public class Product {
private Integer productId;
private String productName;
private String manufacturer;
private Integer priority;
private String description;
private Integer status;
// Getters and Setters
// toString() method
}
Mapper Interface
package com.example.mapper;
import com.example.entity.Product;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
public interface ProductMapper {
/**
* Fetch all products
* @return List<Product>
*/
List<Product> fetchAll();
/**
* Fetch product details by ID
* @param id
* @return Product
*/
Product fetchById(int id);
/**
* Multi-condition dynamic query
* Parameter接收方式:
* 1.散装参数
* 2.对象参数
* 3.map集合参数
* @param status
* @param manufacturer
* @param productName
* @return List<Product>
*/
List<Product> searchByCondition(@Param("status")int status,
@Param("manufacturer")String manufacturer,
@Param("productName")String productName);
/**
* Single condition dynamic query
* @param product
* @return
*/
List<Product> searchByConditionSingle(Product product);
/**
* Add new product
* @param product
*/
void addProduct(Product product);
/**
* Update product information
* @param product
* @return
*/
int updateProduct(Product product);
/**
* Batch delete products
* @param ids
*/
void deleteByIds(@Param("ids")int[] ids);
}
Mapper XML Configuration
<mapper namespace="com.example.mapper.ProductMapper">
<resultMap id="productResultMap" type="com.example.entity.Product">
<result column="product_name" property="productName"/>
<result column="manufacturer" property="manufacturer"/>
</resultMap>
<select id="fetchAll" resultMap="productResultMap">
SELECT *
FROM products;
</select>
<select id="fetchById" resultMap="productResultMap">
SELECT *
FROM products
WHERE id = #{id};
</select>
<select id="searchByCondition" resultMap="productResultMap">
SELECT * FROM products
<where>
<if test="status != null">
AND status = #{status}
</if>
<if test="manufacturer != null and manufacturer != ''">
AND manufacturer LIKE #{manufacturer}
</if>
<if test="productName != null and productName != ''">
AND productName LIKE #{productName}
</if>
</where>
</select>
<select id="searchByConditionSingle" resultMap="productResultMap">
SELECT * FROM products
<where>
<choose>
<when test="status != null">
status = #{status}
</when>
<when test="manufacturer != null and manufacturer != ''">
manufacturer LIKE #{manufacturer}
</when>
<when test="productName != null and productName != ''">
productName LIKE #{productName}
</when>
</choose>
</where>
</select>
<insert id="addProduct" useGeneratedKeys="true" keyProperty="productId">
INSERT INTO products (product_name, manufacturer, priority, description, status)
VALUES (#{productName},#{manufacturer},#{priority},#{description},#{status});
</insert>
<update id="updateProduct">
UPDATE products
<set>
<if test="productName != null and productName != ''">
product_name = #{productName},
</if>
<if test="manufacturer != null and manufacturer != ''">
manufacturer = #{manufacturer},
</if>
<if test="priority != null">
priority = #{priority},
</if>
<if test="description != null and description != ''">
description = #{description},
</if>
<if test="status != null">
status = #{status},
</if>
</set>
WHERE id = #{id};
</update>
<delete id="deleteByIds">
DELETE FROM products
WHERE id IN
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</delete>
</mapper>
Test Class
package com.example.test;
import com.example.entity.Product;
import com.example.mapper.ProductMapper;
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 org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class ProductMapperTest {
@Test
public void testFetchAll() throws IOException {
// 1. Load MyBatis core configuration file and get SqlSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 2. Get SqlSession object
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3. Get ProductMapper interface proxy object
ProductMapper productMapper = sqlSession.getMapper(ProductMapper.class);
// 4. Execute query and process results
List<Product> products = productMapper.fetchAll();
System.out.println(products);
// 5. Release resources
sqlSession.close();
}
@Test
public void testFetchById() throws IOException {
int id = 1;
// 1. Load MyBatis core configuration file and get SqlSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 2. Get SqlSession object
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3. Get ProductMapper interface proxy object
ProductMapper productMapper = sqlSession.getMapper(ProductMapper.class);
// 4. Execute query and process results
Product product = productMapper.fetchById(id);
System.out.println(product);
// 5. Release resources
sqlSession.close();
}
@Test
public void testSearchByCondition() throws IOException {
int status = 1;
String manufacturer = "TechCorp";
String productName = "Smartphone";
// Process parameters
manufacturer = "%" + manufacturer + "%";
productName = "%" + productName + "%";
// 1. Load MyBatis core configuration file and get SqlSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 2. Get SqlSession object
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3. Get ProductMapper interface proxy object
ProductMapper productMapper = sqlSession.getMapper(ProductMapper.class);
// 4. Execute query and process results
List<Product> products = productMapper.searchByCondition(status, manufacturer, productName);
System.out.println(products);
// 5. Release resources
sqlSession.close();
}
@Test
public void testAddProduct() throws IOException {
// Simulate frontend parameters
String productName = "New Gadget";
String manufacturer = "InnovateCo";
int priority = 5;
String description = "Latest innovation in technology";
int status = 1;
// Process parameters
Product product = new Product();
product.setProductName(productName);
product.setManufacturer(manufacturer);
product.setPriority(priority);
product.setDescription(description);
product.setStatus(status);
// 1. Load MyBatis core configuration file and get SqlSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 2. Get SqlSession object with auto-commit
SqlSession sqlSession = sqlSessionFactory.openSession(true);
// 3. Get ProductMapper interface proxy object
ProductMapper productMapper = sqlSession.getMapper(ProductMapper.class);
// 4. Execute add operation
productMapper.addProduct(product);
// 5. Get auto-generated ID
int generatedId = product.getProductId();
System.out.println("Generated ID: " + generatedId);
// 6. Release resources
sqlSession.close();
}
@Test
public void testUpdateProduct() throws IOException {
// Simulate frontend parameters
int id = 2;
String productName = "Updated Gadget";
int priority = 6;
String description = "Updated with latest features";
int status = 2;
// Process parameters
Product product = new Product();
product.setProductId(id);
product.setProductName(productName);
product.setPriority(priority);
product.setDescription(description);
product.setStatus(status);
// 1. Load MyBatis core configuration file and get SqlSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 2. Get SqlSession object with auto-commit
SqlSession sqlSession = sqlSessionFactory.openSession(true);
// 3. Get ProductMapper interface proxy object
ProductMapper productMapper = sqlSession.getMapper(ProductMapper.class);
// 4. Execute update operation
int affectedRows = productMapper.updateProduct(product);
System.out.println("Affected rows: " + affectedRows);
// 5. Release resources
sqlSession.close();
}
@Test
public void testDeleteByIds() throws IOException {
int[] ids = {1, 3, 5};
// 1. Load MyBatis core configuration file and get SqlSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 2. Get SqlSession object with auto-commit
SqlSession sqlSession = sqlSessionFactory.openSession(true);
// 3. Get ProductMapper interface proxy object
ProductMapper productMapper = sqlSession.getMapper(ProductMapper.class);
// 4. Execute batch delete operation
productMapper.deleteByIds(ids);
// 5. Release resources
sqlSession.close();
}
}
Annotation-Based Development Approach
MyBatis also supports annotations for simple SQL operations:
- Query: @Select
- Insert: @Insert
- Update: @Update
- Delete: @Delete
Annotation-based development eliminates the need for XML mapping files. SQL statements are defined directly in interface methods:
package com.example.mapper;
import com.example.entity.Product;
import org.apache.ibatis.annotations.*;
import java.util.List;
@Mapper
public interface ProductAnnotationMapper {
@Select("SELECT * FROM products WHERE id = #{id}")
Product fetchById(int id);
@Insert("INSERT INTO products (product_name, manufacturer, priority, description, status) " +
"VALUES (#{productName}, #{manufacturer}, #{priority}, #{description}, #{status})")
void addProduct(Product product);
@Update("UPDATE products SET product_name = #{productName}, " +
"manufacturer = #{manufacturer}, priority = #{priority}, " +
"description = #{description}, status = #{status} WHERE id = #{id}")
int updateProduct(Product product);
@Delete("DELETE FROM products WHERE id = #{id}")
int deleteById(int id);
}