스프링 JDBC 프로그래밍 - MyBatis 연동

2021. 4. 22. 03:48 Java 관련/MyBatis, iBatis

스프링 JDBC 프로그래밍 - MyBatis 연동

이 글에서는 Oracle DB 11g를 사용한다고 가정한다.

다른 DB를 사용해도 무방하다.

 

MyBatis

- Spring JDBC 프로그래밍을 쉽게 작업할 수 있도록 만든 라이브러리

- Mapper의 역할을 확장하여 쿼리문 작성을 모두 Mapper에서 할 수 있도록 지원한다.


의존성 추가

Spring JDBC, Oracle JDBC 드라이버, Apache Commons DBCP와 MyBatis 라이브러리 의존성을 추가한다.

<!-- Spring JDBC -->
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-jdbc</artifactId>
	<version>5.1.9.RELEASE</version>
</dependency>

<!-- Oracle JDBC Driver -->
<dependency>
	<groupId>com.oracle</groupId>
	<artifactId>ojdbc6</artifactId>
	<version>11.2.0.3</version>
</dependency>

<!-- Apache Commons DBCP -->
<dependency>
	<groupId>org.apache.commons</groupId>
	<artifactId>commons-dbcp2</artifactId>
	<version>2.7.0</version>
</dependency>

<!-- MyBatis -->
<dependency>
	<groupId>org.mybatis</groupId>
	<artifactId>mybatis</artifactId>
	<version>3.5.2</version>
</dependency>

<dependency>
	<groupId>org.mybatis</groupId>
	<artifactId>mybatis-spring</artifactId>
	<version>2.0.2</version>
</dependency>

MyBatis 라이브러리는 총 2개를 추가해야 한다. mybatis-spring은 MyBatis와 Spring을 연동할수 있도록 하는 라이브러리이다.

 

Oracle DB를 사용할 경우 Oracle JDBC 드라이버를 관리하는 레파지토리를 추가해야 한다.

<repository>
	<id>oracle</id>
	<name>ORACLE JDBC Repository</name>
	<url>http://code.lds.org/nexus/content/groups/main-repo</url>
</repository>

 

테이블 구조

대상 테이블은 다음과 같다.

create table jdbc_table(
int_data number not null,
str_data varchar2(500) not null
);

 

Mapper 인터페이스 정의

public interface MapperInterface {

}

Mapper 인터페이스는 DAO 대신 사용되며 여기에 MyBatis의 @Select, @Insert, @Update, @Delete 애노테이션을 사용해서 DB 연동에 필요한 쿼리문과 메소드를 정의할 것이다.

 

DataSource, SqlSessionFactory, Mapper 빈 정의

스프링 빈 설정 클래스에서 DataSource, SqlSessionFactory, Mapper 빈을 정의한다.

import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.mapper.MapperFactoryBean;

@Configuration
@ComponentScan
public class BeanConfigClass {
	
	// data source
	@Bean
	public BasicDataSource dataSource() {
		BasicDataSource source = new BasicDataSource();
		source.setDriverClassName("oracle.jdbc.OracleDriver");
		source.setUrl("jdbc:oracle:thin:@localhost:1521:orcl");
		source.setUsername("scott");
		source.setPassword("1234");
		
		return source;
	}
	
	// SqlSessionFactory
	@Bean
	public SqlSessionFactory factory(BasicDataSource source) throws Exception{
		SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
		factoryBean.setDataSource(source);
		SqlSessionFactory factory = factoryBean.getObject();
		
		return factory;
	}
	
	// Mapper
	@Bean
	public MapperFactoryBean<MapperInterface> test_mapper(SqlSessionFactory factory) throws Exception{
		MapperFactoryBean<MapperInterface> factoryBean = new MapperFactoryBean<MapperInterface>(MapperInterface.class);
		factoryBean.setSqlSessionFactory(factory);
		
		return factoryBean;
	}
}

SqlSessionFactory 빈은 메소드 파라미터로 BasicDataSource를 주입받고 MapperFactoryBean은 SqlSessionFactory를 주입받는다.

