1. Database Framework의 종류
1. MyBatis
- 러닝 커브가 간단함(배우기가 쉬움)
- SQL문 기반
- 복잡한 쿼리를 사용할 때 많이 사용
- MyBatis 공식 참조 문서
https://mybatis.org/mybatis-3/
2. Hibernate
- 러닝 커브가 복잡함(배우기가 어려움)
- 메서드 기반
- 단순한 쿼리를 사용할 때 많이 사용
2. MyBatis 기본 사용 준비 (DataSource 객체 생성 및 DB연결정보를 멤버변수에 대입하기)
1. 필요한 라이브러리 다운로드
- pom.xml 수정을 통해 다운로드 (mvnrepository.com)
1) MyBatis Library 다운로드
- 최신버전 사용
2) MyBatis-Spring 다운로드 : MyBatis와 Spring을 연결하는 Library
- 최신버전 사용
3) Spring-jdbc 다운로드
- 현재 사용중인 Spring Framework 버전과 동일한 버전을 다운로드
4) jdbc 다운로드
- DB와 맞는 버전을 다운로드
2. Sample XML 생성
- 폴더 생성
1) src/main/resources 밑에 database폴더 생성
2) database 폴더 밑에 mappers, config 폴더 생성
- xml 생성
1) mappers 폴더 밑에 sampleMapper.xml 생성 (폴더명, 파일명은 상관없음)
2) sampleMapper.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="sample"></mapper>
- MyBatis 공식 문서 Configuration XML -> Handling Enums 의 xml 스키마를 복사
- sample mapper 태그 생성
- 앞으로 SQL문이 들어갈 공간임- MyBatis 설정 파일 생성 후 등록
1) src -> webapp -> WEB-INF -> spring -> database-context.xml 생성
- root-context.xml을 사용해도 괜찮으나, 따로 만들어서 관리하는 것임
- 폴더명 우클릭 -> new -> Spring Bean Configuration File
2) Web.xml에 database-context.xml 파일을 등록
<context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/spring/root-context.xml</param-value> <param-value>/WEB-INF/spring/database-context.xml</param-value> </context-param>
- 위와 같이 추가
- 서버가 실행되면 database-context.xml이 참조될 수 있도록 하는 작업임
- *** root-context 아래에 추가해야 예외가 안생김
- 2022.03.08 수정, context-param 하나밖에 인식을 못함, *-context.xml 하나로 통합해야 함!!
3. database.properties 파일 생성 후 database-context에 value 대입
1) src/main/resources/database/config 밑에 database.properties 파일 생성
- database.properties : DB의 로그인 정보 (ID, PW, IP주소)를 담는 파일
- Git ignore에 database.properties를 무시하도록 등록 (외부인이 DB접근 정보를 접하지 못하게 하기 위함)
- properties 파일 : key와 value로 구성
- properties 파일 한글 인코딩 설정
--- Window -> Preferences -> General -> Content Type
--- Text 선택 -> Java Properties File -> Default Encoding을 UTF-8로 변경후 Update
- database.properties 파일에 DB 로그인 정보 작성oracle.username=ID oracle.password=PW oracle.url=jdbc:oracle:thin:@DB의 IP주소:1521:orcl oracle.driver=oracle.jdbc.driver.OracleDriver
- 위와 같이 작성
2) database-context에 database.properties파일의 참조 주소를 작성
- database-context가 database.properties파일을 참조할 수 있게 태그를 작성<context:property-placeholder location="classpath:database/config/database.properties"/>
- context:property-placeholder 태그가 보이지 않으면 하단 NameSpace에서 context태그 추가
- src/main/resources 는 애플리케이션 배포 시 사라지는 폴더임
- 그 구간을 classpath 구간이라고 함
- classpath: 밑에, database 폴더 이하로 경로를 작성해주면 됨
3) database-context에 properties 값 대입<!-- DB 연결 정보가 들어있는 properties 파일의 위치를 알려주는 태그 --> <context:property-placeholder location="classpath:database/config/database.properties"/> <!-- DataSource 객체 생성, properties 파일에 저장된 연결정보를 DataSource 멤버변수에 대입 --> <bean class="org.springframework.jdbc.datasource.DriverManagerDataSource" id="dataSource"> <property name="username" value="${oracle.username}"></property> <property name="password" value="${oracle.password}"></property> <property name="url" value="${oracle.url}"></property> <property name="driverClassName" value="${oracle.driver}"></property> </bean>
- value 값에는 properties 파일에서 선언한 key명이 들어가면 됨
4. DataSource 객체가 만들어졌는지 Test
public class DataSourceTest extends InitTestCase{ @Autowired private DataSource dataSource; @Test public void connectionTest() { assertNotNull(dataSource); assertNotNull(dataSource.getConnection()); } }
- DataSource 객체가 만들어짐 = 예전에 DBConnector 객체가 만들어진것과 동일
- getConnection() 메서드 호출
--- 예전에 dbConnector.getConnection() 메서드 호출해서 Connection 객체를 만든 것과 동일
- 둘다 Null이 아니면 정상적으로 설정 완료
설명1. MyBatis를 사용하는 이유, 지금 한 설정의 의미
이전에는 메서드를 하나씩 실행할 때마다
Connection 객체를 통해 DB에 로그인해서 데이터 꺼내서 작업을 했었다.
MyBatis를 사용하게 되면,
서버가 시작할 때 Data Source가 요청이 들어오기 전에
Connection 객체를 수십개 (기본은 20개)를 만들어서 Connection pool이라는 곳에 저장을 해 놓는다.
그리고 요청이 들어오면 Data Source가 pool에서 로그인된 Connection 객체를 빌려준다.
그리고 다 사용하면 다시 pool에 반환을 해준다.
원래 우리가 기존에 DB와 연결을 했을 때를 생각해보자.
클라이언트에서 어떤 요청이 들어오면 컨트롤러를 거쳐 DAO의 메서드를 호출하게 되는데,
메서드를 호출할때 마다 Connection 객체를 만들어서 DB에 로그인을 했었다.
근데 MyBatis를 사용하게 되면
이미 로그인된 Connection 객체를 미리 많이 만들어 놓은 다음 필요한 곳에 빌려주는 개념인 것이다.
그리고 기존에 DB와 연결을 했을 때, 각각 메서드 안에 SQL문을 작성했었다.
근데 SQL문도 Java에서 분리해버린다. 대신 xml 파일에 작성을 해버린다.
최종적으로 우리가 지금까지 DB와 연결을 했을 때를 생각해보면,
1) DB 연결
2) SQL Query문 작성
3) 작성한 Query문을 DB로 미리 전송
4) ? 값 적용
5) 최종 전송 후 결과처리
이 과정을 DAO 클래스의 메서드 하나하나마다 작성해주었었다.
근데, MyBatis를 사용하면 이 모든 과정을 알아서 해준다.
프레임워크가 해주는 일이 무엇이었는가? 개발자는 소스코드로직에만 집중하라는 소리이다.
MyBatis를 통해서 앞으로는 DAO클래스의 메서드들은 리턴하는 값만 쓰게 될 것이다.
물론 자동은 없다. 당연히 몇가지 설정이 필요하다.
위에 써 놓은 설명은 그래서 그런 설정을 하기위해 작성해놓은 것이다.
database.properties 파일을 보면,
우리가 기존에 DBConnector 클래스에서 작성해놓았던
DB연결정보들이 그대로 들어가 있는 것을 볼 수 있다.
물론 database-context.xml의 value에 바로 직접 값을 대입해도 되지만,
굳이 properties 파일로 따로 빼 놓은 이유는 DB에 접근할 수 있는 중요 데이터들이기 때문에 숨겨놓기 위해서이다.
gitIgnore에 database.properties를 등록해 놓으면, git에는 DB 연결 정보는 올라가지 않기 때문이다.
그래서, database.properties 파일에 DB연결정보를 작성한 다음
database-context.xml에 value에 넣는 이 작업은 결국 우리가 기존에 DBConnector 클래스는 만드는 작업과 동일하다.
근데, 이렇게 한번 database-context.xml에 객체(bean)을 만들어 놓게 되면,
앞으로는 우리가 Connection 객체를 만들지 않아도 된다는 소리이다.
즉, 메서드 하나마나 Connection con = dbConnection.getConnect() 이 작업 안해도 된다는 소리이다.
이런 작업들을 개발자가 하지 않기 위해 하는 설정들이라고 보면 된다.
우선 지금 설정에서 DataSource 객체를 만든 것은 기존의 DBConnector 객체를 만들 것과 동일하고,
DataSource.getConnection()을 하면 기존의 DBConnector.getConnection() 작업과 똑같다고 보면 된다.
Connection 객체를 생성하는 것과 똑같다.
3. SQL문 연결 준비 (SqlSession 객체 생성)
1. database-context.xml에 SqlSessionFactoryBean 객체 추가 생성
- SqlSessionFactoryBean 객체가 필요한 것 : Connection 객체, mapper.xml의 위치, config파일의 위치
1) dataSource 멤버변수에 위에 만들어놓은 DataSource객체를 주입
2) mapperLocations 멤버변수에 위에 만들어놓은 sampleMapper.xml의 위치값을 대입
3) config파일 생성 후 위치값 대입
- <configuration></configuration> 미리 적어둘것, 안적어두면 객체 생성을 못함
<!-- Config 파일 --> <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> </configuration>
<!-- database-context.xml --> <bean class="org.mybatis.spring.SqlSessionFactoryBean" id="sqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"></property> <property name="mapperLocations" value="classpath:database/mappers/*Mapper.xml"></property> <property name="configLocation" value="classpath:database/config/mybatisConfig.xml"></property> </bean>
2. database-context.xml에 SqlSessionTemplate 객체 추가 생성
<!-- bean class 를 통해 객체를 생성하면 기본적으로 Default 생성자를 통해 객체를 생성하게 됨 --> <!-- 근데 SqlSessionTemplate 클래스는 기본 생성자가 없음, 생성자에 값을 넣어주어야 함 --> <bean class="org.mybatis.spring.SqlSessionTemplate" id="sqlSession"> <constructor-arg name="sqlSessionFactory" ref="sqlSessionFactoryBean"></constructor-arg> </bean>
- 최종적으로 DB와 연결하기 위해 우리가 사용하는 객체는 sqlSession (이름) 이다.
3. 객체가 만들어졌는지 확인
public class DataSourceTest extends InitTestCase{ @Autowired private SqlSession session; @Test public void sessionTest() { assertNotNull(session); } }
설명1. MyBatis가 작동하는 원리
우선 어떤 객체가 DB에 연결이 되어있는지를 SqlSessionFactoryBean 객체에 알려주어야 한다.
그래서 dataSource 멤버변수에 아까 위에서 만들어놓은 DataSource객체의 id값을 주입하면 된다.
그리고 MyBatis를 사용하면 Java에 SQL문을 작성하는 것이 아니라, 따로 xml 파일에 작성한다고 했다.
SQL문을 작성하는 xml파일은 우선 sampleMapper.xml 파일이다. 이는 아까 2번 세팅에서 만들어 놓았었다.
이 파일의 경로는 src/main/resources 아래 database/mappers/*Mapper.xml 에 만들어 놓았다.
근데, src/main/resources은 나중에 애플리케이션을 배포하면 없어지는 폴더이다.
그래서 나중에 이 공간은 classpath로 바뀌게 되기 때문에 최종 주소는
classpath:database/mappers/*Mapper.xml 가 되는 것이다.
이 주소를 mapperLocations 멤버변수의 값(value)에 넣어주면 된다.
나중에 어차피 SQL문을 적어놓는 xml파일은 이름을 통일시켜서 생성하는 것을 권장하게 된다.
그 이유는, 위에 주소를 보면 *Mapper.xml이다.
mappers 폴더 밑의 Mapper.xml로 끝나는 모든 파일이 mapper의 경로라는 소리이다.
만약 저렇게 적지 않고 xml파일의 이름을 통일시키지 않는다면, 일일히 다 적어주어야 하기에
앞으로 SQL문을 적는 xml파일은 뒤에 굳이 Mapper가 아니더라도
통일된 이름을 정해놓고, 저런식으로 주소를 value값으로 넘겨주면 된다.
그리고 MyBatis의 여러 기능을 이용할 수 있는 태그의 스키마를 사용하고,
설정을 모아놓는 config파일을 만든다음에 이 파일의 경로도 마찬가지로 등록을 해준다.
다음에 필요한 객체는 SqlSessionTemplate 객체이다.
우리가 앞으로 MyBatis를 사용하면서 최종적으로 사용하게 될 객체이다.
id는 그냥 간단하게 SqlSesstion이라고 설정해 놓았다.
자, 지금까지 설정한 것을 되새겨보자.
DB 연결정보를 저장해 놓고, 최종적으로 DB와 연결을 하는 객체는 DataSource 객체이다.
그리고 이 DataSource 객체는 SqlSessionFactoryBean 객체의 멤버변수에 저장을 해두었다.
그리고, SQL문을 작성하는 xml 파일의 경로도 역시 SqlSessionFactoryBean 객체의 멤버변수에 저장을 해두었다.
근데, 최종적으로 우리가 사용할 객체는 뭐다? SqlSessionTemplate(SqlSesstion) 객체이다.
그렇다면, SqlSessionTemplate 객체에다가 SqlSessionFactoryBean객체의 정보를 넘겨주면 끝 아닌가? 맞다.
그래서 애초에 SqlSessionTemplate 객체는 Default 생성자가 없다.
즉, 이 객체를 만들기 위해서는 생성자의 매개변수로 꼭 SqlSessionFactoryBean객체를 주어야 한다.
그래서 위의 코드를 보면, <constructor-arg> 태그를 통해서
SqlSessionTemplate 객체의 SqlSessionFactory 라는 멤버변수에
SqlSessionFactoryBean객체의 참조주소인 sqlSessionFactoryBean을 주입시켜준 것을 확인할 수 있다.
이러면 결국 SqlSessionTemplate 객체는,
최종적으로 DB와 연결을 하는 객체는 DataSource 객체,
그리고 이 객체를 멤버로 가지고 있고 xml 파일의 경로를 알고 있는 SqlSessionFactoryBean 객체를
멤버로 가지고 있기 때문에
최종적으로 우리가 SqlSessionTemplate 객체를 사용하게 되는 것이다.
<context:property-placeholder location="classpath:database/config/database.properties"/>
<bean class="org.springframework.jdbc.datasource.DriverManagerDataSource" id="dataSource">
<property name="username" value="${oracle.username}"></property>
<property name="password" value="${oracle.password}"></property>
<property name="url" value="${oracle.url}"></property>
<property name="driverClassName" value="${oracle.driver}"></property>
</bean>
<bean class="org.mybatis.spring.SqlSessionFactoryBean" id="sqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="mapperLocations" value="classpath:database/mappers/*Mapper.xml"></property>
</bean>
<bean class="org.mybatis.spring.SqlSessionTemplate" id="sqlSession">
<constructor-arg name="sqlSessionFactory" ref="sqlSessionFactoryBean"></constructor-arg>
</bean>
위의 xml 코드가 최종적으로 database-xml의 세팅을 마무리한 코드이다.
그냥 복사해서 붙여넣기만 해도 작동은 되겠지만,
이 원리를 알고 있어야 한다.
아까도 말했지만, 기존에 우리가 DB와 연결했던 작업들을 생각해보라.
1) DB 연결
2) SQL Query문 작성
3) 작성한 Query문을 DB로 미리 전송
4) ? 값 적용
5) 최종 전송 후 결과처리
이거? 앞으로 MyBatis가 다 해준다.
근데, 이걸 다 해주기를 바란다면, 최소한 어떻게 세팅을 하는지는 알아야 한다는 것이다.
우리가 부서테이블의 전체 정보를 출력했을 때를 MyBatis로 간단하게 구현해보면 아래와 같다.
<mapper namespace="com.cares.s1.dept.DeptDAO">
<!-- DAO 클래스의 메서드명과 id를 매핑시키면 됨 -->
<select id="list" resultType="com.cares.s1.dept.DeptDTO">
SELECT * FROM DEPARTMENTS
</select>
</mapper>
@Repository
public class DeptDAO {
@Autowired
private SqlSession sqlSession;
private final String NAMESPACE="com.cares.s1.dept.DeptDAO.";
public List<DeptDTO> list() throws Exception {
return sqlSession.selectList(NAMESPACE+"list");
}
}
위와 같이 작성해주면 그냥 끝이다.
List에 부서정보가 모두 담기게 된다.
MyBatis 사용법은 다음 글에서 다룰 예정이다.
'웹개발 풀스택 과정 > Spring Legacy' 카테고리의 다른 글
| 39일차(2022.02.18) _ MyBatis - TypeAliase 설정 (0) | 2022.02.18 |
|---|---|
| 38일차(2022.02.17) _ MyBatis 사용법 - Mapper, DAO 연결 (0) | 2022.02.17 |
| 37일차(2022.02.16) _ Junit Test Case 사용법 (0) | 2022.02.16 |
| 36일차(2022.02.15) _ Spring Project 생성 후 기본 설정 (0) | 2022.02.15 |
| 36일차(2022.02.15) _ DI(Dependency Injection), 객체 생성/주입 Annotation/XML, IOC(제어의 역전) (0) | 2022.02.15 |