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

         
lemon_zc1949
05-09-28 9 2423

目前我做了个小小的试验,证明了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>


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>



事务管理器配置:

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


业务门面:

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



最后配置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>



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

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


分别调用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();

}



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

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

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



但前面的 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 下一页