Spring은 여러 개의 모듈로 이루어져 있으며, 각 모듈은 서로간의 의존관계를 가집니다.
예를 들어,
1) Spring의 DI 기능만 필요하다면 의존성으로 Spring Core
, Spring Context
를 추가해주면 되고
2) Spring의 AOP 기능만 필요하다면 의존성으로 Spring Core
, Spring Beans
를 추가해주면 되며
3) Spring Web MVC 기능은 Spring Context Support
와 Spring Web
4) Spring ORM 을 쓰려면, Spring Core
, Spring Context
, Spring AOP
, Spring DAO
( DB 연결 및 Transaction 관리 ) 가 있어야 합니다.
DBCP는 데이터베이스 커넥션 풀의 약자로, 클라이언트 요청마다 DB에서의 인증 및 커넥션 생성을 하여 진행하는 것이 아닌, 미리 커넥션을 여러 개 만들어서 웹 어플리케이션 환경에서 응답속도를 개선하기 위해 사용합니다. ( 커넥션 만드는 비용을 줄일 수 있기 떄문 )
DB_ID
, DB_PW
로 인증하는 시간 낭비, 자원 낭비이러한 Connection Pool의 라이브러리로 Apache Commons DBCP를 많이 사용합니다.
기존 코드에서는 ojdbc6.jar
의 OracleDataSource
를 직접 의존 ( new로 생성 )하여 커넥션 풀을 만들고, 해당 커넥션에서 물어온 Connection으로 DB연결을 수행했습니다.
이러한 DataSource를 Spring Context에 Bean으로 등록하여 사용한다면, 추후 요구사항 변경 시 코드 수정을 줄여 유지보수성을 좋게할 수 있습니다.
또한, Oracle의 DataSource를 직접 의존하는 방법 외에 Tomcat 자체에서 제공해주는 DataSource를 사용하는 방법도 있습니다. ( Apache Commons DBCP )
pom.xml
에 commons-dbcp-1.4.jar
, commons pool.jar
를 추가해주면 됩니다.JNDI
- Java Naming And Directory Interface
내 자바 코드에서 남의 자원을 쉽게 사용하고 관리할 수 있게 해준다!
이와 관련한 기술로 RMI ( Remote Method Interface )가 있음.
Java 네트워킹의 가장 핵심, 고급 기술에 해당하는 것이 JNDI + RMI 이다.
MyBatis의 Context를 불러올 때 JNDI를 사용하기에 언급하고 감.
네트워크 자원에 이름을 통해 접근할 수 있도록 합니다.
LDAP (파일 리소스 공유 체계)
Low단의 기술에는 JNDI를 기반으로한 응용 기술을 사용합니다.
JNDI를 사용하여 Java 자체 코드에서 DataSource 자원을 사용할 수 있습니다.
static DataSource ds;
public Connection dbConn(){
Connection conn = null;
try {
initialContext ctx = new InitialContext();
Context envCtx = (Context) ctx.lookup("java:/comp/env");
ds = (DataSource) envCtx.lookup("jdbc/MyDataSource_MYNAME");
System.out.println("DataSource Lookup 성공!");
} catch(NamingException e){
System.err.println("lookup 실패 : " + e.getMessage());
}
}
jdbc:thin:...
이런 URL 규칙과도 같은 것이다. )<!-- 리소스 설정 -->
<resource-ref>
<description>My DataSource</description>
<res-ref-name>jdbc/MyDataSource_MYNAME</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
web.xml
을 볼 수 있었던 것은 톰캣의 context.xml
에 WEB-INF/web.xml
이 표시되어 있었기 때문.<!-- Tomcat context.xml -->
<Resource
name="jdbc/MyDataSource_MYNAME"
auth="Container"
type="javax.sql.DataSource"
maxTotal="100" -- 100개의 DataSource ( = Session )
maxIdle="30" -- 대기자 30명까지 대기
maxWaitMillis="10000"
username="it"
password="0000"
driverClassName="oracle.jdbc.driver.OracleDriver"
url="jdbc:oracle:thin:@127.0.0.1:1521:XE"/>
이를 Java 자체에서 호출 테스트를 했을 때 실패했습니다. ( JNDI를 통한 Call, lookup할 때 X ) => 윈도우 자체에서 환경변수 설정이 필요했습니다.
자바 자체에서 순수 데이터소스를 사용하는 것은 실패했지만, ( 가능합니다. )
Spring Container의 도움을 받아 DataSource (=DBCP)
를 사용해보겠습니다.
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd"
>
<!-- 로그출력 : log4j -->
<mvc:resources mapping="/resources/**" location="/resources/"/>
<mvc:annotation-driven/>
<context:component-scan base-package="com.lec08.dao" />
<!-- datasource -->
<bean id="MY_tomcat_ds"
class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName"
value="oracle.jdbc.driver.OracleDriver" />
<property name="url"
value="jdbc:oracle:thin:@localhost:1521:XE" />
<property name="username"
value="it"/>
<property name="password"
value="0000" />
</bean>
DataSource
의 XML을 보면, destroy-method=”close”
가 있습니다. 이는 자동으로 자원을 close 해준다.
따라서 이 DataSource
를 DAO에서 주입받아 사용하면, finally
문의 자원을 닫아주는 행위를 하지 않아도 됩니다. ( 코드 중복 제거 )
데이터 엑세스 계층의 코드 작성을 단순화하고 일관된 데이터 접근 방법을 제공합니다.
JDBC, ORM ( Mybatis, Hibernate ), JPA 등의 다양한 데이터 접근 기술을 제공합니다.
JdbcTemplate
( JDBC를 단순히 사용 가능 )을 제공합니다.
JPA
= Java Persistence API
ORM
을 위한 표준 인터페이스ORM(Object Relation Mapping)
Entity
라는 형태로 고나리합니다.pom.xml
에 추가힙니다.<!-- mapper 관련 -->
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
<!-- mybatis-spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<!-- Mybatis-spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.0</version>
</dependency>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<arti
factId>spring-ibatis</artifactId>
<version>2.0.8</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.ibatis</groupId>
<artifactId>ibatis-sqlmap</artifactId>
<version>2.3.4.726</version>
</dependency>
-----------------------------------------------------------------
스프링 DAO(Data Access Object)
- 데이터 액세스 계층의 코드 작성을 단순화하고 일관된 데이터 접근 방법을 제공
- JDBC, ORM(Hibernate, Mybatis, ...), JPA 등의 다양한 데이터 접근 기술 제공
- JdbcTemplate(단순) 제공
- ORM(Object Relation Mapping) : 자바객체-테이블 매핑
- JPA(Java Persistence API) : ORM을 위한 표준 인터페이스
-----------------------------------------------------------------
----------------------------------------------------------
*** JdbcTemplate
----------------------------------------------------------
public Post updatePost(Long id, Post updateParam) {
String sql = "UPDATE post SET title=?, content=?, MODIFIED_DATE=? where id=?";
template.update(sql,
updateParam.getTitle(),
updateParam.getContent(),
updateParam.getModifiedDate(),
id);
}
----------------------------------------------------------
*** JPA
----------------------------------------------------------
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<User, Long> {
//slect * from user where uname = ?
List<User> findByName(String name);
}
----------------------------------------------------------
*** ORM(Mybatis)
----------------------------------------------------------
package com.lec09.orm;
public class MemberVO {
private int id;
private String name;
private String email;
private Date regdate;
// getters and setters
}
package com.lec09.orm.mapper;
public interface MemberMapper {
void myMethodName__insert(MemberVO mvo);
}
'MemberMapper.xml'
<mapper namespace="com.lec09.mapper.MemberMapper">
<insert id="myMethodName__insert" parameterType="com.lec09.orm.MemberVO">
INSERT INTO member (name, email) VALUES (#{name}, #{email})
</insert>
</mapper>
@Service
public class MemberServiceImpl {
@Autowired
private MemberMapper memberMapper;
public void addMember(MemberVO prmVO) {
memberMapper.myMethodName__insert(prmVO);
}
}
----------------------------------------------------------
*** ORM(Hibernate)
----------------------------------------------------------
@Data
@Table(name = "Member")
@Entity
public class Board implements java.io.Serializable {
@Id
@Column(name = "seq")
@GenenratedValue(strategy = GenerationType.AUTO)
private int seq;
@Column(name = "title", nullable = false)
private String title;
public Board() {}
public Board(String title) {
this.title = title;
}
}
hibernate-board-mapper.xml
@Temporal(TemporalType.TIME)
private Date playTime;
@Temporal(TemporalType.DATE)
private Date added;
<hibernate-mapping>
<class name="com.lec09.orm.BoardVO" table="board">
<meta attribute="class-description">
Represents a single playable track in the music database.
@author Jum Elliott (with help from Hibernate)
</meta>
<id name="seq" type="int" column="seq">
<meta attribute="scope-set">protected</meta>
<generataor class="native">
</id>
<property name="title" type="string" not-null="true"/>
</class>
</hibernate-mapping>
public class ServiceImpl {
SessionFactory sessionFactory = HibernateUtil5.getSessionFactory();
SessionFactory session = sessionFactory.openSession();
Transaction tx = null;
public void svcMethodd() {
try {
tx = session.beginTransaction();
// 쿼리 작성
tx.commit();
} catch (RuntimeException e) {
if (tx != null) tx.rollback();
} finally {
session.close();
}
sessionFactory.close();
}
}
----------------------------------------------------------