Stored Procedure가 성능 면에서는 일반 Query 보다 앞선 다는 걸 알면서도 선뜻 사용하기가 주저해진다. 익숙하지 않는 부분이 하나 일 것이고, 디버깅도 쉽지 않기 때문일 것이다.

뭐... 요즘처럼 JDBC 이외에 ORM 까지 사용하는 세상에 Stored Procedure는 정말 찬밥 이기 쉬운 듯 하다.

하지만... 장점도 있는 것이... DB dependent 한 Code를 Stored Procedure로 숨길 수도 있는데.. 이 부분은 Product를 개발하는 입장에서는 정말 매력적인 장점이 아닐까 생각 된다.

뭐.. 어쩌다가 요즘 혼자 개발하다가 갑자기 Stored Procedure를 쓸 일이 생기니 좀 당황 스러웠다.

생각해 보면 예전에 DBA가 SQL*PLUS에서 Stored Procedure를 어떻게 실행하는 지 물어 보기도 했으니.. 그리 부끄러워 할 일은 아닌 듯 하다.

일단 Stored Procedure를 실행 할려면 아래 처럼 하면 된다.

var rc refcursor;

execute ( ... , : rc);

print rc;

우리회사는 보통 Cursor를 제일 마지막에 사용하다 보니 위에 처럼 Output Cursor를 마지막에 넣어 주고... print 문으로 Cursor를 찍어 본다.

그리고 개발을 하다 보니 Stored Procedure가 LOOPING을 도는 것 같은 데 확인할 방법이 없다.

뭐.. 이럴 때는 Query를 확인 해야 하는 데 아래와 같이 CURSOR OPEN 하기 전에 Query를 찍으면 도움이 될 듯 하다.

dbms_output.put_line(p_sql);

근데.. 이걸 했는데도 Query가 콘솔에 찍히지 않아 왜 그런가 확인해 봤더니 아래 환경 변수를 ON 시켜 주어야 한다나..

SET SERVEROUTPUT ON

확인해 보니깐..
조건절을 잘못 넣어서 2억개가 넘는 ROW를 CURSOR에 넣고 있었다...-.-


어쩟든 기존에 개발 되어 있던 여러 Stored Procedure를 참조해서 필요한 Stored Procedure를 개발했는데.
참 어처구니 없는 것이... PL/SQL에는 문자열 split 함수가 없다.
인터넷을 뒤지고 다녔더니.. 다들 자기 들 만의 문자열 split 함수를 올려 놨다.
마침 Vinayak이 방에 놀러 왔길 래 사정 얘기를 했더니..
OAS에서 Cursor, Pipe를 이용해 구현한 함수와 사용 예제를 보여주어 덕분에 쉽게 해결 됐다.
다음에 또 stored procedure를 개발할 일이 생겼을 떄는 split 함수가 지원 되기를 기원한다.


'개발자세상 > Database관련' 카테고리의 다른 글

오라클 DB에서 테이블마다 용량 구하기  (0) 2013.08.10
Overlap 데이터 구하기  (0) 2013.08.04
오라클 실행계획 보기  (0) 2010.03.03
ORACLE 사용자 생성  (0) 2010.03.03
ORA-30557  (0) 2009.12.09
Posted by headiron
,
원래 블로그나 SNS에 회사 일은 안 올리는 게 제 철칙인데,
한국에서 요청을 하셔서 혹시나 하는 마음에 올려 봅니다.

제가 몸 담고 있는 247리얼미디어 에서 자바 개발자를 모집합니다.

간단히 우리 회사를 소개하면...
전세계 1위의 광고 대행사 그룹인 WPP( 서비스 업체들 임에도 전직원이 12만명 정도 되는 큰 그룹 입니다.) 계열사이며,본사는 미국에 있습니다.

주료 솔루션으로는 Display 광고 솔루션인 OAS와 검색 광고 Optimizer인 Decide DNA가 있습니다.

