내용 목차
본 장에서는 JEUS의 기본 프로바이더인 EclipseLink에 대한 설정을 설명한다. 이러한 설정은 JPA 스펙에서 정의되지 않는 기능을 구현하기 위해 필요한 부분으로, 각 애플리케이션에 맞게 정확하게 설정되어야 한다.
사용 환경, 데이터베이스 타입에 따른 설정과 자동으로 데이터베이스 스키마를 생성하는 설정에 대해 설명한다.
사용 환경에 따라 데이터베이스의 설정 방법이 달라진다.
Java EE 환경(또는 모드)은 JEUS의 Managed Server(이하 MS) 위에서 웹 컨테이너, EJB 컨테이너, 애플리케이션 클라이언트 컨테이너를 의미한다.
좀 더 정확하게는 각 컨테이너에서 컨트롤하는 Thread를 의미한다. 예를 들어 웹 엔진에 설정하는 Web Thread Pool의 Thread이다. 만약 애플리케이션이 직접 생성한 Thread Pool의 Thread처럼 컨테이너가 관리하지 않는 Thread 상에서는 Java SE 환경과 똑같다.
사용할 데이터베이스 대상에 대한 설정은 persistence.xml Descriptor에 설정한다. 사용할 트랜잭션의 종류에 따라서 <jta-data-source>와 <non-jta-data-source> 값을 설정한다.
글로벌 트랜잭션을 사용하는 경우
<transaction-type>의 값을 'JTA'로 설정한다.
<jta-data-source>에 해당 데이터소스의 JNDI 이름을 설정한다.
로컬 트랜잭션을 사용하는 경우
<transaction-type>의 값을 'RESOURCE_LOCAL'로 설정한다.
<non-jta-data-source>에 해당 데이터소스의 JNDI 이름을 설정한다.
[예 2.1] Java EE 모드에서 데이터베이스 설정 예
<?xml version="1.0" encoding="UTF-8"?> <persistence xmlns="http://java.sun.com/xml/ns/persistence"> <persistence-unit name="em" transaction-type="JTA"> <jta-data-source>jdbc/MyDB</jta-data-source> </persistence-unit> </persistence>
1. Java EE 환경에서는 <transaction-type> 값을 지정하지 않을 경우 기본적으로 JTA 트랜잭션으로 설정한다.
2. JEUS에서 DB 데이터소스를 설정하는 방법은 “JEUS Server 안내서”의 “제6장 DB Connection Pool과 JDBC”를 참고한다.
Java SE 환경(또는 모드)은 Java EE 컨테이너에서 사용하지 않고 Java Standalone 클라이언트와 같은 환경에서 사용하는 경우를 말한다. 이때는 로컬 트랜잭션만 사용할 수 있으며, 사용되는 데이터베이스의 JDBC 설정을 프로퍼티로 설정해야 한다.
다음의 예제와 같이 <transaction-type>의 값을 'RESOURCE_LOCAL'로 설정한다.
[예 2.2] Java SE 모드에서 데이터베이스 설정 예
<?xml version="1.0" encoding="UTF-8"?> <persistence xmlns="http://java.sun.com/xml/ns/persistence"> <persistence-unit name="em" transaction-type="RESOURCE_LOCAL"> <properties> <property name="eclipselink.jdbc.driver" value="org.apache.derby.jdbc.ClientDriver"/> <property name="eclipselink.jdbc.url" value="jdbc:derby://localhost:1527/testdb"/> <property name="eclipselink.jdbc.user" value="APP"/> <property name="eclipselink.jdbc.password" value="APP"/> </properties> </persistence-unit> </persistence>
다음은 프로퍼티 값에 대한 설명이다.
기본적으로 해당 데이터베이스 타입을 JDBC 커넥션 정보를 통해 자동으로 감지한다. 자동 감지 기능이 제대로 동작하지 않거나, 별도의 다른 데이터베이스를 사용하는 경우라면 'eclipselink.target-database' 프로퍼티를 설정할 수 있다.
데이터베이스 타입은 JDBC 드라이버의 DatabaseMetaData.getDatabaseProductName()을 사용하여, 데이터베이스 벤더 이름을 regular expression으로 비교하는 방식을 사용한다.
[예 2.3] 데이터베이스 타입 설정 예
<?xml version="1.0" encoding="UTF-8"?> <persistence xmlns="http://java.sun.com/xml/ns/persistence"> <persistence-unit name="em"> <jta-data-source>jdbc/MyDB</jta-data-source> <properties> <property name="eclipselink.target-database" value="DB2"/> </properties> </persistence-unit> </persistence>
다음은 지원되는 데이터베이스 타입 값에 대한 설명이다.
[표 2.2] eclipselink.target-database 프로퍼티
값 | 설명 |
---|---|
Auto | 자동 감지(기본값) |
Attunity | Attunity DBMS |
Cloudscape | Cloudscape DBMS |
DB2 | IBM DB2 DBMS |
DB2Mainframe | IBM DB2 Mainframe DBMS |
DBase | DBase DBMS |
Derby | Apache Derby DBMS |
HSQL | HSQL DBMS |
Informix | Informix DBMS |
JavaDB | JavaDB DBMS |
MySQL4 | MySQL DBMS |
Oracle | Oracle DBMS |
PointBase | PointBase DBMS |
PostreSQL | PostreSQL DBMS |
SQLAnyWhere | SQLAnywhere DBMS |
SQLServer | Microsoft SQLServer DBMS |
Sybase | Sybase DBMS |
TimesTen | Oracle Timesten DBMS |
Customized class name | 기본적으로 지원되지 않는 DBMS를 추가할 때 사용한다. |
기본적으로 지원되지 않는 DBMS의 경우 별도로 DBMS 지원 기능을 구현하여 사용할 수 있다. 이때는 해당 클래스 이름을 지정한다. 이에 대한 자세한 내용은 본 안내서의 참고 자료를 참고한다.
자동으로 DB 스키마를 생성하는 기능을 사용하는 경우 설정한다. 이를 사용하면 애플리케이션을 deploy할 때 DB 테이블 및 제약 사항(Constraints)을 자동으로 생성한다.
[예 2.4] 스키마 자동 생성 설정 예
<?xml version="1.0" encoding="UTF-8"?> <persistence xmlns="http://java.sun.com/xml/ns/persistence"> <persistence-unit name="em"> <jta-data-source>jdbc/MyDB</jta-data-source> <properties> ... <property name="eclipselink.ddl-generation" value="create-tables" /> ... </properties> </persistence-unit> </persistence>
관련된 프로퍼티 설정은 다음과 같다.
DDL을 생성할 때 기본적으로 다음과 같이 Java 타입을 해당 데이터베이스 SQL 타입에 맞게 생성한다.
[표 2.3] Java Type to SQL Type Mappings
Java Type | Derby, JavaDB, Cloudscape | Oracle | DB2 | Sybase | SQLServer | MySQL |
---|---|---|---|---|---|---|
boolean, Boolean | SMALLINT | NUMBER(1) | SMALLINT | BIT | BIT | TINYINT(1) |
int, Integer | INTEGER | NUMBER(10) | INTEGER | INTEGER | INTEGER | INTEGER |
long, Long | BIGINT | NUMBER(19) | INTEGER | NUMERIC(19) | NUMERIC(19) | BIGINT |
float, Float | FLOAT | NUMERIC(19,4) | FLOAT | FLOAT(16) | FLOAT(16) | FLOAT |
double, Double | FLOAT | NUMERIC(19,4) | FLOAT | FLOAT(32) | FLOAT(32) | DOUBLE |
short, Short | SMALLINT | NUMBER(5) | SMALLINT | SMALLINT | SMALLINT | SMALLINT |
byte, Byte | SMALLINT | NUMBER(3) | SMALLINT | SMALLINT | SMALLINT | SMALLINT |
java.lang.Number | DECIMAL | NUMBER(38) | DECIMAL(15) | NUMERIC(38) | NUMERIC(28) | DECIMAL(38) |
java.math.BigInteger | BIGINT | NUMBER(38) | BIGINT | NUMERIC(38) | NUMERIC(28) | BIGINT |
java.math.BigDecimal | DECIMAL | NUMBER(38) | DECIMAL(15) | NUMERIC(38) | NUMERIC(28) | DECIMAL(38) |
java.lang.String | VARCHAR(255) | VARCHAR(255) | VARCHAR(255) | VARCHAR(255) | VARCHAR(255) | VARCHAR(255) |
char, Character | CHAR(1) | CHAR(1) | CHAR(1) | CHAR(1) | CHAR(1) | CHAR(1) |
byte[], Byte[], java.sql.Blob | BLOB(64000) | LONG RAW | BLOB(64000) | TEXT | TEXT | TEXT(64000) |
char[], Character[], java.sql.Clob | CLOB(64000) | LONG | CLOB(64000) | TEXT | TEXT | TEXT(64000) |
java.sql.Date | DATE | DATE | DATE | DATETIME | DATETIME | DATE |
java.sql.Time | TIME | DATE | TIME | DATETIME | DATETIME | TIME |
java.sql.Timestamp | TIMESTAMP | DATE | TIMESTAMP | DATETIME | DATETIME | DATETIME |
JPA에서는 기본적으로 Persistence Context라고 하는 1st-level Caching을 지원하고 있다. 하지만, 일반적으로 Persistence Context는 트랜잭션별로 새로 생성되기 때문에(Extended Persistence Context는 이에 해당하지 않음) 트랜잭션 간에 Caching을 지원하지 않는다. 이를 보완하기 위해 TopLink Essentials에서는 2nd-level Caching 기능을 제공한다.
2nd-level Caching은 EntityManagerFactory 레벨에서 지원되기 때문에, 동일한 EntityManagerFactory에서 생성된 모든 EntityManager의 경우 이 공유 Cache를 사용하게 된다. 즉, Persistence Context에 없는 Entity를 가져올 때 2nd-level Caching을 참고하여 존재하는 경우에 이를 가져온다. 따라서 반복적인 Read 작업의 경우 성능 향상을 가져오게 된다.
[예 2.5] Caching 방식 설정 예
<?xml version="1.0" encoding="UTF-8"?> <persistence xmlns="http://java.sun.com/xml/ns/persistence"> <persistence-unit name="em"> <jta-data-source>jdbc/MyDB</jta-data-source> <properties> ... <property name="eclipselink.ddl-generation" value="create-tables" /> <property name="eclipselink.cache.type.default" value="NONE" /> <property name="eclipselink.cache.size.default" value="999" /> <property name="eclipselink.cache.shared.default" value="false" /> ... </properties> </persistence-unit> </persistence>
다음은 Caching에 관련된 옵션에 대한 설명이다.
2nd-level Caching이 사용될 때 주의할 것은 외부 애플리케이션에 의해 또는 직접 데이터베이스의 데이터를 변경하는 경우 해당 내용이 Caching에 반영되지 않는다는 점이다. 이런 경우 데이터베이스의 최신 값이 아닌 Caching된 값이 리턴되기 때문에 애플리케이션에 이를 고려해야 한다.
Caching 옵션을 애플리케이션 환경을 고려하여 적절히 설정하거나, EntityManager.refresh(), eclipselink.refresh Query 힌트 또는 locking(pessimistic/optimistic) 등을 사용하여 이런 문제를 피할 수 있다.
Query 힌트는 Query 객체를 사용할 때 프로바이더에서 제공하는 기능을 사용하도록 한다.
다음 예제와 같이 Query를 실행할 때 설정할 수도 있고, Named Query를 사용하는 경우 @QueryHint Annotation을 사용하여 지정할 수도 있다.
[예 2.6] Query 힌트 사용 예제
List employees = em.createQuery("SELECT e FROM Employee e WHERE e.name = :name") .setParameter("name", name) .setHint("eclipselink.refresh", true) .getResultList();
제공하는 Query 힌트는 다음과 같다.
좀 더 자세한 로그를 보고 싶다면 Logging 레벨을 설정할 수 있다.
기본적으로 Logging 레벨은 JEUS 서버에 전체적으로 적용되는 레벨(기본적으로 INFO)을 따르게 되지만, 이를 Persistence Unit별로 변경할 경우 eclipselink.logging.level 프로퍼티로 설정할 수 있다.
Logger의 경우 Java EE 모드에서는 기본적으로 JEUS에서 제공되는 Logger(JEUS Logger)를 사용하게 되며, Java SE 모드에서는 standard output으로 출력되는 DefaultLogger를 사용하게 된다. 이를 변경하려면 eclipselink.logging.logger 프로퍼티로 설정할 수 있다.
[예 2.7] Logging 설정 예
<?xml version="1.0" encoding="UTF-8"?> <persistence xmlns="http://java.sun.com/xml/ns/persistence"> <persistence-unit name="em"> <jta-data-source>jdbc/MyDB</jta-data-source> <properties> ... <property name="eclipselink.logging.level" value="FINE"/> <property name="eclipselink.logging.logger" value="DefaultLogger"/> ... </properties> </persistence-unit> </persistence>
다음은 설정에 대한 자세한 설명이다.
1. EclipseLink에 대한 자세한 설정은 http://wiki.eclipse.org/EclipseLink/UserGuide/JPA를 참고한다.
2. TopLink에서 EclipseLink로 전환할 경우 http://www.eclipse.org/eclipselink/documentation/2.4/solutions/migrnativetoplink.htm를 참고한다.