Транзакция не откатывается при использовании аннотации Spring 3 @Transactional - PullRequest
2 голосов
/ 18 марта 2011

Я использую аннотацию @Transactional для Spring (версия 3.0), чтобы продемонстрировать поддержку транзакций в Spring, но не могу заставить ее работать (несмотря на то, что сталкивался с похожими проблемами, с которыми люди сталкивались на этом и других технических форумах).

Вот моя запись конфигурации Spring в spring-application-context.xml:

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

  <tx:annotation-driven /> 

  <bean id="formatDao" class="com.gj.dao.FormatDao">
    <property name="dataSource" ref="dataSource"/>
  </bean>

Вот мой транзакционный метод в моем тестовом классе:

  @Transactional(readOnly = true)
  public class FormatDaoTest
  {

      private static ApplicationContext context = new FileSystemXmlApplicationContext(
        "c:\\catalogue\\src\\com\\gj\\conf\\spring-application-context.xml");

      public static void main(String[] args)
      {
    FormatDaoTest test = new FormatDaoTest();
    test.doTransaction();
      }


      @Transactional(propagation = Propagation.REQUIRES_NEW, readOnly = false)
      public void doTransaction()
      {

    IDao dao = (IDao) context.getBean("formatDao");

    Format newFormat = new Format(1, "Test Format 1");

    // Creating a single format
    dao.create(newFormat);

    List newFormatList = new ArrayList();
    newFormatList.add(new Format(2, "Test Format 2"));
    newFormatList.add(new Format(3, "Test Format 3"));
    newFormatList.add(new Format(4, "Test Format 4"));
    newFormatList.add(new Format(5, "Test Format 5"));

    // Creating a list of formats 
    dao.create(newFormatList);

    List updatedFormatList = new ArrayList();
    updatedFormatList.add(new Format(1, "My Test Format 1"));
    updatedFormatList.add(new Format(2, "My Test Format 2"));
    updatedFormatList.add(new Format(3, "My Test Format 3"));

    // Update a list of formats
    dao.update(updatedFormatList);

    Format updatedFormat = new Format(4, "My Test Format 4 with a long format description so allowed table column size is exceeded");

    // Update a single format resulting in a java.sql.SQLException: ORA-12899: value too large for column
    // "RSSPPF1_OWNER"."FORMAT"."FORMAT_DESC" (actual: 88, maximum: 30)
    dao.update(updatedFormat);


      }

  }

Выдается следующее исключение SQL(как и следовало ожидать):

Exception in thread "main" org.springframework.jdbc.UncategorizedSQLException: PreparedStatementCallback; uncategorized SQLException for SQL [UPDATE FORMAT SET format_desc = ? WHERE format_id = ?]; SQL state [72000]; error code [12899]; ORA-12899: value too large for column "RSSPPF1_OWNER"."FORMAT"."FORMAT_DESC" (actual: 88, maximum: 30)
  ; nested exception is java.sql.SQLException: ORA-12899: value too large for column "RSSPPF1_OWNER"."FORMAT"."FORMAT_DESC" (actual: 88, maximum: 30)

    at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:83)
    at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:80)
    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:602)
    at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:811)
    at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:833)
    at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.update(NamedParameterJdbcTemplate.java:260)
    at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.update(NamedParameterJdbcTemplate.java:264)
    at com.gj.dao.FormatDao.update(FormatDao.java:68)
    at com.gj.test.FormatDaoTest.doTransaction(FormatDaoTest.java:62)
    at com.gj.test.FormatDaoTest.main(FormatDaoTest.java:26)
  Caused by: java.sql.SQLException: ORA-12899: value too large for column "RSSPPF1_OWNER"."FORMAT"."FORMAT_DESC" (actual: 88, maximum: 30)

    at oracle.jdbc.driver.SQLStateMapping.newSQLException(SQLStateMapping.java:70)
    at oracle.jdbc.driver.DatabaseError.newSQLException(DatabaseError.java:131)
    at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:204)
    at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:455)
    at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:413)
    at oracle.jdbc.driver.T4C8Oall.receive(T4C8Oall.java:1034)
    at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:194)
    at oracle.jdbc.driver.T4CPreparedStatement.executeForRows(T4CPreparedStatement.java:953)
    at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1222)
    at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3387)
    at oracle.jdbc.driver.OraclePreparedStatement.executeUpdate(OraclePreparedStatement.java:3468)
    at oracle.jdbc.driver.OraclePreparedStatementWrapper.executeUpdate(OraclePreparedStatementWrapper.java:1062)
    at org.springframework.jdbc.core.JdbcTemplate$2.doInPreparedStatement(JdbcTemplate.java:817)
    at org.springframework.jdbc.core.JdbcTemplate$2.doInPreparedStatement(JdbcTemplate.java:1)
    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:586)
    ... 7 more

Однако после создания исключения транзакция не откатывается, и я вижу, что предыдущие вставки и обновления базы данных перед созданием исключения были зафиксированы в FORMAT таблица:

  FORMAT_ID FORMAT_DESC
  1     My Test Format 1
  2     My Test Format 2
  3     My Test Format 3
  4     Test Format 4
  5     Test Format 5

Я ожидал бы, что после этого исключения ничего не будет зафиксировано в базе данных.

Кто-нибудь знает, где я иду не так, и мне не хватает какой-то ключевой концепции здесь?

Любая помощь будет принята с благодарностью!

1 Ответ

6 голосов
/ 18 марта 2011

@Transactional применяется только к bean-компонентам, управляемым Spring (если вы не настроили расширенные функции), тогда как в вашем случае FormatDaoTest не управляется Spring.

Я думаю, вы можете сделатьв качестве быстрого исправления:

public static void main(String[] args) {
    FormatDaoTest test = context.getAutowireCapableBeanFactory()
        .createBean(FormatDaoTest.class);
    test.doTransaction();
}  

В качестве более элегантного решения вы можете использовать среду Spring TestContext, которая поддерживает тесты с поддержкой транзакций из коробки, см. 9.3.5.4 Управление транзакциями .

...