우리팀은 OAS 중에 일부 모듈 기능 개발 및 신규 모듈 개발을 담당하고 있습니다.

팀 구성은 미국에 Director와 저, 한국에 다수의 개발자로 구성되어 있습니다.
( 저도 작년 까지 약 4년 넘게 한국에 있다가 미국으로 옮기게 되었습니다.)

OAS 개발 관련 전체 팀들이 대부분 미국에 있으므로,
업무 하면서 영어를 사용하고 배울 수 있는 좋은 기회입니다.
 
개발 방법론은 SCRUM을 사용하며,
다양한 기술과 솔루션 개발 및 운영에 대한 노하우를 배울 수 있는 기회입니다.
( 주요 고객들이 미국 , 유럽 등에 있으며 - 물론 한국에도 있습니다.
  - 주로 ASP로 서비스 하기 때문에 , SI 성 업무는 없다고 보셔도 됩니다. )

갠적으로 우리 회사에 와서..
1. 영어를 직접 업무에 사용하다 보니 실력이 늘었으며,
2. 솔루션 개발 및 운영에 대한 노하우를 배웠고.
3. 다양한 신기술을 실무에 적용할 수 있었습니다.
물론 제일 큰 것은...
미국에서 근무하는 기회를 잡은 거 겠구요.

보다 자세한 내용은 아래 페이지를 참조하세요.
http://www.okjsp.pe.kr/seq/184813


'개발자세상' 카테고리의 다른 글

Hibernate interceptor  (0) 2015.05.20
Curl에서 SOAP API 사용하기  (0) 2014.05.07
자바?  (0) 2011.04.01
Long Term Plan?  (0) 2011.02.19
이젠 모바일인가...  (2) 2010.12.05
Posted by headiron
,

자바?

개발자세상 2011. 4. 1. 13:17
몇 일 전에 제임스 고슬링이 구글에 입사 했다는 뉴스가 눈에 띄더니,
오늘 REST 관련 자료를 찾다가 조대협씨가 MS에서 일한다는 내용이 눈에 띈다.

사실 제임스 고슬링이 ORACLE을 그만 둔지는 꽤 되었고, 생각해 보니 조대협씨가 MS 들어갔다는 얘기도 살짝 들었던 기억이 난다.

하지만 최근 ORACLE이 돌아가는 분위기를 보다보니 위 사실들이 더 충격적으로 다가오는 느낌이다.

많은 자바 개발자들이 SUN이 IBM에 인수되었어야 했다고 아쉬워한다.(그리고 했다.)
그리고 오라클이 SUN을 인수 했을 때 우려하던 일들이 서서히 나타나고 있다.

사실 SUN이 자바를 잘 디자인 하고 발전시켜 왔기에 지금과 같은 자바 부흥기가 왔다고 할 수 있는데,ORACLE은 그런 점을 기대하기에는 너무 상업적인 회사이다.

앞으로 어떤일이 벌어 질지는 모르겠다.

하지만 지금 상황으로는 예전 만큼이나 자바가 각광받기에는 조금 어려워 지지 않을까 생각된다.

그것만큼이나 걱정되는 건... 나 스스로 프로그래머라는 단어보다는 자바 개발자라는 단어가 더 익숙해 졌다는 사실이다.


'개발자세상' 카테고리의 다른 글

Curl에서 SOAP API 사용하기  (0) 2014.05.07
[구인공고] 247리얼미디어.  (0) 2011.06.23
Long Term Plan?  (0) 2011.02.19
이젠 모바일인가...  (2) 2010.12.05
Spring Security  (0) 2009.12.21
Posted by headiron
,

Long Term Plan?

개발자세상 2011. 2. 19. 10:40
Sales 측 요청으로 잠재 Client와 API 관련 검토 미팅을 하는데 ( Conference 로...^^ ) 고객이 API 관련 Long Term Plan을 물어 본다.

