使用 Spring 3 @Transactional 注解时事务不会回滚
我使用 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
@Transactional
仅应用于 Spring 管理的 bean(除非您配置了高级功能),而在您的情况下,FormatDaoTest
不由 Spring 管理。我想您可以执行以下操作作为快速修复:
作为更优雅的解决方案,您可以使用 Spring TestContext 框架,它支持开箱即用的事务感知测试,请参阅 9.3.5.4 事务管理。
@Transactional
is applied to the Spring-managed beans only (unless you have configured advanced features), whereas in your caseFormatDaoTest
isn't managed by Spring.I guess you can do the following as a quick fix:
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.