проблема с транзакцией mybatis-spring

#spring #transactions #mybatis

#spring #транзакции #mybatis

Вопрос:

У меня возникли проблемы с использованием транзакции CMT Spring с mybatis, у меня есть класс, который использует 2 MapperFactoryBean для вставки записи.

При вставке записей возникает исключение ограничения ВНЕШНЕГО КЛЮЧА; похоже, что оба выполняются в разных сеансах, и второй не смог найти недавно вставленный идентификатор.

При передаче null во внешнем ключе второй записи; исключение не генерируется, но и транзакция не фиксируется.

Откат работает нормально, если возникает какое-либо исключение.

Вот моя конфигурация

     <tx:jta-transaction-manager />

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">        
    <property name="url" value="${database.url}"/>
    <property name="driverClassName" value="${database.driverClassName}"/>
    <property name="username" value="${database.username}"/>
    <property name="password" value="${database.password}"/>   
    <property name="defaultAutoCommit" value="false" />
    </bean>

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

    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />            
    <property name="configLocation" value="classpath:dataAccess-config.xml"/>  
    </bean>

    <bean id="taskRecordMapper" class="org.mybatis.spring.MapperFactoryBean">       
    <property name="sqlSessionFactory" ref="sqlSessionFactory" /> 
    <property name="mapperInterface" value="TaskRecordMapper"/>
    </bean>

    <bean id="taskTagRecordMapper" class="org.mybatis.spring.MapperFactoryBean">       
    <property name="sqlSessionFactory" ref="sqlSessionFactory" />
    <property name="mapperInterface" value="TaskTagRecordMapper"/>
    </bean>
  

Фрагмент кода

     @Transactional(propagation= Propagation.REQUIRED)
    public boolean assignTask(Object source, TaskType taskType, String description,
                                long assignedTo, long createdBy, long escalationId,
                                boolean isAssignedToGroup, long parentTaskId,
                                Date deadline, TaskPriority taskPriority) throws Exception
    {
         
    EntityType entityType = TaskUtil.getEntityType(source);
    long entityId = TaskUtil.getIdFromObject(source);
            
    TaskRecord newTask = new TaskRecord();
    
    newTask.setAssignedTo((isAssignedToGroup) ? null : assignedTo);
    newTask.setCategory(entityType.toString());
    newTask.setCreatedBy(createdBy); 
    newTask.setCreatedOn(new Date());
    newTask.setDeadline(deadline);
    newTask.setDescription(description);
    newTask.setEntityId(entityId);
    newTask.setEscalationId(escalationId); 
    newTask.setIsAssignedToGroup(isAssignedToGroup);
    newTask.setIsDeleted(false);
    newTask.setModifiedBy(null);
    newTask.setModifiedOn(null);
    newTask.setOwner(createdBy); 
    newTask.setParentId((parentTaskId == 0) ? null : parentTaskId);
    newTask.setPriority(taskPriority.toString());
    newTask.setReferenceNo(null);
    newTask.setResult(null);
    newTask.setStatus(TaskStatus.InProgress.toString());
    newTask.setType(taskType.toString());
    
    boolean rValue = taskRecordMapper.insert(newTask) > 0;
    
    
    if(rValue amp;amp; isAssignedToGroup)
    {   
        TaskTagRecord tag = new TaskTagRecord();
        
        tag.setTaskId(newTask.getId());
        tag.setName("RoleId");
        tag.setValue(String.valueOf(assignedTo));
        
        rValue = taskTagRecordMapper.insert(tag) > 0;
    }
        
    
    return rValue;
    }
  

Спасибо в ожидании

