首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 其他教程 > 互联网 >

Spring 事物错误[Transaction rolled back because it has been marked as rollback-only]

2013-01-02 
Spring 事物异常[Transaction rolled back because it has been marked as rollback-only]spring通过Trans

Spring 事物异常[Transaction rolled back because it has been marked as rollback-only]
spring通过TransactionInterceptor和AbstractPlatformTransactionManager的实现类控制数据库事务。

创建数据库
Animal表

create table Animal(name nvarchar(20))

Person表
create table Person(name nvarchar(20))


一、配置文件
1.applicationContext.xml
<import resource="applicationContext-common.xml"/><import resource="applicationContext-service.xml"/>

2.applicationContext-service.xml
<bean id="baseService" abstract="true"><property name="dataSource" ref="dataSource"/></bean><bean id="animalService" parent="baseService"/><bean id="personService" parent="baseService"/><bean id="allService" parent="baseService"><property name="animalService" ref="animalService"/><property name="personService" ref="personService"/></bean>

3.applicationContext-common.xml
 <!-- 配置属性配置文件  --><bean id="propertyConfigurer" destroy-method="close">          <property name="driverClassName" value="${jdbc.database.driverClassName}"/>          <property name="url" value="${jdbc.database.url}"/>          <property name="username" value="${jdbc.database.username}"/>          <property name="password" value="${jdbc.database.password}"/>      </bean>  <!-- 配置事务管理器 --><bean id="transactionManager"ref="dataSource" /></bean><!-- 具体事务配置 --><aop:config><aop:pointcut expression="execution(* service.*.*(..))"id="allManagerMethods" /><aop:advisor advice-ref="txAdvice" pointcut-ref="allManagerMethods" /></aop:config><!-- 事务传播特性的配置 --><tx:advice id="txAdvice" transaction-manager="transactionManager"><tx:attributes><tx:method name="*" propagation="REQUIRED" /></tx:attributes></tx:advice>

4.jdbc.properties
jdbc.database.driverClassName=oracle.jdbc.driver.OracleDriverjdbc.database.url=jdbc:oracle:thin:@127.0.0.1:1521:oraclejdbc.database.username=scottjdbc.database.password=tiger

二、service类
service.AllService
public interface AllService {public void addAll(String personName,String animalName) throws Exception;}

service.impl.AllServiceImpl
public class AllServiceImpl extends JdbcDaoSupport implements AllService {private PersonService personService;private AnimalService animalService;@Overridepublic void addAll(String personName, String animalName) throws Exception {try{personService.addPerson(personName);}catch (Exception e) {System.out.println(e.toString());}animalService.addAnimal(animalName);}public void setPersonService(PersonService personService) {this.personService = personService;}public void setAnimalService(AnimalService animalService) {this.animalService = animalService;}}

service.AnimalService
public interface AnimalService {public void addAnimal(String animalName) throws Exception;}

service.impl.AnimalServiceImpl
public class AnimalServiceImpl  extends JdbcDaoSupport implements AnimalService{@Overridepublic void addAnimal(String animalName) throws Exception {this.getJdbcTemplate().update("insert into ANIMAL values(?)",new Object[]{animalName});}}

service.PersonService
public interface PersonService {public void addPerson(String personName)throws Exception;}

service.impl.PersonServiceImpl
public class PersonServiceImpl extends JdbcDaoSupport implements PersonService {@Overridepublic void addPerson(String personName) throws Exception {this.getJdbcTemplate().update("insert into PERSON values(?)",new Object[]{personName});}}

三、测试代码
public class SpringTest {private static ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");public static void main(String[] args) throws Exception{AllService allService=(AllService) applicationContext.getBean("allService");String personName="will";String animalName="小狗";allService.addAll(personName,animalName);}}

执行以上代码,在数据库中可以成功插入数据。
可是如果把personName赋值为一个很长的字符串(超过20位,超过数据库指定长度),就会抛出如下错误
org.springframework.jdbc.UncategorizedSQLException: PreparedStatementCallback; uncategorized SQLException for SQL [insert into PERSON values(?)]; SQL state [72000]; error code [12899]; ORA-12899: 列 "SCOTT"."PERSON"."NAME" 的值太大 (实际值: 32, 最大值: 20); nested exception is java.sql.SQLException: ORA-12899: 列 "SCOTT"."PERSON"."NAME" 的值太大 (实际值: 32, 最大值: 20)Exception in thread "main" org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-onlyat org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:695)at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:321)at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:116)at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:89)at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)at $Proxy2.addAll(Unknown Source)at test.SpringTest.main(SpringTest.java:16)

已经在AllServiceImpl中的addAll中捕获了personService.addPerson这个抛出异常的方法调用。从控制台的打印中,可以发现错误的源是插入的Person表中的name字段太长。虽然在AllServiceImpl.addAll中已经捕获了异常,AllServiceImpl.addAll并未抛出异常,可是事务还是没有提交成功。

经过调试,发现spring处理普通的jdbc事物大致如此:每当调用事物管理的方法时(这里就是aop:pointcut expression匹配的方法),首先会调用TransactionInterceptor的invoke方法,在方法中spring会检测是否要开启事物(根据具体的配置文件而定),然后具体在调用具体的那个真正要处理的方法。如果这个真正处理的方法抛出了异常(如果在这个真正执行的方法内部有异常,但是自我捕获了,那么对于spring而言,这个方法并没有抛出异常),spring会根据配置判断这个异常是否要使得事物回滚,如果要回滚,那么就是设置一个标记,标记有关这一个connection的所有事物都要回滚。

所以,虽然AllServiceImpl.addAll中没有抛出异常,但是personService.addPerson这个调用抛出了异常,并且这个方法spring是要做事物处理的,一旦personService.addPerson抛出异常,TransactionInterceptor中invoke方法会捕获这个异常,然后标记有关这个connection的事务做回滚,就算在AllServiceImpl.addAll捕获了这个异常,但是animalService.addAnimal是无法插入数据的

热点排行