请教一个关于多数据源的分布式事务问题?

现实中有两个数据库位于不同的数据库服务主机上,因为有些业务操作涉及到对这两个数据库的数据插入等,而且它们应该包含在一个事务中

完成。我现在做了一个例子模拟跨数据源的分布式事务管理,但最后不能对数据库中的表进行写操作,查询就可以。我下面详细描述一下我这

个例子程序 ,看看我的做法有什么问题嘛?

1、后台数据库 SQL Server 2000 + sp3,我创建了2个数据库来模拟两个数据源,每个数据库上一张表,需要对这两张表完成分别执行一个插入操

作,并放在一个事务中,即要么两张表都插入了新的数据,要么都别插入。

2、持久层用Hibernate映射(下面是详细映射配置文件)

-------数据源 1 的hibernate.cfg.xml----------------
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE hibernate-configuration
PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-2.0.dtd">

<hibernate-configuration>
<session-factory >

<property name="connection.datasource">TestDB</property>
<property name="transaction.factory_class">net.sf.hibernate.transaction.JTATransactionFactory</property>
<property name="transaction.manager_lookup_class">net.sf.hibernate.transaction.WeblogicTransactionManagerLookup</property>
<property name="dialect">net.sf.hibernate.dialect.SQLServerDialect</property>
<property name="hibernate.connection.provider_class">net.sf.hibernate.connection.DatasourceConnectionProvider</property>
<property name="hibernate.jndi.class">weblogic.jndi.WLInitialContextFactory</property>
<property name="hibernate.jdbc.fetch_size">100</property>
<property name="hibernate.jdbc.batch_size">50</property>
<property name="show_sql">true</property>

<mapping resource="test/Addressbook.hbm.xml" />

</session-factory>
</hibernate-configuration>

-------数据源 1 的hibernate.cfg.xml----------------

-------数据源 2 的hibernate.cfg.xml----------------
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE hibernate-configuration
PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-2.0.dtd">

<hibernate-configuration>
<session-factory >
<property name="connection.datasource">txyyDB</property>
<property name="transaction.factory_class">net.sf.hibernate.transaction.JTATransactionFactory</property>
<property name="transaction.manager_lookup_class">net.sf.hibernate.transaction.WeblogicTransactionManagerLookup</property>
<property name="dialect">net.sf.hibernate.dialect.SQLServerDialect</property>
<property name="hibernate.connection.provider_class">net.sf.hibernate.connection.DatasourceConnectionProvider</property>
<property name="hibernate.jndi.class">weblogic.jndi.WLInitialContextFactory</property>
<property name="hibernate.jdbc.fetch_size">100</property>
<property name="hibernate.jdbc.batch_size">50</property>
<property name="show_sql">true</property>

<mapping resource="test/Txyy.hbm.xml" />

</session-factory>
</hibernate-configuration>

-------数据源 2 的hibernate.cfg.xml----------------


3、应用服务器采用Weblogic 8.1

在服务器中分别配置了2个连接池,分别对应两个数据源,数据库驱动采用了XA的SQL驱动。

4、一个例子程序,如下:

-----------例子程序源代码-----------------------
package test;

import net.sf.hibernate.*;
import net.sf.hibernate.cfg.Configuration;
import java.io.*;
import java.util.*;
import util.NamingContext;
import javax.transaction.*;
import javax.naming.*;

public class MyTest {

public static SessionFactory sf1

public static SessionFactory sf2;

static{
try{
Configuration config1 = new Configuration().configure("/hfcfg/hibernate.cfg.xml"); // 创建数据源1的Config对象
Configuration config2 = new Configuration().configure("/cfg/hibernate.cfg.xml"); // 创建数据源2的Config对象

// 根据配置创建对应2个数据源的SessionFactory对象
sf1= config.buildSessionFactory();
sf2 = config1.buildSessionFactory();

}catch(Exception e){e.printStackTrace();}
}

MyTest(){}

// 主要的业务测试方法,分别对两个数据源中的两张表执行插入操作,并置于同一事务下
public List test() throws Exception{

Context ctx = util.NamingContext.getInitialContext();
UserTransaction tx =(UserTransaction) ctx.lookup("javax.transaction.UserTransaction");

if(tx != null) {
System.out.println("获取UserTransaction实例 = " + tx.toString() + "--" + tx.getClass());
}

// 事务开始
tx.begin();
Session s1 = sf1.openSession();
Session s2 = sf2.openSession();

List addressList = null;
try{

addressList = session.find("from Addressbook as c order by c.name asc");

addressbook ar = new Addressbook();
ar.setAddress("中山大学");
ar.setName("hf");
ar.setPhone("111");
s1.save(ar);

Txyy ty = new Txyy();
ty.setYyms("test");
s2.save(ty);

for (Iterator it = addressList .iterator(); it.hasNext(); ) {
System.out.println(((Addressbook) it.next()).getName());
}

tx.commit(); // 事务提交

}catch (Exception e) {
if (tx != null) {
System.out.println("||||------事务回滚了--------||||");
tx.rollback();
}
throw e;
}finally {
s1.close();
s2.close();
}
return addressList;
}
}


