JBoss下的JTA使用理解


先給出通過JBoss容器獲取JTA事務的方法

private UserTransaction getUserTransaction() throws ServletException {
UserTransaction ut;
try {
InitialContext ic = new InitialContext();
//comp java:/UserTransaction
ut = (UserTransaction) ic.lookup("java:comp/UserTransaction");
} catch(Exception e) {
throw new ServletException(e);
}
return ut;
}

經測試使用串“java:comp/UserTransaction”從JNDI獲取JTA事務。啟動后發現拋類型轉換異常

org.jboss.tm.usertx.client.ServerVMClientUserTransaction cannot be cast to javax.transaction.UserTransaction

應用中多余引入了jta.jar導致。該jar已由JBoss提供,應用中刪除即可.

另外有一點注意,如果是通過spring來獲取事務管理器,上述異常出現時,只記錄debug級別日志,不拋出異常,這點很變態,不知道寫spring那群人怎么想的,spring取得TM代碼如下:

protected UserTransaction findUserTransaction() {
        String jndiName = DEFAULT_USER_TRANSACTION_NAME;
        try {
            UserTransaction ut = getJndiTemplate().lookup(jndiName, UserTransaction.class);
            if (logger.isDebugEnabled()) {
                logger.debug("JTA UserTransaction found at default JNDI location [" + jndiName + "]");
            }
            this.userTransactionObtainedFromJndi = true;
            return ut;
        }
        catch (NamingException ex) {
            if (logger.isDebugEnabled()) {
                logger.debug("No JTA UserTransaction found at default JNDI location [" + jndiName + "]", ex);
            }
            return null;
        }
    }

 


JTA屬於分布式事務,如何結合JDBC事務呢,即在JTA事務內,對數據庫的操作也具有事務特性。

通常在JBoss容器中使用數據庫時,一般會在jboss-4.0.5.GA\server\default\deploy目錄下面配置數據源,本地事務配置如下:

<datasources>
<local-tx-datasource>
<jndi-name>java:mysqlDS</jndi-name>
<connection-url>jdbc:mysql://192.168.0.10:1521/test</connection-url>
<driver-class>com.mysql.Driver</driver-class>
<user-name>root</user-name>
<password>root</password>

<min-pool-size>5</min-pool-size>
<max-pool-size>100</max-pool-size>
</local-tx-datasource>
</datasources>

在JBoss應用中通過JNDI獲取該數據源時,JTA中對數據庫的操作是不能回滾的,需要配置成分布式事務的形式,即:

<?xml version="1.0" encoding="UTF-8"?>
<datasources>
<xa-datasource>
<jndi-name>mySQLDataSource</jndi-name>
<track-connection-by-tx>true</track-connection-by-tx>
<xa-datasource-class>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</xa-datasource-class>
<new-connection-sql>set autocommit=1</new-connection-sql>
<no-tx-separate-pools>true</no-tx-separate-pools>
<xa-datasource-property name="Url">jdbc:mysql://127.0.0.1:3306/mytest?autoReconnect=true</xa-datasource-property>
<xa-datasource-property name="User">root</xa-datasource-property>
<xa-datasource-property name="Password">root</xa-datasource-property>

<transaction-isolation>TRANSACTION_READ_COMMITTED</transaction-isolation>

<exception-sorter-class-name>
org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter
</exception-sorter-class-name>
<type-mapping>mySQL</type-mapping>

<!--pooling parameters-->
<min-pool-size>5</min-pool-size>
<max-pool-size>100</max-pool-size>
<blocking-timeout-millis>5000</blocking-timeout-millis>
<idle-timeout-minutes>15</idle-timeout-minutes>
</xa-datasource>
</datasources>

轉自:http://www.jdon.com/jivejdon/thread/30264 的一段說明。

