SQL Server 2008이 나온 것 같아서 검색해보니 나왔더군요.
그래서 설치를 해봤습니다.
설치하는 매우 애먹었습니다. 설치하기전에 필요한게 뭐그리 많은지-_-;

우선 이 사이트에서 받으면 됩니다.
http://www.microsoft.com/express/sql/register/default.aspx
이 사이트에서 좀 웃긴점은 Register and Download SQL Server 2008 Express를 클릭하면 MSN아이디로 로그인 하라고 나오는데 로그인 후 개인정보 수정 후에 다운로드 사이트가 MS SQL 2005 Express사이트로 갑니다-_-;
그래서 우리는 저걸 클릭하지말고-_-;

http://www.microsoft.com/express/sql/download/
요걸 클릭해서 받습니다-_-;
우선 3가지가 있는데요.
저는 아주 간단하게 쓸 것이어서 두번째껄로 받았습니다. 저번에 MS SQL 2005를 설치할 때 처럼 SQL Server Management Studio하나만 있으면 되니깐요 ^^

SQL Server 2008 Express with Tools
저는 이걸로 받았습니다. 클릭한 다음에 Change Language해서 Korean으로 바꿔주는 거 잊지마세요!

다운 받은 파일을 실행하려고 하면 망할 놈의 인스톨러가 .net Framework 3.5를 요구합니다.
그래서 검색을 해서 설치를 했습니다.
설치를 하고 다시 실행했습니다. 그랬더니 .net Framework 3.5 SP1을 요구합니다..........
......이....내가 전에 글씨를 잘못 본 건가....-_-; 암튼 그래서 윈도우즈 업데이트에서 해주는지 Windows Update를 실행했습니다. 여기서 ......안해줍니다 ㅠ
또 다운로드를 검색했습니다 ㅠ
http://www.microsoft.com/downloads/details.aspx?displaylang=ko&FamilyID=ab99342f-5d1a-413d-8319-81da479ab0d7
여기서 받아서 설치를 합니다.

설치를 진행하다보면.....Windows Installer 4.5가 필요하다고 합니다.....
아놔....첨부터 니가 알아서 설치를 해주던가....-_-;
http://www.microsoft.com/downloads/details.aspx?displaylang=ko&FamilyID=5a58b56f-60b6-4412-95b9-54d056d6f9f4

자....이제 마치 다 된 느낌입니다. 막 설치를 준비하고 있습니다.
설치를 하려고 이것저것 설치가 되었는지 검색을 하더군요. 그러더니 8개정도 성공하고, 1개가 실패했습니다-_-;
1개 뭔가 설치되지 않아서 그렇다고 하는데요.
그건 Windows PowerShell이였습니다.......아놔.......

여기도 참 어이없는게 downloads사이트를 찾아서 버전이 여러 개가 있어서 영문용과 MUI용이 있어서 한글도 되는가 해서 MUI용을 받았더니.....설치가 안되더군요 ㅠ
그래서 다시 영문버전으로 받았습니다. 요아래 사이트에서 받으시면 돼요.
http://www.microsoft.com/windowsserver2003/technologies/management/powershell/download.mspx

오....이제 된 것 같은.....-_-;
설치를 계속 진행했습니다.
설치는 2005버전이랑 비슷한데 UI만 좀 바뀌었습니다.
잘 몰라서 다음신공으로..... 다음으로 안넘어가지면 이것저것 클릭해서.....설치를 무사히 마쳤습니다.

2008에서 좀 신기한 기능이 있었는데요.
PowerShell을 설치를 해야하는데, 데이터베이스를 생성하고 오른쪽 버튼을 누르면 PowerShell 시작 이라는 메뉴가 있습니다. 클릭을 하게 되면 우리가 시작 -> 실행 -> cmd 하는 것과 같은 창이 나타납니다.
재미있는 건 이 PowerShell이라는 게 UNIX계열의 bash, sh, csh, ksh 같은 것 같더군요. 더 신기한 건....
습관이 ls치는건데 우연히 여기서 ls를 쳤는데 먹혀요-_-;
UNIX에서 사용하는 명령어들이 다 되더군요. 검색해보니 alias기능으로 alias한 거라고 하던데...
사용자 삽입 이미지

이걸로 MySQL의 mysql>처럼 명령어를 사용해서 컨트롤 할 수 있는 것 같기도하고.....
원래 MS SQL Server에서는 안됐었나...-_-;

 
Posted by 머드초보
,
 
이 망할 놈의 오라클은 LIMIT이 지원되지 않습니다.
LIMIT이 얼마나 편한데!!!
오라클에서 LIMIT과 같은 기능이 필요했습니다.