정팀장님이 계시니깐, 나야 따로 할 말이 없지만 그 얘기를 들으니 머리가 좀 띵하다.

우리 제폼의 API를 책임지고 있다는 놈이
앞으로 우리 시스템을 어떻게 발전시키겠다는 계획 없이 그냥 흘러가고 있다는 생각을 하니깐 골이 띵하다.

시키는 일만 하는 타성에 젖어, 내 제품을( 물론 내 개인 거는 아니지만 ) 어떤 방향으로 가져가겠다는 생각이나 포부도 없었구나 생각을 하니 많이 반성이 된다.

내 회사와 우리 제품에 자부심을 가지면서도 어떻게 가꾸어 나가겠다는 생각이 없는 건 큰 문제 인듯 하다.

내 인생 , 내 회사, 내 제품에 대한 긴 안목의 계획을 세워나가야 할 그런 시간이 온 듯 하다.

'개발자세상' 카테고리의 다른 글

[구인공고] 247리얼미디어.  (0) 2011.06.23
자바?  (0) 2011.04.01
이젠 모바일인가...  (2) 2010.12.05
Spring Security  (0) 2009.12.21
ASP.NET 크레튜 강의 수강 소감  (0) 2009.12.15
Posted by headiron
,
주말에 뭔가 좀 해 볼까 했는데
PVT 일정이 잡히는 바람에 그냥 동네에 머물기로 했다.

대신 반스&노블스나 가서 책이나 좀 사기로 했다.
인터넷으로 검색해 보니 Target 있는 지역에 함께 있다.
살아 가다 보니 North Wales 지역이 생각보다는 살기 괜찮은 듯 싶다.

반스&노블스, Macy's 백화점, Cosco, Assi Mart 등.
관광서를 제외한 다른 상점 같은 것들은 많이 있는 듯 싶다.
( 관공서는 NorrisTown 지역에 많이 몰려 있는듯 )

여하튼 Web Service 관련 책 좀 사볼까 해서 Amazon에서 평점 괜찮은 걸로 2개를 고른다음에 가 보았다.

근데.. 이런.... 그 큰 서점에 컴퓨터 관련 책장은 달랑 하나.
그 중 반은 Window 관련 , 반은 아이폰/안드로이드...
자바 관련 책은...-.-

그래도 한참 벤처 바람 불때는 교보문고 같은데 한쪽을 자바 관련 책으로 도배를 했었는데.-.-
결국 미국도 모바일쪽으로 많이 넘어 가고 있는건가 싶다.

Amazon으로 볼때는 그래도 프로그래밍 관련 전문서적은 좀 많은 것 같았는데..

결국 나도 그런 부분을 조금씩 보면서 준비를 해야 하는 듯 싶다.

'개발자세상' 카테고리의 다른 글

자바?  (0) 2011.04.01
Long Term Plan?  (0) 2011.02.19
Spring Security  (0) 2009.12.21
ASP.NET 크레튜 강의 수강 소감  (0) 2009.12.15
티맥스 소식  (0) 2009.11.10
Posted by headiron
,
1. explain plan for
   select * from emp;

    select * from table(dbms_xplan.display);

2. explain plan
    set statement_id = 'stmt1' for
    select * from emp;

    select * from table(dbms_xplan.display('plan_table','stmt1','all'));
    select * from table(dbms_xplan.display('plan_table','stmt1','typical'));
    select * from table(dbms_xplan.display('plan_table','stmt1','basic'));

'개발자세상 > Database관련' 카테고리의 다른 글

Overlap 데이터 구하기  (0) 2013.08.04
Stored Procedure 개발 / 실행  (0) 2012.12.08
ORACLE 사용자 생성  (0) 2010.03.03
ORA-30557  (0) 2009.12.09
Oracle Table Column Rename  (0) 2009.10.28
Posted by headiron
,
CREATE USER 사용자명
IDENTIFIED BY 패스워드
DEFAULT TABLESPACE 테이블스페이스명
TEMPORARY TABLESPACE TEMP
PROFILE DEFAULT
ACCOUNT UNLOCK;