View Code
通過對Mysql日志進行分析,發現在一次用戶刪除操作中並不是單純的使用單個數據庫連接來完成。通過進一步的跟蹤發現,在I2SS中每一次調用數據庫操作的方法總會試圖獲取一個新的connection。而且還有一個嚴重的問題就是我們的程序中利用UserTransaction 對事務進行控制(注 此API 僅用於控制JTA事務),而我們的數據源配置確是<local-tx-datasource>。如果利用JTA控制事務,而數據源是本地事務數據源的,兩者搭配的情況是事務不會起作用,這就意味着從 JDBC 連接池接收連接時,會從該池將 AutoCommit 設置為 true。這就預示我們的JTA事務控制根本就不起作用。這也就解釋了為什么用戶刪除事務操作失敗的原因。
為了支持I2SS框架,目前的解決方式就是替換支持分布式事務的驅動,修改數據源配置將其替換成<xa-datasource>。配置文件如下:
<datasources>
<xa-datasource>
<jndi-name>DataSource</jndi-name>
<track-connection-by-tx>true</track-connection-by-tx>
<xa-datasource-class>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</xa-datasource-class>
<new-connection-sql>set autocommit=1</new-connection-sql>
<no-tx-separate-pools>true</no-tx-separate-pools>
<xa-datasource-property name="Url">jdbc:mysql://127.0.0.1:3306/sms1?autoReconnect=true</xa-datasource-property>
<xa-datasource-property name="User">smsdb</xa-datasource-property>
<xa-datasource-property name="Password">smsdb</xa-datasource-property>

<transaction-isolation>TRANSACTION_READ_COMMITTED</transaction-isolation>

<exception-sorter-class-name>
org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter
</exception-sorter-class-name>
<type-mapping>mySQL</type-mapping>

<!--pooling parameters-->
<min-pool-size>5</min-pool-size>
<max-pool-size>100</max-pool-size>
<blocking-timeout-millis>5000</blocking-timeout-millis>
<idle-timeout-minutes>15</idle-timeout-minutes>
</xa-datasource>
</datasources>
在上述配置文件中用戶色標記出的元素需要特別注意,而且這四個配置元素必須同時使用。下面將進行詳細解釋:
1、<no-tx-separate-pools>
這個元素的設定使得兩個連接池能夠分開:一個支持JTA事務的連接,另一個不支持JTA事務的連接。連接池在第一次使用時創建。
2、<track-connection-by-tx>
當這個值設置為true時,連接管理器會保持一個XID-to-connection影射表,當事務結束時而且所有的連接關閉或者未被引用時連接將放回連接池。這樣做的副作用是不會掛起或者恢復連接的XAResource里的XID,這個行為和本地事務是一樣的。
3、<xa-datasource-class>
指定javax.sql.XASDataSource實現類的全名
4、<new-connection-sql>
當新的連接創建時執行此語句。
在我們的配置文件中,我們進行了如下配置:
<new-connection-sql> set autocommit=1</new-connection-sql>
這樣做的原因是因為我們通過MySQLXADataSource中獲取的連接默認被設置成autocommit 為false,如果我們的連接並入到事務中時(即事務啟動之后獲取的連接),會統一由UserTransaction 進行提交。對於那些沒有並入事務中的單連接,就會出現操作一直不能提交的錯誤,可能出現XAER_OUTSIDE 異常。通過上述的設置,我們可以將單連接操作放入一個隔離的連接池中,並將其設置為自動提交。
【避免此類問題的建議】
產生這個問題的原因可以歸結為I2SS框架中事務處理不當,connection 封裝不合理。為了適應框架改用分布式事務,理論上講會造成非常大的性能開銷。

注意需要在JBoss中引入支持XA的數據庫驅動包

獲取數據源和數據庫連接的方式為:

//獲取數據源:
InitialContext ic = new InitialContext();
ds = (DataSource) ic.lookup("java:mySQLDataSource");

//獲取連接
Connection conn = ds.getConnection();

一個事務操作實例如下:

try {
ut.begin();
Admin a = new Admin();
a.setId(2);
adminDAO.delAdmin(a);
System.out.println("before add:" + cache.get("KEY-10"));
int index = serviceWithinTx(servletResponse, cache);
System.out.println("after add:" + cache.get("KEY-10"));
printLine(servletResponse, "Bye #" + (index + 1));
ut.commit();

} catch (Exception e) {
printLine(servletResponse, "Caught a " + e.getClass() + "! Rolling Tx back");
if (!printStackTrace) {
PrintWriter s = servletResponse.getWriter();
e.printStackTrace(s);
s.flush();
}
rollbackTransaction(ut);
}

OK!在JBoss容器環境中,利用JTA分布式事務特性將應用中事務(如:Ehcache中支持獲取JBoss JTA事務管理器)與數據庫事務(即JDBC事務,包括多JBDC事務)組合起來的實現成功了,但是在非JBoss容器環境下該如何處理呢?下一篇再解決。





免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM