스프링에서 제공하는 트랜젝션을 MySQL과 Oracle에다가 적용을 해봤습니다.
제가 잘 이해를 못하는 건지 모르겠는데, Oracle에서는 ReadOnly가 안먹혀요-_-;
MySQL에서는 먹히는데....-_-; Oracle에서는 자체적으로 transaction에서 ReadOnly를 설정하는게 있더군요.
또 Oracle은 트랜젝션기반이라고 하더라구요. 암튼, 참 어렵습니다-_-;
우선 삽질한 코드입니다.
MySQL로 해보았습니다.

필요한 lib입니다.
spring.jar - 스프링할껀데 필요하겠죠?-_-;
commons-logging.jar - 스프링하려면 이눔이 있어야 돼요-_-; 위에 있는 lib와 종속돼요-_-;
ibatis-2.3.0.677.jar - ibatis로 할껍니다. 이게 db연동을 쉽게 해주니까요-_-;
mysql-connector-java-5.1.5-bin.jar - mysql connector가 필요하겠죠!

프로젝트를 만듭시다. TestTransaction이라는 프로젝트를 만듭시다.
최상위 src폴더에다가 applicationContext.xml파일을 만듭시다.

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:tx="http://www.springframework.org/schema/tx"
 xsi:schemaLocation="
  http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
  http://www.springframework.org/schema/tx
  http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">

 <tx:annotation-driven />
 
 <!-- MySQL용 -->
 <bean id="dataSource"
  class="org.springframework.jdbc.datasource.DriverManagerDataSource"
  p:driverClassName="com.mysql.jdbc.Driver"
  p:url="jdbc:mysql://db주소"
  p:username="dbid" p:password="dbpw" />
 
   <!--  Transaction manager for iBATIS Daos -->
 <bean id="transactionManager"
  class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
  p:dataSource-ref="dataSource" />
 
 <!-- SqlMap setup for iBATIS Database Layer -->
 <bean id="sqlMapClient"
  class="org.springframework.orm.ibatis.SqlMapClientFactoryBean"
  p:dataSource-ref="dataSource"
  p:configLocation="classpath:SqlMapConfig.xml" />
 
<bean id="insertDataMysql" class="com.mudchobo.TestInsertMysql"
  p:sqlMapClient-ref="sqlMapClient"/>
</beans>
[/code]
TestInsert라는 interface를 작성해봅시다.
TestInsert.java
[code]
package com.mudchobo;

import org.springframework.transaction.annotation.Transactional;

public interface TestInsert {

 @Transactional(readOnly=true, rollbackFor={Throwable.class})
 public void insertData() throws Throwable;
}
[/code]
인터페이스에다가 트랜젝션을 걸어도 되더라구요-_-; 구현되는 모든놈이 저 옵션으로 트랜젝션이 먹히는 듯 합니다. 근데 별로 안좋은 방법인듯한데-_-; 그냥 메소드에 거는게.....-_-; 보면 readOnly옵션에다가 Throwable예외가 발생하면 롤백합니다.

구현해봅시다.
TestInsertMysql.java
[code]
package com.mudchobo;

import java.io.IOException;

import org.springframework.orm.ibatis.support.SqlMapClientDaoSupport;

public class TestInsertMysql extends SqlMapClientDaoSupport implements
  TestInsert {

 @Override
 public void insertData() throws Throwable {
   getSqlMapClientTemplate().insert("insertData");
   System.out.println("mysql에 insert성공");
   throw new IOException();
 }
}
[/code]
insert를 시키고, 강제로 IOException을 발생시켰습니다.

ibatis xml부분을 봅시다.
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="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">
     insert into TESTDATA (DATA) values ('MUDCHOBO')
    </insert>
</sqlMap>
[/code]
보시면 단순 insert를 하고 있습니다-_-;

main부분입니다.
TestTransaction.java
[code]
package com.mudchobo;

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

public class TestTransaction {
 public static void main(String[] args) throws Throwable{
  String[] configLocation = {"applicationContext.xml"};
  ApplicationContext context =
   new ClassPathXmlApplicationContext(configLocation);
 
  TestInsert testInsertMysql =
   (TestInsert) context.getBean("insertData");
  try {
   testInsertMysql.insertData();
  } catch (Throwable e) {
   System.out.println("예외발생");
  }
}
[/code]
이걸 실행하면 트랜젝션이 readOnly이기 때문에 insert하려고 하면 에러가 나버리겠죠.
Connection is read-only. Queries leading to data modification are not allowed; nested exception is com.ibatis.common.jdbc.exception.NestedSQLException:
요런 에러를 보실 수 있습니다.

Oracle은 다음 장에서-_-;
http://mudchobo.tomeii.com/tt/258 여기에 계속-_-;

 
Posted by 머드초보
,
 

정말 초간단예제군요-_-;
어노테이션을 사용하면 굉장히 편해져요.
저번주 스터디시간에 한 내용을-_-;

AOP를 적용하려면 인터페이스가 있어야 돼요.
Apple이라는 인터페이스를 만들어 봅시다.
com.mudchobo.example4라는 패키지에 Apple이라는 interface를 만듭시다.
Apple.java
[code]
package com.mudchobo.example4;

public interface Apple {
 public void println();
}
[/code]
println이라는 메소드가 하나있네요. 구현해봅시다.
AppleImpl.java
[code]
package com.mudchobo.example4;

public class AppleImpl implements Apple {

