MyBatis

2024. 1. 4. 16:09
728x90

1. MyBatis Framework

- JDBC만 이용해 데이터베이스를 쓴다면...? 복잡하고 실수하기 쉽다.. ㅠㅡㅠ

public void executeInsert(Student student) {
    String sql = "INSERT INTO student (name, age, phone, email) VALUES (?, ?, ?, ?)";
    try (Connection connection = dataSource.getConnection();
         PreparedStatement statement = connection.prepareStatement(sql)){

        statement.setString(1, student.getName());
        statement.setInt(2, student.getAge());
        statement.setString(3, student.getPhone());
        statement.setString(4, student.getEmail());

        statement.executeUpdate();
    } catch (SQLException e) {
        log.error(e.getMessage(), e);
    }
}

 

MyBatis Framework

: JDBC를 이용하지만, JDBC를 활용하기 위해 필요한 많은 과정을 추상화하여 복잡함을 줄임.

- Java interface의 메서드에 개발자가 정해둔 SQL문을 매핑하여 사용하도록 만들어짐. 

- 인자와 결과를 Java 객체로서 활용가능.

 

MyBatis 시작하기

1) 프로젝트 의존성 추가하기

//build.gradle 설정 추가
dependencies {
	implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:3.0.3'
}

 

2) 스프링부트 데이터베이스 설정하기 : application.yml / application.properties

  • url : 데이터베이스에 접속하기 위한 URL
  • driver-class-name : 데이터베이스를 사용할 때 사용할 JDBC 드라이버. (사용하는 RDBMS에 따라 다름)
  • username/ password : 데이터베이스의 접속 정보를 작성하는 곳
//application.yml
spring:
  datasource:
    url: jdbc:sqlite:db.sqlite
    driver-class-name: org.sqlite.JDBC
#   username: sa
#   password: password


//application.properties
spring.datasource.url=jdbc:sqlite:db.sqlite
spring.datasource.driver-class-name=org.sqlite.JDBC

 

3) MyBatis 관련 설정하기 : application.yml / application.properties

//application.yml 
mybatis:
  mapper-locations: "classpath:mybatis/mappers/*.xml"
  type-aliases-package: "com.example.crud.model"
  configuration:
    map-underscore-to-camel-case: true
    