MapperFactoryBean의 제네릭 타입으로 이전에 정의한 Mapper 인터페이스를 지정한다.

객체 생성 방법은 위 코드를 참고한다.

 

VO 클래스

@Component
@Scope("prototype")
public class JdbcBean {
	
	private int int_data;
	private String str_data;
	
	public int getInt_data() {
		return int_data;
	}
	public void setInt_data(int int_data) {
		this.int_data = int_data;
	}
	public String getStr_data() {
		return str_data;
	}
	public void setStr_data(String str_data) {
		this.str_data = str_data;
	}
}

테이블 구조와 동일한 VO 클래스를 생성한다.

Component를 붙여 VO클래스를 빈으로 등록하고 scope는 prototype으로 한다.

컬럼과 매핑되는 필드를 선언할때 컬럼명과 필드명을 동일하게 하는게 설정이 줄어 코딩하기 편하다.

 

Insert, Select, Update, Delete 구현

MyBatis를 사용하면 쿼리문을 Mapper 인터페이스에 정의한다.

 

1) Insert

import org.apache.ibatis.annotations.Insert;

public interface MapperInterface {

	@Insert("insert into jdbc_table (int_data, str_data) values (#{int_data}, #{str_data})")
	void insert_data(JdbcBean bean);
}

MyBatis의 @Insert 애노테이션을 사용해서 insert를 구현한다.

#{}에 프로퍼티명을 써서 값을 바인딩할 수 있다.

 

public static void main(String[] args) {

	AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(BeanConfigClass.class);
	
	MapperInterface mapper = ctx.getBean("test_mapper", MapperInterface.class);
	
	// insert
	JdbcBean bean2 = new JdbcBean();
	bean2.setInt_data(100);
	bean2.setStr_data("문자열100");
	mapper.insert_data(bean2);

	JdbcBean bean3 = new JdbcBean();
	bean3.setInt_data(200);
	bean3.setStr_data("문자열200");
	mapper.insert_data(bean3);
	
	ctx.close();
}	

사용 시에는 정의한 Mapper 빈을 Mapper 인터페이스 타입으로 받아서 메소드를 호출하면 된다.

 

2) Select

import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;

public interface MapperInterface {

	@Insert("insert into jdbc_table (int_data, str_data) values (#{int_data}, #{str_data})")
	void insert_data(JdbcBean bean);
    
	/*
	@Results({
		@Result(column = "int_data", property = "int_data"),
		@Result(column = "str_data", property = "str_data")
	})
	*/
	@Select("select int_data, str_data from jdbc_table")
	List<JdbcBean> select_data();
}

MyBatis의 @Select 애노테이션을 사용해서 select를 구현한다.

컬럼명과 프로퍼티명이 다르다면 주석처리한 코드와 같이 @Results, @Result를 사용해서 설정해주어야 한다.

같으면 생략할 수 있다.

 

public static void main(String[] args) {

	AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(BeanConfigClass.class);
	
	MapperInterface mapper = ctx.getBean("test_mapper", MapperInterface.class);
    
	// insert
	JdbcBean bean2 = new JdbcBean();
	bean2.setInt_data(100);
	bean2.setStr_data("문자열100");
	mapper.insert_data(bean2);

	JdbcBean bean3 = new JdbcBean();
	bean3.setInt_data(200);
	bean3.setStr_data("문자열200");
	mapper.insert_data(bean3);    
	
	// select
	List<JdbcBean> list1 = mapper.select_data();
	for(JdbcBean bean1 : list1) {
		System.out.printf("int_data : %d\n", bean1.getInt_data());
		System.out.printf("str_data : %s\n", bean1.getStr_data());
		System.out.println("--------------------------------------");
	}
	
	ctx.close();
}	

 

3) Update

import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Update;

public interface MapperInterface {

	@Insert("insert into jdbc_table (int_data, str_data) values (#{int_data}, #{str_data})")
	void insert_data(JdbcBean bean);
    
