java - mybatis 사용 (no spring)
검색하다 보면 mybatis 사용하는 예제들은 다 spring에 붙여서 쓰던데,
이번에 나는 executable jar로 말아서 사용했어야 해서 (배치작업용)
그것에 대해 작성해보려고 한다.
- lib 폴더에 jar 파일 가져다 놓고 import 하기
- db 정보, mybatis 설정, mapper 설정하기
- 이제 사용하기
순으로 정리 된다.
필요한 라이브러리를 jar를 받아준다.
다른 건 필요 없고, 각 DB에 맞는 라이브러리 와 mybatis 라이브러리 두 개를 넣어준다.
eclipse 기준으로 프로젝트 우클릭 → Build Path → Libraries → Add jars 해서 두 개의 라이브러리를 추가해 준다.
properties를 설정해 준다.
spring에 붙여서 쓸 때처럼 properties를 설정해줘야 하는데
db 설정 (db.properties)
#mysql - table
table.driver = com.mysql.cj.jdbc.Driver
table.url = jdbc:mysql://{ip}:{port}/{DB이름}?useUniCode=yes&characterEncoding=utf8
table.user = {db id}
table.password = {db password}
#mysql - table2
table2.driver = com.mysql.cj.jdbc.Driver
table2.url = jdbc:mysql://127.0.0.1:3306/localtestdb?useUniCode=yes&characterEncoding=utf8
table2.user = root
table2.password = 1234
크게 driver, url, user, password 이렇게 세팅해 주면 된다.
한 개의 DB만 쓸 때는 하나만, 여러개를 쓸때는 이렇게 각 DB 별로 정보를 세팅해 주면 된다.
mybatis 설정 (MyBatisConfig.xml)
environment에 위에서 설정했던 db 정보들 (driver, url, user, password)을 넣어준다.
여러 db 정보들은 enviroments 안에 각 enviroment 정보로 세팅…
각 environment는 id를 가지고 있고, 나중에 java에서는 이 id를 기준으로 사용한다.
mapper 경로는 같은 jar안에 꾸겨넣어서 쓸 거면 resources로, jar바깥에서 참조할 거면 url로 절대경로 써주면 된다. 나 같은 경우는 jar 바깥에 구성하고 나중에 db가 변경되거나, 쿼리를 변경해야 할 때를 대비해 바깥에 빼놓았어서 url로 절대경로를 써줬다. (절대경로 사용 시에는 (file:///) 을 접두사로 붙여준다.)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="table_mysql">
<environment id="table_mysql">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${table.driver}"/>
<property name="url" value="${table.url}"/>
<property name="username" value="${table.user}"/>
<property name="password" value="${table.password}"/>
</dataSource>
</environment>
<environment id="table2_mysql">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${table2.driver}"/>
<property name="url" value="${table2.url}"/>
<property name="username" value="${table2.user}"/>
<property name="password" value="${table2.password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="conf/Mapper_table.xml"/>
<mapper url="file:///{mapper 절대경로}/Mapper_table2.xml"/>
</mappers>
</configuration>
mapper.xml 설정 (실제 사용될 쿼리들)
mapper.xml에는 실제 사용될 쿼리들을 적어준다.
중요한 건 mapper의 namespace, 쿼리별 id, 쿼리의 인자(parameterType), 쿼리의 결과(resultType)이다.
<?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="conf.Mapper_table">
<select id="totalCount" resultType="map">
select count(1) as cnt
from dummytable
;
</select>
</mapper>
java에서 사용할 때,
resultType 변수명 = sqlSession.select(”namespace. 쿼리 id”, parameterType의 변수)로 사용하니까…
그럼 이 파일들은 어디에 놓냐? 자기 마음이겠지만… 내 경우엔
패키지를 하나 구성해서 해당 영역에 넣어줬다. 물론 eclipse 내에서 실행할 때는 이렇게 두고 하지만
jar로 만들어 실행할때는 외부에 해당 conf 폴더를 따로 두고 그 폴더를 읽게 구성했다.
사용하기
사용하기 앞서, 위에 설정했던 파일을 읽어드릴 config.java 파일들을 구성해야 한다.
세팅한 순서대로 DB 설정을 읽고 → mybtis 설정을 읽고 → mapper를 불러온다
//DBConfig.java
package mybatisTest.db;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Properties;
public class DBConfig {
public static Properties prop = new Properties();
static {
try {
InputStream is = DBConfig.class.getResourceAsStream("../conf/db.properties");
if(is == null) {
is = new FileInputStream("./conf/db.properties");
}
prop.load(is);
is.close();
}catch(Exception e) {
e.printStackTrace();
System.out.println("db.properties file not found!");
}
}
}
eclipse 내 실행 시에는 resource를 통해서 읽게끔(같은 패키지내 config 파일), jar 실행시에는 외부의 conf 파일을 읽게끔 구성했다.
중요한 건 prop형식으로 config 설정 값을 static으로 가지고 있다는 점이다.
mybatis 설정 파일을 읽기
//MybatisConfig.java
package mybatisTest.db;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class MybatisConfig {
private static SqlSessionFactory table_sqlSessionFactory;
private static SqlSessionFactory table2_sqlSessionFactory;
static {
try {
InputStream is = MybatisConfig.class.getResourceAsStream("../conf/MyBatisConfig.xml");
if(is == null)
is = new FileInputStream("./conf/MyBatisConfig.xml");
table_sqlSessionFactory = new SqlSessionFactoryBuilder().build(is, "table_mysql", DBConfig.prop);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
static {
try {
InputStream is = MybatisConfig.class.getResourceAsStream("../conf/MyBatisConfig.xml");
if(is == null)
is = new FileInputStream("./conf/MyBatisConfig.xml");
table2_sqlSessionFactory = new SqlSessionFactoryBuilder().build(is, "table2_mysql", DBConfig.prop);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static SqlSessionFactory getTableSqlSesionFactory() {
return table_sqlSessionFactory;
}
public static SqlSessionFactory getTable2SqlSessionFactory() {
return table2_sqlSessionFactory;
}
}
코드가 긴데 그냥
sqlSessionFactory 선언하기
mybatisConfig.xml 파일 읽어서 sqlSessionFactory에 넣기
get 메소드 구현하기
3단계다.
두 번씩 반복된 건 각 DB별로 구현된 거라 그렇고, 뭐 코드 중복 싫으면 짧게 줄이는 거고…
주의해야 할 점은 sqlSessionFactoryBuilder 부분에 어떤 DB를 가져올 건지, environment에 설정된 id 값을 넣어주는 데 있다.
마지막으로,
실제 쿼리를 가져다 쓰고 해당 쿼리 결괏값을 불러오는 클래스를 구현한다.
//Table.java
package mybatisTest.db;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
public class Table {
public void totalCountTable1() {
List<Map<String, Object>> criteras = new ArrayList<Map<String,Object>>();
SqlSessionFactory sqlSessionFactory = MybatisConfig.getTableSqlSesionFactory();
try(SqlSession sqlSession = sqlSessionFactory.openSession(false)) {
criteras = sqlSession.selectList("conf.Mapper_table.totalCount");
System.out.println(criteras);
}
}
public void totalCountTable2() {
List<Map<String, Object>> criteras = new ArrayList<Map<String,Object>>();
SqlSessionFactory sqlSessionFactory = MybatisConfig.getTable2SqlSessionFactory();
try(SqlSession sqlSession = sqlSessionFactory.openSession(false)) {
criteras = sqlSession.selectList("conf.Mapper_table2.totalCount");
System.out.println(criteras);
}
}
}
각 DB별로 sqlSessionFactory를 달리 설정했으니 선언해 줄 때 조심하고,
mapper에 박혀있는 namespace와 쿼리 id로 쿼리 실행 및 결괏값을 받아준다.
패키지 구조는 이렇다.
실제로 다른 클래스에서 쿼리 값을 사용할 땐 이렇게 사용한다.
package mybatisTest.batchMain;
import mybatisTest.db.Table;
public class MainModule {
public static void main(String[] args) {
Table table = new Table();
table.totalCountTable1();
table.totalCountTable2();
}
}
전체 패키지 구조는 이렇다.