Вот трассировка стека

 org.springframework.dao.DataIntegrityViolationException: SqlSession operation; SQL []; The INSERT statement conflicted with the FOREIGN KEY constraint "FK_task_tag_task". The conflict occurred in database "TEMP", table "dbo.task", column 'id'.; nested exception is com.microsoft.sqlserver.jdbc.SQLServerException: The INSERT statement conflicted with the FOREIGN KEY constraint "FK_task_tag_task". The conflict occurred in database "TEMP", table "dbo.task", column 'id'.
    at org.springframework.jdbc.support.SQLStateSQLExceptionTranslator.doTranslate(SQLStateSQLExceptionTranslator.java:101)
    at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:72)
    at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:80)
    at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:80)
    at org.mybatis.spring.SqlSessionTemplate.wrapException(SqlSessionTemplate.java:364)
    at org.mybatis.spring.SqlSessionTemplate$7$1.doInSqlSession(SqlSessionTemplate.java:344)
    at org.mybatis.spring.SqlSessionTemplate.execute(SqlSessionTemplate.java:173)
    at org.mybatis.spring.SqlSessionTemplate.execute(SqlSessionTemplate.java:155)
    at org.mybatis.spring.SqlSessionTemplate$7.invoke(SqlSessionTemplate.java:339)
    at $Proxy18.insert(Unknown Source)
    at com.task.service.TaskService.assignTask(TaskService.java:184)
    at com.task.service.TaskService.assignTask(TaskService.java:137)
    at com.core.mapper.TaskServiceTest.main(TaskServiceTest.java:38)
Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: The INSERT statement conflicted with the FOREIGN KEY constraint "FK_task_tag_task". The conflict occurred in database "TEMP", table "dbo._task", column 'id'.
    at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDatabaseError(SQLServerException.java:196)
    at com.microsoft.sqlserver.jdbc.SQLServerStatement.getNextResult(SQLServerStatement.java:1454)
    at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.doExecutePreparedStatement(SQLServerPreparedStatement.java:388)
    at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement$PrepStmtExecCmd.doExecute(SQLServerPreparedStatement.java:338)
    at com.microsoft.sqlserver.jdbc.TDSCommand.execute(IOBuffer.java:4026)
    at com.microsoft.sqlserver.jdbc.SQLServerConnection.executeCommand(SQLServerConnection.java:1416)
    at com.microsoft.sqlserver.jdbc.SQLServerStatement.executeCommand(SQLServerStatement.java:185)
    at com.microsoft.sqlserver.jdbc.SQLServerStatement.executeStatement(SQLServerStatement.java:160)
    at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.execute(SQLServerPreparedStatement.java:320)
    at org.apache.commons.dbcp.DelegatingPreparedStatement.execute(DelegatingPreparedStatement.java:169)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.apache.ibatis.logging.jdbc.PreparedStatementLogger.invoke(PreparedStatementLogger.java:45)
    at $Proxy38.execute(Unknown Source)
    at org.apache.ibatis.executor.statement.PreparedStatementHandler.update(PreparedStatementHandler.java:22)
    at org.apache.ibatis.executor.statement.RoutingStatementHandler.update(RoutingStatementHandler.java:51)
    at org.apache.ibatis.executor.SimpleExecutor.doUpdate(SimpleExecutor.java:29)
    at org.apache.ibatis.executor.BaseExecutor.update(BaseExecutor.java:75)
    at org.apache.ibatis.executor.CachingExecutor.update(CachingExecutor.java:43)
    at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:118)
    at org.apache.ibatis.session.defaults.DefaultSqlSession.insert(DefaultSqlSession.java:107)
    at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:56)
    at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:38)
    at $Proxy18.insert(Unknown Source)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.mybatis.spring.SqlSessionTemplate$7$1.doInSqlSession(SqlSessionTemplate.java:342)
    ... 7 more
  

Вот журнал ОТЛАДКИ

 02:41:32,465 INFO  main [ClassPathXmlApplicationContext] Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@1bc887b: startup date [Thu May 26 02:41:32 GST 2011]; root of context hierarchy
