DATOR


Apache Metamodel Project

Apache Metamodel Project


최근 재밌는 아파치 프로젝트가 인큐베이터에 있는걸 발견했다. Apache Metamodel - metamodel.apache.org 버전이 벌써 5.1인걸 보니 나온지 한참 되었는데 이제야 알게 되었다. 이 프로젝트가 내 관심을 끈 이유는 MetaModel 이라는 프로젝트 명 때문이다. 우리가 데이터 모델링할 때 사용하는 메타 모델이라는 용어가 아파치 프로젝트에 왜 등장하는지 궁금해서 내용을 보았는데 우리가 알고 있는 데이터 모델 패턴 중의 하나인 그 메타모델은 아니다.



d28w5o7HZjZsiONpe-QnFI6qoFtv8KFI-1nOAaMzsFRknNaS74bbW5zg8cIafJsnD4T671w9vEuha_hAJX0RvdhvRDKoJGcIrgfx1n_LDxPqi2OLg6exw9cU_ttI0tJ-khMOAD-f


이 프로젝트는 다양한 데이터 저장소에서 통일 된 데이터 액세스 제공하는 것이 목적으로 하는 자바 라이브러리이다. 하나의 인터페이스로 다양한(현존하는 거의 모든) 데이터 저장소에 접근이 가능하며 같은 API로 처리가 가능하다.

이러한 개념은 기존의 하이버네이트도 다이얼렉트를 교체하여 사용하는 하이버네이트의 사상과도 비슷하긴 하지만, 하이버네이트는 어쨌든 ORM 이기 때문에 객체관계매핑에 의존한 처리를 할 수 밖에 없는데 이 프로젝트는 별도의 매핑 없이 런타임시에 데이터 컨텍스트 개체만 바꿔가면서 다양한 데이터 저장소에 접근하여 처리가 가능하다. 아직 정확한 파악은 안되었지만 API 형태를 보면 하이버네이트의 그것과 비슷한 부분이 많다.


DataContext dataContext = DataContextFactory.create[TypeOfDatastore](...);

DataSet dataSet = dataContext.query()

   .from("libraries")

   .select("name")

   .where("language").eq("Java")

   .and("enhances_data_access").eq(true)

   .execute();



dataContext.executeUpdate(new UpdateScript() {

   public void run(UpdateCallback callback) {

       // CREATE a table

       Table table = callback.createTable("contributors")

           .withColumn("id").ofType(INTEGER)

           .withColumn("name").ofType(VARCHAR).execute();

           

       // INSERT INTO table

       callback.insertInto(table)

           .value("id", 1).value("name", "John Doe").execute();

       callback.insertInto(table)

           .value("name", "Jane D.").execute();

       

       // UPDATE table

       callback.update(table).value("name","Jane Doe")

           .where("id").eq(2).execute();

       

       // DELETE FROM table

       callback.deleteFrom(table).where("id").eq(1).execute();

   }

});



이 프로젝트에서 굳이 DB라고 하지 않고 데이터저장소라는 단어를 사용하는 이유는 일반 RDBMS는 물론이고, RDB의 형태가 아닌 NoSQL DB, 엘라스틱서치와 같은 검색엔진, CSV 파일, 엑셀 파일에 대해서도 동일한 인터페이스로 액세스가 가능하기 때문이다. 이러한 장점은 최근 다양한 데이터를 처리해야 하는 솔루션에 적합한 형태이다.

이미 이 라이브러리를 사용한 솔루션도(DataCleaner ..등등?) 존재하고 있다.


뭔가 재밌는 것들이 많아지고 있다.




Leave Comments

댓글 쓰기 권한이 없습니다. 회원 가입후에 사용 가능합니다

토탈커맨더에서 현재 폴더 위치로 babun 쉘 바로 사용하기

토탈커맨더에서 현재 폴더 위치 기준으로 babun 쉘을 바로 띄우고 싶을 때 아래과 같이 설정하면 된다.


/bin/env CHERE_INVOKING=%P /bin/zsh.exe


babun2.png


babun 쉘에 대해서 궁금한 사람은 아래 링크를 참조하세요.

http://babun.github.io/

Leave Comments

댓글 쓰기 권한이 없습니다. 회원 가입후에 사용 가능합니다

