시작하기 전에: 필요한 사전 지식
MyBatis-Plus를 학습하기 위해서는 먼저 아래 기술 스택을 익히는 것이 중요합니다:
- MyBatis
- Spring 프레임워크
- Spring MVC
이러한 기초가 탄탄해야 MyBatis-Plus의 편의성과 확장성을 제대로 이해하고 활용할 수 있습니다.
왜 MyBatis-Plus를 사용하는가?
개발 과정에서 반복적인 CRUD 작업은 시간과 노력을 많이 소모합니다. MyBatis-Plus는 이러한 문제를 해결하기 위해 설계된 강력한 ORM 도구입니다. JPA, tk-mybatis 등과 마찬가지로 개발 생산성을 높이는 목적을 가지고 있으며, 다음과 같은 장점을 제공합니다:
- 기존 코드에 영향 없이 기능을 확장 (무침투성)
- 자동화된 기본 쿼리 생성
- 코드 양 감소 및 유지보수 용이성 향상
공식 사이트 및 문서
자세한 정보는 공식 문서를 참고하세요: https://baomidou.com
주요 특징
- 무침투 아키텍처: 기존 프로젝트에 영향을 주지 않으며, 의존성 추가만으로 기능을 사용할 수 있습니다.
- 고성능: 기본 CRUD 메서드는 시작 시 자동 주입되며 성능 저하가 거의 없습니다.
- 강력한 조건 쿼리 지원: QueryWrapper 등을 통해 복잡한 조건도 간결하게 표현 가능.
- Lambda 표현식 지원: 필드 이름 오타 방지를 위해 메서드 참조 기반 쿼리 작성이 가능합니다.
- ID 자동 생성: Snowflake 알고리즘 기반의 분산 고유 ID 생성을 포함하여 다양한 전략 제공.
- ActiveRecord 모드: 엔티티 클래스가 Model을 상속하면 객체 기반 CRUD 연산이 가능해집니다.
- 코드 생성기 내장: Mapper, Service, Controller 등의 코드를 자동 생성하여 초기 개발 시간 단축.
- 물리적 페이징 플러그인: 데이터베이스 종류에 맞는 최적화된 페이징 쿼리를 자동 생성합니다.
- SQL 성능 분석: 실행 시간이 긴 쿼리를 로그로 출력하여 성능 병목 탐지에 유용합니다.
- 전역 인터셉터: 잘못된 전체 삭제나 업데이트 작업을 차단할 수 있어 안정성 향상.
빠른 시작 가이드
- 데이터베이스 생성
샘플 데이터 삽입:DROP TABLE IF EXISTS user; CREATE TABLE user ( id BIGINT NOT NULL COMMENT '기본 키', name VARCHAR(30) NULL DEFAULT NULL COMMENT '이름', age INT NULL DEFAULT NULL COMMENT '나이', email VARCHAR(50) NULL DEFAULT NULL COMMENT '이메일', PRIMARY KEY (id) );INSERT INTO user (id, name, age, email) VALUES (1, 'Jone', 18, 'test1@baomidou.com'), (2, 'Jack', 20, 'test2@baomidou.com'), (3, 'Tom', 28, 'test3@baomidou.com'); - Spring Boot 프로젝트 설정
의존성 추가 (Maven):
<dependencies> <!-- MySQL 드라이버 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!-- Lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <!-- MyBatis-Plus Starter --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.3.1</version> </dependency> </dependencies>주의: mybatis와 mybatis-plus를 동시에 사용하지 마세요. 충돌 가능성 있음.
- application.yml 설정
spring: datasource: url: jdbc:mysql://localhost:3306/mybatis_plus?useSSL=false&serverTimezone=Asia/Seoul&characterEncoding=UTF-8 username: root password: your_password driver-class-name: com.mysql.cj.jdbc.Driver # MyBatis-Plus 로깅 활성화 mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl - 엔티티 클래스 작성
@Data @NoArgsConstructor @AllArgsConstructor public class User { private Long id; private String name; private Integer age; private String email; } - Mapper 인터페이스 정의
@Repository public interface UserMapper extends BaseMapper<User> { // BaseMapper를 상속함으로써 자동으로 CRUD 메서드 제공 }부트스트랩 클래스에 스캔 어노테이션 추가:
@SpringBootApplication @MapperScan("com.example.mapper") public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } - 테스트 코드 작성
@SpringBootTest class UserMapperTest { @Autowired private UserMapper userMapper; @Test void testSelectAll() { List<User> users = userMapper.selectList(null); users.forEach(System.out::println); } }
기본 CRUD 확장 기능
1. 데이터 삽입 및 ID 전략
기본적으로 ID_WORKER (Snowflake 기반) 전략을 사용합니다. 자동 증가를 원할 경우:
@Data
public class User {
@TableId(type = IdType.AUTO)
private Long id;
// ...
}
DB의 해당 컬럼도 AUTO_INCREMENT로 설정되어야 합니다.
2. 업데이트 작업
@Test
void testUpdate() {
User user = new User();
user.setId(2L);
user.setName("Updated Name");
userMapper.updateById(user);
}
MyBatis-Plus는 null 필드는 업데이트하지 않으며, 실제로 변경된 값만 반영됩니다.
3. 자동 필드 채우기 (생성일/수정일)
실제 운영 환경에서는 등록일과 수정일을 자동 관리하는 것이 좋습니다.
@Data
public class User {
// ...
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
}
핸들러 클래스 작성:
@Component
@Slf4j
public class AutoFillHandler implements 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());
}
}
4. 논리 삭제 (Soft Delete)
물리적 삭제 대신 상태 값으로 삭제 여부를 표시합니다.
-- 테이블에 deleted 컬럼 추가
ALTER TABLE user ADD COLUMN deleted TINYINT DEFAULT 0;
엔티티에 어노테이션 추가:
@TableLogic
private Integer deleted;
설정 파일에 전역 설정 추가:
mybatis-plus:
global-config:
db-config:
logic-delete-value: 1
logic-not-delete-value: 0
이후 모든 삭제 쿼리는 UPDATE로 변환되고, 조회 시 deleted = 0인 레코드만 반환됩니다.
5. 낙관적 락 (Optimistic Locking)
동시성 제어를 위한 버전 번호 기반 메커니즘입니다.
-- version 컬럼 추가
ALTER TABLE user ADD COLUMN version INT DEFAULT 1;
엔티티에 추가:
@Version
private Integer version;
인터셉터 등록:
@Configuration
@MapperScan("com.example.mapper")
public class MyBatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
}
6. 조건 쿼리 (QueryWrapper)
@Test
void testQueryWrapper() {
QueryWrapper<User> wrapper = new QueryWrapper<>();
// 이름이 null이 아니고 이메일이 포함된 조건
wrapper.isNotNull("name")
.like("email", "test")
.ge("age", 18);
List<User> users = userMapper.selectList(wrapper);
users.forEach(System.out::println);
}
코드 자동 생성기 (Code Generator)
MyBatis-Plus는 코드 생성기를 제공하여 반복적인 코드 작성을 줄여줍니다.
public class CodeGenerator {
public static void main(String[] args) {
FastAutoGenerator.create(
"jdbc:mysql://localhost:3306/mybatis_plus", "root", "password")
.globalConfig(builder -> {
builder.author("developer") // 작성자
.outputDir(System.getProperty("user.dir") + "/src/main/java"); // 출력 경로
})
.packageConfig(builder -> {
builder.parent("com.example")
.moduleName("demo")
.entity("model")
.mapper("mapper")
.service("service")
.controller("controller");
})
.strategyConfig(builder -> {
builder.entityBuilder()
.enableLombok()
.logicDeleteColumnName("deleted")
.versionColumnName("version");
builder.mapperBuilder()
.enableBaseResultMap()
.enableBaseColumnList();
builder.serviceBuilder()
.formatServiceFileName("%sService");
builder.controllerBuilder()
.enableRestStyle();
builder.addInclude("user"); // 생성할 테이블 지정
})
.execute();
}
}
이 방식을 사용하면 엔티티, 매퍼, 서비스, 컨트롤러 코드를 몇 초 만에 생성할 수 있습니다.