为什么我的 spring jdbc 事务管理器不工作?

Why my spring transaction manager for jdbc is not working?

我已经为 JDBC 配置了事务管理器,但是当我这样做时:

dao.insert(something);
throw new UnsupportedOperationException();

事务不回滚

<aop:aspectj-autoproxy />

<!-- define JDBC datasource by DBCP -->
    <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <property name="url" value="jdbc:mysql://localhost:3306/ts" />
        <property name="username" value="root" />
        <property name="password" value="1234" />
    </bean>

    <!--  DataSourceTransactionManager for jdbc -->
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <bean id="fooDao" class="com.oolong.dao.FooDao">
        <property name="dstm" ref="txManager"></property>
    </bean>

    <bean id="fooService" class="com.oolong.service.DefaultFooService">
        <property name="fooDao" ref="fooDao"></property>
    </bean>

    <tx:advice id="txAdvice" transaction-manager="txManager">
        <tx:attributes>
            <tx:method name="get*" read-only="true" propagation="REQUIRED"/>
            <tx:method name="*" read-only="false"  propagation="REQUIRED" 
                rollback-for="java.lang.RuntimeException"/>
        </tx:attributes>
    </tx:advice>

    <aop:config>
        <aop:pointcut id="fooServiceOperation" expression="execution(* com.oolong.service.FooService.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceOperation"/>
    </aop:config>

这是一个简单的例子,一个DefaultFooService实现了FooService接口。 该服务有一个 dao,FooDao,有一个方法将记录插入 table.

当我运行代码。交易尚未创建!当然不能回滚。

FooService 接口

package com.oolong.service;

import com.oolong.model.Foo;

public interface FooService {

    Foo getFoo(String fooName);

    Foo getFoo(String fooName, String barName);

    void insertFoo(Foo foo);

    void updateFoo(Foo foo);
}

DefaultFooService.java

package com.oolong.service;

import com.oolong.dao.FooDao;
import com.oolong.model.Foo;

public class DefaultFooService implements FooService {

    private FooDao fooDao;

    public void setFooDao(FooDao fooDao) {
        this.fooDao = fooDao;
    }

    public Foo getFoo(String fooName) {

        throw new UnsupportedOperationException();
    }

    public Foo getFoo(String fooName, String barName) {
        throw new UnsupportedOperationException();
    }

    public void insertFoo(Foo foo) {
        fooDao.insert();
        throw new UnsupportedOperationException();
    }

    public void updateFoo(Foo foo) {
        throw new UnsupportedOperationException();
    }
}

FooDao.java

package com.oolong.dao;

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;

import javax.sql.DataSource;

import org.springframework.jdbc.datasource.DataSourceTransactionManager;

public class FooDao {

    private DataSourceTransactionManager dstm;

    public void setDstm(DataSourceTransactionManager dstm) {
        this.dstm = dstm;
    }