我最后写了一个测试JSP,仅仅就是调用这个MyTest类的Test方法,但服务器控制台打出的信息,没有任何异常,查询结果打印出来了,但插入

操作没有执行,数据库中表的内容未发生任何改变,一直很疑惑,不知问题出在哪里?

hibernate配置文件前面一些内容没显示出来,重新贴一下。


-------数据源 1 的hibernate.cfg.xml----------------
<?xml version="1.0" encoding="utf-8" ?>
!DOCTYPE hibernate-configuration
PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-2.0.dtd">

<hibernate-configuration>
<session-factory >
<property name=
"connection.datasource">TestDB</property>
<property name=
"transaction.factory_class">net.sf.hibernate.transaction.JTATransactionFactory</property>
<property name=
"transaction.manager_lookup_class">net.sf.hibernate.transaction.WeblogicTransactionManagerLookup</property>
<property name=
"dialect">net.sf.hibernate.dialect.SQLServerDialect</property>
<property name=
"hibernate.connection.provider_class">net.sf.hibernate.connection.DatasourceConnectionProvider</property>
<property name=
"hibernate.jndi.class">weblogic.jndi.WLInitialContextFactory</property>
<property name=
"hibernate.jdbc.fetch_size">100</property>
<property name=
"hibernate.jdbc.batch_size">50</property>
<property name=
"show_sql">true</property>
<mapping resource=
"test/Addressbook.hbm.xml" />
</session-factory>
</hibernate-configuration>

-------数据源 1 的hibernate.cfg.xml----------------


-------数据源 2 的hibernate.cfg.xml----------------
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE hibernate-configuration
PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-2.0.dtd">

<hibernate-configuration>
<session-factory >

<property name=
"connection.datasource">txyyDB</property>
<property name=
"transaction.factory_class">net.sf.hibernate.transaction.JTATransactionFactory</property>
<property name=
"transaction.manager_lookup_class">net.sf.hibernate.transaction.WeblogicTransactionManagerLookup</property>
<property name=
"dialect">net.sf.hibernate.dialect.SQLServerDialect</property> -- dialect
<property name=
"hibernate.connection.provider_class">net.sf.hibernate.connection.DatasourceConnectionProvider</property>
<property name=
"hibernate.jndi.class">weblogic.jndi.WLInitialContextFactory</property>
<property name=
"hibernate.jdbc.fetch_size">100</property>
<property name=
"hibernate.jdbc.batch_size">50</property>
<property name=
"show_sql">true</property>
<mapping resource=
"test/Txyy.hbm.xml" />
</session-factory>
</hibernate-configuration>

-------数据源 2 的hibernate.cfg.xml----------------


-----------例子程序源代码-----------------------
package test;

import net.sf.hibernate.*;
import net.sf.hibernate.cfg.Configuration;
import java.io.*;
import java.util.*;
import util.NamingContext;
import javax.transaction.*;
import javax.naming.*;

public class MyTest {

public static SessionFactory sf1

public static SessionFactory sf2;

static{
try{
Configuration config1 = new Configuration().configure("/hfcfg/hibernate.cfg.xml"); // 创建数据源1的Config对象
Configuration config2 = new Configuration().configure(
"/cfg/hibernate.cfg.xml"); // 创建数据源2的Config对象

// 根据配置创建对应2个数据源的SessionFactory对象
sf1= config.buildSessionFactory();
sf2 = config1.buildSessionFactory();

}catch(Exception e){e.printStackTrace();}
}

MyTest(){}

// 主要的业务测试方法,分别对两个数据源中的两张表执行插入操作,并置于同一事务下
public List test() throws Exception{

Context ctx = util.NamingContext.getInitialContext();
UserTransaction tx =(UserTransaction) ctx.lookup(
"javax.transaction.UserTransaction");

if(tx != null) {
System.out.println(
"获取UserTransaction实例 = " + tx.toString() + "--" + tx.getClass());
}

// 事务开始
tx.begin();
Session s1 = sf1.openSession();
Session s2 = sf2.openSession();

List addressList = null;
try{

addressList = session.find(
"from Addressbook as c order by c.name asc");

addressbook ar = new Addressbook();
ar.setAddress(
"gz");
ar.setName(
"hf");
ar.setPhone(
"111");
s1.save(ar);

Txyy ty = new Txyy();
ty.setYyms(
"test");
s2.save(ty);

for (Iterator it = addressList .iterator(); it.hasNext(); ) {
System.out.println(((Addressbook) it.next()).getName());
}

tx.commit();
// 事务提交

}catch (Exception e) {
if (tx != null) {
System.out.println(
"||||------事务回滚了--------||||");
tx.rollback();
}
throw e;
}finally {
s1.close();
s2.close();
}
return addressList;
}
}

写段有效的JTA代码给你参考,前后顺序都很重要,否则就不写进入:


javax.transaction.UserTransaction tx = new InitialContext().lookup("javax.transaction.UserTransaction");
Session s1 = sf.openSession(); ... s1.flush();
s1.close(); ...

Session s2 = sf.openSession(); ...
s2.flush();
s2.close();

tx.commit();

多谢banq,按你给的顺序重写了一下测试代码已经搞定,可以插进数据了~~^_^