@Transactional似乎没有创建任何交易

时间:2012-07-05 18:17:12

标签: spring-mvc postgresql-9.1 transactional

我试图在Spring MVC应用程序中使用@Transactional来获得原子性。问题是,无论何时调用带注释的函数,它都不会创建事务。这是我目前的设置:

申请背景:

<?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:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd" >

    <!-- Root Context: defines shared resources visible to all other web components -->

    <tx:annotation-driven transaction-manager="txManager"/>

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

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" >
        <property name="driverClassName" value="org.postgresql.Driver" />
        <property name="url" value="jdbc:postgresql://localhost:5432/qas" />
        <property name="username" value="postgres" />
        <property name="password" value="P0stgr3s" />   
    </bean>

    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate" >
        <constructor-arg name="dataSource" ref="dataSource" />
    </bean>

</beans>

控制器文件:

package com.silverthorn.txtest;

import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * Handles requests for the application home page.
 */
@Controller
public class HomeController {

    private static final Logger logger = LoggerFactory.getLogger(HomeController.class);

    @Autowired
    private TagsDAO tagsDAO;

    /**
     * Simply selects the home view to render by returning its name.
     */
    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String home(Locale locale, Model model) {
        logger.info("Welcome home! the client locale is "+ locale.toString());

        Date date = new Date();
        DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);

        String formattedDate = dateFormat.format(date);

        model.addAttribute("serverTime", formattedDate );

        return "home";
    }

    @RequestMapping(value="/tags", method=RequestMethod.GET)
    public @ResponseBody ResponseDocument addTags(@RequestParam("tag") String[] tags) {
        ResponseDocument doc = new ResponseDocument();

        try {
            tagsDAO.addTags(tags);
        } catch ( RuntimeException e ) {
            doc.setError("Could not add tags");
        }

        return doc;
    }

}

和DAO文件:

package com.silverthorn.txtest;

import java.util.HashMap;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Repository("tagsDAO")
public class TagsDAO {

    @Autowired 
    private NamedParameterJdbcTemplate jdbcTemplate;

    @Transactional(propagation = Propagation.REQUIRED)
    public void addTags(String[] tags) {
        Map<String, Object> params = new HashMap<String, Object>();
        for(String tag : tags) {
            params.put("tag", tag);
            jdbcTemplate.update("INSERT INTO qas.tags (tag) VALUES (:tag)", params);
        }
    }

}

以下是事务失败时的输出日志示例:

DEBUG: org.springframework.jdbc.core.JdbcTemplate - Executing prepared SQL update
DEBUG: org.springframework.jdbc.core.JdbcTemplate - Executing prepared SQL statement [INSERT INTO qas.tags (tag) VALUES (?)]
DEBUG: org.springframework.jdbc.datasource.DataSourceUtils - Fetching JDBC Connection from DataSource
DEBUG: org.springframework.jdbc.core.JdbcTemplate - SQL update affected 1 rows
DEBUG: org.springframework.jdbc.datasource.DataSourceUtils - Returning JDBC Connection to DataSource
DEBUG: org.springframework.jdbc.core.JdbcTemplate - Executing prepared SQL update
DEBUG: org.springframework.jdbc.core.JdbcTemplate - Executing prepared SQL statement [INSERT INTO qas.tags (tag) VALUES (?)]
DEBUG: org.springframework.jdbc.datasource.DataSourceUtils - Fetching JDBC Connection from DataSource
DEBUG: org.springframework.jdbc.datasource.DataSourceUtils - Returning JDBC Connection to DataSource
INFO : org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loading XML bean definitions from class path resource [org/springframework/jdbc/support/sql-error-codes.xml]
INFO : org.springframework.jdbc.support.SQLErrorCodesFactory - SQLErrorCodes loaded: [DB2, Derby, H2, HSQL, Informix, MS-SQL, MySQL, Oracle, PostgreSQL, Sybase]
DEBUG: org.springframework.jdbc.support.SQLErrorCodesFactory - Looking up default SQLErrorCodes for DataSource [org.apache.commons.dbcp.BasicDataSource@704fb]
DEBUG: org.springframework.jdbc.datasource.DataSourceUtils - Fetching JDBC Connection from DataSource
DEBUG: org.springframework.jdbc.datasource.DataSourceUtils - Returning JDBC Connection to DataSource
DEBUG: org.springframework.jdbc.support.SQLErrorCodesFactory - Database product name cached for DataSource [org.apache.commons.dbcp.BasicDataSource@704fb]: name is 'PostgreSQL'
DEBUG: org.springframework.jdbc.support.SQLErrorCodesFactory - SQL error codes for 'PostgreSQL' found
DEBUG: org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator - Translating SQLException with SQL state '23505', error code '0', message [ERROR: duplicate key value violates unique constraint "tags_pkey"
  Detail: Key (tag)=(hello) already exists.]; SQL was [INSERT INTO qas.tags (tag) VALUES (?)] for task [PreparedStatementCallback]

从日志文件中可以看出,看起来没有创建任何事务。如果没有创建事务,显然无法将更新回滚到数据库。我现在已经把头撞在墙上2天了,而且还没有能够更接近达到预期的行为。我能得到的任何帮助都将不胜感激。

1 个答案:

答案 0 :(得分:2)

只是为了确保 - 如果你的路径中没有可能成为问题的CGLIB库。您将需要CGLIB,因为您的@Repository没有接口,并且Spring将在这种情况下为@Transactional注释类创建CGLIB代理(如果CGLIB不存在则会失败)。您可以使用CGLIB或aspectj代理。