GRANT DBA,RESOURCES TO 사용자명;

ALTER USER 사용자명 DEFAULT ROLE ALL;

GRANT UNLIMITED TABLESPACE TO 사용자명;

'개발자세상 > Database관련' 카테고리의 다른 글

Stored Procedure 개발 / 실행  (0) 2012.12.08
오라클 실행계획 보기  (0) 2010.03.03
ORA-30557  (0) 2009.12.09
Oracle Table Column Rename  (0) 2009.10.28
오라클 Function Compile/ 생성시 Ora-00942 오류..  (1) 2009.06.22
Posted by headiron
,
백업 중 중간 경유지 역활을 하던 테스트 서버가 죽어
다른 서버를 경유해서 offsite 백업을 진행하게 script를 짜려고 하나다
키 기반 인증을 설정하려고 했더니

아뿔싸 그 내용을 테스트 서버에 있던 wiki에 정리 해 놨었다는...-.-

일단 시스템 운영 팀에 문의를 해서 아래와 같이 받았다.

Client측에서
shell> ssh-keygen -t rsa 실행
shell> cd ~/.ssh
shell> id_rsa.pub에 생성된 공용키 정보를 저장

Server측 (remote )에서
shell>> cd ~/.ssh
shell>> vi authorized_keys
shell>> Clicent측에서 생성된 공용키 정보를 authorized_keys 파일 끝에 추가한다.

주의 사항 
출처 : http://soul.tistory.com/37

서버에서 sshd.conf 파일을 수정해줍니다.

  vi /etc/ssh/sshd.conf

  sshd.conf 파일안에 AuthorizedKeysFile 항목이 주석처리가 되어있으면 주석해제를 해주고 위에서 별도의 이름으로 키파일을

    변경하였다면 임의로 지정한 파일명으로 변경해주면 됩니다.

   (예 - AuthorizedKeysFile      .ssh/test_keys)

 - sshd.conf 수정 후 sshd 서비스를 재시작 합니다.    service sshd restart   또는  /etc/init.d/sshd restart


ssh는 다른 사용자가 쓰기 권한을 갖을 수 있다면 키를 전송하지 않습니다.
예상컨데 .ssh/ 디렉토리를 user가 직접 생성했는데 이게 775(rwxrwxr-x) 로 생성됐을 것 같습니다.
.ssh/ 디렉토리는 700으로 .ssh/ 아래의 파일은 600으로 변경
authorized 파일을 생성할 경우에 644 ( rw-r--r-- ) 로 설정을 하여야 한다.
테스트 서버에서 작업 중에 664 ( rw-rw-r--)로 생성되었는데, 적용이 되지 않아 다른 서버와 비교후에 권한을 644로 바꾸니 바로 적용되었다.



Posted by headiron
,
WSDL2Java로 나온 Class들 전체를 javac로 실행하다 보니 out of memory가 발생한다.

구글링을 해보니 두가지 방법이 보인다.

1. javac Task에 fork="true" memoryMaximumSize="512M" 을 주는 방법
  ( fork를 기재 하지 않을 경우 memoryMaximumSize Option은 ignore 된다. )

2. javac Task에 compilerarg option을 준다.
    javac -help를 입력할 경우 javac 입력시 사용할 수 있는 Option이 나오게 되며 이 중 적절한 option을 입력하면 된다.
<javac srcdir="gen" destdir="gen-bin" debug="on" fork="true">
   
<compilerarg value="-J-Xmx512M" />
</javac>

   ( command prompt 내에서는 -J-Xmx를 입력할 경우 java stack size를 입력할 수 있는 걸로 나오는데 eclipse 의 ant plugin 에서는 해당 option이 먹지 않는걸로 나온다. )
