포스코x코딩온 웹 풀스택 양성과정

[포스코x코딩온] 웹 풀스택 과정 18주차 회고 | Spring JDBC, MyBatis

Codult 2024. 4. 18. 23:42
728x90

SQL Mapper와 ORM

Spring은 대표적으로 SQL Mappler와 ORM을 데이터베이스와의 상호작용 방식으로 갖는다. 두 방식 모두 Java 객체와 데이터베이스 간의 상호 작용을 한다는 공통점이 있다.

📌 SQL Mapper

  • 주요 목적: SQL 쿼리와 Java 메서도/객체 간의 매핑을 중심으로 한다.
  • SQL 쿼리를 직접 작성해야 하며, 해당 쿼리의 결과를 Java 객체에 매핑한다.
  • 동적 SQL 생성, 조건문, 반복문 등의 SQL 작성에 보다 유연하다.
  • SQL 쿼리의 세밀한 튜닝이 필요할 때 주로 사용한다.
  • 예: JDBCTemplate, MyBatis

📌 ORM

  • 주요 목적: Java 객체와 데이터베이스 테이블 간의 관계를 매핑한다.
  • Java 객체 (Entity)가 데이터베이스 테이블과 어떻게 매핑될지를 정의한다.
  • 대분분의 CRUD 연산에 대한 SQL을 자동으로 생성하며, 객체지향적으로 데이터를 다룰 수 있다.
  • 예: Hibernate, JPA

📌 H2 Database

Java로 작성된 인메모리(in-memory) 관계형 데이터베이스 이다.

  • 설치 없이 사용 가능하며, 개발과 테스트를 빠르게 진행할 수 있다.
  • 인메모리 모두로 실행되면, 어플리케이션 종료 시 모든 데이터가 사라진다.
  • dependency 추가하여 H2 Database 생성할 수 있다.
implementation 'org.springframework.boot:spring-boot-starter-data-jdbc'
runtimeOnly 'com.h2database:h2'
  • 서버를 실행할 때마다 h2 database의 jdbc url이 난수로 변경되기 때문에, Application.properties 파일에서 이름을 지정해줄 수 있다.
spring.h2.console.enabled=true
spring.datasource.url=jdbc:h2:mem:mytestserverdb
  • localhost:8080/h2-console 으로 접속할 수 있다.


📌 Spring JDBC

JDBC(Java DataBase Connectivity)

  • Java에서 DB에 접근할 수 있도록 하는 Java API 이다.
  • 반복적이고 지루한 코드 작성이 필요하며, SQL 예외처리, 리소스 관련 (연결, 문, 결과 집합 닫기 등) 등의 복잡한 작업을 직접 처리해야 한다.

Spring JDBC

  • JDBC의 복잡성을 줄이기 위한 Sprign 프레임워크의 일부이다.
  • DB 작업을 단순화하고 코드의 양을 줄여준다.
  • 작동방식: 기존 JDBC 코드의 많은 부분을 추상화하고 템플릿 디자인 패턴을 이용한다.

  • JDBC Driver: 특정 DB와의 통신을 담당한다. (JDBC API가 제공하는 인터페이스와 실제 DB 간 연결하는 역할)

💡 JDBC 사용하기

sql 파일 생성

reosource 폴더에 생성할 테이블 정보를 담은 sql 파일을 만든다.

// schema.sql

create table users
    (
    id bigint not null,
    name varchar(255) not null,
    address varchar(255) not null,
    primary key (id)
    );

sql 쿼리 생성

실행하고자 하는 sql 쿼리를 작성하여 JdbcTemplate과 연결한다.

// UserJdbcRepository.java

@Repository
public class UserJdbcRepository {
	@Autowired
    private JdbcTemplate jdbc;
    private static String INSERT_USER =
    	"""
        	insert into users(id, name, address) values (?, ?, ?);
        """;
    private static String DELETE_USER = 
    	"""
        	delete fro users where id = ?;
        """;
    
    public void insert(Users user) {
    	jdbc.update(INSERT_USER, user.getId(), user.getName(), user.getAddress());}
	}
    public void deleteId(long id) {	
    	jdbc.update(DELETE_USER, id);
    }

 

📌 MyBatis

SQL Mapper로써, JDBC로 처리하는 상당 부분의 코드와 파라미터 설정 및 결과 매핑을 대신해주며, 객체 지향 언어인 Java와 관계형 데이터베이스 프로그래밍을 좀 더 쉽게 할 수 있도록 도와주는 프레임워크이다.