Groovy를 이용해 멀티스레드로 SQL 실행시키기

Groovy SQL을 둘러봤으니 이번엔 Groovy SQL을 이용해서 만든 스크립트 예제를 하나 보겠습니다. 
아래 Groovy 스크립트는 많은 수의 BR검증SQL에 대해서 멀티스레드를 이용해서 동시에 여러개의 SQL을 실행시키게 만든 스크립트입니다. 데이터베이스의 성능이 받춰주는 만큼 스레드 갯수를 조절해서 실행시키면 SQL이 끝나기를 기다리는 시간을 많이 줄일 수 있습니다. 스레드 갯수는 적절히 조절할 필요가 있습니다. 짧은 코드지만 꽤 다양하게 활용이 가능한 스크립트입니다.

import java.sql.*
import groovy.sql.Sql
import java.util.concurrent.*

/**
 * BR 검증SQL을 일괄 실행시켜서 결과값을 확인하기 위한 클래스이다.
 * 
 * @author hkwee
 * @since  2012-05-03
 */
class ExecBRSql{
	def THREADS = 5
	
	def url = "jdbc:oracle:thin:@127.0.0.1:1521:ora10g"
	def userid = "scott"
	def passwd = "tiger"
	def driver = "oracle.jdbc.driver.OracleDriver"
	
	static void main(String[] args) {
		def execBrSql = new ExecBRSql()
		execBrSql.execute()
	}
	
	private void execute() {
		def sql = Sql.newInstance(url, userid, passwd, driver)
		
		def queue = new ArrayBlockingQueue<String>(1000);
		def pool = Executors.newFixedThreadPool(THREADS)
		
		def nDq = """
				select dq_no, dq_table, br_sql 
				  from n_dq 	
				 order by dq_no
					"""
		
		sql.eachRow(nDq) { row ->
			def sqlDto = new SqlDto()
			sqlDto.no = row.dq_no
			sqlDto.sql = row.br_sql
			
			queue << sqlDto
		}
		
		def item = null
		
		while (item = queue.take()) {
			pool.execute(new ExecuteStatement(item))
			
			if (queue.size() == 0)
				break
		}
		
		pool.shutdown();
	}
}

class ExecuteStatement implements Runnable {
	
	def sqlDto = null	
	def ExecuteStatement(sqlDto) {
		this.sqlDto = sqlDto
	}
	
	@Override
	public void run() {
	def url = "jdbc:oracle:thin:@127.0.0.1:1521:ora10g"
	def userid = "scott"
	def passwd = "tiger"
	def driver = "oracle.jdbc.driver.OracleDriver"

		def sql = Sql.newInstance(url, userid, passwd, driver)			
		def THREAD_NAME = Thread.currentThread().getName()			
		def insertQuery = """insert into temp_n_dq (dq_no, col1, col2, col3, col4, col5, col6, col7, col8, col9, col10)
								values (?,?,?,?,?,?,?,?,?,?,?)"""										
		def vals = new Object[11]		
		try {
			println "[${THREAD_NAME}], ${sqlDto.no} - " + this.sqlDto.sql.replaceAll("\n", "")
			
			sql.query(sqlDto.sql) { rs ->
				vals = new Object[11]
				def meta = rs.metaData
				def isClean = true;
				vals[0] = sqlDto.no
				
				while(rs.next()){
					for (int i = 1; i <= (meta.columnCount > 10 ? 10 : meta.columnCount); i++) {
						vals[i] = rs.getString(i)
					}
					
					sql.executeUpdate(insertQuery, vals)
					isClean = false;
				}
				
				if (isClean) {
					vals[1] = "no data"
					sql.executeUpdate(insertQuery, vals)
				}
			}
		} catch (Exception e) {
			println "[${THREAD_NAME}], ${sqlDto.no} - error : ${e.message}"
			sql.executeUpdate(insertQuery, [sqlDto.no, e.message])
		} finally {
			sql.close()
			println "[${THREAD_NAME}], ${sqlDto.no} - finished .."
		}
	}
}

class SqlDto {
	def no
	def sql
}




Leave Comments

댓글 쓰기 권한이 없습니다. 회원 가입후에 사용 가능합니다