การ config database จะมีอยู่ 2 แบบ น่ะครับ คือ
1. แบบ Resources Local คือ เราเป็นคน config database ไว้ใน web application ของเราเลย ข้อดีคือ ไม่ต้อง config อะไรเพิ่มเติม เมื่อเอาไป deploy แต่มีข้อเสียคือ เวลาเปลียน database ที เราก็ต้องมาแก้ code application ของเราใหม่ตลอด
2. แบบ JTA (Java Transaction API) คือวิธีนี้
เราจะ config database ไว้ที่ application
server โดยใช้ JNDI แล้วให้ web
application ของเรา point ไปที่ resources
นั้นแทน ข้อดีคือจัดการง่าย เวลาที่ต้องการเปลี่ยนแปลง database
ก็ไม่ต้องมาแก้ไข code application ของเรา ใหม่ การ maintenance และ management อะไรต่างๆ ง่ายกว่า และที่สำคัญคือรองรับ XA transaction หรือ Global transaction ที่สามารถทำ transaction แบบ multiple data-store
ได้อีกด้วย แต่ข้อเสียคือ
ต้อง config ที่ application server เพิ่มเติม ไม่เสร็จสับในทีเดียวเหมือน resource local
การ config จะต้องเป็นแบบใดแบบหนึ่งเท่านั้น
ปกติผมจะใช้แบบที่ 2 (JTA) เพราะว่ามัน management ได้ง่ายกว่า
ทั้ง 2 อย่างนี้ มีส่วนที่ต่างกันอยู่ 2 ไฟล์ครับ คือ
1. applicationContext-database*.xml
2. persistence*.xml
ซึ่งจะ config ไม่เหมือนกัน
1.Config Library : pom.xml
dependencies ค่อนข้างจะเยอะหน่อยน่ะครับ เพราะว่าผมเผื่อไปถึง spring แล้วก็ JSF ด้วย
... ... ... <properties> ... ... ... <org.springframework.version>3.1.3.RELEASE</org.springframework.version> </properties> <dependencies> <!-- primefaces --> <dependency> <groupId>org.primefaces</groupId> <artifactId>primefaces</artifactId> <version>3.4.2</version> </dependency> <!-- primefaces --> <!-- Spring --> <!-- imports import org.springframework.web.jsf.FacesContextUtils; import org.springframework.stereotype.Service; => [@Service] --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${org.springframework.version}</version> <type>jar</type> </dependency> <!-- imports import org.springframework.ui.freemarker.FreeMarkerConfigurationFactoryBean; import org.springframework.mail.javamail.JavaMailSenderImpl; import org.springframework.mail.javamail.MimeMessageHelper; import org.springframework.stereotype.Service; => [@Service] org.springframework.context.support.ResourceBundleMessageSource --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${org.springframework.version}</version> <type>jar</type> </dependency> <!-- *****************************************************************--> <!-- ******* important library on load application context import org.springframework.beans.factory.annotation.Autowired; --> <!-- Bean Factory and JavaBeans utilities (depends on spring-core) Define this if you use Spring Bean APIs (org.springframework.beans.*) --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${org.springframework.version}</version> </dependency> <!-- Expression Language (depends on spring-core) Define this if you use Spring Expression APIs (org.springframework.expression.*) --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-expression</artifactId> <version>${org.springframework.version}</version> </dependency> <!-- Aspect Oriented Programming (AOP) Framework (depends on spring-core, spring-beans) Define this if you use Spring AOP APIs (org.springframework.aop.*) --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${org.springframework.version}</version> </dependency> <!-- Application Context (depends on spring-core, spring-expression, spring-aop, spring-beans) This is the central artifact for Spring's Dependency Injection Container and is generally always defined --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${org.springframework.version}</version> </dependency> <!-- Transaction Management Abstraction (depends on spring-core, spring-beans, spring-aop, spring-context) Define this if you use Spring Transactions or DAO Exception Hierarchy (org.springframework.transaction.*/org.springframework.dao.*) --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>${org.springframework.version}</version> </dependency> <!-- JDBC Data Access Library (depends on spring-core, spring-beans, spring-context, spring-tx) Define this if you use Spring's JdbcTemplate API (org.springframework.jdbc.*) --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${org.springframework.version}</version> </dependency> <!-- Object-to-Relation-Mapping (ORM) integration with Hibernate, JPA, and iBatis. (depends on spring-core, spring-beans, spring-context, spring-tx) Define this if you need ORM (org.springframework.orm.*) --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>${org.springframework.version}</version> </dependency> <!-- Object-to-XML Mapping (OXM) abstraction and integration with JAXB, JiBX, Castor, XStream, and XML Beans. (depends on spring-core, spring-beans, spring-context) Define this if you need OXM (org.springframework.oxm.*) --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-oxm</artifactId> <version>${org.springframework.version}</version> </dependency> <!-- *****************************************************************--> <!-- Spring Data--> <!-- JPA --> <!-- imports import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Sort; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; => [@Transactional] --> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-jpa</artifactId> <version>1.1.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-commons-core</artifactId> <version>1.3.2.RELEASE</version> </dependency> <!-- Spring Data--> <!-- Spring --> <!-- JPA --> <!-- imports import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; import javax.persistence.TableGenerator; import javax.persistence.Version; import javax.persistence.OneToMany; import javax.persistence.ManyToOne; import javax.persistence.ManyToMany; --> <dependency> <groupId>org.eclipse.persistence</groupId> <artifactId>javax.persistence</artifactId> <version>2.0.3</version> </dependency> <dependency> <groupId>org.eclipse.persistence</groupId> <artifactId>eclipselink</artifactId> <version>2.3.2</version><!-- 2.3.2 --> </dependency> <!-- meta model --> <dependency> <groupId>org.eclipse.persistence</groupId> <artifactId>org.eclipse.persistence.jpa.modelgen.processor</artifactId> <version>2.3.2</version> <scope>provided</scope> </dependency> <!-- JPA --> <!-- apache common --> <!-- StringUtils --> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>1.3.2</version> </dependency> <dependency> <groupId>commons-dbcp</groupId> <artifactId>commons-dbcp</artifactId> <version>1.4</version> </dependency> <dependency> <groupId>commons-lang</groupId> <artifactId>commons-lang</artifactId> <version>2.4</version> </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.1.1</version> </dependency> <!-- apache common --> <!-- javax --> <!-- imports [*^=javax] import javax.faces.application.FacesMessage; import javax.faces.application.FacesMessage.Severity; import javax.faces.context.FacesContext; import javax.servlet.ServletContext; import javax.mail.MessagingException; import javax.mail.internet.MimeMessage; --> <dependency> <groupId>javax</groupId> <artifactId>javaee-web-api</artifactId> <version>6.0</version> <scope>provided</scope> </dependency> <!-- javax --> <!-- JSF API and Implementation --> <dependency> <groupId>com.sun.faces</groupId> <artifactId>jsf-api</artifactId> <version>2.1.1-b04</version> </dependency> <dependency> <groupId>com.sun.faces</groupId> <artifactId>jsf-impl</artifactId> <version>2.1.1-b04</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.1.2</version> </dependency> <dependency> <groupId>taglibs</groupId> <artifactId>standard</artifactId> <version>1.1.2</version> </dependency> <!-- JSF API and Implementation --> </dependencies> <repositories> <repository> <url>http://download.eclipse.org/rt/eclipselink/maven.repo/</url> <id>eclipselink</id> <layout>default</layout> <name>Repository for library EclipseLink (JPA 2.0)</name> </repository> <repository> <id>spring-snapshot</id> <name>Spring Maven SNAPSHOT Repository</name> <url>http://repo.springsource.org/libs-snapshot</url> </repository> <repository> <url>http://repository.primefaces.org/</url> <id>primefaces</id> <layout>default</layout> <name>Repository for library PrimeFaces 3.2</name> </repository> </repositories> ... ... ...2. Spring Config : applicationContext.xml
<?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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd"> <!-- เพื่อให้ใช้ annotation ของ spring ได้--> <context:annotation-config /> <!-- เพื่อให้ spring framework เริ่ม scan code เพื่ออ่านข้อมูลตั้งแต่ com.blogspot.na5cent.configdatabase--> <context:component-scan base-package="com.blogspot.na5cent.configdatabase" /> </beans>3.1. Spring Database Config : Resource Local
applicationContext-database-resource-local.xml
<?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:tx="http://www.springframework.org/schema/tx" xmlns:jpa="http://www.springframework.org/schema/data/jpa" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:context="http://www.springframework.org/schema/context" 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-3.1.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd"> <!-- ที่ๆ เก็บ คำสั่ง JPQL ไว้--> <jpa:repositories base-package="com.blogspot.na5cent.configdatabase.repositories"/> <!-- ใช้ transaction manager ของ org.springframework.orm.jpa.JpaTransactionManager --> <tx:annotation-driven transaction-manager="transactionManager" /> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"/> <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" /> <bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <!-- อ้างถึง persistence.xml ที่มี persistenceUnitName ชื่อ ConfigDB --> <property name="persistenceUnitName" value="ConfigDB"/> <!-- สถานที่เก็บ persistence.xml เก็บไว้ที่ class path --> <property name="persistenceXmlLocation" value="classpath:persistence.xml"/> <!-- อ้างถึง data source ว่าใช้ database ตัวไหน --> <property name="dataSource" ref="dataSource" /> <!-- ใช้ JPQL ของ EclipseLink --> <property name="jpaDialect" ref="jpaDialect"/> <property name="jpaVendorAdapter" ref="jpaVendorAdapter"/> </bean> <bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter " /> <bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.EclipseLinkJpaDialect " /> <!-- database connection pool--> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="oracle.jdbc.OracleDriver"/> <property name="url" value="jdbc:oracle:thin:@localhost:1521:orcl"/> <property name="username" value="HR"/> <property name="password" value="HR"/> </bean> </beans>3.2. Spring Database Config : JTA
<?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:tx="http://www.springframework.org/schema/tx" xmlns:jpa="http://www.springframework.org/schema/data/jpa" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:context="http://www.springframework.org/schema/context" 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-3.1.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd"> <jpa:repositories base-package="com.blogspot.na5cent.configdatabase.repositories"/> <jee:jndi-lookup id="dataSource" jndi-name="jdbc/ConfigDB" /> <tx:annotation-driven transaction-manager="transactionManager"/> <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"/> <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" /> <bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="persistenceUnitName" value="ConfigDB"/> <property name="persistenceXmlLocation" value="classpath:persistence.xml"/> <property name="jpaDialect" ref="jpaDialect"/> <property name="jpaVendorAdapter"> <bean class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter "/> </property> </bean> <bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.EclipseLinkJpaDialect " /> </beans>4.1. Entity Class Config : Resource Local
persistence.xml
<?xml version="1.0" encoding="UTF-8"?> <persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"> <persistence-unit name="ConfigDB" transaction-type="RESOURCE_LOCAL"> <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider> <non-jta-data-source/> <class>com.blogspot.na5cent.configdatabase.repositories.Student</class> <exclude-unlisted-classes>true</exclude-unlisted-classes> <properties> <!-- OFF : This setting disables the generation of the log output. You may want to set logging to OFF during production to avoid the overhead of logging. SEVERE : This level enables reporting of failure cases only. Usually, if the failure occurs, the application stops. WARNING : This level enables logging of issues that have a potential to cause problems. For example, a setting that is picked by the application and not by the user. INFO : This level enables the standard output. The contents of this output is very limited. It is the default logging level if a logging level is not set. CONFIG : This level enables logging of such configuration details as your database login information and some metadata information. You may want to use the CONFIG log level at deployment time. FINE : This level enables logging of the first level of the debugging information and SQL. You may want to use this log level during debugging and testing, but not at production. FINER : This level enables logging of more debugging information than the FINE setting. For example, the transaction information is logged at this level. You may want to use this log level during debugging and testing, but not at production. FINEST : This level enables logging of more debugging information than the FINER setting, such as a very detailed information about certain features (for example, sequencing). You may want to use this log level during debugging and testing, but not at production. ALL : This level currently logs at the same level as FINEST. --> <property name="eclipselink.logging.level" value="FINEST"/> <property name="eclipselink.logging.timestamp" value="false"/> <property name="eclipselink.logging.session" value="false"/> <property name="eclipselink.logging.thread" value="false"/> <property name="eclipselink.logging.parameters" value="true"/> <!-- By default EclipseLink uses a shared object cache, that caches a subset of all objects read and persisted for the persistence unit. The EclipseLink shared cache differs from the local EntityManager cache. The shared cache exists for the duration of the persistence unit (EntityManagerFactory, or server) and is shared by all EntityManagers and users of the persistence unit. The local EntityManager cache is not shared, and only exists for the duration of the EntityManager or transaction. The benefit of the shared cache, is that once an object has been read, if it is read again using the find operation, the database does not need to be accessed. Also if the object is read through any Query, it will not need to be rebuilt, and its relationships will not need to be re-fetched. The limitation of the shared cache, is that if the database is changed directly through JDBC, or by another application or server, the objects in the shared cache will be stale. --> <property name="eclipselink.cache.shared.default" value="false"/> <!-- Specify your application server: JBoss: JBoss Application Server OC4J: OC4J persistence provider SAPNetWeaver_7_1: SAP NetWeaver Application Server 7.1 (and higher) SunAS9: Sun Application Server 9 WebLogic: Oracle WebLogic Server WebLogic_10: Oracle WebLogic Server 10 WebLogic_9: Oracle WebLogic Server 9 WebSphere: IBM WebSphere WebSphere_6_1: IBM WebSphere 6.1 WebSphere_7: IBM WebSphere 7 Default (TargetServer.None) --> <property name="eclipselink.target-server" value="SunAS9"/> <!-- Weaving is a technique of manipulating the byte-code of compiled Java classes. The EclipseLink JPA persistence provider uses weaving to enhance both JPA entities and Plain Old Java Object (POJO) classes for such things as lazy loading, change tracking, fetch groups, and internal optimizations. Weaving can be performed either dynamically at runtime, when entities are loaded, or statically at compile time by post-processing the entity .class files. By default, EclipseLink uses dynamic weaving whenever possible. This includes inside an Java EE 5/6 application server and in Java SE when the EclipseLink agent is configured. Dynamic weaving is recommended as it is easy to configure and does not require any changes to a project's build process. --> <property name="eclipselink.weaving" value="static"/> <property name="eclipselink.ddl-generation" value="create-tables"/> </properties> </persistence-unit> </persistence>4.2. Entity Class Config : JTA
<?xml version="1.0" encoding="UTF-8"?> <persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"> <persistence-unit name="ConfigDB" transaction-type="JTA"> <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider> <jta-data-source>jdbc/ConfigDB</jta-data-source> <class>com.blogspot.na5cent.configdatabase.repositories.Student</class> <exclude-unlisted-classes>true</exclude-unlisted-classes> <properties> ... ... ... ที่เหลือเหมือนกันกับ resource local ทั้งหมด ...
5. Web application config : web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"> <context-param> <param-name>javax.faces.PROJECT_STAGE</param-name> <param-value>Development</param-value> </context-param> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/applicationContext*.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <servlet> <servlet-name>Faces Servlet</servlet-name> <servlet-class>javax.faces.webapp.FacesServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> <session-config> <session-timeout> 30 </session-timeout> </session-config> <welcome-file-list> <welcome-file>index.xhtml</welcome-file> </welcome-file-list> </web-app>6. Entity Class : Student.java
package com.blogspot.na5cent.configdatabase.repositories; import java.io.Serializable; import javax.persistence.Entity; import javax.persistence.Id; /** * * @author Redcrow */ @Entity public class Student implements Serializable { @Id private String id; private String name; public Student() { } public Student(String id) { this.id = id; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public int hashCode() { int hash = 3; hash = 79 * hash + (this.id != null ? this.id.hashCode() : 0); return hash; } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final Student other = (Student) obj; if ((this.id == null) ? (other.id != null) : !this.id.equals(other.id)) { return false; } return true; } }ในกรณีที่คุณ config เป็นแบบ JTA สิ่งที่คุณต้องทำเพิ่มคือ ต้องไป config ที่ application server เพิ่มเติมครับ ดูที่เรื่อง การ config JDBC Connection Pool (GlassFish Server)
สอบเรื่องการจัดการของ data source JNDI
ตอบลบถ้ามี User 100 คน ในส่วนการเปิดปิด Connection นี้
ตัว data source นี้จัดการเองหมดเลยหรือเปล่าครับ ?
และเมื่อเรามีการกำหนดค่า Max connection ไว้ที่ 50
และมี user เข้ามา 100 connection
มันจะมีการจัดการอย่างไรบ้างหรอครับ ?
connection ก็คือ connection
ตอบลบuser ก็คือ user ครับ มองคนละอย่างกัน
max connection = 50
หมายถึงมันจะสร้าง connection pool สลับการใช้งานกัน ไม่เกิน 50 connection
เพราะเรา set ไว้แค่นี้
ถ้าในขณะนั้นมีการใช้ connection ในปริมาณที่คาดว่าจะเกิน 50 ล่ะจะเป็นยังไง?
คำตอบคือ รอครับ
วิธีแก้คือ set max ไว้สูงๆ ก็ได้ครับ
เช่น max = 100 connections
มันไม่ได้แปลว่า มันจะสร้างทีเดียว 100 connections เลย
เพราะการ set มันจะมี max มี min
application server จะตัดสินใจ เพิ่มลด connection pool ให้เองโดยอัตโนมัติครับ