//application.properties
mybatis.mapper-locations=classpath:mybatis/mappers/*.xml
mybatis.type-aliases-package=com.example.mybatis.model
mybatis.configuration.map-underscore-to-camel-case=true

 

** properties VS yaml

: 둘다 java 프로젝트에서 설정하는데 사용.

- properties : 단순 키=값 형태로 정리된 설정

- yaml : 설정이 계층 구조로 이뤄져 가독성이 뛰어남.

 

2. Annotation으로 SQL 작성

1) StudentMapper interface 생성/ @Mapper 애너테이션 추가

@Mapper
public interface StudentMapper {

}

 

2) Select 메서드 만들어보기

@Mapper
public interface StudentMapper {
    //Mybatis는 인터페이스의 메서드에 SQL을 연결시킨다.
    // 마이바티스의 세션을 이용해서 인터페이스의 메서드를 실행하면
    // 연결된 SQL이 실행된다. 
    @Select("SELECT * FROM students;")
    List<StudentDto> selectStudentAll();
}

 

3) Dao 객체 만들기

//Data Access Object
// 데이터 통신을 담당하는 클래스임을 스프링에 알려줌.
public class StudentDao {
    // Mybatis와 데이터베이스를 연결해주는 객체
    private final SqlSessionFactory sessionFactory;

    // Spring Boot안에 만들어진 SqlSessionFactory Bean이 자동으로 주입된다.
    public StudentDao(SqlSessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }
}

 

4) SELECT ALL

: 데이터베이스에서 학생 데이터를 불러오는 메서드 만들어보기

- SqlSession : DataBase와 MyBatis가 연결되었다는 것을 상징하는 객체. Mapper interface 제

//StudentDao class

    // 데이터베이스에서 학생 데이터를 전부 불러오는 메서드
    public List<StudentDto> readStudentsAll(){
        // SqlSession은 MyBatis와 데이터베이스가 연결되었다는 것을 상징하는 객체
        try (SqlSession session = sessionFactory.openSession()) {
            // Mapper 인터페이스를 가져온다. (그 안의 메서드를 실행가능)
            StudentMapper mapper = session.getMapper(StudentMapper.class);
            return mapper.selectStudentAll();
        }
    }

>> 이렇게 하면 마이바티스로 연결하여 학생 정보 전체 선택 조회 가능...

 

5) INSERT : 학생 데이터 넣기

- StudentMapper 메서드 생성 >> 인자 전달은 #{param}으로 전달하여 SQL의 해당 부분을 대치한다. 

// StudentMapper interface
    @Insert("INSERT INTO students (name, email) " +
            "VALUES(#{name}, #{email})")
    void insertStudent(StudentDto dto);

- StudentDao에서 메서드 생성 : StudentDto를 받아 학생을 데이터베이스에 추가하는 메서드

// StudentDao class
    public void insertStudent(StudentDto dto) {
        try (SqlSession session = sessionFactory.openSession()) {
            StudentMapper mapper = session.getMapper(StudentMapper.class);
            mapper.insertStudent(dto);
        }
    }

- service에서 메서드 생성 

//StudentService class
	public void createStudent(String name, String email) {
        StudentDto dto = new StudentDto();
        dto.setName(name);
        dto.setEmail(email);
        dao.insertStudent(dto);
    }

 

6) SELECT ONE : 학생 객체 한명 반환

- StudentMapper 메서드 생성 >> 인자 전달은 #{param}으로 전달하여 SQL의 해당 부분을 대치한다. 

// StudentMapper interface
    @Select("SELECT * FROM student " +
            "where id = #{id};")
    StudentDto selectStudentOne(Long id);

- StudentDao에서 메서드 생성 : StudentDto를 받아 학생을 데이터베이스에 추가하는 메서드

// StudentDao class
    // id를 Long으로 받아 데이터베이스에서 id가 같은 줄을 반환하는 메서드
    public StudentDto readStudentOne(Long id) {
        try (SqlSession session = sessionFactory.openSession()) {
            StudentMapper mapper = session.getMapper(StudentMapper.class);
            return mapper.selectStudentOne(id);
        }
    }

- service에서 메서드 생성 

//StudentService class
	public StudentDto readStudentOne(Long id) {
        return dao.readStudentOne(id);
    }

 

7) UPDATE : 학생 객체 수정

- StudentMapper 메서드 생성 >> 인자 전달은 #{param}으로 전달하여 SQL의 해당 부분을 대치한다. 

// StudentMapper interface
    @Update("UPDATE student SET " +
            "name=#{name}, " +
            "email=#{email} " +
            "where id=#{id}")
    void updateStudent(StudentDto dto);

- StudentDao에서 메서드 생성 : StudentDto를 받아 학생을 데이터베이스에 추가하는 메서드

// StudentDao class
    public void updateStudent(StudentDto dto) {
        try (SqlSession session = sessionFactory.openSession()) {
            StudentMapper mapper = session.getMapper(StudentMapper.class);
            mapper.updateStudent(dto);
        }
    }

- service에서 메서드 생성 

//StudentService class
	public StudentDto updateStudent(Long id, String name, String email) {
        StudentDto dto = this.readStudentOne(id);
        dto.setName(name);
        dto.setEmail(email);
        dao.updateStudent(dto);
        return dto;
    }

 

8) DELETE : 학생 객체 삭제

- StudentMapper 메서드 생성 >> 인자 전달은 #{param}으로 전달하여 SQL의 해당 부분을 대치한다. 

// StudentMapper interface
    @Delete("DELETE FROM student " +
            "WHERE id=#{id}")
    void deleteStudent(Long id);

- StudentDao에서 메서드 생성 : StudentDto를 받아 학생을 데이터베이스에 추가하는 메서드

// StudentDao class
    public void deleteStudent(Long id) {
        try (SqlSession session = sessionFactory.openSession()) {
            StudentMapper mapper = session.getMapper(StudentMapper.class);
            mapper.deleteStudent(id);
        }
    }

- service에서 메서드 생성 

//StudentService class
    public void deleteStudent(Long id) {
        StudentDto dto = this.readStudentOne(id);
        dao.deleteStudent(id);
    }

 

 

3. XML로 SQL 작성

1) XML과 interface 연결

- interface 정의

public interface StudentXmlMapper {}

 

- xml 파일 필수 설정

//resources > StudentMapper.xml

<?xml version="1.0" encoding="UTF-9" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
	"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

 

- XML mapper 설정

  • namespace : 어떤 interface와 연결할 xml인지를 지정
  • id : 연결하고자 하는 인터페이스의 메서드 이름
  • resultType : SQL 결과를 담기위한 자료형(클래스) 
  • parameterType : SQL에 전달할 인자 타입 (일반적인 자바 클래스를 사용할 수 있다.)
<mapper namespace="com.example.crud.mapper.StudentXmlMapper">
<!--실행하고 싶은 SQL을 넣어줄 수 있다. -->
    <select id="selectStudentAll" resultType="com.example.crud.model.StudentDto">
        select * from student;
    </select>
</mapper>

 

- repository에서의 사용방법은 annotation과 동일하다.

@RequiredArgsConstructor
@Repository
public class StudentXmlDao {
    private final SqlSessionFactory sessionFactory;

    public List<StudentDto> readStudentAll() {
        //사용방식은 annotation 기반과 동일하다.
        try (SqlSession session = sessionFactory.openSession()) {
            StudentXmlMapper mapper = session.getMapper(StudentXmlMapper.class);
            return mapper.selectStudentAll();
        }
    }
}

 

--> xml 활용한 방법은 좀더 복잡한 sql문 사용 가능하여 복잡한 쿼리가 필요한 프로젝트에서 많이 사용한다. 

쿼리를 그 자체로 활용할 수 있다는 장점이 있다~

(annotation 활용한 방법은 간단한 쿼리문만으로도 가능할 때 주로 사용.)

 

 

전체 코드 **

더보기

- StudentMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.example.crud.mapper.StudentXmlMapper">
    <select id="selectStudentAll" resultType="StudentDto">
        select * from student;
    </select>

    <select id="readStudentOne" resultType="StudentDto"
            parameterType="Long">
        select *
        from student
        where id = #{id};
    </select>

    <insert id="insertStudent" parameterType="StudentDto">
        insert into student (name, email)
        VALUES (#{name}, #{email});
    </insert>

    <update id="updateStudent" parameterType="StudentDto">
        update student
        set name = #{name},
            email=#{email}
        where id = #{id};
    </update>

    <delete id="deleteStudent" parameterType="Long">
        delete
        from student
        where id = #{id};
    </delete>
</mapper>

- StudentXmlMapper.java

import com.example.crud.model.StudentDto;

import java.util.List;

public interface StudentXmlMapper {
    List<StudentDto> selectStudentAll();
    void insertStudent(StudentDto dto);
    StudentDto readStudentOne(Long id);
    void updateStudent(StudentDto dto);
    void deleteStudent(Long id);
}

- StudentXmlDao.java

import com.example.crud.mapper.StudentMapper;
import com.example.crud.mapper.StudentXmlMapper;
import com.example.crud.model.StudentDto;
import lombok.RequiredArgsConstructor;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.stereotype.Repository;

import java.util.List;

//bean 객체 등록
@RequiredArgsConstructor
@Repository
public class StudentXmlDao {
    private final SqlSessionFactory sessionFactory;

    public List<StudentDto> readStudentAll() {
        //사용방식은 annotation 기반과 동일하다.
        try (SqlSession session = sessionFactory.openSession()) {
            StudentXmlMapper mapper = session.getMapper(StudentXmlMapper.class);
            return mapper.selectStudentAll();
        }
    }

    public void insertStudent(StudentDto dto) {
        try (SqlSession session = sessionFactory.openSession()) {
            StudentXmlMapper mapper = session.getMapper(StudentXmlMapper.class);
            mapper.insertStudent(dto);
        }
    }

    public StudentDto readStudentOne(Long id) {
        try (SqlSession session = sessionFactory.openSession()) {
            StudentXmlMapper mapper = session.getMapper(StudentXmlMapper.class);
            return mapper.readStudentOne(id);
        }
    }

    public void updateStudent(StudentDto dto) {
        try (SqlSession session = sessionFactory.openSession()) {
            StudentXmlMapper mapper = session.getMapper(StudentXmlMapper.class);
            mapper.updateStudent(dto);
        }
    }

    public void deleteStudent(Long id) {
        try (SqlSession session = sessionFactory.openSession()) {
            StudentXmlMapper mapper = session.getMapper(StudentXmlMapper.class);
            mapper.deleteStudent(id);
        }
    }
}

- StudentService.java

import com.example.crud.model.StudentDto;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
@RequiredArgsConstructor
public class StudentService {

    private final StudentXmlDao xmlDao;

    public void createStudent(String name, String email) {
        StudentDto dto = new StudentDto();
        dto.setName(name);
        dto.setEmail(email);
        xmlDao.insertStudent(dto);
    }

    //현재 등록된 모든 학생을 반환한다.
    public List<StudentDto> readStudentAll() {
        return xmlDao.readStudentAll();
    }

    //id를 받아서 하나의 학생 데이터를 반환한다.
    public StudentDto readStudentOne(Long id) {
        return xmlDao.readStudentOne(id);
    }

    public StudentDto updateStudent(Long id, String name, String email) {
        StudentDto dto = this.readStudentOne(id);
        dto.setName(name);
        dto.setEmail(email);
        xmlDao.updateStudent(dto);
        return dto;
    }

    //id를 바탕으로 학생을 제거하는 메서드
    public void deleteStudent(Long id) {
        StudentDto dto = this.readStudentOne(id);
        xmlDao.deleteStudent(id);
    }
}
728x90

'Programming > Spring, SpringBoot' 카테고리의 다른 글

Spring Beans  (0) 2024.01.15
Spring Data JPA (Java Persistence API)  (2) 2024.01.07
Post/Redirect/Get : redirect를 사용해야하는 이유  (0) 2024.01.04
Spring MVC & Thymeleaf  (4) 2024.01.03
스프링부트 기초  (0) 2024.01.03

BELATED ARTICLES

more