MyBatis-Plus is an enhanced toolkit for MyBatis providing CRUD operations, query wrappers, pagination, code generation, and Spring Boot integration.
—
MyBatis-Plus provides seamless Spring Boot integration with auto-configuration, properties binding, starter dependencies, and comprehensive configuration options for rapid application development.
Main auto-configuration class for MyBatis-Plus integration.
@Configuration
@ConditionalOnClass({SqlSessionFactory.class, SqlSessionFactoryBean.class})
@ConditionalOnSingleCandidate(DataSource.class)
@EnableConfigurationProperties(MybatisPlusProperties.class)
@AutoConfigureAfter({DataSourceAutoConfiguration.class, MybatisLanguageDriverAutoConfiguration.class})
public class MybatisPlusAutoConfiguration implements InitializingBean {
/**
* Create SqlSessionFactory bean
* @param dataSource Data source
* @return SqlSessionFactory instance
* @throws Exception if configuration fails
*/
@Bean
@ConditionalOnMissingBean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception;
/**
* Create SqlSessionTemplate bean
* @param sqlSessionFactory SqlSessionFactory instance
* @return SqlSessionTemplate instance
*/
@Bean
@ConditionalOnMissingBean
public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory);
/**
* Create MapperScannerConfigurer for automatic mapper scanning
* @return MapperScannerConfigurer instance
*/
@Bean
@ConditionalOnMissingBean
public MapperScannerConfigurer mapperScannerConfigurer();
}Configuration properties class for MyBatis-Plus settings.
/**
* MyBatis-Plus configuration properties
*/
@ConfigurationProperties(prefix = "mybatis-plus")
public class MybatisPlusProperties {
/**
* MyBatis configuration file location
*/
private String config;
/**
* MyBatis configuration file location (alias for config)
*/
private String configLocation;
/**
* Mapper XML file locations
*/
private String[] mapperLocations = new String[]{"classpath*:/mapper/**/*.xml"};
/**
* Type aliases package
*/
private String typeAliasesPackage;
/**
* Type aliases super type
*/
private Class<?> typeAliasesSuperType;
/**
* Type handlers package
*/
private String typeHandlersPackage;
/**
* Executor type
*/
private ExecutorType executorType;
/**
* Configuration properties
*/
private Properties configurationProperties;
/**
* MyBatis-Plus global configuration
*/
private GlobalConfig globalConfig = new GlobalConfig();
// getters and setters...
}Interface for customizing MyBatis Configuration.
/**
* Configuration customizer interface
*/
@FunctionalInterface
public interface ConfigurationCustomizer {
/**
* Customize MyBatis Configuration
* @param configuration MyBatis Configuration instance
*/
void customize(Configuration configuration);
}Interface for customizing MyBatis-Plus properties.
/**
* MyBatis-Plus properties customizer interface
*/
@FunctionalInterface
public interface MybatisPlusPropertiesCustomizer {
/**
* Customize MyBatis-Plus properties
* @param properties MybatisPlusProperties instance
*/
void customize(MybatisPlusProperties properties);
}Spring Boot VFS implementation for resource loading.
/**
* Spring Boot VFS implementation
*/
public class SpringBootVFS extends VFS {
/**
* Check if VFS is valid for current environment
* @return true if valid
*/
@Override
public boolean isValid();
/**
* List resources matching the path pattern
* @param path Resource path pattern
* @return List of resource URLs
* @throws IOException if resource loading fails
*/
@Override
protected List<String> list(URL path, String forPath) throws IOException;
}Basic Spring Boot Setup:
<!-- pom.xml -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.7</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency># application.yml
spring:
datasource:
url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8
username: root
password: password
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis-plus:
mapper-locations: classpath*:/mapper/**/*.xml
type-aliases-package: com.example.entity
configuration:
map-underscore-to-camel-case: true
cache-enabled: false
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
db-config:
id-type: AUTO
logic-delete-field: deleted
logic-delete-value: 1
logic-not-delete-value: 0Application Configuration:
@SpringBootApplication
@MapperScan("com.example.mapper")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}Comprehensive Configuration:
# application.yml
mybatis-plus:
# MyBatis mapper xml file path
mapper-locations: classpath*:/mapper/**/*.xml
# MyBatis type aliases package
type-aliases-package: com.example.entity
# MyBatis type aliases super type
type-aliases-super-type: com.example.base.BaseEntity
# MyBatis type handlers package
type-handlers-package: com.example.typehandler
# MyBatis executor type
executor-type: SIMPLE
# MyBatis configuration
configuration:
# Enable automatic camel case mapping
map-underscore-to-camel-case: true
# Cache configuration
cache-enabled: true
lazy-loading-enabled: true
aggressive-lazy-loading: false
# Log implementation
log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl
# Call setters on null values
call-setters-on-nulls: true
# Return instance for empty row
return-instance-for-empty-row: true
# Auto mapping behavior
auto-mapping-behavior: PARTIAL
# Auto mapping unknown column behavior
auto-mapping-unknown-column-behavior: NONE
# Default statement timeout
default-statement-timeout: 30
# Default fetch size
default-fetch-size: 100
# MyBatis-Plus global configuration
global-config:
# Banner configuration
banner: true
# Database configuration
db-config:
# Primary key type
id-type: ASSIGN_ID
# Table prefix
table-prefix: t_
# Schema
schema: test_db
# Column format
column-format: '%s'
# Property format
property-format: '%s'
# Table name underline conversion
table-underline: true
# Column name underline conversion
column-underline: true
# Capital mode
capital-mode: false
# Logic delete configuration
logic-delete-field: deleted
logic-delete-value: 1
logic-not-delete-value: 0
# Field strategy
insert-strategy: NOT_NULL
update-strategy: NOT_NULL
where-strategy: NOT_NULLConfiguration Beans:
@Configuration
public class MybatisPlusConfig {
/**
* MyBatis-Plus interceptor configuration
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// Pagination interceptor
PaginationInnerInterceptor paginationInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
paginationInterceptor.setMaxLimit(1000L);
paginationInterceptor.setOverflow(true);
interceptor.addInnerInterceptor(paginationInterceptor);
// Optimistic locking interceptor
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
// Block attack interceptor
interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
return interceptor;
}
/**
* Meta object handler for auto-fill
*/
@Bean
public MetaObjectHandler metaObjectHandler() {
return new MetaObjectHandler() {
@Override
public void insertFill(MetaObject metaObject) {
this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
}
@Override
public void updateFill(MetaObject metaObject) {
this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
}
};
}
/**
* Custom ID generator
*/
@Bean
public IdentifierGenerator identifierGenerator() {
return new CustomIdGenerator();
}
/**
* SQL injector for custom methods
*/
@Bean
public ISqlInjector sqlInjector() {
return new DefaultSqlInjector() {
@Override
public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
List<AbstractMethod> methodList = super.getMethodList(mapperClass);
// Add custom methods
methodList.add(new SelectByIdWithDeleted());
methodList.add(new DeleteAllMethod());
return methodList;
}
};
}
}Custom Configuration Customizers:
@Component
public class MyBatisConfigurationCustomizer implements ConfigurationCustomizer {
@Override
public void customize(Configuration configuration) {
// Custom MyBatis configuration
configuration.setMapUnderscoreToCamelCase(true);
configuration.setDefaultStatementTimeout(30);
configuration.setDefaultFetchSize(100);
// Add custom type handlers
configuration.getTypeHandlerRegistry().register(LocalDateTime.class, JdbcType.TIMESTAMP, LocalDateTimeTypeHandler.class);
// Add custom object wrappers
configuration.setObjectWrapperFactory(new CustomObjectWrapperFactory());
}
}
@Component
public class MyBatisPlusPropertiesCustomizer implements MybatisPlusPropertiesCustomizer {
@Override
public void customize(MybatisPlusProperties properties) {
// Custom MyBatis-Plus properties
GlobalConfig globalConfig = properties.getGlobalConfig();
GlobalConfig.DbConfig dbConfig = globalConfig.getDbConfig();
// Set custom configurations
dbConfig.setIdType(IdType.ASSIGN_ID);
dbConfig.setTablePrefix("sys_");
dbConfig.setLogicDeleteField("is_deleted");
dbConfig.setLogicDeleteValue("1");
dbConfig.setLogicNotDeleteValue("0");
}
}Conditional Configuration:
@Configuration
public class MybatisPlusConfig {
@Bean
@ConditionalOnProperty(name = "mybatis-plus.pagination.enabled", havingValue = "true", matchIfMissing = true)
public PaginationInnerInterceptor paginationInnerInterceptor() {
PaginationInnerInterceptor interceptor = new PaginationInnerInterceptor(DbType.MYSQL);
interceptor.setMaxLimit(1000L);
return interceptor;
}
@Bean
@ConditionalOnProperty(name = "mybatis-plus.tenant.enabled", havingValue = "true")
public TenantLineInnerInterceptor tenantLineInnerInterceptor() {
return new TenantLineInnerInterceptor(new CustomTenantLineHandler());
}
@Bean
@Profile("dev")
public MybatisPlusInterceptor devMybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// Development-specific interceptors
interceptor.addInnerInterceptor(new SqlExplainInterceptor());
return interceptor;
}
@Bean
@Profile("prod")
public MybatisPlusInterceptor prodMybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// Production-specific interceptors
interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
interceptor.addInnerInterceptor(new IllegalSQLInnerInterceptor());
return interceptor;
}
}Multiple DataSource Configuration:
@Configuration
public class MultiDataSourceConfig {
@Primary
@Bean("primaryDataSource")
@ConfigurationProperties(prefix = "spring.datasource.primary")
public DataSource primaryDataSource() {
return DruidDataSourceBuilder.create().build();
}
@Bean("secondaryDataSource")
@ConfigurationProperties(prefix = "spring.datasource.secondary")
public DataSource secondaryDataSource() {
return DruidDataSourceBuilder.create().build();
}
@Primary
@Bean("primarySqlSessionFactory")
public SqlSessionFactory primarySqlSessionFactory(@Qualifier("primaryDataSource") DataSource dataSource,
MybatisPlusInterceptor interceptor) throws Exception {
MybatisSqlSessionFactoryBean factory = new MybatisSqlSessionFactoryBean();
factory.setDataSource(dataSource);
factory.setPlugins(interceptor);
factory.setMapperLocations(new PathMatchingResourcePatternResolver()
.getResources("classpath*:/mapper/primary/**/*.xml"));
return factory.getObject();
}
@Bean("secondarySqlSessionFactory")
public SqlSessionFactory secondarySqlSessionFactory(@Qualifier("secondaryDataSource") DataSource dataSource,
MybatisPlusInterceptor interceptor) throws Exception {
MybatisSqlSessionFactoryBean factory = new MybatisSqlSessionFactoryBean();
factory.setDataSource(dataSource);
factory.setPlugins(interceptor);
factory.setMapperLocations(new PathMatchingResourcePatternResolver()
.getResources("classpath*:/mapper/secondary/**/*.xml"));
return factory.getObject();
}
@Primary
@Bean("primarySqlSessionTemplate")
public SqlSessionTemplate primarySqlSessionTemplate(@Qualifier("primarySqlSessionFactory") SqlSessionFactory factory) {
return new SqlSessionTemplate(factory);
}
@Bean("secondarySqlSessionTemplate")
public SqlSessionTemplate secondarySqlSessionTemplate(@Qualifier("secondarySqlSessionFactory") SqlSessionFactory factory) {
return new SqlSessionTemplate(factory);
}
}
@MapperScan(basePackages = "com.example.mapper.primary", sqlSessionTemplateRef = "primarySqlSessionTemplate")
@Configuration
public class PrimaryMapperConfig {
}
@MapperScan(basePackages = "com.example.mapper.secondary", sqlSessionTemplateRef = "secondarySqlSessionTemplate")
@Configuration
public class SecondaryMapperConfig {
}Testing Configuration:
@TestConfiguration
public class TestMybatisPlusConfig {
@Bean
@Primary
public DataSource testDataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.addScript("classpath:schema.sql")
.addScript("classpath:data.sql")
.build();
}
@Bean
public MybatisPlusInterceptor testMybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// Test-specific interceptors only
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
return interceptor;
}
}
@SpringBootTest
@Transactional
@Rollback
class UserServiceTest {
@Autowired
private UserService userService;
@Test
void testSaveUser() {
User user = new User();
user.setName("Test User");
user.setEmail("test@example.com");
boolean result = userService.save(user);
assertThat(result).isTrue();
assertThat(user.getId()).isNotNull();
}
@Test
void testPageQuery() {
Page<User> page = new Page<>(1, 10);
IPage<User> result = userService.page(page);
assertThat(result.getRecords()).isNotEmpty();
assertThat(result.getTotal()).isGreaterThan(0);
}
}Monitoring and Health Checks:
@Component
@ConditionalOnProperty(name = "management.health.mybatis-plus.enabled", havingValue = "true", matchIfMissing = true)
public class MybatisPlusHealthIndicator implements HealthIndicator {
@Autowired
private SqlSessionFactory sqlSessionFactory;
@Override
public Health health() {
try {
// Test database connectivity
try (SqlSession session = sqlSessionFactory.openSession()) {
session.getConnection().isValid(1000);
return Health.up()
.withDetail("database", "Available")
.withDetail("mybatis-plus", "Operational")
.build();
}
} catch (Exception e) {
return Health.down(e)
.withDetail("database", "Unavailable")
.withDetail("mybatis-plus", "Non-operational")
.build();
}
}
}
@Component
@EventListener
public class MybatisPlusEventListener {
private static final Logger logger = LoggerFactory.getLogger(MybatisPlusEventListener.class);
@EventListener
public void handleApplicationReady(ApplicationReadyEvent event) {
logger.info("MyBatis-Plus integration initialized successfully");
}
@EventListener
public void handleContextClosed(ContextClosedEvent event) {
logger.info("MyBatis-Plus integration shutting down");
}
}This comprehensive Spring Boot integration provides seamless auto-configuration, extensive customization options, and production-ready defaults for rapid development with MyBatis-Plus.
Install with Tessl CLI
npx tessl i tessl/maven-com-baomidou--mybatis-plus