참고 URL : http://stackoverflow.com/questions/16935/ants-javac-tasks-throws-stackoverflowexception
http://blog.paran.com/rabbitshin/6134979
Posted by headiron
,

Spring Security

개발자세상 2009. 12. 21. 19:22

B3 진행하면서 Spring 의 Remoting 호출을 지원하면서 해당 호출을 Login Base로 진행하기 위해서 Spring Security를 두가지 방식으로 지원하게 되었다.

하나는 Config 설정에 의한 , 다른 하나는 LDAP Base.

어차피 Spring Security의 로그인이 Filter Chain을 적용하는 것이기에 Multiple Filter Chain을 확인해 봤더니 Login Path를 통해서 Multiple Filter Chain을 지원하고 있었다.

우선 web.xml 을 변경하여야 한다.

    <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
        <init-param>
            <param-name>targetBeanName</param-name>
            <param-value>springSecurityFilterChain</param-value>
        </init-param>
    </filter>

보통의 경우는 springSecurityFilterChain 만 선언하면 문제가 없는데
multiple 한 fileter chain을 명시적으로 Spring Security Config에 선언해 주어야 하기 때문에 반드시 targetBeanName을 선언하여 value에는 Spring Security 설정에서 사용한 FilterChain Bean Name을 선언해 주어야 한다.

Spring Security 내부의 Filter Chain이 아닌 명시적인 Filter Chain을 사용하여야 하기 때문에 사용하는 방식에 맞추어 Filter Chain Config를 선언하여야 한다.

    <bean id="springSecurityFilterChain" class="org.springframework.security.util.FilterChainProxy">
        <s:filter-chain-map path-type="ant">
            <s:filter-chain pattern="/batchProcessService/**" filters="httpSessionContextIntegrationFilter,digestProcessingFilter,exceptionTranslationFilter,filterSecurityInterceptor" />
            <s:filter-chain pattern="/approvalProcessService/**" filters="httpSessionContextIntegrationFilter,digestProcessingFilter,exceptionTranslationFilter,filterSecurityInterceptor" />
            <s:filter-chain pattern="/**" filters="ldapHttpSessionContextIntegrationFilter,logoutFilter,authenticationProcessingFilter,securityContextHolderAwareRequestFilter,anonymousProcessingFilter,ldapExceptionTranslationFilter,sessionFixationProtectionFilter,ldapFilterInvocationInterceptor"/>
        </s:filter-chain-map>
    </bean>

web.xml 에서 선언했던 filterChain을 위와 같이 설정한다.
filter-chain의 pattern attribute에 선언된 URL에 맞추어 각각 선언된 Filter Chain이 적용이 된다.