    public void insert() {
        try {
            DataSource ds = dstm.getDataSource();
            Connection conn = ds.getConnection();

            String sql = "insert into item (wid, answer, isCorrect, choiceWid) "
                    + "values ('1', '1', 1, '1')";

            Statement st = conn.createStatement();
            st.executeUpdate(sql);

        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

AppContainer.java

public class AppContainer {

    public static void main(final String[] args) throws Exception {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("/beans.xml", AppContainer.class);
        FooService fooService = (FooService) ctx.getBean("fooService");
        fooService.insertFoo(new Foo());
    }
}

抛出UnsupportedOperationException前log4j输出的信息:

Loaded NamespaceHandler mappings: {http://www.springframework.org/schema/p=org.springframework.beans.factory.xml.SimplePropertyNamespaceHandler, http://www.springframework.org/schema/mvc=org.springframework.web.servlet.config.MvcNamespaceHandler, http://www.springframework.org/schema/util=org.springframework.beans.factory.xml.UtilNamespaceHandler, http://www.springframework.org/schema/jee=org.springframework.ejb.config.JeeNamespaceHandler, http://www.springframework.org/schema/websocket=org.springframework.web.socket.config.WebSocketNamespaceHandler, http://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler, http://www.springframework.org/schema/oxm=org.springframework.oxm.config.OxmNamespaceHandler, http://www.springframework.org/schema/jdbc=org.springframework.jdbc.config.JdbcNamespaceHandler, http://www.springframework.org/schema/cache=org.springframework.cache.config.CacheNamespaceHandler, http://www.springframework.org/schema/c=org.springframework.beans.factory.xml.SimpleConstructorNamespaceHandler, http://www.springframework.org/schema/tx=org.springframework.transaction.config.TxNamespaceHandler, http://www.springframework.org/schema/jms=org.springframework.jms.config.JmsNamespaceHandler, http://www.springframework.org/schema/task=org.springframework.scheduling.config.TaskNamespaceHandler, http://www.springframework.org/schema/lang=org.springframework.scripting.config.LangNamespaceHandler, http://www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandler}
Creating shared instance of singleton bean 'org.springframework.aop.config.internalAutoProxyCreator'
Creating instance of bean 'org.springframework.aop.config.internalAutoProxyCreator'
Eagerly caching bean 'org.springframework.aop.config.internalAutoProxyCreator' to allow for resolving potential circular references
Finished creating instance of bean 'org.springframework.aop.config.internalAutoProxyCreator'
Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@3224f60b: defining beans [org.springframework.aop.config.internalAutoProxyCreator,dataSource,txManager,fooDao,fooService,txAdvice,fooServiceOperation,org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0]; root of factory hierarchy
Returning cached instance of singleton bean 'org.springframework.aop.config.internalAutoProxyCreator'
Creating shared instance of singleton bean 'dataSource'
Creating instance of bean 'dataSource'
Creating shared instance of singleton bean 'org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0'
Creating instance of bean 'org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0'
Eagerly caching bean 'org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0' to allow for resolving potential circular references
Creating instance of bean 'fooServiceOperation'
Finished creating instance of bean 'fooServiceOperation'
Finished creating instance of bean 'org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0'
Eagerly caching bean 'dataSource' to allow for resolving potential circular references
Returning cached instance of singleton bean 'org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0'
Returning cached instance of singleton bean 'org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0'
Finished creating instance of bean 'dataSource'
Creating shared instance of singleton bean 'txManager'
Creating instance of bean 'txManager'
Returning cached instance of singleton bean 'org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0'
Eagerly caching bean 'txManager' to allow for resolving potential circular references
Returning cached instance of singleton bean 'dataSource'
Invoking afterPropertiesSet() on bean with name 'txManager'
Returning cached instance of singleton bean 'org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0'
Returning cached instance of singleton bean 'org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0'
Finished creating instance of bean 'txManager'
Creating shared instance of singleton bean 'fooDao'
Creating instance of bean 'fooDao'
Returning cached instance of singleton bean 'org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0'
Eagerly caching bean 'fooDao' to allow for resolving potential circular references
Returning cached instance of singleton bean 'txManager'
Returning cached instance of singleton bean 'org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0'
Returning cached instance of singleton bean 'org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0'
Finished creating instance of bean 'fooDao'
Creating shared instance of singleton bean 'fooService'
Creating instance of bean 'fooService'
Returning cached instance of singleton bean 'org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0'
Eagerly caching bean 'fooService' to allow for resolving potential circular references
Returning cached instance of singleton bean 'fooDao'
Returning cached instance of singleton bean 'org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0'
Returning cached instance of singleton bean 'org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0'
Creating shared instance of singleton bean 'txAdvice'
Creating instance of bean 'txAdvice'
Eagerly caching bean 'txAdvice' to allow for resolving potential circular references
Returning cached instance of singleton bean 'txManager'
Creating instance of bean '(inner bean)#63021689'
Returning cached instance of singleton bean 'org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0'
Returning cached instance of singleton bean 'org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0'
Returning cached instance of singleton bean 'org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0'
Finished creating instance of bean '(inner bean)#63021689'
Invoking afterPropertiesSet() on bean with name 'txAdvice'
Finished creating instance of bean 'txAdvice'
Finished creating instance of bean 'fooService'
Returning cached instance of singleton bean 'txAdvice'
Returning cached instance of singleton bean 'org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0'
Returning cached instance of singleton bean 'lifecycleProcessor'
Returning cached instance of singleton bean 'fooService'

看到这个:

Application code is required to retrieve the JDBC Connection via DataSourceUtils.getConnection(DataSource) instead of a standard Java EE-style DataSource.getConnection() call. Spring classes such as JdbcTemplate use this strategy implicitly.

感谢@JB Nizet、@SachinSarawgi。

我应该使用 JdbcTemplate。