	/*
	@Results({
		@Result(column = "int_data", property = "int_data"),
		@Result(column = "str_data", property = "str_data")
	})
	*/
	@Select("select int_data, str_data from jdbc_table")
	List<JdbcBean> select_data();
    
	@Update("update jdbc_table set str_data = #{str_data} where int_data = #{int_data}")
	void update_data(JdbcBean bean);    
}

MyBatis의 @Update 애노테이션을 사용해서 update를 구현한다.

 

public static void main(String[] args) {

	AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(BeanConfigClass.class);
	
	MapperInterface mapper = ctx.getBean("test_mapper", MapperInterface.class);
    
	// insert
	JdbcBean bean2 = new JdbcBean();
	bean2.setInt_data(100);
	bean2.setStr_data("문자열100");
	mapper.insert_data(bean2);

	JdbcBean bean3 = new JdbcBean();
	bean3.setInt_data(200);
	bean3.setStr_data("문자열200");
	mapper.insert_data(bean3);    
	
	// select
	List<JdbcBean> list1 = mapper.select_data();
	for(JdbcBean bean1 : list1) {
		System.out.printf("int_data : %d\n", bean1.getInt_data());
		System.out.printf("str_data : %s\n", bean1.getStr_data());
		System.out.println("--------------------------------------");
	}
    
	// update
	JdbcBean bean4 = new JdbcBean();
	bean4.setInt_data(100);
	bean4.setStr_data("문자열300");
	mapper.update_data(bean4);    
	
	ctx.close();
}	

 

4) Delete

import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Update;
import org.apache.ibatis.annotations.Delete;

public interface MapperInterface {

	@Insert("insert into jdbc_table (int_data, str_data) values (#{int_data}, #{str_data})")
	void insert_data(JdbcBean bean);
    
	/*
	@Results({
		@Result(column = "int_data", property = "int_data"),
		@Result(column = "str_data", property = "str_data")
	})
	*/
	@Select("select int_data, str_data from jdbc_table")
	List<JdbcBean> select_data();
    
	@Update("update jdbc_table set str_data = #{str_data} where int_data = #{int_data}")
	void update_data(JdbcBean bean);    

	@Delete("delete from jdbc_table where int_data = #{abc}")
	void delete_data(int int_data);
}

MyBatis의 @Delete 애노테이션을 사용하여 delete를 구현한다.

객체의 프로퍼티와 달리 한 개의 기본 타입 파라미터는 #{}에 아무 이름이나 지정할 수 있다.

위 delete 추상 메소드에서도 int 타입의 파라미터를 int_data라는 이름으로 받지만 #{abc}로 바인딩하고 있다.

 

public static void main(String[] args) {

	AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(BeanConfigClass.class);
	
	MapperInterface mapper = ctx.getBean("test_mapper", MapperInterface.class);
    
	// insert
	JdbcBean bean2 = new JdbcBean();
	bean2.setInt_data(100);
	bean2.setStr_data("문자열100");
	mapper.insert_data(bean2);

	JdbcBean bean3 = new JdbcBean();
	bean3.setInt_data(200);
	bean3.setStr_data("문자열200");
	mapper.insert_data(bean3);    
	
	// select
	List<JdbcBean> list1 = mapper.select_data();
	for(JdbcBean bean1 : list1) {
		System.out.printf("int_data : %d\n", bean1.getInt_data());
		System.out.printf("str_data : %s\n", bean1.getStr_data());
		System.out.println("--------------------------------------");
	}
    
	// update
	JdbcBean bean4 = new JdbcBean();
	bean4.setInt_data(100);
	bean4.setStr_data("문자열300");
	mapper.update_data(bean4); 
    
	// delete
	mapper.delete_data(100);    
	
	ctx.close();
}	

 

관련 글

스프링 JDBC 프로그래밍 - JdbcTemplate

 

출처 : atoz-develop.tistory.com/entry/%EC%8A%A4%ED%94%84%EB%A7%81-JDBC-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-MyBatis-%EC%97%B0%EB%8F%99?category=869245