02:41:32,512 INFO  main [XmlBeanDefinitionReader] Loading XML bean definitions from class path resource [dataAccessApplicationContext.xml]
02:41:33,034 INFO  main [DefaultListableBeanFactory] Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@173b262: defining beans [org.springframework.beans.factory.config.PropertyPlaceholderConfigurer#0,org.springframework.context.config.internalBeanConfigurerAspect,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.beans.factory.config.PropertyOverrideConfigurer#0,dataSource,transactionManager,sqlSessionFactory,managedTransactionFactory,springApplicationContext]; root of factory hierarchy
02:41:34,512 DEBUG main [Connection] ooo Connection Opened
02:41:34,659 DEBUG main [PreparedStatement] ==>  Executing: select id, order_number, com_id, order_date, status, source, created_on, created_by, is_deleted, modified_on, modified_by from order WHERE ( id = ? and is_deleted = ? ) 
02:41:34,660 DEBUG main [PreparedStatement] ==> Parameters: 264(Long), false(Boolean)
02:41:34,699 DEBUG main [ResultSet] <==    Columns: id, order_number, com_id, order_date, status, source, created_on, created_by, is_deleted, modified_on, modified_by
02:41:34,709 DEBUG main [ResultSet] <==        Row: 264, 00277-100410, 1041, 2010-01-01 00:00:00.0, Pending, COMPANY A, 2011-05-24 00:21:00.337, 1, 0, null, null
02:41:34,723 DEBUG main [Connection] xxx Connection Closed
02:41:34,742 DEBUG main [Connection] ooo Connection Opened
02:41:34,747 DEBUG main [PreparedStatement] ==>  Executing: insert into task (type, status, owner, description, context_id, deadline, assigned_to, parent_id, priority, escalation_id, reference_no, result, created_on, created_by, modified_on, modified_by, category, entity_id, is_deleted, is_assigned_to_group) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) 
02:41:34,747 DEBUG main [PreparedStatement] ==> Parameters: Investigation(String), InProgress(String), 1(Long), Please investigate this order(String), null, 2011-05-27 02:41:34.736(Timestamp), null, null, Normal(String), 1(Long), null, null, 2011-05-26 02:41:34.737(Timestamp), 1(Long), null, null, Order(String), 264(Long), false(Boolean), true(Boolean)
02:41:34,757 DEBUG main [PreparedStatement] ==>  Executing: select @@identity 
02:41:34,757 DEBUG main [PreparedStatement] ==> Parameters: 
02:41:34,763 DEBUG main [ResultSet] <==    Columns: 
02:41:34,763 DEBUG main [ResultSet] <==        Row: 94
02:41:34,782 DEBUG main [Connection] xxx Connection Closed
02:41:34,800 DEBUG main [Connection] ooo Connection Opened
02:41:34,803 DEBUG main [PreparedStatement] ==>  Executing: insert into task_tag (name, value, task_id ) values (?, ?, ? ) 
02:41:34,804 DEBUG main [PreparedStatement] ==> Parameters: RoleId(String), 1(String), 94(Long)
02:41:34,842 INFO  main [XmlBeanDefinitionReader] Loading XML bean definitions from class path resource [org/springframework/jdbc/support/sql-error-codes.xml]
02:41:34,859 INFO  main [SQLErrorCodesFactory] SQLErrorCodes loaded: [DB2, Derby, H2, HSQL, Informix, MS-SQL, MySQL, Oracle, PostgreSQL, Sybase]
02:41:34,944 DEBUG main [Connection] xxx Connection Closed
  

Комментарии:

1. Можете ли вы включить DEBUG ведение журнала в следующих классах и перезапуск: org.springframework.orm, org.springframework.jdbc и java.sql. Пожалуйста, опубликуйте выходные данные журнала.

2. Спасибо за ответ AngerClown; опубликовал вывод журнала;

Ответ №1:

Из журнала ОТЛАДКИ похоже, что tx никогда не запускался. Я думаю, проблема в том, что @Transactional по умолчанию не включена. Вам нужно добавить <tx:annotation-driven transaction-manager="transactionManager" /> в свой XML-файл Spring.

Комментарии:

1. Да, AngerClown, после добавления тега, управляемого аннотациями, была инициирована транзакция, но у меня была проблема в моем коде также в том, что конкретный метод выдает исключение, из-за которого откат не запускается, как только я изменил свой метод commit, и откат работает должным образом. Спасибо, ребята, что помогли мне.

2. @Danish как вы это измените? У меня такая же проблема: (

Ответ №2:

Не уверен, что это решит проблему, но что-то определенно не так с:

 <tx:jta-transaction-manager/>
  

Это означает, что вы используете JTA, как при делегировании обработки транзакций серверу приложений.
И также у вас есть

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

Это означает, что вы используете обработку транзакций Spring. Я не вижу, чтобы на этот компонент где-либо явно ссылались, но, вероятно, это вызывает некоторые проблемы. Каким путем вы хотите пойти, делегировать appserver (вы работаете на реальном сервере приложений или используете Tomcat / Jetty?), или позволить Spring обрабатывать транзакции? В последнем случае удалите директиву JTA, в другом — удалите определение TransactionManager (или измените класс на JTA transaction manager).

Комментарии:

1. Спасибо abalogh за ваш ответ. Я хочу, чтобы Spring обрабатывал транзакции, я удалил <tx:jta-transaction-manager /> из конфигурации; после этого протестировал вышеупомянутые сценарии и все еще получаю те же результаты

2. Можете ли вы опубликовать свой stacktrace?

3. Опубликовал трассировку стека. Спасибо

4. Это не устраняет вашу проблему, но я хотел уточнить, что Spring также будет обрабатывать транзакции с <tx:jta-transaction-manager /> , но это означает, что у вас не может быть источника данных или другого определения txManager в вашем XML-файле.