특징

1) 쉬운 접근성과 코드의 간결함

  • JDBC의 모든 기능을 MyBatis에서 사용할 수 있다.
  • 복잡한 JDBC 코드를 걷어내 깔끔한 소스코드를 유지할 수 있다.

2) SQL문과 프로그래밍 코드의 분리

  • SQL문과 프로그래밍 코드가 분리되어 있어, SQL에 변경이 있을 때 다시 컴파일할 필요가 없다.

3) 다양한 프로그래밍 언어로 구현가능

  • Java, C#, NET, Ruby

💡 MyBatis 사용하기

설정작업

dependency 라이브러리로 MyBatis를 추가한다.

//build.gradle

	implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:3.0.2'
	testImplementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter-test:3.0.2'

application.properties 파일에서 도메인과 mapper xml 파일을 가져올 위치를 설정해준다.

// application.properties

	mybatis.type-aliases-package=com.example.mybatis.testmybatis.domain
	mybatis.mapper-locations=mybatis-mapper/*.xml

sql문 작성

create table users
(
    id bigint not null auto_increment,
    name varchar(255) not null,
    address varchar(255) not null,
    primary key(id)
);

값을 지정하는 도메인 파일을 작성한다.

//Users.java (도메인)
public class Users {
	private long id;
    private String name;
    private String address;
    
    // getter, setter 추가 ...
}

도메인에서 실제로 작업이 필요한 변수는 변수 선언, getter, setter을 설정한 DTO파일을 생성한다. (DTO 파일을 생성함으로써, DB에서 전달받은 값에 무작위로 접근하는 것을 방지할 수 있다.)

// UsersDTO.java (DTO)
public class UsersDTO {
	private long id;
    private String name;
    private String address;
    
    // getter, setter 추가 ...
}

xml 파일 작성

실행하고자 하는 sql 쿼리를 xml 파일에 작성한다.
namespace로 mapper를 사용할 파일의 경로를 지정하고, sql 쿼리에 id를 설정하여 사용 시, 해당 id로 쿼리를 불러올 수 있다.

// UsersMapper.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.mybatis.testmybatis.mapper.UsersMapper">
    <select id="findAll" resultType="com.example.mybatis.testmybatis.domain.Users">
    // Users 도메인에 해당하는 resultType으로 지정해주었다.
        SELECT * FROM users
    </select>
</mapper>

Mapper 작성

인터페이스로 작성하여, 필요한 곳에 @Autowired 의존성 주입하여 사용할 수 있다.
xml 파일에서 작성한 쿼리의 id로 불러올 수 있다.
쿼리는 Mapper 인터페이스에서도 바로 작성할 수 있다.

//UsersMapper.java
@Mapper
public interface UserMapper {
	List<Users> findAll();
    
    // 직접 sql문 선언하여 메서드와 연결
    @Insert("INSERT INTO users (name, address) VALUES (#{name}, #{address})")
}

Service 작성

Controller에서 전달받은 요청에 따라, 특정 쿼리를 실행하거나 쿼리 실행 후 결과값을 원하는 형태로 전달하는 등의 작업을 담당한다.

//UsersService.java
@Service
public class UsersService {
	@Autowired
    private UsersMapper usersMapper;
    
    public List<UsersDTO> getUsersList(){
    	List<Users> result = usersMapper.findAll();
        List<UsersDTO> users = new ArrayList<>();
        for (int i = 0; i < result.size(); i++) {
        	UsersDTO user = new UsersDTO();
            user.setId(result.get(i).getId());
            user.setName(result.get(i).getName());
            user.setAddress(result.get(i).getAddress());
            users.add(user);
        }
    	return users;
   }
   
   public void addUser(Users user) { usersMapper.insert(user);}
}

Controller 작성

요청에 따라 적절한 Service의 메서드가 실행되도록 한다.

//UsersController.java

@Controller
public class UsersController {
	@Autowired
    public UsersService usersService;
    
    @GetMapping("/users")
    public String getUsers(Model model) {
    	List<UsersDTO> usersList = usersService.getUsersList();
        model.addAttribute("list", usersList);
        return "user";
    }
    
    @GetMapping("/insert")
    public String getInsertUser(@RequestParam String name, @RequestParam String address, Model model) {
    	Users user = new Users();
        user.setName(name);
        user.setAddress(address);
        usersService.addUser(user);
        model.addAttribute("list", null);
        return "user";
    }
}

 

728x90