TẠO TRANSACTION VỚI CONTAINER-MANAGED TRANSACTION
TẠO TRANSACTION VỚI CONTAINER-MANAGED TRANSACTION
Author: Võ Văn Hải
CNC-Aptech, Tp HCM
Website: http://vovanhai.wordpress.com
Email: vovanhaiqn@google.com
- Giới thiệu
Trong EJB với container-managed transactions (CMT), EJB Container sẽ quản lý mọi giao dịch bên dưới với database. Đây là cách phát triển ứng dụng EJB transaction đơn giản và dễ dàng nhất bởi vì người phát triển không phải viết code để begins, commits, và roll-back giao dịch. Container-managed transactions không đòi hỏi tất cả các phương thức pahi3 có sự giao dịch. Khi triển khai 1 bean, chúng ta sẽ chỉ định phương thức nào trong bean sẽ thực thi vói giao dịch bằng cách thiết lập các thuộc tính trong EJB’s deployment descriptor.
- Một ví dụ sử dụng CMT
Sau đây là 1 ví dụ EJB với CMT để sinh viên đăng ký các môn học.
- Tạo Remote Interface
|
package cmt;
import java.rmi.RemoteException; import java.util.Collection; import javax.ejb.EJBObject;
public interface EnrollmentCart extends EJBObject { public void addEnrollment(EnrollmentInfo enroll) throws RemoteException; public void deleteEnrollment(int itemId) throws RemoteException; public Collection getEnrollments() throws RemoteException; public void emptyCart() throws RemoteException; public void register() throws InsufficientRoomException, RemoteException; }
|
- Tạo Home Interface
|
package cmt;
import java.rmi.RemoteException; import javax.ejb.CreateException; import javax.ejb.EJBHome;
public interface EnrollmentCartHome extends EJBHome { EnrollmentCart create() throws CreateException, RemoteException; } |
- Tạo Bean’s Class
|
package cmt;
import java.rmi.RemoteException; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Collection; import java.util.HashSet; import java.util.Iterator;
import javax.ejb.CreateException; import javax.ejb.EJBException; import javax.ejb.SessionBean; import javax.ejb.SessionContext; import javax.ejb.SessionSynchronization; import javax.naming.InitialContext;
public class EnrollmentCartEJB implements SessionBean, SessionSynchronization { private SessionContext ejbCtx; private HashSet cart; private boolean isFailed = false;
public EnrollmentCartEJB(){} // SessionSynchronization methods public void afterBegin() {} public void beforeCompletion() { if (isFailed) ejbCtx.setRollbackOnly(); } public void afterCompletion(boolean committed) { if (committed == false) throw new EJBException(“Transaction afterCompletion failed”); System.out.println(“afterCompletion: Transaction succeeds…”); } // Business methods public void addEnrollment(EnrollmentInfo enroll) throws RemoteException { cart.add(enroll); } public void register() throws InsufficientRoomException, RemoteException { java.sql.Statement stmt = null; java.sql.Statement stmt2 = null; java.sql.Connection conn = null; System.out.println(“register: started..”); try{ InitialContext initCtx = new InitialContext(); javax.sql.DataSource ds = (javax.sql.DataSource)initCtx.lookup (“java:comp/env/jdbc/studentsDB”); conn = ds.getConnection(); stmt = conn.createStatement(); stmt2 = conn.createStatement(); } catch (Exception e){ e.printStackTrace(); } try{ Iterator it = cart.iterator(); while (it.hasNext()){ EnrollmentInfo enroll=(EnrollmentInfo)it.next(); ResultSet rs = stmt.executeQuery (“SELECT * FROM COURSES WHERE COURSE_ID=’” + enroll.getCourseId()+“‘”); while (rs.next()){ int mlimit = rs.getInt(“MAX_LIMIT”); int curr = rs.getInt(“CURR_ENROLL”); if (mlimit < curr + 1){ isFailed = true; ejbCtx.setRollbackOnly(); throw new InsufficientRoomException(); }else{ curr++; stmt2.executeUpdate(“UPDATE COURSES SET CURR_ENROLL =” + curr + ” WHERE COURSE_ID=’” + enroll.getCourseId()+“‘”); System.out.println(“register: Database updated for: “+ enroll.getCourseId()); } } } System.out.println(“register: success..”); }catch (SQLException ex){ // This is a system level exception throw new EJBException (“Transaction rollback due to SQLException: “+ ex.getMessage()); } } public Collection getEnrollments() throws RemoteException { return cart; }
public void emptyCart() throws RemoteException { cart.clear(); } public void deleteEnrollment(int itemId) throws RemoteException { for(Iterator i = getEnrollments().iterator(); i.hasNext(); ) { EnrollmentInfo tmpEnrol = (EnrollmentInfo) i.next(); if (tmpEnrol.getItemId() == itemId) { getEnrollments().remove(tmpEnrol); break; } } } // EJB methods public void setSessionContext(SessionContext ctx){ this.ejbCtx = ctx; } public void ejbCreate() throws CreateException{ cart = new HashSet(); } public void ejbRemove() {} public void ejbActivate(){} public void ejbPassivate(){} } |
- Tạo Helper Classes
|
package cmt;
public class EnrollmentInfo implements java.io.Serializable { public int itemId = 0; public int studentId = 0; public String courseId = null; public EnrollmentInfo (int itemId, int studentId, String courseId) { this.itemId = itemId; this.studentId = studentId; this.courseId = courseId; } public int getItemId(){ return itemId; } public int getStudentId(){ return studentId; } public String getCourseId(){ return courseId; } }
|
|
|
|
package cmt;
public class InsufficientRoomException extends Exception { public InsufficientRoomException() { super(); } public InsufficientRoomException(Exception e) { super(e.toString()); } public InsufficientRoomException(String s) { super(s); } }
|
- Đóng gói thành file jar
- Tạo file ejb-jar.xml
|
<?xml version=“1.0″?> <!DOCTYPE ejb-jar PUBLIC ‘-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN’ ‘http://java.sun.com/dtd/ejb-jar_2_0.dtd’> <ejb-jar> <enterprise-beans> <session> <ejb-name>EnrollmentCart</ejb-name> <home>cmt.EnrollmentCartHome</home> <remote>cmt.EnrollmentCart</remote> <ejb-class>cmt.EnrollmentCartEJB</ejb-class> <session-type>Stateful</session-type> <transaction-type>Container</transaction-type>
<resource-env-ref> <resource-env-ref-name>jdbc/studentsDB</resource-env-ref-name> <resource-env-ref-type>javax.sql.DataSource</resource-env-ref-type> </resource-env-ref> </session> </enterprise-beans> <assembly-descriptor> <container-transaction> <description>All methods must be make transaction</description> <method> <ejb-name>EnrollmentCart</ejb-name> <method-name>*</method-name> </method> <trans-attribute>Required</trans-attribute> </container-transaction> </assembly-descriptor> </ejb-jar> |
-
- Tạo file jboss.xml
|
<?xml version=“1.0″ encoding=“UTF-8″?>
<jboss> <enterprise-beans> <session> <ejb-name>EnrollmentCart</ejb-name> <jndi-name>cmt/EnrollmentCartCMT</jndi-name> <resource-env-ref> <resource-env-ref-name>jdbc/studentsDB</resource-env-ref-name> <jndi-name>java:/Students_DSN</jndi-name> </resource-env-ref> </session> </enterprise-beans>
<container-configurations> <container-configuration> <container-name>Standard Stateful SessionBean</container-name> <container-cache-conf> <cache-policy> org.jboss.ejb.plugins.LRUStatefulContextCachePolicy </cache-policy> <cache-policy-conf> <max-capacity>10</max-capacity> </cache-policy-conf> </container-cache-conf> </container-configuration> </container-configurations> </jboss> |
-
- Tạo file build.bat
|
javac -d . *.java pause |
Chạy file này để biên dịch. Đảm bảo mọi thứ phải OK.
-
- Tạo file makejar.bat
|
jar cvf EJB_CMT.jar cmt/*.class META-INF/*.xml pause |
Tạo file này để tạo file jar, nếu OK ta được file EJB_CMT.jar
- Triển khai
- Tạo database:
CREATE TABLE COURSES
(
COURSE_ID VARCHAR(10) NOT NULL,
COURSE_NAME VARCHAR(64),
FEE NUMERIC(18),
MAX_LIMIT INT,
CURR_ENROLL INT
);
CREATE TABLE STUDENTS
(
STUDENT_ID VARCHAR(12) NOT NULL,
FIRST_NAME VARCHAR(15) ,
LAST_NAME VARCHAR(15) ,
ADDRESS VARCHAR(164),
EMAIL_ADDRESS VARCHAR(64)
);
CREATE TABLE ENROLLMENTS
(
ENROLLMENT_ID VARCHAR(64),
STUDENT_ID VARCHAR(64),
COURSE_ID VARCHAR(64)
) ;
-
- Tạo 1 ODBC Data source với tên là students
-
- Tạo file (hoặc sửa file) mssql-ds.xml trong thư mục %JBOSS_HOME%\server\default\deploy\
|
<?xml version=“1.0″ encoding=“UTF-8″?> <!– Các Datasource khac neu co nam o day –>
<datasources> <local-tx-datasource> <jndi-name>Students_DSN</jndi-name> <connection-url>jdbc:odbc:students</connection-url> <driver-class>sun.jdbc.odbc.JdbcOdbcDriver</driver-class> <user-name>sa</user-name> <password></password>
<metadata> <type-mapping>MS SQLSERVER2000</type-mapping> </metadata> </local-tx-datasource>
</datasources> |
-
- Triển khai EJB_CMT.jar bằng cách copy file EJB_CMT.jar vào thư mục %JBOSS_HOME%\server\default\deploy\
Kết quả:
|
… 13:30:14,644 INFO [ProxyFactory] Bound EJB Home ‘EnrollmentCart’ to jndi ‘cmt/EnrollmentCartCMT’ 13:30:14,660 INFO [EJBDeployer] Deployed: file:/C:/javaSoft/jboss-4.2.2.GA/server/default/deploy/EJB_CMT.jar
|
- Thiết kế client
- Tạo thư mục client, copy thư mục cmt vào đó, sau đó xóa bỏ file EnrollmentCartEJB.class
- Tạo file Client.java có nội dung sau
|
import java.util.Collection; import java.util.Iterator; import javax.naming.Context; import javax.naming.InitialContext; import cmt.EnrollmentCart; import cmt.EnrollmentCartHome; import cmt.EnrollmentInfo; public class Client { public static void main(String[] argv){ System.out.print(“Demonstration the use of CMT\n”); try{ //thiet lap bien moi truong System.setProperty(“java.naming.factory.initial”, “org.jnp.interfaces.NamingContextFactory”); System.setProperty( “java.naming.provider.url”, “localhost:1099″ ); System.setProperty( “java.naming.factory.url.pkgs”, “org.jboss.naming” );
Context initialContext = new InitialContext(); Object object = initialContext.lookup(“cmt/EnrollmentCartCMT”); EnrollmentCartHome enrollmentCartHome = (EnrollmentCartHome) javax.rmi.PortableRemoteObject.narrow(object, EnrollmentCartHome.class); EnrollmentCart enrollmentCart = (EnrollmentCart) enrollmentCartHome.create(); // Add enrollment courses enrollmentCart.addEnrollment(new EnrollmentInfo(1, 15, “CS201″)); enrollmentCart.addEnrollment(new EnrollmentInfo(2, 15, “CS205″)); enrollmentCart.addEnrollment(new EnrollmentInfo(3, 15, “CS231″)); // register the courses enrollmentCart.register(); print(“Following courses are registered successfully:”); Collection coll = enrollmentCart.getEnrollments(); for (Iterator i = coll.iterator(); i.hasNext();){ EnrollmentInfo enroll = (EnrollmentInfo) i.next(); print(“Course id: “ + enroll.getCourseId()); } enrollmentCart.remove(); } catch ( Exception e){ print(“Enrolled courses failed to register.\n”); e.printStackTrace(); } } static void print(String s){ System.out.println(s); } } |
-
- Tạo file build.bat
|
javac -d . *.java pause |
-
- Tạo file run.bat
|
java Client pause |
- Thử nghiệm
- Chạy file run.bat. Kết quả sẽ cho như sau
|
Demonstration the use of CMT Following courses are registered successfully: Course id: CS201 Course id: CS205 Course id: CS231
|
CHÚC THÀNH CÔNG!