Spring - Quartz를 사용하여 스케쥴러 구현하기
가끔 서버에서 주기적으로 어떠한 작업을 하고자 할때 리눅스에서는 크론탭을 사용하여 주기적으로 어떠한 작업을 처리합니다.
이런 주기적 작업을 처리하기위해 Spring에서 지원해 주는 Quartz스케쥴러를 통해 크론탭과 같은 역할을 하는 스케쥴러를 작성할 수 있습니다.
이번에는 Spring 과 Quartz를 연동하여 스케줄러를 작성해 보겠습니다.
작업순서는
스프링 기본 세팅 -> Quartz 세팅 순으로 작업하겠습니다.
1. 스프링 기본 설정
1) springframework.org 로 이동하셔서 스프링 라이브러리를 다운 받습니다.
위와 같은 페이지가 뜨면 해당사항을 입력하시고 Access Download 를 클릭하셔서 다운로드 페이지로 이동합니다. (귀찮으신 분들은 하단의 파란색으로 "download page"를 선택하시면 입력하시지 않고도 다운로드 페이지로 이동하실수 있습니다.
많은 버전의 라이브러리 중 spring-framework-2.5.6.SEC02.zip 를 다운 받습니다. 다른 버전을 다운 받으셔도 상관없습니다만 버전에 따라 세팅 내용이 조금 씩 달라지므로 같은 버전의 라이브러리로 진행하는 것이 나을 것같네요~^^.
2) 이렇게 라이브러리까지 다운로드 받고 나면 Eclipse와 같은 IDE에서 Dynamic Web Project를 선택하여 Project를 한개 생성합니다.
(저는 SpringQuartz 라는 이름으로 생성했습니다.)
3) 프로젝트가 생성되면 프로젝트 안에 /WEB-INF/lib 디렉토리에 스프링 라이브러리를 압축 푼 곳에 있는 dist/spring.jar 파일을 추가합니다.
* 팁 : 프로젝트를 진행하다 보면 위와같이 라이브러리 버전이 없는 jar파일을 그냥 추가하는 경우가 있는데 나중에 라이브러리를 업데이트 해야 할일이 생기게 되면 위와같이 spring.jar 라고 되어있으면 지금 적용되어 있는 버전이 몇 인지 알수가 없습니다. 그렇기 때문에 항상 라이브러리 추가하실때는 추가하시는 라이브러리의 버전 번호를 파일이름 뒤에 추가하는 습관을 들이 시는게 좋습니다.
ex) spring-2.5.6.jar
4) 프로젝트 안에 생성된 web.xml에 Spring을 사용하기 위한 세팅을 추가해 줍니다.
* 저는 Quartz를 사용하기 위한 최소한의 Spring 세팅을 해놓았기 때문에 세팅 내용이 단순합니다. 만약 웹프로젝트와 함께 Quartz를 사용하신다면 웹에 맞게 설정하시고 사용하셔야 함을 알려드립니다.^^
- <?xml version="1.0" encoding="UTF-8"?>
- <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns="http://java.sun.com/xml/ns/javaee"
- xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
- http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <listener>
- <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
- </listener>
- <context-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>/WEB-INF/config/applicationContext*.xml</param-value>
- </context-param>
- </web-app>
5) 쿼츠 라이브러리를 다운로드 받고 라이브러리를 추가해 줍니다.
쿼츠 라이브러리 다운로드 하신다음 압축을 풀어 줍니다.
해당 라이브러리를 프로젝트의 lib 디렉토리에 복사하여 넣어줍니다.
- quartz-all-1.8.3.jar
- 압축푼 lib 디렉터리의 log4j-1.2.14.jar
- 압축푼 lib 디렉터리의 slf4j-api-1.5.10.jar
- 압축푼 lib 디렉터리의 slf4j-log4j12-1.5.10.jar
를 추가 해 줍니다.
마지막으로 apache의 commons-logging-1.1.1.jar 를 다운로드 하셔서 위와 같이 프로젝트의 lib에 추가해주시면 라이브러리 추가는 끝이 납니다.
6) Quartz의 핵심적인 기능을 할 /WEB-INF/config/applicationConext.xml 을 작성합니다.
스케쥴러의 핵심 세팅은 3가지 정도 입니다.
하나. 실제 주기적으로 실행될 클래스 등록
둘. 스케줄러가 동작하는 interval time 설정
셋. 실제 동작하게 끔 설정
이런 세가지가 있겠습니다.
스케줄러 동작방식에는 두가지가 존재 합니다.
-Simple : interval time이 간단하게 동작하는 방식으로 몇초, 혹은 몇분, 몇시간 단위로 작동하고 싶을때 사용합니다.
<Simple type setting>
- <?xml version="1.0" encoding="UTF-8" ?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:context="http://www.springframework.org/schema/context"
- xmlns:p="http://www.springframework.org/schema/p"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- 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">
- <!-- 하나.주기적으로 실행될 클래스 설정 -->
- <!-- property name은 jobClass로 fix, value는 사용자가 작성한 class 파일 위치 -->
- <bean id="simpleQuartzJob" class="org.springframework.scheduling.quartz.JobDetailBean">
- <property name="jobClass" value="net.test.quartz.SimpleQuartzJob"/>
- </bean>
- <!-- 둘.스케줄러의 interval time 설정 -->
- <!-- 쿼츠에는 아래와 같이 몇초에 한번씩 돌게 하는 Simple type 과 -->
- <!-- 무슨 요일 몇시에 한번씩 돌게 하는 날짜로 지정하는 Cron type 이 있다. -->
- <!-- 현재는 Simple type으로 세팅 -->
- <!-- jobDetail은 위에서 설정한 실제 동작할 클래스 id를 적어준다 -->
- <!-- startDelay는 서버 시작후 몇초 뒤에 시작할지 세팅(ms 단위) -->
- <!-- repeatInterval은 몇 초에 한번씩 실행될 건지 세팅(ms 단위: 현재 1초) -->
- <bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean">
- <property name="jobDetail" ref="simpleQuartzJob"/>
- <property name="startDelay" value="1000"/>
- <property name="repeatInterval" value="1000"/>
- </bean>
- <!--셋. 실제 동작하게끔 설정 -->
- <!--ref bean은 위에서 설정한 interval time 아이디를 넣어주면 됨 -->
- <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
- <property name="triggers">
- <list>
- <ref bean="simpleTrigger"/>
- </list>
- </property>
- <!-- Quartz 실행시 세팅 -->
- <property name="quartzProperties">
- <props>
- <prop key="org.quartz.threadPool.class">org.quartz.simpl.SimpleThreadPool</prop>
- <prop key="org.quartz.threadPool.threadCount">5</prop>
- <prop key="org.quartz.threadPool.threadPriority">4</prop>
- <prop key="org.quartz.jobStore.class">org.quartz.simpl.RAMJobStore</prop>
- <prop key="org.quartz.jobStore.misfireThreshold">60000</prop>
- </props>
- </property>
- </bean>
- </beans>
-Cron : linux 의 Cron tab 과 같은 역할을 하는 타입니다. 즉 몇월, 몇일 몇시에 동작하게 하고 싶으면 Cron type을 사용하시면 됩니다.
<Cron type setting>
- <?xml version="1.0" encoding="UTF-8" ?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:context="http://www.springframework.org/schema/context"
- xmlns:p="http://www.springframework.org/schema/p"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- 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">
- <!--하나. 주기적으로 실행될 클래스 설정 -->
- <bean id="cronQuartzJob" class="org.springframework.scheduling.quartz.JobDetailBean">
- <property name="jobClass" value="net.test.quartz.CronQuartzJob"/>
- </bean>
- <!--둘. 스케줄러의 interval time 설정-->
- <!--cronExpression을 통해서 스캐줄러 주기를 설정한다. -->
- <bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
- <property name="jobDetail" ref="cronQuartzJob"/>
- <property name="cronExpression" value="0/1 * * * * ?"/>
- </bean>
- <!--셋. 실제 동작하게끔 설정 -->
- <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
- <property name="triggers">
- <list>
- <ref bean="cronTrigger"/>
- </list>
- </property>
- <property name="quartzProperties">
- <props>
- <prop key="org.quartz.threadPool.class">org.quartz.simpl.SimpleThreadPool</prop>
- <prop key="org.quartz.threadPool.threadCount">5</prop>
- <prop key="org.quartz.threadPool.threadPriority">4</prop>
- <prop key="org.quartz.jobStore.class">org.quartz.simpl.RAMJobStore</prop>
- <prop key="org.quartz.jobStore.misfireThreshold">60000</prop>
- </props>
- </property>
- </bean>
- </beans>
Cron type을 사용하려면 CronExpression을 알아야 합니다.
*Cron Expression
cron expression의 각각의 필드는 다음을 나타낸다.(왼쪽 -> 오른쪽 순)
필드 이름 | 허용 값 | 허용된 특수 문자 |
Seconds | 0 ~ 59 | , - * / |
Minutes | 0 ~ 59 | , - * / |
Hours | 0 ~ 23 | , - * / |
Day-of-month | 1 ~ 31 | , - * ? / L W |
Month | 1 ~12 or JAN ~ DEC | , - * / |
Day-Of-Week | 1 ~ 7 or SUN-SAT | , - * ? / L # |
Year (optional) | empty, 1970 ~ 2099 | , - * / |
Cron Expression 의 특수문자
'*' : 모든 수를 나타냄. 분의 위치에 * 설정하면 "매 분 마다" 라는 뜻.
'?' : day-of-month 와 day-of-week 필드에서만 사용가능. 특별한 값이 없음을 나타낸다.
'-' : "10-12" 과 같이 기간을 설정한다. 시간 필드에 "10-12" 이라 입력하면 "10, 11, 12시에 동작하도록 설정" 이란 뜻.
',' : "MON,WED,FRI"와 같이 특정 시간을 설정할 때 사용한다. "MON,WED,FRI" 이면 " '월,수,금' 에만 동작" 이란 뜻.
'/' : 증가를 표현합니다. 예를 들어 초 단위에 "0/15"로 세팅 되어 있다면 "0초 부터 시작하여 15초 이후에 동작" 이란 뜻.
'L' : day-of-month 와 day-of-week 필드에만 사용하며 마지막날을 나타냅. 만약 day-of-month 에 "L" 로 되어 있다면 이번 달의 마지막에 실행하겠다는 것을 나타냄.
'W' : day-of-month 필드에만 사용되며, 주어진 기간에 가장 가까운 평일(월~금)을 나타낸다. 만약 "15W" 이고 이번 달의 15일이 토요일이라면 가장가까운 14일 금요일날 실행된다. 또 15일이 일요일이라면 가장 가까운 평일인 16일 월요일에 실행되게 된다. 만약 15일이 화요일이라면 화요일인 15일에 수행된다.
"LW" : L과 W를 결합하여 사용할 수 있으며 "LW"는 "이번달 마지막 평일"을 나타냄
"#" : day-of-week에 사용된다. "6#3" 이면 3(3)번째 주 금요일(6) 이란 뜻이된다.1은 일요일 ~ 7은 토요일
Expression | Meaning |
"0 0 12 * * ?" | 매일 12시에 실행 |
"0 15 10 ? * *" | 매일 10시 15분에 실행 |
"0 15 10 * * ?" | 매일 10시 15분에 실행 |
"0 15 10 * * ? *" | 매일 10시 15분에 실행 |
"0 15 10 * * ? 2010" | 2010년 동안 매일 10시 15분에 실행 |
"0 * 14 * * ?" | 매일 14시에서 시작해서 14:59분 에 끝남 |
"0 0/5 14 * * ?" | 매일 14시에 시작하여 5분 간격으로 실행되며 14:55분에 끝남 |
"0 0/5 14,18 * * ?" | 매일 14시에 시작하여 5분 간격으로 실행되며 14:55분에 끝나고, 매일 18시에 시작하여 5분간격으로 실행되며 18:55분에 끝난다. |
"0 0-5 14 * * ?" | 매일 14시에 시작하여 14:05 분에 끝난다. |
* 시간에 맞춰 돌아가는 스케줄러에서 다른 클래스를 사용하고 싶을 때는 다음과 같이 설정합니다.
- <!-- 스프링 DI : 사용할 Service 객체를 생성 -->
- <bean id="quartzJobService" class="net.test.quartz.service.impl.QuartzJobServiceImpl"/>
- <bean id="simpleQuartzJob" class="org.springframework.scheduling.quartz.JobDetailBean">
- <property name="jobClass" value="net.test.quartz.SimpleQuartzJob"/>
- <!-- 사용하고자 하는 class의 bean id를 등록 -->
- <property name="jobDataAsMap">
- <map>
- <entry key="quartzJobService">
- <ref local="quartzJobService"/>
- </entry>
- </map>
- </property>
- </bean>
*두가지 스케줄러를 동시에 실행 시킬때
- <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
- <property name="triggers">
- <!--트리거를 두개 생성후 아래와 같이 세팅 -->
- <list>
- <ref bean="simpleTrigger"/>
- <ref bean="cronTrigger"/>
- </list>
- </property>
- <property name="quartzProperties">
- <props>
- <prop key="org.quartz.threadPool.class">org.quartz.simpl.SimpleThreadPool</prop>
- <prop key="org.quartz.threadPool.threadCount">5</prop>
- <prop key="org.quartz.threadPool.threadPriority">4</prop>
- <prop key="org.quartz.jobStore.class">org.quartz.simpl.RAMJobStore</prop>
- <prop key="org.quartz.jobStore.misfireThreshold">60000</prop>
- </props>
- </property>
- </bean>
7) 실제 작동할 Class파일 생성
- package net.test.quartz;
- import net.test.quartz.service.QuartzJobService;
- import org.quartz.JobExecutionContext;
- import org.quartz.JobExecutionException;
- import org.springframework.scheduling.quartz.QuartzJobBean;
- public class SimpleQuartzJob extends QuartzJobBean{
- //실행될 클래스는 꼭 QuartzJobBean을 상속받아야 되며
- //executeInternal method를 override 하면 자동으로 이 메소드가 실행
- //Spring의 DI를 사용하여 Service객체를 setting
- //DI를 사용하지 않는다면 필요 없는 부분
- private QuartzJobService quartzJobService;
- public void setQuartzJobService(QuartzJobService quartzJobService) {
- this.quartzJobService = quartzJobService;
- }
- @Override
- protected void executeInternal(JobExecutionContext ex)throws JobExecutionException {
- quartzJobService.printLog();
- }
- }
위와 같은 방식으로 Spring과 Quartz를 사용하여 스케줄러를 사용할 수 있습니다.
함께 업로드 하는 파일은 제가 직접 작업한 프로젝트이구요. 함께 확인 해 보시면 쉽게 쿼츠를 사용하실수 있으실 겁니다.~^^
출처 : http://javastore.tistory.com/96
'개발 > Java' 카테고리의 다른 글
JNI 라이브러리 파일의 경로 동적 설정 (0) | 2011.02.25 |
---|---|
Velocity의 기본 문법 (0) | 2011.02.11 |
EHCache를 이용한 캐시 구현 (0) | 2011.01.05 |
javaBean 코드를 좀더 사용하기 편하게 하는 Lombok (0) | 2011.01.04 |
java.lang.NoSuchMethodError: org.objectweb.asm.ClassWriter (0) | 2010.11.21 |
BitmapData를 PNG나 JPG로 변환하여 ByteArray로 서버에 전송하는 방법
로컬자원을 서버에 전송하기 위해 우리는 FileReference Class를 사용하면 된다.
FileReference로 파일을 서버에 전송하는 방법은 많이 공개가 되어 있다.
알다시피 FileReference의 browse()함수를 호출한 뒤, select 이벤트가 발생시 upload() 함수를 이용하여 선택한 로컬자원을 서버로 보낸다.
서버에서는 아주 단순하게 서버 임시 저장소에 저장된 파일을 원하는 곳에 복사하기만 하면 된다.
php의 경우 move_uploaded_file() 메소드를 사용하면 되겠다.
그럼 Flex 시행도중 캡쳐한 화면을 저장하는 경우에도 위와 같은 방법으로 저장이 가능할까?
나는 예전에 ImageSnapshot 클래스를 이용해 base64로 변환해서 서버로 전송한 뒤에 base64를 decode하여 저장하는 방법에 대해서 언급한적이 있다. (http://blog.jidolstar.com/301 참고)
이 방법의 단점은 이미지가 큰 경우 base64로 encode, decode 하는 과정에서 서버성능 및 클라이언트 성능에 따라 속도 및 부하에 영향을 준다. 그러므로 이 방법으로는 PNGEncoder 및 JPGEncoder로 PNG, JPG 파일 형식에 맞는 데이타를 만들었다고 해도, FileReference와 같이 데이타를 전송을 할 수 없었다.
하지만 Google을 열심히 돌아다녔다니 이 문제점에 대한 해결의 실마리를 찾을 수 있었다.
(역시 Google!!!)
간단히 방법을 요약하자면
화면을 BitmapData로 만들어 PNGEncoder나 JPGEncoder를 이용하여 encode한 다음, 그 결과값인 byteArray값을 서버에 전송한다. 전송된 데이타는 FileReference에서 upload()을 이용해 보낸 파일을 저장할때와 동일하게 저장하면 되겠다.
1. BitmapData로 캡쳐해라.
아래 target은 캡쳐할 UIComponent와 같은 DisplayObject 객체이다.
단, BitmapData를 이용해서 화면을 캡쳐할 대상이 외부 동영상이나 사진같은 거라면 crossdomain.xml 에 대한 check가 있어야 한다. 컨텐츠 로드시 checkPolicyFile 속성을 true로 설정할 필요가 있겠다.
그리고 2880px 이상의 크기는 BitmapData로 만들 수 없다.
2. JPG나 PNG로 Encode 하여 ByteArray를 얻는다.
Flex 3 SDK에는 mx.graphics.codec 패키지에 JPGEncoder와 PNGEncoder가 있다. 인터넷을 뒤져보면 GIFEncoder등도 있을것이다. Flex 2 환경에서 작업한다면 Google code에 Adobe AS3 Corelib에 이들이 제공된다. 만약 JPGEncoder를 사용한다면 다음과 같이 하면 되겠다.
Flex 3 SDK는 이러한 Encoder가 IImageEncoder로 구현되었다. 필요하다면 언제 어디서나 Encoder를 바꿔야 하는 경우 IImageEncoder를 사용하는 것이 좋을 수 있겠다.
가령 아래 예제처럼 말이다.
3. 서버에 ByteArray를 전송한다.
데이타를 전송할때는 FileReference를 사용하지 않는다.
바로 URLLoader와 URLRequest만 이용해서 전송이 가능하다. 참고 데이타는 POST방식으로 URLVariable을 이용해서 보낼 수 있다.
위에 진한 부분에 대한 클래스는 아래에 정의되어 있다. 당신은 이 클래스가 어떻게 구성되었는가 열심히 공부할 필요가 없다.(원한다면 해도 된다. 말리지 않음 ^^)
한가지 중요한 정보를 언급하겠다.
URLLoader를 이용해 서버에 전송할때, 프로그램이 같은 도메인상에 있는 경우에는 보안문제가 없다. 하지만 다른 도메인에 위치한 서버로 이미지를 전송할때는 반드시 crossdomain.xml을 check해야한다.
1. Security.loadPolicyFile(http://다른도메인/crossdomain.xml); 를 URLLoader의 load()함수를 호출하기 전에 호출한다.
2. Flash Player 9.0.124.0 버전부터는 HTTP Header 보안취약점을 해결하기 위해서 cross domain 정책이 변경되었는데.... 서버측에 있는 crossdomain.xml에 allow-http-request-headers-from가 추가되어져야 한다. 이것은 HTTP 헤더 전송을 허용할지 결정해준다.
위 처럼 서버측 crossdomain.xml에 allow-http-request-headers-from을 추가함으로 다른 도메인간에 HTTP 헤더 전송을 허용할 수 있다.
서로 다른 도메인에 SWF와 서버측 코드가 배치되어 있다면 반드시 이 사실을 숙지하길 바란다.
3. Flash Player 10에서는 사용자 인터렉션이 반드시 필요하다.
다음글을 참고하세요.
4. 서버측 코드 작성
만약 위 3번 코드에서 var parameters:URLVariables를 아래와 같이 작성했다고 하자.
그럼 PHP 코드로 아래와 같은 방법처럼 만들면 되겠다.(테스트는 안해봤음)
마지막 save Comple 메시지를 받기 위해서는 Flex의 Complete 이벤트 발생시 아래와 같은 방법으로 받으면 되겠다. 이것을 알아내는데도 많이 힘들었다. 일종의 팁이다. ^^;
글쓴이 : 지돌스타(http://blog.jidolstar.com/352)
'개발 > FLEX & AIR' 카테고리의 다른 글
FlashVars 사용법 (0) | 2011.08.24 |
---|---|
flashBuilder 4.5 plug-in의 메뉴가 한글로 나올때 해결법 (0) | 2011.06.23 |
air를 이용한 SQLlite 사용하기 (0) | 2011.01.13 |
Flex DataGrid Tooltip dataTipFunction Example (0) | 2010.11.11 |
[Flex] flex Image, bitmap등의 결과물을 인쇄 및 저장하기 (0) | 2010.08.25 |
air를 이용한 SQLlite 사용하기
var dbFile : File = File.desktopDirectory.resolvePath("application.db");
//table생성
var conn:SQLConnection = new SQLConnection(); //DB를 연결합니다..
conn.open(dbFile);
var syntax:String = "CREATE TABLE IF NOT EXISTS testTable (" +
"no INTEGER PRIMARY KEY AUTOINCREMENT," +
"title TEXT," +
"url TEXT" +
")";
sendQuery(conn, syntax);
//스키마 정보 확인
try {
conn.loadSchema();
var schemaResult:SQLSchemaResult = conn.getSchemaResult();
if (schemaResult) {
for(var obj:String in schemaResult.tables){
var table:SQLTableSchema = schemaResult.tables[obj] as SQLTableSchema;
log("[" + table.name + "] 스키마(Schema)");
for(var prop:String in table.columns){
var column:SQLColumnSchema = table.columns[prop] as SQLColumnSchema;
log("name:" + column.name + ",dataType:" + column.dataType + ",primaryKey:" + column.primaryKey + ",allowNull:" + column.allowNull + ",autoIncrement:" + column.autoIncrement + ",defaultCollationType:" + column.defaultCollationType);
}
}
}
} catch(e:Error) {
log("테이블이 없습니다.");
}
//등록
syntax = "INSERT INTO testTable (title, url) VALUES ('Adobe AIR Devpia.', 'http://airdev.tistory.com/')"; //no는 자동으로 증가
sendQuery(conn, syntax);
syntax = "INSERT INTO testTable (title, url) VALUES ('아폴로케이션[Apollocation]', 'http://cafe.naver.com/apollocation')"; //no는 자동으로 증가
sendQuery(conn, syntax);
//조회
var syntax:String = "SELECT * FROM testTable";
var responder:Responder = new Responder(
function(e:SQLResult):void {
var result:Array = e.data;
var numRows:int = result.length;
for(var i:int = 0; i < numRows; i++){
log("필드 번호 :" + i);
for(var columnName:String in result[i]){
log(columnName + " :" + result[i][columnName]);
}
}
}
);
sendQuery(conn, syntax, -1, responder);
//DB 삭제
syntax = "DROP TABLE testTable";
sendQuery(conn, syntax);
private function sendQuery(conn:SQLConnection, syntax:String, prefetch:int=-1, responder:Responder=null):void { //쿼리 실행
var stm:SQLStatement = new SQLStatement();
stm.sqlConnection = conn;
stm.text = syntax;
stm.execute(prefetch, responder); //prefetch : 가져올 데이터 개수(-1이면 모두), responder : 결과, 상태 Responder
}
'개발 > FLEX & AIR' 카테고리의 다른 글
flashBuilder 4.5 plug-in의 메뉴가 한글로 나올때 해결법 (0) | 2011.06.23 |
---|---|
BitmapData를 PNG나 JPG로 변환하여 ByteArray로 서버에 전송하는 방법 (0) | 2011.01.13 |
Flex DataGrid Tooltip dataTipFunction Example (0) | 2010.11.11 |
[Flex] flex Image, bitmap등의 결과물을 인쇄 및 저장하기 (0) | 2010.08.25 |
[FLEX] Flex 상에서 stage가 null 일경우 (0) | 2010.08.20 |
EHCache를 이용한 캐시 구현
EHCache를 이용한 기본적인 캐시 구현 방법 및 분산 캐시 구현 방법을 살펴본다.
EHCache의 주요 특징 및 기본 사용법
게시판이나 블로그 등 웹 기반의 어플리케이션은 최근에 사용된 데이터가 또 다시 사용되는 경향을 갖고 있다. 80:20 법칙에 따라 20%의 데이터가 전체 조회 건수의 80%를 차지할 경우 캐시를 사용함으로써 성능을 대폭적으로 향상시킬 수 있을 것이다.
본 글에서는 캐시 엔진 중의 하나인 EHCache의 사용방법을 살펴보고, Gaia 시스템에서 EHCache를 어떻게 사용했는 지 살펴보도록 하겠다.
EHCache의 주요 특징
EHCache의 주요 특징은 다음과 같다.
- 경량의 빠른 캐시 엔진
- 확장(scable) - 메모리 & 디스크 저장 지원, 멀티 CPU의 동시 접근에 튜닝
- 분산 지원 - 동기/비동기 복사, 피어(peer) 자동 발견
- 높은 품질 - Hibernate, Confluence, Spring 등에서 사용되고 있으며, Gaia 컴포넌트에서도 EHCache를 사용하여 캐시를 구현하였다.
EHCache를 사용하기 위해서는 다음과 같은 작업이 필요하다.
- EHCache 설치
- 캐시 설정 파일 작성
- CacheManager 생성
- CacheManager로부터 구한 Cache를 이용한 CRUD 작업 수행
- CacheManager의 종료
EHCache 배포판은 http://ehcache.sourceforge.net/ 사이트에 다운로드 받을 수 있다. 배포판의 압축을 푼 뒤, ehcache-1.2.x.jar 파일이 생성되는 데, 이 파일을 클래스패스에 추가해준다. 또한, EHCache는 자카르타의 commons-logging API를 사용하므로, commons-logging과 관련된 jar 파일을 클래스패스에 추가해주어야 한다.
ehcache.xml 파일
EHCache는 기본적으로 클래스패스에 존재하는 ehcache.xml 파일로부터 설정 파일을 로딩한다. 가장 간단한 ehcache.xml 파일은 다음과 같이 작성할 수 있다.
<diskStore path="java.io.tmpdir"/>
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
maxElementsOnDisk="10000000"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU"
/>
<cache name="simpleBeanCache"
maxElementsInMemory="10"
eternal="false"
overflowToDisk="false"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
memoryStoreEvictionPolicy="LRU" />
</ehcache>
위 코드에서 <defaultCache> 태그는 반드시 존재해야 하는 태그로서, 코드에서 캐시를 직접 생성할 때 사용되는 캐시의 기본 설정값을 저장한다. <cache> 태그는 하나의 캐시를 지정할 때 사용된다. name 속성은 캐시의 이름을 지정하며, 코드에서는 이 캐시의 이름을 사용하여 사용할 Cache 인스턴스를 구한다.
설정 파일에 대한 자세한 내용은 뒤에서 살펴보기로 하자.
CacheManager 생성
ehcache.xml 파일을 작성했다면 그 다음으로 할 작업은 net.sf.ehcache.CacheManager 객체를 생성하는 것이다. CacheManager 객체는 다음의 두 가지 방법 중 한가지 방식을 사용하여 생성할 수 있다.
- CacheManager.create() : 싱글톤 인스턴스 사용
- new CacheManager() : 새로운 CacheManager 인스턴스 생성
싱글톤 인스턴스가 아닌 직접 CacheManager 객체를 조작하려면 다음과 같이 new를 사용하여 CacheManager 인스턴스를 생성해주면 된다.
두 방식 모두 클래스패스에 위치한 ehcache.xml 파일로부터 캐시 설정 정보를 로딩한다.
만약 클래스패스에 위치한 ehcache.xml 파일이 아닌 다른 설정 파일을 사용하고 싶다면 다음과 같이 URL, InputStream, 또는 String(경로) 객체를 사용하여 설정 파일의 위치를 지정할 수 있다.
CacheManager cacheManager = new CacheManager(configFile);
Cache에 CRUD 수행
CacheManager 인스턴스를 생성한 다음에는 CacheManager 인스턴스로부터 Cache 인스턴스를 구하고, Cache 인스턴스를 사용하여 객체에 대한 캐시 작업을 수행할 수 있게 된다.
Cache 구하기
net.sf.ehcache.Cache 인스턴스는 CacheManager.getCache() 메소드를 사용하여 구할 수 있다.
Cache cache = cacheManager.getCache("simpleBeanCache");
CacheManager.getCache() 메소드에 전달되는 파라미터는 ehcache.xml 설정 파일에서 <cache> 태그의 name 속성에 명시한 캐시의 이름을 의미한다. 지정한 이름의 Cache 인스턴스가 존재하지 않을 경우 CacheManager.getCache() 메소드는 null을 리턴한다.
Create/Update 작업 수행
Cache 인스턴스를 구한 다음에는 Cache.put() 메소드를 사용하여 캐시에 객체를 저장할 수 있다. 아래 코드는 Cache.put() 메소드의 사용예이다.
SimpleBean newBean = new SimpleBean(id, name);
Element newElement = new Element(newBean.getId(), newBean);
cache.put(newElement);
Cache.put() 메소드는 net.sf.ehcache.Element 객체를 전달받는다. Element 클래스는 캐시에 저장될 원소를 나타내며, 키와 값을 사용하여 원소를 표현한다. Element 객체를 생성할 때 첫번째 파라미터는 원소의 키를 의미하며, 두번째 파라미터는 원소의 값을 의미한다.
EHCache는 캐시에 저장될 각각의 객체들을 키를 사용하여 구분하기 때문에, Element 객체를 생성할 때 (의미상) 서로 다른 객체는 서로 다른 키를 사용해야 한다.
Map과 마찬가지로 EHCache가 제공하는 Cache는 삽입을 하거나 기존의 값을 수정할 때 모두 Cache.put() 메소드를 사용한다. 기존에 캐시에 저장된 객체를 수정하길 원한다면 다음과 같이 동일한 키를 사용하는 Element 객체를 Cache.put() 메소드에 전달해주면 된다.
cache.put(newElement);
...
Element updatedElement = new Element(id, updatedBean);
cache.put(updatedElement);
Read 작업 수행
Cache에 보관된 객체를 사용하려면 Cache.get() 메소드를 사용하면 된다. Cache.get() 메소드는 키를 파라미터로 전달받으며, 키에 해당하는 Element 객체를 리턴하며 관련 Element과 존재하지 않을 경우 null을 리턴한다. 아래 코드는 Cache.get() 메소드의 사용예이다.
SimpleBean bean = (SimpleBean) element.getValue();
Element.getValue() 메소드는 캐시에 저장된 객체를 리턴한다. 만약 Serializable 하지 않은 객체를 값으로 저장했다면 다음과 같이 Element.getObejectValue() 메소드를 사용하여 값을 구해야 한다.
NonSerializableBean bean = (NonSerializableBean) element.getObjectValue();
Delete 작업 수행
Cache에 보관된 객체를 삭제하려면 Cache.remove() 메소드를 사용하면 된다. 아래 코드는 Cache.remove() 메소드의 사용예이다.
Cache.remove() 메소드는 키에 해당하는 객체가 존재하여 삭제한 경우 true를 리턴하고, 존재하지 않은 경우 false를 리턴한다.
CacheManager의 종료
사용이 종료된 CacheManager는 다음과 같이 shutdown() 메소드를 호출하여 CacheManager를 종료해야 한다.
Cache 값 객체 사용시 주의사항
캐시에 저장되는 객체는 레퍼런스가 저장된다. 따라서, 동일한 키에 대해 Cache.put()에 전달한 Element의 값과Cache.get()으로 구한 Element의 값은 동일한 객체를 참조하게 된다.
Element element = new Element(key, bean);
cache.put(element);
Element elementFromCache = cache.get(key);
SimpleBean beanFromCache = (SimpleBean)elementFromCache.getValue();
(bean == beanFromCache); // true
(element == elementFromCache); // false
위 코드에서 Cache.put()에 전달된 element 객체와 Cache.get()으로 구한 elementFromCache 객체는 서로 다른 객체이다. 하지만, 두 Element 객체가 갖고 있는 값은 동일한 객체를 참조하고 있다. 따라서, 캐시에 값으로 저장된 객체를 변경하게 되면 캐시에 저장된 내용도 변경되므로, 캐시 사용시 이 점에 유의해야 한다.
캐시 설정
캐시 설정 파일에 <cache> 태그를 이용하여 캐시를 설정했었다. 캐시 설정과 관련하여 <cache> 태그는 다양한 속성을 제공하고 있는데, 이들 속성에는 다음과 같은 것들이 존재한다.
name | 캐시의 이름 | 필수 |
maxElementsInMemory | 메모리에 저장될 수 있는 객체의 최대 개수 | 필수 |
eternal | 이 값이 true이면 timeout 관련 설정은 무시되고, Element가 캐시에서 삭제되지 않는다. | 필수 |
overflowToDisk | 메모리에 저장된 객체 개수가 maxElementsInMemory에서 지정한 값에 다다를 경우 디스크에 오버플로우 되는 객체는 저장할 지의 여부를 지정한다. | 필수 |
timeToIdleSeconds | Element가 지정한 시간 동안 사용(조회)되지 않으면 캐시에서 제거된다. 이 값이 0인 경우 조회 관련 만료 시간을 지정하지 않는다. 기본값은 0이다. | 선택 |
timeToLiveSeconds | Element가 존재하는 시간. 이 시간이 지나면 캐시에서 제거된다. 이 시간이 0이면 만료 시간을 지정하지 않는다. 기본값은 0이다. | 선택 |
diskPersistent | VM이 재 가동할 때 디스크 저장소에 캐싱된 객체를 저장할지의 여부를 지정한다. 기본값은 false이다. | 선택 |
diskExpiryThreadIntervalSeconds | Disk Expiry 쓰레드의 수행 시간 간격을 초 단위로 지정한다. 기본값은 120 이다. | 선택 |
memoryStoreEvictionPolicy | 객체의 개수가 maxElementsInMemory에 도달했을 때,모메리에서 객체를 어떻게 제거할 지에 대한 정책을 지정한다. 기본값은 LRU이다. FIFO와 LFU도 지정할 수 있다. | 선택 |
아래 코드는 몇 가지 설정 예이다.
sampleCache1 캐시. 최대 10000개의 객체를 저장할 수 있으며,
5분 이상 사용되지 않거나 또는 10분 이상 캐시에 저장되어 있을 경우
캐시에서 제거된다. 저장되는 객체가 10000개를 넘길 경우,
디스크 캐시에 저장한다.
-->
<cache name="sampleCache1"
maxElementsInMemory="10000"
maxElementsOnDisk="1000"
eternal="false"
overflowToDisk="true"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
memoryStoreEvictionPolicy="LFU"
/>
<!--
sampleCache2 캐시. 최대 1000개의 객체를 저장한다.
오버플로우 된 객체를 디스크에 저장하지 않기 때문에
캐시에 최대 개수는 1000개이다. eternal이 true 이므로,
timeToLiveSeconds와 timeToIdleSeconds 값은 무시된다.
-->
<cache name="sampleCache2"
maxElementsInMemory="1000"
eternal="true"
overflowToDisk="false"
memoryStoreEvictionPolicy="FIFO"
/>
<!--
sampleCache3 캐시. 오버플로우 되는 객체를 디스크에 저장한다.
디스크에 저장된 객체는 VM이 재가동할 때 다시 캐시로 로딩된다.
디스크 유효성 검사 쓰레드는 10분 간격으로 수행된다.
-->
<cache name="sampleCache3"
maxElementsInMemory="500"
eternal="false"
overflowToDisk="true"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
diskPersistent="true"
diskExpiryThreadIntervalSeconds="600"
memoryStoreEvictionPolicy="LFU"
/>
분산 캐시
EHCache는 분산 캐시를 지원한다. EHCache는 피어(peer) 자동 발견 및 RMI를 이용한 클러스터간 데이터 전송의 신뢰성 등 분산 캐시를 위한 완전한 기능을 제공하고 있다. 또한, 다양한 옵션을 통해 분산 상황에 맞게 설정할 수 있도록 하고 있다.
참고로, EHCache는 RMI를 이용하여 분산 캐시를 구현하고 있기 때문에, Serializable 한 객체만 분산 캐시에서 사용 가능하다. 키 역시 Serializable 해야 한다.
분산 캐시 구현 방식
EHCache는 한 노드의 캐시에 변화가 생기면 나머지 노드에 그 변경 내용을 전달하는 방식을 사용한다. 즉, 클러스터에 있는 캐시 인스턴스가 n개인 경우, 한번의 변경에 대해 n-1개의 변경 통지가 발생한다.
각 노드의 캐시간 데이터 전송은 RMI를 통해서 이루어진다. EHCache가 데이터 전송 기술로서 RMI를 사용하는 이유는 다음과 같다.
- 자바에서 기본적으로 제공하는 원격 메커니즘
- 안정화된 기술
- TCP 소켓 옵션을 튜닝할 수 있음
- Serializable 한 객체를 지원하기 때문에, 데이터 전송을 위해 XML과 같은 별도의 포맷으로 변경할 필요가 없음
EHCache는 클러스터에 새로운 노드가 추가돌 경우 해당 노드를 자동적으로 발견하는 방식과, 지정된 노드 목록에 대해서만 클러스터의 노드로 사용하는 방식을 지원하고 있다.
멀티캐스트 방식
멀티캐스트 모드를 사용한 경우, 지정한 멀티캐스트 IP(224.0.0.1~239.255.255.255)와 포트에 참여하는 노드를 자동으로 발견하게 된다. 지정한 IP와 포트에 참여한 노드는 자기 자신을 다른 노드에 통지한다. 이 방식을 사용하면 클러스터에 동적으로 노드를 추가하거나 제거할 수 있다.
노드 목록 지정 방식
클러스터에 포함되는 노드 목록을 지정한다. 동적으로 새로운 노드를 추가하거나 기존 노드를 제거할 수 없다.
분산 캐시 설정
분산 캐시를 사용하기 위해서는 다음과 같은 세 개의 정보를 지정해주어야 한다.
- CacheManagerPeerProvider - 피어 발견 관련 설정
- CacheManagerPeerListener - 메시지 수신 관련 설정
- 캐시별 CacheReplicator - 메시지 생성 규칙 설정
CacheManagerPeerProvider는 새롭게 추가된 노드를 발견하는 방식을 지정한다.
노드를 자동으로 발견하는 멀티캐스트 방식을 사용하려면 다음과 같이 설정한다.
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=automatic,
multicastGroupAddress=230.0.0.100, multicastGroupPort=1234" />
위 코드에서 properties 속성의 값에 사용된 프로퍼티는 다음과 같다.
peerDiscovery | automatic으로 지정하면 멀티캐스트 방식을 사용한다. |
multicaseGroupAddress | 멀티캐스트 IP |
multicaseGroupPort | 포트 번호 |
하나의 클러스터에 포함될 노드들은 동일한 멀티캐스트 IP와 포트 번호를 사용해야 한다.
클러스터에 참여할 노드 목록을 지정하는 IP 방식을 사용하려면 다음과 같이 설정한다.
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=manual,
rmiUrls=//server2:12345/cache1|//server2:12345/cache2" />
위 코드에서 properties 속성의 값에 사용된 프로퍼티는 다음과 같다.
peerDiscovery | manual로 지정한 IP 지정 방식이다. |
rmiUrls | 분산 노드에 참여할 서버 및 캐시 목록을 지정한다. 현재 노드의 정보는 포함시켜서는 안 된다. |
이 경우, rmiUrls에 명시된 포트 번호는 뒤에 살펴볼 CacheManagerPeerListener가 사용할 포트 번호를 지정해주어야 한다.
CacheManagerPeerListener 설정
노드를 발견하는 방식을 지정했다면, 다음으로 할 작업은 클러스터에 있는 다른 노드에서 발생한 변경 정보를 수신할 때 사용할 포트 번호를 지정하는 것이다. 다음과 같은 코드를 이용하여 수신과 관련된 포트 번호를 설정할 수 있다.
class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
properties="port=12345, socketTimeoutMillis=120000" />
위 코드에서 properties 속성의 값에 사용된 프로퍼티는 다음과 같다.
port | 메시지를 수신할 때 사용되는 포트 |
socketTimeoutMillis | 이 노드에 메시지를 보냈을 때 메시지 전송을 기다리는 시간. 기본값은 2000ms. |
캐시별 CacheReplicator 설정
분산 환경에 적용되어야 하는 캐시는 캐시의 내용이 변경되었을 때 다른 노드에 있는 캐시에 변경 내역을 알려주어야 한다. <cacheEventListenerFactory> 태그를 사용하면, 언제 어떻게 캐시의 변경 내역을 통지할지의 여부를 지정할 수 있다. 아래 코드는 설정의 예이다.
maxElementsInMemory="100"
eternal="false"
overflowToDisk="false"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
memoryStoreEvictionPolicy="LRU">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicateUpdatesViaCopy=true,replicateUpdates=true" />
</cache>
위 코드와 같이 <cacheEventListenerFactory>의 구현 클래스로 RMICacheReplicatorFactory를 지정하면 캐시에 변경이 생길 때 마다 해당 변경 내역을 클러스터에 참여하고 있는 노드의 캐시에 통지하게 된다. properties 속성에 프로퍼티를 지정하면, 캐시 요소의 추가, 변경, 삭제 등에 대해 통지 방식을 적용할 수 있다. 설정할 수 있는 프로퍼티는 다음과 같다.
replicatePuts | 캐시에 새로운 요소가 추가됐을 때 다른 노드에 복사할지의 여부 |
replicateUpdates | 캐시 요소의 값이 변경되었을 때 다른 노드에 값을 복사할지의 여부 |
replicateRemovals | 캐시 요소가 삭제되었을 때 다른 노드에 반영할지의 여부 |
replicateAsynchronously | 비동기로 값을 복사할지의 여부 |
replicateUpdatesViaCopy | 새로운 요소를 다른 노드에 복사할 지 아니면 삭제 메시지를 보낼지의 여부 |
asynchronousReplicationIntervalMillis | 비동기 방식을 사용할 때 변경 내역을 다른 노드에 통지하는 주기. 기본값은 1000. |
위 속성의 기본값은 모두 true이다. 따라서, 기본 설정값을 사용하려면 다음과 같이 properties 속성을 사용하지 않아도 된다.
memoryStoreEvictionPolicy="LRU">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory" />
</cache>
어플리케이션 구동시 캐시 데이터 로딩하기
CacheManager가 초기화 될 때, 클러스터에 있는 다른 캐시로부터 데이터를 로딩할 수 있다. 이는 초기 구동이 완료된 후 곧 바로 서비스를 제공할 수 있음을 의미한다. 초기 구동시 다른 노드로부터 캐시 데이터를 로딩하려면 다음과 같이 <bootstrapCacheLoaderFactory> 태그의 구현 클래스를 RMIBootstrapCacheLoaderFactory로 지정해주면 된다.
memoryStoreEvictionPolicy="LRU">
<bootstrapCacheLoaderFactory
class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory"
properties="bootstrapAsynchronously=true,
maximumChunkSizeBytes=5000000" />
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory" />
</cache>
RMIBootstrapCacheLoaderFactory에 전달 가능한 프로퍼티 목록은 다음과 같다.
bootstrapAsynchronously | 비동기적으로 수행할지의 여부를 지정 |
maximumChunkSizeBytes | 클러스터의 다른 노드로부터 로딩 가능한 데이터의 최대 크기 |
RMIBoostrapCacheLoaderFactory를 설정하면 캐시를 초기화 할 때, 원격지 노드의 캐시에 저장된 데이터를 로딩하여 로컬 캐시에 저장한다.
분산 캐시 고려사항
분산 캐시를 사용할 때에는 다음과 같은 내용을 고려해야 한다.
- 노드 증가에 따라 네트워크 트래픽 증가:
많은 양의 네트워크 트래픽이 발생할 수 있다. 특히 동기 모드인 경우 성능에 영향을 받을 수 있다. 비동기 모드인 경우 버퍼에 변경 내역을 저장하였다가 일정한 주기로 버퍼에 쌓인 내역을 다른 노드에 통지하기 때문에 이 문제를 다소 완하시킬 수 있다. - 데이터 불일치 발생 가능성:
두 노드에서 동시에 동일한 캐시의 동일한 데이터에 대한 변경을 수행할 경우, 두 노드 사이에 데이터 불일치가 발생할 수 있다. 캐시 데이터의 불일치가 매우 심각한 문제가 될 경우, 동기 모드(replicateAsynchronously=false)와 복사 메시지 대신 삭제 메시지를 전송(replicateUpdatesViaCopy=false)함으로써 이 문제를 해결할 수 있다.
'개발 > Java' 카테고리의 다른 글
Velocity의 기본 문법 (0) | 2011.02.11 |
---|---|
Spring - Quartz를 사용하여 스케쥴러 구현하기 (0) | 2011.02.08 |
javaBean 코드를 좀더 사용하기 편하게 하는 Lombok (0) | 2011.01.04 |
java.lang.NoSuchMethodError: org.objectweb.asm.ClassWriter (0) | 2010.11.21 |
JAVA를 이용한 정규식 간단 사용법 (0) | 2010.09.30 |
javaBean 코드를 좀더 사용하기 편하게 하는 Lombok
annotation으로 javaBean의 중북되고 반복되는 코드를 한결 편리하게 사용할 수 있는 유틸이 있네요.
getter, setter, toString, hasCode등과 같이 bean을 만들때 매번 불편하고 가독성 없이 추가만 해주었는데
이 유틸리티를 사용하면 이런 불편함이 많이 줄어들것으로 생각이 됩니다.
딱히 javaBean이 아니라 다른곳에서도 유용하게 사용하실 수 있습니다.
사용법및 설치법은 다른 여러가지 방법으로도 사용을 할 수 있다고 하나 이클립스에서 설정하는 법을 설명하겠습니다.
다운로드 : http://projectlombok.org/
설치방법 : 해당 사이트에서 lombok.jar 파일을 다운받은 후 console에서 다운로드 경로로 이동한 다음
java -jar lombok.jar 명령을 입력하게 되면 GUI 창이 노출이 됩니다. 해당 창이 노출이 되면 eclipse 파일의 경로를 지정하고
install/update 버튼을 선택하기면 하면 설치가 끝납니다.
사용방법 : http://www.ibm.com/developerworks/kr/library/os-lombok/index.html
'개발 > Java' 카테고리의 다른 글
Spring - Quartz를 사용하여 스케쥴러 구현하기 (0) | 2011.02.08 |
---|---|
EHCache를 이용한 캐시 구현 (0) | 2011.01.05 |
java.lang.NoSuchMethodError: org.objectweb.asm.ClassWriter (0) | 2010.11.21 |
JAVA를 이용한 정규식 간단 사용법 (0) | 2010.09.30 |
Weblogic에러 - Didn't meet stated Content-Length (0) | 2010.05.28 |
Mysql 버전별 DB, USER 생성하기
# 버전별 MySQL user , db , database 생성하기
mysql 버전에 따라서 레코드 숫자가 틀려서 생성 할 때 마다 귀찮은 점이 있다.
적어 두고 생성시 복사해서 사용하는게 편리 하다.
반드시 ID , NAME , DATABASE 이름을 변경하여 사용하시기 바랍니다.
MySQL 3
create database 데이타베이스명;
insert into user values ('localhost','아이디',password('비밀번호'),'N','N','N','N','N','N','N','N','N','Y','N','N','N','N');
insert into db values ('localhost','아이디','디비이름','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y');
flush privileges;
MySQL 4
create database 데이타베이스명;
insert into user values ('localhost','아이디',password('비밀번호'),'N','N','N','N','N','N','N','N','N','Y','N','N','N','N','N','N','N','N','N','N','N','','blob','blob','blob','0','0','0');
insert into db values ('localhost','아이디','디비이름','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y');
flush privileges;
MySQL 5
insert into user values ('localhost','아이디',password('비밀번호'),'N','N','N','N','N','N','N','N','N','Y','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','','blob','blob','blob','0','0','0','0');
insert into db values ('localhost','아이디','디비이름','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y');
flush privileges;
커스텀 설정은 다음과 같은 명령어로 필드 값을 본뒤에 수정 하여 사용할 수 있습니다.
desc user;
desc db;
모든 작업 후 반드시 flush privileges; 로 적용합니다. (모든 작업은 가상으로 작업 된 뒤 적용 시점에 작동 됩니다.)
MySQL 데이타 베이스, 삭제하기
내용 delete from user where user='해당유저이름';
delete from db where db='해당디비이름';
flush privileges; (적용)
사용자 추가
MYSQL에서 유저를 추가하는 방법은 두가지가 있습니다.
일반적으로는 유저를 위한 전용 데이터베이스를 하나 생성해 주고, 해당 데이터베이스에 접속할 권한을 주게 됩니다.
이 때 권한은 local에서만 접속할 권한을 주거나, JDBC등을 이용한다면 외부에서도 접속할 권한을 주어야 합니다.
1. CREATE USER와 GRANT 명령어 사용 (또는)
2. INSERT, UPDATE, DELETE를 사용해서 직접 관리 테이블을 수정하기를 통한 추가
기존 글을 찾아보면 2번의 내용이 많지만 전문가가 아니라면 개인적으로는 쉬운 1번을 추천합니다.
먼저 root 유저로 로그인합니다. 암호가 없을 경우
c:\mysql\bin> mysql -u root mysql
암호가 존재할 경우
c:\mysql\bin> mysql -u root mysql -p
mysql에 접속한 후에 유저가 사용할 데이터 베이스를 만듭니다. 데이터베이스 명은 ps3_psn 으로 합니다.
mysql> create database ps3_psn;
먼저 ryu라는 유저를 생성합니다. 암호는 ssf4로 하겠습니다.
mysql> create user 'ryu'@'localhost' identified by 'ssf4';
ryu 유저에게 ps3_psn 데이터베이스를 로컬에서만 접속할 수 있게 권한을 줍니다.
mysql> GRANT ALL PRIVILEGES ON ps3psn.* TO 'ryu'@'localhost'
-> WITH GRANT OPTION;
ryu 유저에게 모든 데이터베이스를 로컬에서 접속할 권합을 준다면
mysql> GRANT ALL PRIVILEGES ON *.* TO 'ryu'@'localhost'
ryu 유저에게 ps3_psn 데이터베이스에 원격에서도 접속할 권한을 줍니다. JDBC 등에서 사용하려면 이런 식으로 합니다.
mysql> GRANT ALL PRIVILEGES ON ps3_psn.* TO 'ryu'@'%' ->
WITH GRANT OPTION;
접속권한 보기
mysql> SHOW GRANTS FOR 'ryu'@'localhost';
유저 생성하고 권한 부여하기
1. test 유저를 생성하고 testdb라는 데이터베이스에 모든 권한 부여하기(단, 이 유저는 localhost 에서만 접근 가능하며 접근을 위해서 패스워드 필요)
2. test 유저는 모든 호스트에서 testdb에 접근 할 수 있지만 select, insert 권한만 가진다.
3. test 유저는 192.168.0으로 시작하는 모든 컴퓨터에서 접근 가능하며 모든 DB에 모든 권한을 가진다.
[출처] http://blog.naver.com/forspeed4?Redirect=Log&logNo=130037742496
[출처] http://k502000.blog.me/30097017893
[출처] http://blog.omyworld.co.kr/entry/Mysql-user-생성-및-권한-부여
'개발 > Database' 카테고리의 다른 글
mysql 5.5 db 생성 및 사용자 권한 주기 (0) | 2011.03.23 |
---|---|
오라클 모니터링 SQL (0) | 2011.02.25 |
How to install Oracle Client 11g on Windows 7? (0) | 2010.09.27 |
[mysql] mysql 암화화 하기 (0) | 2010.06.03 |
[mysql] column add, modify, delete (0) | 2010.04.15 |
[jquery] ajax 사용하기
$.ajax({
type: "GET",
url: "test.js",
dataType: "script"
});
기본형을 보시면 ajax() 라는 메서드안에 속성 3개를 가진 객체를 생성한후 인자로 때려넣고 있군요.
동적으로 js파일을 로드해서 실행시키는 기능을합니다. 기능이 재밌어 보이긴하는데, 실제로 별로 안쓸것같네요 -_-;
타입2.
$.ajax({
type: "POST",
url: "some.php",
data: "name=John&location=Boston",
success: function(msg){
alert( "Data Saved: " + msg );
}
});
some.php 에 POST 타입으로 name 과 location 을 parameter 로 넘기고있네요. success 프라퍼티는 서버에서 http response 를 받은후에 수행될 콜백함수를 지정합니다. "데이타가 저장되었어염" 라고 알려주네요.
갠적으로 이 타입을 가장많이 사용하고있습니다. 실무에서도 가장많이 사용되죠.
타입3.
$.ajax({
url: "test.html",
cache: false,
success: function(html){
$("#results").append(html);
}
});
cache 라는 프라퍼티가 추가되었군요. test.html 을 가장 최근에 수정된 페이지로 받겠다는거죠.
"캐쉬를 사용하지 않겠다" 이겁니다. html 을 받은후에 results라는 아이디를 가진 엘리먼트의 자식노드로써 추가하고있네요. 쌩 dom api 로 쓰면 이렇겠죠. document.getElementById("results").innerHTML = html;
음 근데 이거랑은 좀 차이점이있어요. append 는 "result 엘리먼트의 자식이 존재할경우, 가장 마지막 자식으로 붙인다" 라는 규칙을 가지고있거든요. 반면에 innerHTML 으로넣으면 자식이 존재하든안하든 덮어써버리는거죠. 기존의 html 엘리먼트는 사라지고 새로운 엘리먼트로 교체되는 개념입니다.
타입4.
var html = $.ajax({
url: "some.php",
async: false
}).responseText;
async(비동기) 라는 프라퍼티가 추가되었군요. false를 때려넣었으니까 "동기"로 요청한다는말이네요.
뭔말이냐면, some.php로 request를 날린후에 response가 오기전까지는 브라우저를 블락킹 시켜버립니다.
유저의 어떠한 인터렉션도 허용되지않죠. 보시면 콜백함수를 때려넣는 success라는 프라퍼티도없네요
그럼 어떻게 응답데이타를 받나염? 바로 저렇게요. var html = $.ajax().responseText;
어차피 서버로부터 response 가 오기전까지는 스크립트수행이 블락되어있으니까 저 코드가 가능한겁니다.
웹플밍을 하다보면 이 타입을 "써야만" 할때가 종종있더군요.
타입 5.
var xmlDocument = [create xml document];
$.ajax({
url: "page.php",
processData: false,
data: xmlDocument,
success: handleResponse
});
[출처] http://boast.tistory.com
'개발 > Javascript' 카테고리의 다른 글
HTML 우클릭 금지와 드레그 금지 (0) | 2013.11.05 |
---|---|
[Android]app <---> javascript 통신 (0) | 2011.04.18 |
javascript 정리 (0) | 2010.12.17 |
[jquery] JQuery Ajax 사용하기 (0) | 2010.07.23 |
[javascript] 위도, 경로를 이용한 거리 계산 소스 (0) | 2010.07.14 |
javascript 정리
<script language="javascript"> <script language="javascipt" src="src.js">
이벤트 처리!!
window 객체의 프로퍼티
frame 객체
document 객체
navigator 객체
event 객체
screen 객체
form 객체
location 객체
link 객체
anchor 객체
history 객체
image 객체
area 객체
Array 객체
Boolean 객체
Function 객체
Global 객체
Math 객체
Number 객체
Object 객체
String 객체
|
내용출처 : [기타] 블로그 집필 - 뎅구르르까껑의 블로그 |
'개발 > Javascript' 카테고리의 다른 글
[Android]app <---> javascript 통신 (0) | 2011.04.18 |
---|---|
[jquery] ajax 사용하기 (0) | 2010.12.17 |
[jquery] JQuery Ajax 사용하기 (0) | 2010.07.23 |
[javascript] 위도, 경로를 이용한 거리 계산 소스 (0) | 2010.07.14 |
유용한 jQuery 플러그인 리스트 (0) | 2010.06.18 |
java.lang.NoSuchMethodError: org.objectweb.asm.ClassWriter
java.lang.NoSuchMethodError: org.objectweb.asm.ClassWriter.<init>(I)V
==============================================================
1. Removed Hibernate's asm.jar,cglib-2.1.3.jar and asm-attrs.jar from classpath.
2. Placed cglib-nodep-2.1_3.jar in classpath (downloaded from
http://repo1.maven.org/maven2/cglib/cglib-nodep/2.1_3/).
3. Included asm3.0.jar from CXF2.0.1 from distribution into the classpath.
http://forge.objectweb.org/projects/asm/
'개발 > Java' 카테고리의 다른 글
EHCache를 이용한 캐시 구현 (0) | 2011.01.05 |
---|---|
javaBean 코드를 좀더 사용하기 편하게 하는 Lombok (0) | 2011.01.04 |
JAVA를 이용한 정규식 간단 사용법 (0) | 2010.09.30 |
Weblogic에러 - Didn't meet stated Content-Length (0) | 2010.05.28 |
annotation for acegi (0) | 2010.05.27 |
eclipse workspace 바로가기 링크 만들기
D:\dev\eclipse\eclipse.exe -data "워크스페이스경로" -showlocation
'개발 > IDE' 카테고리의 다른 글
eclipse copy & Paste 느린 현상 (0) | 2015.04.02 |
---|---|
eclipse.ini 설정 (0) | 2014.04.22 |
Eclipse 유용한 PLUG-IN (0) | 2009.10.24 |
[eclipse] 자주쓰는 이클립스 단축키 (0) | 2008.12.24 |
Eclipse plug-in (0) | 2008.12.06 |