 @Override
 public void println(){
  System.out.println("Apple : 맛있다");
 }
}
[/code]
사과는 맛있다 라는 메시지를 출력하는군요. 그럼 AOP....(갑자기 두리녀석이 전화를..-_-; 갑자기 2시간남겨놓고 술먹자고 전화하는 이상한놈이네요-_-;)
AOP 클래스를 만들어봅시다.
[code]
package com.mudchobo.example4;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class AnnotLoggingAspect {

 @Around("execution(public * com.mudchobo.example4.*.println*(..))")
 public void logging(ProceedingJoinPoint joinPoint) {
  String methodName = joinPoint.getSignature().getName();
 
  try {
   System.out.println("before : " + methodName);
   joinPoint.proceed();
   System.out.println("after : " + methodName);
  } catch (Throwable e) {
   System.out.println("예외가 발생했어요!");
  }
 }
}
[/code]
Around는 before, after, 예외 등을 다 포함하고 있죠. 그냥 메소드하나 구현하는거라고 보면 돼요.
execution은 AspectJ의 정규식을 넣으면 돼요. 문법은 검색 고고싱~--;
저건 맨앞에는 public, private정하는거고, 두번째는 리턴타입(*면 전부다겠죠?), 그다음은 패키지명 쓰고, (..)부분은 파라메터관련된 부분이죠. 검색고고싱~
저건 com.mudchobo.example4패키지에서 모든클래스중에 println으로 시작하는 메소드에 aop를 적용하겠다는 얘기에요. println메소드는 우리가 방금 구현한 Apple인터페이스에 있죠.

스프링 설정파일을 봅시다. 최상위 폴더에 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:aop="http://www.springframework.org/schema/aop"
 xsi:schemaLocation="
  http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">

 <aop:aspectj-autoproxy />
 
 <bean id="apple" class="com.mudchobo.example4.AppleImpl" />

 <bean class="com.mudchobo.example4.AnnotLoggingAspect" />
 
</beans>
[/code]
자 보면, apple이라는 bean은 우리가 만든 사과클래스구요. aop클래스를 bean으로 해서 선언해주었어요.
만약 SpringIDE를 설치했다면 왼쪽에 보시면 aop가 어디에 또는 몇개 적용이 되어있는지 나와요.
그럼 메인클래스를 보도록 해요.

Main4.java
[code]
package com.mudchobo.example4;

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

public class Main4 {

