반응형

JAVA 서버를 작성해야 할 일이 생겨서 Maven 프로젝트로 생성하여 진행을 하고 있었다. DB에 insert와 select처리가 필요해서 Mybatis 설정작업까지 완료 후, select는 정상동작하는 걸 봤는데 insert처리를 아무리해도 에러가 발생하였다.

 

설정에 문제가 있나???... 점점 당황스러운 시점에 동작하는 insert 쿼리 자체를 넣어도 동작하지 않았다.

 

insert된 결과값을 찍어보니 -2147482646 라는 값이 찍히고 있었다.

 

<setting name="defaultExecutorType" value="BATCH" /> //제거

Mybatis 설정을 하면서 setting부분한 BATCH부분이 문제라고 해서 해당부분을 제거하고 재구동을 해봤지만, 결과값은 정상적으로 1로 나오지만 DB에 반영은 안되고 있었다.

 

 

점점 멘탈이 나가려고 하는 순간 최초에 Mybatis 설정을 하던 부분에서 주석부분이 생각났다.

 

SqlSessionFactory와 SqlSession을 static변수로 처리하고 싱글톤 형태로 특정 객체에서 관리하도록 하였는데,

SqlSession session = sqlSessionFactory.openSession(false);	 //false = Not autoCommit

openSession(false);처리는 autoCommit을 끄는 옵션이였다.

 

해답은 commit이 동작하지 않아서 반영이 안되었기 때문이었다...

순간적으로 부끄러움과 아직 멀었구나가 느껴지는 순간이었다~

 

항상 스프링에서 Mybatis를 사용하다보면 Spring이 알아서 전부 관리해주다보니 까맣게 잊고 있었던 것 같다.

 

Maven프로젝트에서 Mybatis insert처리 후 commit하기

이번일을 계기로 다시한번 공부를 하게되었고, 처리한 방법을 올려볼까 합니다.

 

SqlsessionFactorys.java

package kr.or.kisa.ktoaInterlock.utils;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.apache.log4j.Logger;

public class SqlSessionFactorys {
	
	private static final Logger logger = Logger.getLogger(SqlSessionFactorys.class);
	
	private SqlSessionFactorys() {	}
	
	static SqlSessionFactory sqlSessionFactory;
	
	private static SqlSessionFactory setSqlSessionFactory() {
		SqlSessionFactory sqlSessionFactory = null;
		String resource = "프로젝트내 xml 위치/mybatis-config.xml";
		
		PropertyReader pr = PropertyReader.getInstance();
		Properties props = new Properties();
		props.put("driver"      , pr.get("mybatis.driver"));
		props.put("url"         , pr.get("mybatis.url"));
		props.put("username"    , pr.get("mybatis.user"));		
		props.put("password"    , pr.get("mybatis.password"));	
		
		InputStream inputStream = null;
		try {
		    inputStream = Resources.getResourceAsStream(resource);
		    sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream, props);
		    props.clear();
		} catch (IOException e) { 	
			logger.error(e);
		} finally {
			if(inputStream != null) {
				try {
					inputStream.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return sqlSessionFactory;
	}
	
	public static SqlSession setSqlSession() {
		if(sqlSessionFactory == null) {
			sqlSessionFactory = setSqlSessionFactory();
		}
		SqlSession session = sqlSessionFactory.openSession(false);	 //false = Not autoCommit
		return session;
	}
}

SqlSessionFactory는 싱글톤 형태로 유지하고 쿼리를 진행할때마다 열고 닫아가면서 사용할 SqlSessionFactory를 싱글톤 형태로 관리하는 부분이다.

 

 

SqlSessionUtils.java

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.ibatis.session.SqlSession;
import org.apache.log4j.Logger;

public class SqlSessionUtils {
	private static final Logger logger = Logger.getLogger(SqlSessionUtils.class);
	
	private SqlSessionUtils() {}
	public static SqlSessionUtils instance;
	public static SqlSessionUtils getInstance() {
		if(instance == null) {
			instance = new SqlSessionUtils();
		}
		return instance;
	}
	
	public int insert(String statement, Object params) {
		int res = 0;
		SqlSession session = null;
		try {
			session = SqlSessionFactorys.setSqlSession();
			res = session.insert(statement, params);
			if(res > 0) {
				session.commit();
			}else {
				session.rollback();
			}
		}catch(Exception e) {
			logger.error(e);
			session.rollback();
		}
		session.close();
		return res;
	}
	
	public List<Map<Object, Object>> selectList(String statement, Object params) {
		List<Map<Object, Object>> res = new ArrayList<>();
		SqlSession session = null;
		try {
			session = SqlSessionFactorys.setSqlSession();
			res = session.selectList(statement, params);
		}catch(Exception e) {
			logger.error(e);
		}
		session.close();
		return res;
	}
}

SqlSession의 메소드와 일부러 이름을 맞추고 파라미터 또한 통일시켰다. 다만 리턴값은 좀 다르게 설정하였다.

예제에서는 insert, select만 존재하며, 추가적으로 update, delete, selectOne 등은 추가적으로 작성이 필요하다.

 

매번 동작할때마다 SqlSession에 SqlSessionFactorys에서 처리한 싱글톤을 통해 SqlSession을 열어주고

쿼리 동작이 끝나면 정상적으로 처리된 경우 commit()을 한다.

정상 동작이 아니거나 예외처리가 발생하면 rollback()처리를 해주고, 동작이 끝나면 해당 SqlSession을 닫아준다.

 

 

사용한 Dao 예제 소스)

import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;

import kr.or.kisa.ktoaInterlock.utils.SqlSessionUtils;

public class InterlockDao {
	private static final Logger logger = Logger.getLogger(InterlockDao.class);
	
	private InterlockDao() {}
	private static InterlockDao instance;
	static SqlSessionUtils session = SqlSessionUtils.getInstance();
	
	public static InterlockDao getInstance() {
		if(instance == null) {
			instance = new InterlockDao();
		}
		return instance;
	}
	
	//테이블 데이터 저장
	public int insertRequestTrack(Map<Object, Object> params) throws Exception{
		return session.insert("track.insertTest", params);
	}
}

로그를 확인해보면 오토커밋은 꺼진상태로 정상적으로 JDBC 커넥션이 열리는 모습을 볼 수 있고, insert 동작이 끝나면 commit을 처리하고 JDBC연결을 닫아준다.

 

추가적으로 commit을 한번 처리하면 autoCommit이 켜지는것 같은데, SqlSession을 닫아버리고 다시 꺼진 옵션의 SqlSession을 가져오기 때문에 큰 문제는 없이 계속해서 해당 로직을 사용하여 insert 처리를 할 수 있었다.

반응형