首页 归档 关于 learn love 工具

Mybatis Mapper 測試速度超進化

第一階段:@SpringBootTest

去年產品剛開始開發時,使用 @SpringBootTest 去測試全部 Mapper 的總時間都還在可以接受的範圍。

今年年初由於產品功能慢慢變多,使用 @SpringBootTest 去測試全部 Mapper 的總時間越拉越長,於是開始研究降低總時間的方式。

第二階段:@MyBatisTest

研究的過程中,發現 MyBatis 其實自己有出測試框架,只要在測試中把 @SpringBootTest 換成 @MyBatisTest,就可以大幅降低執行時間,因為 @MyBatisTest 不會像 @SpringBootTest 一樣要準備所有 context。

第三階段:SqlSessionFactory

想針對 Mapper 做純單元測試,只要做到啟動 H2 及取得 Mapper,不需要啟動 Spring Container的 Mapper 純單元測試:使用 SqlSessionFactory!

代码来源

数据脚本 schema.sql

CREATE TABLE cars(id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(150), price INT);

data.sql

INSERT INTO cars(name, price) VALUES('Audi', 52642);
INSERT INTO cars(name, price) VALUES('Mercedes', 57127);
INSERT INTO cars(name, price) VALUES('Skoda', 9000);
INSERT INTO cars(name, price) VALUES('Volvo', 29000);
INSERT INTO cars(name, price) VALUES('Bentley', 350000);
INSERT INTO cars(name, price) VALUES('Citroen', 21000);
INSERT INTO cars(name, price) VALUES('Hummer', 41400);
INSERT INTO cars(name, price) VALUES('Volkswagen', 21600);

工具类 MybatisFactory

import java.util.List;
import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;

/**
 * 构建mybatis测试环境
 */
public class MybatisFactory {
    /**
     * h2 数据源构建
     */
    EmbeddedDatabaseBuilder embeddedDatabaseBuilder = new EmbeddedDatabaseBuilder();

    /**
     * 添加启动脚本
     *
     * @param script
     */
    public void addInitScript(String script) {
        embeddedDatabaseBuilder.addScript(script);
    }

    public MybatisFactory() {
        // h2 数据源构建
        embeddedDatabaseBuilder
                .setType(EmbeddedDatabaseType.H2)
                .setName("test");
    }

    public <T> SqlSessionFactory getSqlSessionFactory(List<Class<T>> mappers) {
        Environment environment =
                new Environment("development", new JdbcTransactionFactory(), embeddedDatabaseBuilder.build());
        Configuration configuration = new Configuration(environment);
        for (Class<T> mapper : mappers) {
            configuration.addMapper(mapper);
        }
        return new SqlSessionFactoryBuilder().build(configuration);
    }
}

测试

import java.util.List;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.junit.Test;

public class FactoryTest {


    @Test
    public void testCar() {
        MybatisFactory mybatisFactory = new MybatisFactory();
        mybatisFactory.addInitScript("db/schema.sql");
        mybatisFactory.addInitScript("db/data.sql");

        SqlSessionFactory sqlSessionFactory = mybatisFactory.getSqlSessionFactory(List.of(CarMapper.class));

        try (SqlSession session = sqlSessionFactory.openSession()) {
            CarMapper carMapper = session.getMapper(CarMapper.class);
            Car car = carMapper.getCarByName("Audi");
            assert car.getPrice() == 52642;
        }

    }

}

Configuration 和 Environment

当使用MyBatis时,Configuration 和 Environment 是两个重要的概念,它们之间存在特定的关系,用于配置和管理数据库连接等运行环境。

Configuration(配置): Configuration 类是MyBatis的核心配置类,负责管理所有配置信息,包括数据库连接、映射关系、插件等。每个Configuration对象对应一个MyBatis配置,通过此对象,可以访问和修改各项配置。

Environment(环境): Environment 类代表MyBatis的运行环境,包括数据库连接信息和事务管理器等。每个Environment对象关联一个数据库连接池(DataSource)和一个事务管理器(TransactionFactory)。

两者之间的关系如下:

每个Configuration对象可以与一个或多个Environment对象关联,表示MyBatis可以在不同环境中运行,例如开发、测试、生产等。

每个Environment对象包含数据库连接池和事务管理器。数据库连接池(DataSource)用于获取连接,事务管理器(TransactionFactory)用于管理事务。每个Environment对象可以配置一个数据库连接池和一个事务管理器,确保正确管理连接和事务。

在MyBatis的配置文件中,您可以使用以下方式配置Environment:

<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://localhost:3306/mydb"/>
            <property name="username" value="username"/>
            <property name="password" value="password"/>
        </dataSource>
    </environment>
</environments>

在上述配置中,通过元素配置了名为 "development" 的环境,关联了一个JDBC事务管理器和一个POOLED数据库连接池。元素指定了连接数据库所需的参数。

总而言之,Configuration是MyBatis的总体配置管理类,而Environment是定义数据库连接和事务管理的环境配置类。您可以根据需求配置多个Environment,然后在Configuration中选择适合的环境来运行。

参考