 public static void main(String[] args) {
  String configLocation = "applicationContext.xml";
  ApplicationContext context = new ClassPathXmlApplicationContext(configLocation);
  Apple apple = (Apple) context.getBean("apple");
  apple.println();
 }
}
[/code]
설정파일을 불러와서 ApplicationContext를 만들고, 거기서 apple이라는 bean을 불러옵니다.
그리고, apple.println()메소드를 호출하게 되면 aop가 적용되어 호출됩니다.

before : println
Apple : 맛있다
after : println

PS.회사프로그램에 스프링을 이용해서 AOP를 적용해보았는데요. 코드가 깔끔해지고, 참 좋은 것 같아요.
회사프로그램에서 예외처리하는 부분이 굉장히 많았는데 이것을 따로 빼서 하나로 합치니-_-; 코드가독성이 올라가네요. 암튼, 좀 더 배워봐야겠네요.
 
Posted by 머드초보
,
 

보통 어플리케이션에서 Properties를 사용하려면 Properties클래스를 사용해서...
Properties properties = new Properties();
properties.load(new FileInputStream("C:/~~~파일명경로");
String mudchobo = properties.getProperty("mudchobo");

이렇게 하면 풀경로를 다 적어줘야지 되더라구요.

이 파일이 클래스패스에 넣어두면 classpath:file.properties 하면 먹혔으면 좋겠는데 안먹히더라구요-_-;
그래서 스프링을 사용하면 클래스패스에 넣어도 할 수 있어요!(아놔 이렇게 하는거 맞나-_-)

properties패키지에 있는 file.properties파일을 불러올겁니다.
mudchobo=dwaeji
hermusseri=meongchungi
2개의 property가 있습니다.

우선 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"
 xsi:schemaLocation="
  http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

 <bean id="messageSource"
  class="org.springframework.context.support.ResourceBundleMessageSource"
  p:basename="properties/file" />
 
 <bean id="messageSourceAccessor"
  class="org.springframework.context.support.MessageSourceAccessor">
  <constructor-arg ref="messageSource" />
 </bean>
</beans>
[/code]
잘 보면 messageSource라는 bean이 있는데 이것은 ResourceBundleMessageSource구요.
p:basename은 해당패키지에서 파일을 찾더라구요.
properties라는 패키지에 file.properties파일을 지정했습니다.

그다음 bean은 MessageSourceAccessor인데요. 말그대로 메시지소스를 접근하는 접근자라고 자신을 표현하고 있네요. 이것의 생성자로 해당 messageSource를 받는군요.

애플리케이션에서 봅시다.
[code]
package test;

import java.util.Locale;

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

public class Test {
 
 public static void main(String[] args) {
  String[] configLocation = {"applicationContext.xml"};
  ApplicationContext context = new ClassPathXmlApplicationContext(configLocation);
 
  MessageSourceAccessor msAccessor =
   (MessageSourceAccessor)context.getBean("messageSourceAccessor");
 
  System.out.println(context.getMessage("mudchobo", null, Locale.getDefault()));
  System.out.println(context.getMessage("hermusseri", null, Locale.getDefault()));
  System.out.println(msAccessor.getMessage("mudchobo"));
  System.out.println(msAccessor.getMessage("hermusseri"));
 }
}
[/code]
MessageSourceAccessor를 선언해서 해당 bean을 가져옵니다.
그러면 MessageSourceAccessor를 통해서 Message를 가져올 수 있습니다.
저걸 사용하지 않게 된다면 ApplicationContext인터페이스에서 getMessage를 지원해서 저걸 통해서도 가져올 수 있습니다. 저렇게 가져온다면, 여기저기 다른 클래스에서 사용하게 된다면 context를 해당 클래스로 넘겨야하는데 이건 applicationContext에서 MessageSourceAccessor를 DI해버리면 해당 클래스에서 사용할 수 있겠죠?^^

다시 말하지만... 정말 이것말곤 방법이 없나-_-; 그냥 Properties에서 할 수 있을 것 같은데-_-;

 
Posted by 머드초보
,
 

우선 service-config.xml파일을 수정해야합니다.
<factories>
  <factory id="springfactory" class="flex.messaging.factory.SpringFactory" />
</factories>
를 추가합니다.

그 다음 remote-config.xml파일을 수정해야합니다.
<destination id="productmanager">
 <properties>
  <factory>springfactory</factory>
  <source>productManager</source>
 </properties>
</destination>
자세히 보시면 factory는 위에 service-config.xml파일에 정의한 놈이고, source는 bean이름입니다.
즉 applicationContext.xml파일에 정의한 그 bean이름을 저기에 적어 놓으면 됩니다.
그러면 그 bean을 flex로 가져와서 쓸 수 있습니다.

아 그리고 프로젝트에서 이상하게 contextroot가 WebContent로 되어있는데 프로젝트이름으로 고쳐줍시다-_-;
프로젝트 이름에 대고 마우스오른쪽버튼(alt+enter) properties를 선택, Flex Server부분 클릭.
context root를 프로젝트이름(SpringAndBlazeds)으로 바꿔줍시다.

자 그러면 flex_src에 있는 SpringAndBlazeds.mxml을 수정해봅시다.
SpringAndBlazeds.mxml
[code]
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"
 applicationComplete="init();">
 
 <mx:Script>
  <![CDATA[
   import mx.controls.Alert;
   import mx.rpc.events.FaultEvent;
   import mx.rpc.events.ResultEvent;
   import mx.rpc.remoting.RemoteObject;
   
   private function init():void {
    var remoteObject:RemoteObject = new RemoteObject();
    remoteObject.destination = "productmanager";
    remoteObject.addEventListener(ResultEvent.RESULT, resultHandler);
    remoteObject.addEventListener(FaultEvent.FAULT, faultHandler);
    remoteObject.getProducts();
   }
   
   private function resultHandler(event:ResultEvent):void{       
       dg.dataProvider = event.result;  
      }     
  
      private function faultHandler(event:FaultEvent):void{       
       Alert.show("실패 메세지 : " + event.fault.message);  
      } 
  ]]>
 </mx:Script>
 
 <mx:DataGrid id="dg" width="100%" height="100%" />
</mx:Application>
[/code]
간단하게 Manager에 있는 getProducts를 호출해서 DataGrid에 넣는 코드입니다.

자 이제 실행해봅시다-_-;
이클립스 오른쪽아래에 server에다가 SpringAndBlazeds프로젝트를 추가합니다.
서버에 대고, 오른쪽버튼누르면, Add and Remove Project클릭해서 추가하면 됩니다.
서버를 가동합니다.
Run Flex Application을 실행해봅시다!-_-;

사용자 삽입 이미지


아....잘되....는.....군.....요......-_-;
 
Posted by 머드초보
,
 

이제 Manager클래스를 만들어봅시다.
실제로 BlazeDS를 이용해서 가져오는 놈은 이 Manager클래스가 되겠죠^^

Java Resources: src에서 오른쪽버튼 클릭하고, New를 해서 interface를 구현합니다.
[code]
package springapp.service;

import java.util.List;
import springapp.domain.Product;

public interface ProductManager {
 public List<Product> getProducts();
}
[/code]
getProducts라는 메소드가 하나 있군요! 구현해봅시다!!!
[code]
package springapp.service;

import java.util.List;

import springapp.dao.ProductDao;
import springapp.domain.Product;

public class ProductManagerImpl implements ProductManager {

 private ProductDao productDao;
 
 @Override
 public List<Product> getProducts() {
  return productDao.getProductList();
 }

 public void setProductDao(ProductDao productDao) {
  this.productDao = productDao;
 }
}
[/code]
getProducts라는 함수는 Dao에서 getProductList를 호출하는 놈이네요.
요 아래에는 setter가 있네요. 이건 spring에서 DI를 하기위해 존재하는 setter입니다^^
서비스도 완성이 되었네요! 이제 설정파일을 작성해봅시다.

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:aop="http://www.springframework.org/schema/aop"
 xmlns:tx="http://www.springframework.org/schema/tx"
 xsi:schemaLocation="http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
 http://www.springframework.org/schema/aop
 http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
 http://www.springframework.org/schema/tx
 http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">

 <!-- Enable @Transactional support -->
 <tx:annotation-driven />

 <!-- Enable @AspectJ support -->
 <aop:aspectj-autoproxy />

 <aop:config>
  <aop:advisor pointcut="execution(* *..ProductManager.*(..))"
   advice-ref="txAdvice" />
 </aop:config>

 <tx:advice id="txAdvice">
  <tx:attributes>
   <tx:method name="save*" />
   <tx:method name="get*" read-only="true" />
  </tx:attributes>
 </tx:advice>

 <bean id="productManager"
  class="springapp.service.ProductManagerImpl">
  <property name="productDao" ref="productDao" />
 </bean>

</beans>
[/code]
Dao부분의 설정파일인 applicationContext-ibatis.xml파일을 봅시다.
applicationContext-ibatis.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:aop="http://www.springframework.org/schema/aop"
 xmlns:tx="http://www.springframework.org/schema/tx"
 xsi:schemaLocation="http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">

 <bean id="propertyConfigurer"
  class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
  p:location="classpath:properties/jdbc.properties" />

 <bean id="dataSource"
  class="org.springframework.jdbc.datasource.DriverManagerDataSource"
  p:driverClassName="${jdbc.driverClassName}" p:url="${jdbc.url}"
  p:username="${jdbc.username}" p:password="${jdbc.password}" />

 <!-- Transaction manager for iBATIS Daos -->
 <bean id="transactionManager"
  class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  <property name="dataSource" ref="dataSource" />
 </bean>

 <!-- SqlMap setup for iBATIS Database Layer -->
 <bean id="sqlMapClient"
  class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
  <property name="dataSource" ref="dataSource" />
  <property name="configLocation"
   value="classpath:springapp/dao/SqlMapConfig.xml" />
 </bean>

 <!-- Add additional Dao definitions here -->
 <bean id="productDao"
  class="springapp.dao.ProductDaoImpl">
  <property name="sqlMapClient" ref="sqlMapClient" />
 </bean>
 
</beans>
[/code]
jdbc.properties파일은 properties라는 package를 만들고, jdbc.properties파일을 넣어버립시다.
[code]
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://DB주소
jdbc.username=DB아이디
jdbc.password=DB비밀번호
[/code]
이 설정들의 bean들의 관계를 보고 싶다면-_-;
Spring Elements에서 오른쪽버튼 클릭하고 properties를 선택.
Bean Support를 선택, Add한 뒤 두개의 설정파일(applicationContext.xml, applicationContext-ibatis.xml)선택.
Config set에서 New하고 Name에 applicationContext라고 하고, 두개다 체크 오케이~
그럼 이제 스프링 설정파일에서 에러를 찾아낼 수 있어요!
bean들의 관계를 그래프로도 볼 수 있네요!
Config set에 추가한 applicationContext에다가 마우스오른쪽버튼을 클릭하면 open graph로 볼 수 있어요!

이제 클라이언트 구현으로....다음 시간에-_-;

 
Posted by 머드초보
,