开始怀疑Spring框架的jdbc事务处理方式

05-09-28 lemon_zc1949
         

目前我做了个小小的试验,证明了Spring的jdbc事务的问题。我的环境:

使用jakarta commons dbcp 的 org.apache.commons.dbcp.BasicDataSource,作为DataSource.

xml中的配置如下:

    <bean id="datasource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <property name="url" value="jdbc:mysql://localhost/TransactionTest" />
        <property name="username" value="zc" />
        <property name="password" value="zc" />
        <property name="defaultAutoCommit" value="false" />
    </bean>
<p>

my sql 数据库TransactionTest中有2个表,一个account, 一个accountprofile,分别弄了2个dao

    <bean id="accountdao"
          class="test.AccountDaoImp" >
          <property name="dataSource" ref="datasource" />
    </bean>
    	 
    <bean id="accountprofiledao"
          class="test.AccountProfileDaoImp" >
          <property name="dataSource" ref="datasource" />
    </bean>

<p>

事务管理器配置:

    <bean id="dbTransactionManager"
    	  class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    	  <property name="dataSource" ref="datasource" />
    </bean>
<p>

业务门面:

    <bean id="accountservice_target"
    	  class="test.AccountService" >
    	  <property name="accountDao" ref="accountdao" />
    	  <property name="accountProfileDao" ref="accountprofiledao" />    	  
    </bean>

<p>

最后配置Spring的事务代理(其实就是利用了aop):

    <bean id="accountservice" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" >
    	<property name="transactionManager" ref="dbTransactionManager" />
    	<property name="target" ref="accountservice_target" />
    	<property name="transactionAttributes" >
    		<props>
    			<prop key="register*">PROPAGATION_REQUIRED</prop>
    		</props>
    	</property>
    </bean>

<p>

我的业务门面实现有个方法:

	public void registerAccount(Account a, AccountProfile ap){
		accountDao.insert(a);
		accountProfileDao.insert(ap);		
	}
<p>

分别调用2个dao的insert()方法,Account, AccountProfile是值对象。

测试代码:

	public static void main(String[] args) {
		FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext("beans.xml");
		
		AccountService service = (AccountService) context.getBean("accountservice");
		
		Account a = new Account();
		a.setId("U001");
		a.setName("zc");
		a.setPhone("123");
		
		AccountProfile ap = new AccountProfile();
		ap.setName(a.getName()); // "zc"
		ap.setPassword("abcdef");
		
		service.registerAccount(a,ap);

		a = new Account();
		a.setId("U002");
		a.setName("zc");
		a.setPhone("123");
		
		ap = new AccountProfile();
		ap.setName(a.getName()); // "zc"
		ap.setPassword("12345");
		
		service.registerAccount(a,ap);
		
		context.close();

	}

<p>

由于表accountprofile 的name 字段是唯一的,所以第2次registerAccount()要出现异常。

也就是在第2次执行registerAccount()时

{
		accountDao.insert(a);
		accountProfileDao.insert(ap);  // 这要抛出异常		
}

<p>

但前面的 accountDao.insert(a) 无法回滚呢?

数据库结果:account有2条记录,id不同,但name相同, accountprofile有1条记录.

数据库不一致, 事务没起到作用。

         

lemon_zc1949
2005-09-28 15:18

Spring的事务有2种方式:

1。编程的方式,使用TransactionTemplate的execute方法。

2。AOP方式,通过配置来启动事务。

我上面的方法是采用AOP方式。

还有,我试验做过,如果使用相同的DataSource,调用它的getConnection(),那么获取的Connection(连接池封装了的)的hashCode都不一样,也就是说Connection是不一样。注射给 2个dao以及TransactionManager的DataSource是同意个DataSource(单列),单他们在使用DataSource的时候可能使用的Connection是不同的,所以无法实现事务混滚, 不知道是不是这样?

有点郁闷。

banq
2005-09-28 21:29

如果你不是MySQL 5.0,你需要指定Mysql的事务机制是INNO DB。

你在JBoss下试验看看。

banq
2005-09-29 10:45

Spring只提供使用JTA JMS等方便使用方式,但是不提供这些服务,必须由容器提供,你需要使用JBoss.

浆糊
2005-09-29 13:25

拜托先确保数据库的事务能力好伐?

2Go 1 2 下一页