使用 Spring 3 @Transactional 注解时事务不会回滚

发布于 2024-10-24 05:50:58 字数 5512 浏览 12 评论 0原文

我使用 Spring(版本 3.0)“@Transactional”注释来演示事务支持 在 Spring 中,但无法使其正常工作(尽管已经看到人们在这方面遇到过类似的问题) 其他技术论坛)。

这是 spring-application-context.xml 中的 Spring 配置条目:

<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

我希望在该异常之后不会看到任何内容提交到数据库。

有人知道我哪里出了问题吗?我在这里错过了一些关键概念吗?

任何帮助将不胜感激!

I am using the Spring (version 3.0) '@Transactional' annotation in order to demonstrate transaction support
in Spring but can't get this working (despite having seen similar issues people have encountered in this and
other technical forums).

Here is my Spring config entry in 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>

Here is my transactional method in my test class:

  @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);


      }

  }

The following SQL exception is thrown (as I would expect):

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

However, after the exception is thrown the transaction does not rollback and I can see the previous database inserts
and updates prior to the exception being thrown have been committed to the FORMAT table:

  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

I would have expected to see nothing committed to the database following this exception.

Does anybody know where I am going wrong and am I missing some key concept here?

Any help would be greatly appreciated!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

请持续率性 2024-10-31 05:50:58

@Transactional 仅应用于 Spring 管理的 bean(除非您配置了高级功能),而在您的情况下,FormatDaoTest 不由 Spring 管理。

我想您可以执行以下操作作为快速修复:

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

作为更优雅的解决方案,您可以使用 Spring TestContext 框架,它支持开箱即用的事务感知测试,请参阅 9.3.5.4 事务管理

@Transactional is applied to the Spring-managed beans only (unless you have configured advanced features), whereas in your case FormatDaoTest isn't managed by Spring.

I guess you can do the following as a quick fix:

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

As a more elegant solution you can use Spring TestContext framework, which supports transaction-aware tests out of the box, see 9.3.5.4 Transaction management.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文