위의 경우
/approvalProcessService/** 및 /batchProcessService/** URL은는"httpSessionContextIntegrationFilter,digestProcessingFilter,exceptionTranslationFilter,filterSecurityInterceptor" Filter Chain이
그 이외의 URL들은
"ldapHttpSessionContextIntegrationFilter,logoutFilter,authenticationProcessingFilter,securityContextHolderAwareRequestFilter,anonymousProcessingFilter,ldapExceptionTranslationFilter,sessionFixationProtectionFilter,ldapFilterInvocationInterceptor"
Filter Chain이 적용되게 된다.

LDAP 을 위해서는 아래의 Bean을 명시적으로 선언하였다.
물론 다른 것에 대해서도 해야 겠지만.^^

    <bean id="ldapHttpSessionContextIntegrationFilter" class="org.springframework.security.context.HttpSessionContextIntegrationFilter" />

    <bean id="logoutFilter" class="org.springframework.security.ui.logout.LogoutFilter">
        <constructor-arg value="로그아웃 후 Redirect될 페이지 URL" />
            <constructor-arg>
                <list>
                    <bean class="org.springframework.security.ui.logout.SecurityContextLogoutHandler" />
                </list>
            </constructor-arg>
        <property name="filterProcessesUrl" value="/j_spring_security_logout" />
         ( Logout Process Path URL )
    </bean>

    <bean id="authenticationProcessingFilter"    class="org.springframework.security.ui.webapp.AuthenticationProcessingFilter">
        <property name="authenticationManager"         ref="ldapAuthenticationManager" />
        <property name="authenticationFailureUrl"     value="/ldapLogin.zul?error=1" />
        <property name="defaultTargetUrl"            value="로그인 시 기본 Redirect 페이지 URL" />
        <property name="filterProcessesUrl"            value="/j_spring_security_check" />
    </bean>

    <bean id="securityContextHolderAwareRequestFilter" class="org.springframework.security.wrapper.SecurityContextHolderAwareRequestFilter" />

    <bean id="anonymousProcessingFilter" class="org.springframework.security.providers.anonymous.AnonymousProcessingFilter">
        <property name="key" value="doesNotMatter" />
        <property name="userAttribute" value="roleAnonymous, ROLE_ANONYMOUS" />
    </bean>           

    <bean id="ldapExceptionTranslationFilter" class="org.springframework.security.ui.ExceptionTranslationFilter">
        <property name="authenticationEntryPoint">
            <bean class="org.springframework.security.ui.webapp.AuthenticationProcessingFilterEntryPoint">
                <property name="loginFormUrl" value="로그인 입력화면 URL" />

            </bean>
        </property>
        <property name="accessDeniedHandler">
            <bean class="org.springframework.security.ui.AccessDeniedHandlerImpl">
            </bean>
        </property>
    </bean>

    <bean id="sessionFixationProtectionFilter" class="org.springframework.security.ui.SessionFixationProtectionFilter" />

    <bean id="ldapFilterInvocationInterceptor" class="org.springframework.security.intercept.web.FilterSecurityInterceptor">
        <property name="authenticationManager" ref="ldapAuthenticationManager" />
        <property name="accessDecisionManager" ref="ldapAccessDecisionManager" />
        <property name="objectDefinitionSource">
            <s:filter-invocation-definition-source>
                <s:intercept-url pattern="/siteList/**" access="IS_AUTHENTICATED_REMEMBERED"/>
                <s:intercept-url pattern="/**"             access="IS_AUTHENTICATED_ANONYMOUSLY"/>
            </s:filter-invocation-definition-source>                       
        </property>
    </bean>

    <bean id="secondLdapProvider"
        class="org.springframework.security.providers.ldap.LdapAuthenticationProvider">
        <s:custom-authentication-provider />
        <constructor-arg>
            <bean               class="org.springframework.security.providers.ldap.authenticator.BindAuthenticator">
                <constructor-arg ref="contextSource" />
                <property name="userSearch">
                    <bean id="userSearch"                        class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
                        <constructor-arg index="0" value="" />
                        <constructor-arg index="1" value="(&amp;(sAMAccountName={0})(objectclass=user))" />                       
                    </bean>
                </property>
            </bean>
        </constructor-arg>
        <constructor-arg>
            <bean class="org.springframework.security.ldap.populator.DefaultLdapAuthoritiesPopulator">
                <constructor-arg ref="contextSource" />
                <constructor-arg value="" />
                <property name="groupSearchFilter" value="(&amp;(member={0})(|(cn=B3 Reader)(cn=B3 Approval)))" />               
                <property name="rolePrefix" value="ROLE_" />
                <property name="searchSubtree" value="true" />
                <property name="convertToUpperCase" value="false" />
            </bean>
        </constructor-arg>
    </bean>

'개발자세상' 카테고리의 다른 글

Long Term Plan?  (0) 2011.02.19
이젠 모바일인가...  (2) 2010.12.05
ASP.NET 크레튜 강의 수강 소감  (0) 2009.12.15
티맥스 소식  (0) 2009.11.10
강사의 조건  (1) 2009.10.22
Posted by headiron
,