最近在开发一个企业的ERP系统,用到多个数据库,某一业务需要同时操作多个数据库,我们使用了JBoss作为Web服务器,数据源采用jdni方式,采用spring4注入方式进行多数据源和事务的配置,采用Hibernate4的SessionFactory进入数据操作, 下面介绍整个过程的配置:
1.Jboss JDBC数据源的配置
系统采用sqlserver2008作为数据库,sqlserver jdbc的配置
建立如下的目录结构:
jboss\modules\com\microsoft\sqlserver\jdbc\SQLServerDriver\main
把jdbc驱动程序sqljdbc4.jar copy到此目录,建立文件module.xml,内容如下:
<module xmlns="urn:jboss:module:1.1" name="com.microsoft.sqlserver.jdbc.SQLServerDriver"> <resources> <resource-root path="sqljdbc4.jar"/> </resources> <dependencies> <module name="javax.api"/> <module name="javax.transaction.api"/> <module name="javax.servlet.api" optional="true"/> </dependencies> </module>2. JBoss jdni数据源设置
打开配置文件jboss\standalone\configuration\standalone.xml,在datasources节点下添加两个datasource, frame和stk 对应两个数据库
和一个drivers
<datasource jndi-name="java:jboss/datasources/framework" pool-name="framework" enabled="true" use-java-context="true"> <connection-url>jdbc:sqlserver://localhost:1433;databaseName=erp_java</connection-url> <driver>mssqlxa</driver> <pool> <min-pool-size>2</min-pool-size> <max-pool-size>10</max-pool-size> </pool> <security> <user-name>sa</user-name> <password>ft4023581</password> </security> </datasource> <datasource jndi-name="java:jboss/datasources/stk" pool-name="stk" enabled="true" use-java-context="true"> <connection-url>jdbc:sqlserver://localhost:1433;databaseName=stk_net</connection-url> <driver>mssqlxa</driver> <pool> <min-pool-size>2</min-pool-size> <max-pool-size>10</max-pool-size> </pool> <security> <user-name>sa</user-name> <password>ft4023581</password> </security> </datasource> <drivers> <driver name="h2" module="com.h2database.h2"> <xa-datasource-class>org.h2.jdbcx.JdbcDataSource</xa-datasource-class> </driver> <driver name="mssqlxa" module="com.microsoft.sqlserver.jdbc.SQLServerDriver"> <xa-datasource-class>com.microsoft.sqlserver.jdbc.SQLServerXADataSource</xa-datasource-class> </driver> </drivers>
注意:为了能同时对两个数据库进行操作(包括增删改),需要在配置文件增加如下内容,
<system-properties> <property name="com.arjuna.ats.arjuna.allowMultipleLastResources" value="true"/> </system-properties>这个内容必须放在配置文件的节点:</extensions>和<management>之间,否则会报错。
如果没有上面allowMultipleLastResources的设置,在进行多数据库更新时会出下如下错误。
javax.resource.ResourceException: IJ000461: Could not enlist in transaction on entering meta-aware object
导致不能open connection.
3.Spring配置文件
<?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:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:jee="http://www.springframework.org/schema/jee" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.2.xsd" > <context:component-scan base-package="com.framework.dao"/> <context:component-scan base-package="com.framework.dao.mssql"/> <context:component-scan base-package="com.framework.service"/> <context:component-scan base-package="com.framework.action"/> <context:component-scan base-package="com.stk.dao.mssql"/> <context:component-scan base-package="com.stk.service"/> <context:component-scan base-package="com.stk.action"/> <jee:jndi-lookup jndi-name="java:jboss/datasources/framework" id="datasourceFW" lookup-on-startup="true"></jee:jndi-lookup> <bean id="sessionFactoryFW" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> <property name="dataSource" ref="datasourceFW"/> <property name="packagesToScan" value="com.framework.domain"/> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">com.util.SQLServerDialect</prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.transaction.factory_class">org.hibernate.engine.transaction.internal.jta.JtaTransactionFactory</prop> <prop key="hibernate.current_session_context_class">jta</prop> </props> </property> </bean> <bean id="hibernateTemplateFW" class="org.springframework.orm.hibernate4.HibernateTemplate" p:sessionFactory-ref="sessionFactoryFW" /> <jee:jndi-lookup jndi-name="java:jboss/datasources/stk" id="datasourceStk" lookup-on-startup="true"></jee:jndi-lookup> <bean id="sessionFactoryStk" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> <property name="dataSource" ref="datasourceStk"/> <!-- --> <property name="packagesToScan" value="com.stk.domain"/> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">com.util.SQLServerDialect</prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.current_session_context_class">jta</prop> <prop key="hibernate.transaction.factory_class">org.hibernate.engine.transaction.internal.jta.JtaTransactionFactory</prop> </props> </property> </bean> <bean id="hibernateTemplateStk" class="org.springframework.orm.hibernate4.HibernateTemplate" p:sessionFactory-ref="sessionFactoryStk" /> <!-- spring 事务管理器 --> <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"> <property name="userTransactionName" value="java:jboss/UserTransaction"/> <property name="transactionManagerName" value="java:jboss/TransactionManager"/> </bean> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="select*" read-only="true" propagation="REQUIRED"/> <tx:method name="get*" read-only="true" propagation="REQUIRED"/> <tx:method name="load*" read-only="true" propagation="REQUIRED"/> <tx:method name="find*" read-only="true" propagation="REQUIRED"/> <tx:method name="query*" read-only="true" propagation="REQUIRED"/> <tx:method name="read*" read-only="true" propagation="REQUIRED"/> <tx:method name="sync*"/> <tx:method name="*" propagation="REQUIRED" rollback-for="Exception"/> </tx:attributes> </tx:advice> <aop:config> <aop:pointcut id="pointcut" expression="execution(* com.*.service.*.*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"/> </aop:config> </beans>