最近由于需求,JBoss需要同时访问两个数据库,一个主,一个从,主在很远的地方,从在很近的地方,主只写数据,从只读数据,也就是说从只查询, 所有数据的更改都要在主上进行。想想,这只要在JBoss中配置两个数据源,一个read,一个write,持久单元也定义两个,与数据源对应,由于我们 代码对EntityManage进行了封装,所以inject两个EntityMnage,一个的持久单元是定义是read,一个是write,在所有数 据更新的地方使用write的EntityManage,其它地方使用read就可以了。但是在配置的过程中还是遇到了不少问题,这些问题都是对 Jboss的数据源的各种配置属性不太了解的原因,所以查查Jboss的资源(Jboss的文档总是写的好简单,大多数情况下只说大概)整理如下。在 Jboss的docs/examples/jca中有各种数据库的数据源配置模版。数据源配置文件总是以*-ds.xml文件命名,部署器是jboss- jca.sar中的XSLSubDeployer。这其中的数据源都使用的是local-tx-datasource定义,平常用的时候也没注意它到底是 什么意思,只是简单的修改其中的参数。
*-ds.xml文件中的XML结构如下:
定义数据源用到的任何MBean服务,并且这些服务要在jboss-service.xml文件中定义
这是最常用的(至少我是这样),配置LocalTxConnectionManager服务,该ConnectionManager只支持“本地事 务”,确切的说,只支持一个数据源的事务,不支持分布事务,本地不是说数据源指定的数据库在本地,可以在任何地方,但local-tx- datasource不能在一个事务中访问两个数据源,即使这两个数据源配置是一样的。也就是一个事务中不能有两个Connection,如果有两个数据 源,后面打开的数据源无法打开链接,并且出现异常:
2009-07-02 12:08:30,892 WARN [com.arjuna.ats.jta.logging.loggerI18N] [com.arjuna.ats.internal.jta.transaction.arjunacore.lastResource.disallow] [com.arjuna.ats.internal.jta.transaction.arjunacore.lastResource.disallow] Adding multiple last resources is disallowed. Current resource is org.jboss.resource.connectionmanager.TxConnectionManager$LocalXAResource@7d3b91b
2009-07-02 12:08:30,902 DEBUG [org.hibernate.util.JDBCExceptionReporter] Cannot open connection [???]
org.jboss.util.NestedSQLException: Could not enlist in transaction on entering meta-aware object!; – nested throwable: (javax.transaction.SystemException: java.lang.Throwable: Unabled to enlist resource, see the previous warnings. tx=TransactionImple < ac, BasicAction: 7f000001:dcdc:4a4c3005:35 status: ActionStatus.ABORT_ONLY >); – nested throwable: (org.jboss.resource.JBossResourceException: Could not enlist in transaction on entering meta-aware object!; – nested throwable: (javax.transaction.SystemException: java.lang.Throwable: Unabled to enlist resource, see the previous warnings. tx=TransactionImple < ac, BasicAction: 7f000001:dcdc:4a4c3005:35 status: ActionStatus.ABORT_ONLY >))
at org.jboss.resource.adapter.jdbc.WrapperDataSource.getConnection(WrapperDataSource.java:94)
at org.hibernate.ejb.connection.InjectedDataSourceConnectionProvider.getConnection(InjectedDataSourceConnectionProvider.java:47)
at org.hibernate.jdbc.ConnectionManager.openConnection(ConnectionManager.java:423)
at org.hibernate.jdbc.ConnectionManager.getConnection(ConnectionManager.java:144)
LocalTxConnectionManager会确保所有的链接都是同一个ManagedConnection(所以两个数据源就是两个Connection就不行),当有一个链接请示时会检查该链接是否存在,存在则用之
该数据源配置XATxConnectionManager服务。XA事务也就是通常所说的分布式事务。在一个事务中可以有多个资源(如数据源),但 这些资源必须能够支持XA事务,支持XA事务的数据库在docs/examples/jca目录中都有一个xa-ds.xml文件,但mysql没 有,mysql是支持XA事务的(我的是mysql 5, jdbc驱动是5.1.7,可以用 xa start ‘test’,'test’; xa end ‘test’,'test’; 来测试一下是否支持)
XA是Open Group提出的分布式事务模型。JTA是sun提出的java事务API(Java Transaction API),也支持XA,或者说实现了XA,使用JTA可以与任何其它支持XA事务的应用集成。
这里有份openlink的文档:http://docs.openlinksw.com/mt/xamt.html
但在我测试的时候,我本来想如果我不再需要两个数据库操作,那我是不是只需要修改数据源配置,把读和写都指定到同一个数据库就行了,代码就不用修改了,但是xa-datasource的两个数据源配置到同样的数据库有异常:
2009-07-02 14:25:28,224 DEBUG [org.hibernate.jdbc.AbstractBatcher] about to open PreparedStatement (open PreparedStatements: 0, globally: 1)
2009-07-02 14:25:28,224 DEBUG [org.hibernate.jdbc.ConnectionManager] opening JDBC connection
2009-07-02 14:25:28,224 DEBUG [org.jboss.resource.connectionmanager.IdleRemover] internalRegisterPool: registering pool with interval 900000 old interval: 450000
2009-07-02 14:25:28,304 WARN [com.arjuna.ats.jta.logging.loggerI18N] [com.arjuna.ats.internal.jta.transaction.arjunacore.xastart] [com.arjuna.ats.internal.jta.transaction.arjunacore.xastart] TransactionImple.enlistResource – xa_start – caught: XAException.XAER_INVAL for < 131075, 27, 25, 1-7f000001:8ab7:4a4c49ba:6e7f000001:8ab7:4a4c49ba:73
2009-07-02 14:25:28,305 ERROR [STDERR] com.mysql.jdbc.jdbc2.optional.MysqlXAException: XAER_INVAL: Invalid arguments (or unsupported command)
2009-07-02 14:25:28,307 ERROR [STDERR] at com.mysql.jdbc.jdbc2.optional.MysqlXAConnection.mapXAExceptionFromSQLException(MysqlXAConnection.java:602)
2009-07-02 14:25:28,307 ERROR [STDERR] at com.mysql.jdbc.jdbc2.optional.MysqlXAConnection.dispatchCommand(MysqlXAConnection.java:585)
2009-07-02 14:25:28,307 ERROR [STDERR] at com.mysql.jdbc.jdbc2.optional.MysqlXAConnection.start(MysqlXAConnection.java:525)
.
.
.
.
org.jboss.util.NestedSQLException: Could not enlist in transaction on entering meta-aware object!; – nested throwable: (javax.transaction.SystemException: java.lang.Throwable: Unabled to enlist resource, see the previous warnings. tx=TransactionImple < ac, BasicAction: 7f000001:8ab7:4a4c49ba:80 status: ActionStatus.ABORT_ONLY >); – nested throwable: (org.jboss.resource.JBossResourceException: Could not enlist in transaction on entering meta-aware object!; – nested throwable: (javax.transaction.SystemException: java.lang.Throwable: Unabled to enlist resource, see the previous warnings. tx=TransactionImple < ac, BasicAction: 7f000001:8ab7:4a4c49ba:80 status: ActionStatus.ABORT_ONLY >))
看mysql日志:
17 Query SHOW COLLATION
17 Query SET NAMES latin1
17 Query SET character_set_results = NULL
17 Query SET autocommit=1
17 Query SET sql_mode='STRICT_TRANS_TABLES'
17 Query SELECT @@session.tx_isolation
17 Query XA START 0x312d37663030303030313a386162373a34613463343962613a6134
,0x37663030303030313a386162373a34613463343962613a6139,0x20003
.
.
.
18 Connect root@localhost ON test
18 Query /* mysql-connector-java-5.1.7 ( Revision: ${svn.Revision} ) */
SELECT @@session.auto_increment_increment
18 Query SHOW COLLATION
18 Query SET NAMES latin1
18 Query SET character_set_results = NULL
18 Query SET autocommit=1
18 Query SET sql_mode='STRICT_TRANS_TABLES'
18 Query SELECT @@session.tx_isolation
18 Query XA START 0x312d37663030303030313a386162373a34613463343962613a6134,
0x37663030303030313a386162373a34613463343962613a6139,0x20003 JOIN
17 Query XA END 0x312d37663030303030313a386162373a34613463343962613a6134,
0x37663030303030313a386162373a34613463343962613a6139,0x20003
17 Query XA ROLLBACK 0x312d37663030303030313a386162373a34613463343962613a6134,
0x37663030303030313a386162373a34613463343962613a6139,0x20003
或许跟两次
XA START 0×312d37663030303030313a386162373a34613463343962613a6134,
0×37663030303030313a386162373a34613463343962613a6139,0×20003
有关:mysql有一个bug讨论的就是这个问题:Bug #17343 XAConnection doesn’t allow second XA START.
或许这是个mysql的bug,所以如果又要要求取消两个数据库的话,只有修改一个persistence.xml,把两个persistence-unit的jta-data-source定义成同一个jndi了
该数据源的链接管理噐是NoTxConnectionManager,不支持事务
同local-tx-datasource,区别是提供了一些容错能力允许Jboss从数据库错误中恢复。不是很理解
同ha-tx-datasource,区别是提供了一些容错能力允许Jboss从数据库错误中恢复。不是很理解
多个数据源可以配置在同一个*-ds.xml文件中,也可以配置在不同的*-ds.xml文件中
jboss 4.2.2GA中没有给出mysql的xa数据源定义,这里给个例子:
version="1.0" encoding="UTF-8"?>> >
> MySqlXADS>
>
com.mysql.jdbc.jdbc2.optional.MysqlXADataSource>
name="Url"> jdbc:mysql://127.0.0.1:3306/temp>
> user name>
> password>
> org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter>
>
> mySQL>
>
>
各配置元素说明参考文档:http://www.jboss.org/file-access/default/members/jbossas/freezone/docs/Server_Configuration_Guide/4/html/Connectors_on_JBoss-Configuring_JDBC_DataSources.html#Configuring_JDBC_DataSources-The_non_transactional_DataSource_configuration_schema