ROWNUM이라는 것을 알게 되었는데, SELECT를 하게 된 결과에 자동으로 처음부터 끝까지 1부터 숫자를 매겨주는 듯했습니다. 아, 그래서 만약에 10번째꺼부터 20번째꺼를 추출해봐야지 라고 이런 쿼리를 날려봤습니다.

[code]SELECT * FROM BIZLIST WHERE ROWNUM >= 10 AND ROWNUM <= 20[/code]
이렇게 하니까 아무것도 안나오더라구요.
이게 안돌아가는 이유는 ROWNUM이라는 놈이 가상 칼럼이랍니다. 그래서 만약 칼럼이 SELECT될 때 10개가 출력되야하는 상황이라면 첫번째꺼 출력하고 ROWNUM을 붙이고, 두번째꺼 출력하고 ROWNUM을 붙이고, 그러다보니 저 조건에 맞지 않게 됩니다.

첫번째 출력될 놈은 ROWNUM이 1인데, 저 조건에 부합하지 않습니다. 그래서 출력이 안되고, 10번째 출력될 놈도 출력하려고 보니 다 조건에 맞지않아요. 그러다보니 차례대로 다 안나옵니다-_-;

즉 조건에 부합한 놈이 출력되고 난다음에 ROWNUM을 붙여줍니다.
그래서 ROWNUM이 10을 1로 바꿔버리면 ROWNUM이 1인놈부터 20개까지는 출력이 되는것이죠.

제가 설명을 좀 못하니 여기를 참조 하세요 ^^
http://www.oracle.com/technology/global/kr/oramag/oracle/06-sep/o56asktom.html

저걸 악(?) 이용하면 LIMIT처럼 구현할 수 있습니다-_-;
[code]SELECT * FROM (SELECT ROWNUM RNUM, BIZLIST.* FROM BIZLIST WHERE STATUS = 'A') A
WHERE A.RNUM BETWEEN 10 AND 20[/code]
쿼리를 잘 보시면 A테이블을 서브쿼리를 날려서 만들어줍니다. 즉 우리가 10~20까지 추출해야할 데이터를 다 추출해서 A라는 테이블을 만듭니다. 여기서 A테이블을 보면 ROWNUM도 칼럼에 추가를 시킵니다. RNUM이라는 이름으로!
그다음 이 추출된 모든 것이 보면 ROWNUM도 다 붙어있습니다. 그래서 이걸 다시 SELECT해서 RNUM이 10과 20사이인 것을 추출하게 하면 되는것이죠.
A테이블에서 WHERE절은 원하는 조건이니 없어도 되는 것이고-_-;
별 것도 아닌데 거창하게 써 놓은 이유는 제가 이것 때문에 반나절을 고생해서 입니다-_-;
아놔....ㅠㅠ

 
Posted by 머드초보
,
 
Thread를 두개를 실행시켜서 DB에 동시에 INSERT를 시켜버리니 INSERT할 때 데이터가 AUTOINCRESEMENT가 아니라 ID부분을 직접 입력해서 하는 부분이면 문제가 발생합니다.
그래서 이 MERGE INTO문을 활용해서 데이터가 있으면 INSERT하고 없으면 UPDATE하는 구문을 만들었습니다.
이렇게 해도 제 생각이지만, Thread한 놈은 이미 데이터가 없는 것을 확인하고 insert를 시도 하려고 하고, 다른 Thread놈은 저 놈이 insert를 아직 하지 않았으니까 검색해서 안나오니 insert를 해보려고 하니 둘 다 insert를 시도하게 되더라구요.

이게 예제 입니다.
우선 테이블구조입니다.
테이블은 autoincreament가 아닌 수동적인 기본키를 사용합니다.
[code]CREATE TABLE "INSERTTABLE" ( "ID" NUMBER NOT NULL ENABLE, "DATA" VARCHAR2(4000) NOT NULL ENABLE, CONSTRAINT "INSERTTABLE_PK" PRIMARY KEY ("ID") ENABLE )
[/code]


applicationContext.xml
[code]<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-2.5.xsd">

    <context:component-scan base-package="thread" />
   
    <!-- oracle용 -->
    <bean id="dataSource"
        class="org.springframework.jdbc.datasource.DriverManagerDataSource"
        p:driverClassName="oracle.jdbc.driver.OracleDriver"
        p:url="jdbc:oracle:thin:@localhost:1521:XE"
        p:username="mudchobo" p:password="1234" />
 
    <!-- SqlMap setup for iBATIS Database Layer -->
    <bean id="sqlMapClient"
        class="org.springframework.orm.ibatis.SqlMapClientFactoryBean"
        p:dataSource-ref="dataSource"
        p:configLocation="classpath:config/SqlMapConfig.xml" />
   
    <bean id="sqlMapClientTemplete"
        class="org.springframework.orm.ibatis.SqlMapClientTemplate"
        p:sqlMapClient-ref="sqlMapClient"/>
           
</beans>
[/code]
SqlMapConfig.xml
[code]<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE sqlMapConfig     
    PUBLIC "-//ibatis.apache.org//DTD SQL Map Config 2.0//EN"     
    "http://ibatis.apache.org/dtd/sql-map-config-2.dtd">

<sqlMapConfig>
    <sqlMap resource="config/Insert.xml" />
</sqlMapConfig>
[/code]
Insert.xml
[code]<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE sqlMap     
PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"
"http://ibatis.apache.org/dtd/sql-map-2.dtd">

<sqlMap namespace="Sqlmap">
       <insert id="insertData">
           MERGE INTO INSERTTABLE
           USING DUAL
           ON (ID = 1)
           WHEN MATCHED THEN
           UPDATE SET
           DATA = 'HERMUSSERI'
           WHEN NOT MATCHED THEN
           INSERT (ID, DATA)
           VALUES (1, 'MUDCHOBO')
       </insert>
      
</sqlMap>
[/code]
ThreadTestDao.java
[code]package thread;

public interface ThreadTestDao {
    public void insertData();
}
[/code]
ThreadTestDaoImpl.java
[code]package thread;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.ibatis.SqlMapClientTemplate;
import org.springframework.stereotype.Repository;

@Repository
public class ThreadTestDaoImpl implements ThreadTestDao {

    @Autowired
    private SqlMapClientTemplate sqlMapClientTemplate;

    @Override
    public void insertData() {
        sqlMapClientTemplate.insert("insertData");
    }
}
[/code]
TestThread.java
[code]package thread;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Scope("prototype")
@Component
public class TestThread extends Thread {

    @Autowired
    private ThreadTestDao threadTestDao;
   
    @Override
    public void run() {
        threadTestDao.insertData();
    }
}
[/code]
ThreadTest.java
[code]package thread;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class ThreadTest {

    public static void main(String[] args) {
        String configLocation = "config/applicationContext.xml";
        ApplicationContext context = new ClassPathXmlApplicationContext(
                configLocation);

        TestThread testThread1 = (TestThread) context
                .getBean("testThread");
        TestThread testThread2 = (TestThread) context
                .getBean("testThread");
       
        testThread1.start();
        testThread2.start();
    }
}
[/code]
실행할 때 계속 몇번을 실행해보면-_-; unique constraint 또는 ORA-00001: 무결성 제약 조건(MUDCHOBO.INSERTTABLE_PK)에 위배됩니다를 볼 수 있을 겁니다.

이게 제 생각인데, 첫번째 스레드가 돌면서 데이터를 확인하니 없길래 insert를 하려던 찰나에 두번째 스레드놈도 거의 동시에 데이터를 확인하니 없어서 insert를 시키려다가 에러가 나는 듯한데요.

트랜잭션도 먹이고 별 지롤을 다 했는데 안되길래 그냥 싱크방식으로 변경해버렸습니다.
insertData라는 메소드에
[code]@Override
    synchronized public void insertData() {
        sqlMapClientTemplate.insert("insertData");
    }
[/code]
메소드 앞에 synchronized를 붙입니다.
이건 어떤 스레드가 호출을 했으면 다음 스레드는 기다린 다음에 접근하게 되는 즉 싱크방식으로 처리를 시킬 수 있는 메소드가 됩니다.
이렇게 처리하면 효율은 좀 떨어지겠지만, 유니크 중복에러는 그나마 막을 수 있습니다.

다른 방법 있으면 좀 알려주세요 ㅠㅠ 고생하고 있습니다 ㅠ




 
Posted by 머드초보
,
 
저는 전에 데이터를 SELECT해와서 데이터가 0개면 INSERT하고, 있는 놈이면 해당 값을 업데이트 하는 식으로 했었는데요. 우연히 MERGE INTO라는 것을 알게 되었네요.

ORACLE에서만 되는 듯 하네요-_-; 9i이상에서만 된다고 하네요.

MERGE INTO의 목적은 어떤 테이블이나 뷰테이블을 해당 목표테이블과 합체(MERGE)하기 위한 목적인데요. 이걸 이용해서 데이터가 들어왔을 때 있는 데이터면 UPDATE하고, 없는 데이터면 INSERT하는 형태로도 쓰일 수 있습니다.

http://radiocom.kunsan.ac.kr/lecture/oracle/sql/merge.html
위에는 MERGE INTO를 잘 설명한 사이트네요.

여기서 조금 응용하면 원하는 대로 구현할 수 있습니다-_-;

MERGE INTO 테이블명  별칭
USING 대상테이블/뷰  별칭
ON 조인조건
WHEN MATCHED THEN
  UPDATE SET
   컬럼1=값1
   컬럼2=값2
WHEN NOT MATCHED THEN
  INSERT (컬럼1,컬럼2,...)
       VALUES(값1,값2,...);

MERGE INTO다음에 나오는 테이블명은 실제로 데이터가 들어가거나 업데이트 되는 테이블이구요.
USING 다음에 나오는 테이블명은 실제 데이터를 가져오거나 할 테이블이구요.
ON은 WHERE과 같은 조건문이죠.
WHEN MATCHED THEN은 매치되는게 있으면 UPDATE하라는 얘기구요.
WHEN NOT MATCHED THEN은 매치되는게 없으면 INSERT하게 되죠.

응용해봅시다.
[code]
           MERGE INTO INSERTTABLE
           USING DUAL
           ON (ID = 1)
           WHEN MATCHED THEN
           UPDATE SET
           DATA = 'idoori'
           WHEN NOT MATCHED THEN
           INSERT (ID, DATA)
           VALUES (1, 'mudchobo')
[/code]
INSERTTABLE이라는 곳에 USING은 DUAL이라고 했는데 DUAL은 dual은 1개의 레코드 만을 갖는 dummy 테이블이라고 합니다. select 1 from dual해버리면, 1이 나오죠. 대상테이블은 필요없으니 dual로 설정합니다.
ON에서 ID = 1은 ID가 1인게 만약 있으면, DATA부분을 idoori로 업데이트하고, 없으면 mudchobo로 넣게 되는겁니다.

아놔 별거 없는데 막 늘어썼네-_-;
 
Posted by 머드초보
,
 

이동국님이 번역해놓은 iBATIS SQL Maps 개발자 가이드를 보고있었습니다.
INSERT를 한번에 많이 해야하는 상황이 발생해서 더 빠르게 하는 방법이 있나? 라는 생각이 들어서 가이드를 보고 있었습니다. 배치라는게 있었는데요.

배치(Batches)
만약 당신이 수행할 많은 수의 쿼리아닌 statement(insert/update/delete)를 가진다면 당신은 추가적인 최적화를 위해서 네트워크 트래픽을 줄이고 JDBC드라이버를 허락하는 배치 같은 작업을 수행하길 원할지도 모른다. 배치를 사용하는 것은 SQL Map API를 사용하면 간단하다. 배치의 경계를 지정하기 위해서 두가지 간단한 메소드를 제공한다.
sqlMap.startBatch();
//…execute statements in between
sqlMap.executeBatch();
executeBatch()를 호출함으로써 모든 배치 statement는 JDBC드라이버를 통해 수행될것이다.

라는 글이 있더군요. 최적화를 시켜주는 것 같은데요. 그럼 더 빠른건가? 라는 생각에 삽질을 해봤습니다.

[code]
@Test
 public void testYesBatch()
 {
  StopWatch stopWatch = new StopWatch();

  stopWatch.start();
  try
  {
   sqlMapClient.startBatch();
   for(int i = 0 ; i < 100000 ; i++)
   {
    Testtemp testtemp = new Testtemp();
    testtemp.setId(i);
    testtemp.setName("성종천");
    sqlMapClient.insert("insertTesttemp", testtemp);
   }
   sqlMapClient.executeBatch();
  }
  catch(SQLException e)
  {
   e.printStackTrace();
  }
  stopWatch.stop();
  System.out.println("배치사용 걸린시간: " + stopWatch.getTotalTimeMillis());
 }
[/code]
Batch를 사용해서 시간을 측정해봤습니다. 100000건을 insert시켜봤는데, 198485가 나왔습니다.

Batch를 안쓰고 해봤습니다.
[code]
@Test
 public void testNoBatch()
 {
  StopWatch stopWatch = new StopWatch();
  stopWatch.start();
  for(int i = 0 ; i < 100000 ; i++)
  {
   Testtemp testtemp = new Testtemp();
   testtemp.setId(i);
   testtemp.setName("성종천");
   sqlMapClientTemplete.insert("insertTesttemp", testtemp);
  }
  stopWatch.stop();
  System.out.println("배치미사용 걸린시간: " + stopWatch.getTotalTimeMillis());
 }
[/code]
100000건 insert하는데 202359나왔습니다.
뭐지 이 차이없다는 것 같은 느낌은.....-_-;

1000건 했을 때는 Batch사용시 20015, 미사용시 20032.......

속도랑은 상관없이 최적화 하는건가-_-; 암튼 뭐 그렇습니다.

 
Posted by 머드초보
,