Browse Source

Remove DbActionExecutionException.

We now raise the exceptions from `NamedParameterJdbcTemplate` directly.

If you used to extract the `cause` of a `DbActionExecutionException` you should now catch that Exception directly.

Original pull request #1956
Closes #831

Signed-off-by: mipo256 <mikhailpolivakha@gmail.com>
pull/2065/head
mipo256 1 year ago committed by Mark Paluch
parent
commit
4e465972fb
No known key found for this signature in database
GPG Key ID: 55BC6374BAA9D973
  1. 16
      spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/AggregateChangeExecutor.java
  2. 7
      spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/AbstractJdbcAggregateTemplateIntegrationTests.java
  3. 5
      spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryConcurrencyIntegrationTests.java
  4. 81
      spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryIntegrationTests.java
  5. 7
      spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-db2.sql
  6. 6
      spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-h2.sql
  7. 6
      spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-hsql.sql
  8. 6
      spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-mariadb.sql
  9. 7
      spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-mssql.sql
  10. 6
      spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-mysql.sql
  11. 7
      spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-oracle.sql
  12. 7
      spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-postgres.sql
  13. 36
      spring-data-relational/src/test/java/org/springframework/data/relational/core/conversion/DbActionExecutionExceptionUnitTests.java

16
spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/AggregateChangeExecutor.java

@ -15,22 +15,21 @@
*/ */
package org.springframework.data.jdbc.core; package org.springframework.data.jdbc.core;
import org.springframework.dao.OptimisticLockingFailureException; import java.util.List;
import org.springframework.data.jdbc.core.convert.DataAccessStrategy; import org.springframework.data.jdbc.core.convert.DataAccessStrategy;
import org.springframework.data.jdbc.core.convert.JdbcConverter; import org.springframework.data.jdbc.core.convert.JdbcConverter;
import org.springframework.data.relational.core.conversion.AggregateChange; import org.springframework.data.relational.core.conversion.AggregateChange;
import org.springframework.data.relational.core.conversion.DbAction; import org.springframework.data.relational.core.conversion.DbAction;
import org.springframework.data.relational.core.conversion.DbActionExecutionException;
import org.springframework.data.relational.core.conversion.MutableAggregateChange; import org.springframework.data.relational.core.conversion.MutableAggregateChange;
import java.util.List;
/** /**
* Executes an {@link MutableAggregateChange}. * Executes an {@link MutableAggregateChange}.
* *
* @author Jens Schauder * @author Jens Schauder
* @author Myeonghyeon Lee * @author Myeonghyeon Lee
* @author Chirag Tailor * @author Chirag Tailor
* @author Mikhail Polivakha
* @since 2.0 * @since 2.0
*/ */
class AggregateChangeExecutor { class AggregateChangeExecutor {
@ -79,8 +78,6 @@ class AggregateChangeExecutor {
} }
private void execute(DbAction<?> action, JdbcAggregateChangeExecutionContext executionContext) { private void execute(DbAction<?> action, JdbcAggregateChangeExecutionContext executionContext) {
try {
if (action instanceof DbAction.InsertRoot<?> insertRoot) { if (action instanceof DbAction.InsertRoot<?> insertRoot) {
executionContext.executeInsertRoot(insertRoot); executionContext.executeInsertRoot(insertRoot);
} else if (action instanceof DbAction.BatchInsertRoot<?> batchInsertRoot) { } else if (action instanceof DbAction.BatchInsertRoot<?> batchInsertRoot) {
@ -110,12 +107,5 @@ class AggregateChangeExecutor {
} else { } else {
throw new RuntimeException("unexpected action"); throw new RuntimeException("unexpected action");
} }
} catch (Exception e) {
if (e instanceof OptimisticLockingFailureException) {
throw e;
}
throw new DbActionExecutionException(action, e);
}
} }
} }

7
spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/AbstractJdbcAggregateTemplateIntegrationTests.java

@ -563,9 +563,8 @@ abstract class AbstractJdbcAggregateTemplateIntegrationTests {
LegoSet entity = new LegoSet(); LegoSet entity = new LegoSet();
entity.id = 100L; // does not exist in the database entity.id = 100L; // does not exist in the database
assertThatExceptionOfType(DbActionExecutionException.class) // assertThatExceptionOfType(IncorrectUpdateSemanticsDataAccessException.class) //
.isThrownBy(() -> template.save(entity)) // .isThrownBy(() -> template.save(entity));
.withCauseInstanceOf(IncorrectUpdateSemanticsDataAccessException.class);
} }
@Test // DATAJDBC-112 @Test // DATAJDBC-112
@ -1165,7 +1164,7 @@ abstract class AbstractJdbcAggregateTemplateIntegrationTests {
aggregate.setVersion(null); aggregate.setVersion(null);
aggregate.setId(23L); aggregate.setId(23L);
assertThatThrownBy(() -> template.save(aggregate)).isInstanceOf(DbActionExecutionException.class); assertThatThrownBy(() -> template.save(aggregate)).isInstanceOf(IncorrectUpdateSemanticsDataAccessException.class);
} }
@Test // DATAJDBC-462 @Test // DATAJDBC-462

5
spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryConcurrencyIntegrationTests.java

@ -53,6 +53,7 @@ import org.springframework.transaction.support.TransactionTemplate;
* *
* @author Myeonghyeon Lee * @author Myeonghyeon Lee
* @author Jens Schauder * @author Jens Schauder
* @author Mikhail Polivakha
*/ */
@ExtendWith(SpringExtension.class) @ExtendWith(SpringExtension.class)
public class JdbcRepositoryConcurrencyIntegrationTests { public class JdbcRepositoryConcurrencyIntegrationTests {
@ -159,7 +160,7 @@ public class JdbcRepositoryConcurrencyIntegrationTests {
} catch (Exception ex) { } catch (Exception ex) {
// When the delete execution is complete, the Update execution throws an // When the delete execution is complete, the Update execution throws an
// IncorrectUpdateSemanticsDataAccessException. // IncorrectUpdateSemanticsDataAccessException.
if (ex.getCause() instanceof IncorrectUpdateSemanticsDataAccessException) { if (ex instanceof IncorrectUpdateSemanticsDataAccessException) {
return null; return null;
} }
throw ex; throw ex;
@ -193,7 +194,7 @@ public class JdbcRepositoryConcurrencyIntegrationTests {
} catch (Exception ex) { } catch (Exception ex) {
// When the delete execution is complete, the Update execution throws an // When the delete execution is complete, the Update execution throws an
// IncorrectUpdateSemanticsDataAccessException. // IncorrectUpdateSemanticsDataAccessException.
if (ex.getCause() instanceof IncorrectUpdateSemanticsDataAccessException) { if (ex instanceof IncorrectUpdateSemanticsDataAccessException) {
return null; return null;
} }
throw ex; throw ex;

81
spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryIntegrationTests.java

@ -15,10 +15,12 @@
*/ */
package org.springframework.data.jdbc.repository; package org.springframework.data.jdbc.repository;
import static java.util.Arrays.*; import static java.util.Arrays.asList;
import static java.util.Collections.*; import static java.util.Collections.emptyList;
import static org.assertj.core.api.Assertions.*; import static java.util.Collections.singletonList;
import static org.assertj.core.api.SoftAssertions.*; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.SoftAssertions.assertSoftly;
import java.io.IOException; import java.io.IOException;
import java.sql.ResultSet; import java.sql.ResultSet;
@ -37,6 +39,7 @@ import java.util.Set;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
@ -49,9 +52,21 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.ClassPathResource;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.dao.IncorrectResultSizeDataAccessException; import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.data.annotation.Id; import org.springframework.data.annotation.Id;
import org.springframework.data.domain.*; import org.springframework.data.annotation.Transient;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.ExampleMatcher;
import org.springframework.data.domain.Limit;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Persistable;
import org.springframework.data.domain.ScrollPosition;
import org.springframework.data.domain.Slice;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Window;
import org.springframework.data.jdbc.core.mapping.AggregateReference; import org.springframework.data.jdbc.core.mapping.AggregateReference;
import org.springframework.data.jdbc.repository.query.Modifying; import org.springframework.data.jdbc.repository.query.Modifying;
import org.springframework.data.jdbc.repository.query.Query; import org.springframework.data.jdbc.repository.query.Query;
@ -64,8 +79,8 @@ import org.springframework.data.jdbc.testing.TestConfiguration;
import org.springframework.data.jdbc.testing.TestDatabaseFeatures; import org.springframework.data.jdbc.testing.TestDatabaseFeatures;
import org.springframework.data.relational.core.mapping.Column; import org.springframework.data.relational.core.mapping.Column;
import org.springframework.data.relational.core.mapping.MappedCollection; import org.springframework.data.relational.core.mapping.MappedCollection;
import org.springframework.data.relational.core.mapping.Table;
import org.springframework.data.relational.core.mapping.Sequence; import org.springframework.data.relational.core.mapping.Sequence;
import org.springframework.data.relational.core.mapping.Table;
import org.springframework.data.relational.core.mapping.event.AbstractRelationalEvent; import org.springframework.data.relational.core.mapping.event.AbstractRelationalEvent;
import org.springframework.data.relational.core.mapping.event.AfterConvertEvent; import org.springframework.data.relational.core.mapping.event.AfterConvertEvent;
import org.springframework.data.relational.core.sql.LockMode; import org.springframework.data.relational.core.sql.LockMode;
@ -104,6 +119,8 @@ public class JdbcRepositoryIntegrationTests {
@Autowired NamedParameterJdbcTemplate template; @Autowired NamedParameterJdbcTemplate template;
@Autowired DummyEntityRepository repository; @Autowired DummyEntityRepository repository;
@Autowired ProvidedIdEntityRepository providedIdEntityRepository;
@Autowired MyEventListener eventListener; @Autowired MyEventListener eventListener;
@Autowired RootRepository rootRepository; @Autowired RootRepository rootRepository;
@Autowired WithDelimitedColumnRepository withDelimitedColumnRepository; @Autowired WithDelimitedColumnRepository withDelimitedColumnRepository;
@ -208,6 +225,18 @@ public class JdbcRepositoryIntegrationTests {
.containsExactlyInAnyOrder(entity.getIdProp(), other.getIdProp()); .containsExactlyInAnyOrder(entity.getIdProp(), other.getIdProp());
} }
@Test // DATAJDBC-611
public void testDuplicateKeyExceptionIsThrownInCaseOfUniqueKeyViolation() {
// given.
ProvidedIdEntity first = ProvidedIdEntity.newInstance(1L, "name");
ProvidedIdEntity second = ProvidedIdEntity.newInstance(1L, "other");
// when/then
Assertions.assertThatCode(() -> providedIdEntityRepository.save(first)).doesNotThrowAnyException();
Assertions.assertThatThrownBy(() -> providedIdEntityRepository.save(second)).isInstanceOf(DuplicateKeyException.class);
}
@Test // DATAJDBC-97 @Test // DATAJDBC-97
public void countsEntities() { public void countsEntities() {
@ -1436,6 +1465,10 @@ public class JdbcRepositoryIntegrationTests {
String getName(); String getName();
} }
interface ProvidedIdEntityRepository extends CrudRepository<ProvidedIdEntity, Long> {
}
interface DummyEntityRepository extends CrudRepository<DummyEntity, Long>, QueryByExampleExecutor<DummyEntity> { interface DummyEntityRepository extends CrudRepository<DummyEntity, Long>, QueryByExampleExecutor<DummyEntity> {
@Lock(LockMode.PESSIMISTIC_WRITE) @Lock(LockMode.PESSIMISTIC_WRITE)
@ -1543,6 +1576,11 @@ public class JdbcRepositoryIntegrationTests {
return factory.getRepository(DummyEntityRepository.class); return factory.getRepository(DummyEntityRepository.class);
} }
@Bean
ProvidedIdEntityRepository providedIdEntityRepository() {
return factory.getRepository(ProvidedIdEntityRepository.class);
}
@Bean @Bean
RootRepository rootRepository() { RootRepository rootRepository() {
return factory.getRepository(RootRepository.class); return factory.getRepository(RootRepository.class);
@ -1886,6 +1924,37 @@ public class JdbcRepositoryIntegrationTests {
} }
} }
static class ProvidedIdEntity implements Persistable<Long> {
@Id
private final Long id;
private String name;
@Transient
private boolean isNew;
private ProvidedIdEntity(Long id, String name, boolean isNew) {
this.id = id;
this.name = name;
this.isNew = isNew;
}
private static ProvidedIdEntity newInstance(Long id, String name) {
return new ProvidedIdEntity(id, name, true);
}
@Override
public Long getId() {
return id;
}
@Override
public boolean isNew() {
return isNew;
}
}
static class DummyEntity { static class DummyEntity {
String name; String name;

7
spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-db2.sql

@ -5,6 +5,7 @@ DROP TABLE LEAF;
DROP TABLE WITH_DELIMITED_COLUMN; DROP TABLE WITH_DELIMITED_COLUMN;
DROP TABLE ENTITY_WITH_SEQUENCE; DROP TABLE ENTITY_WITH_SEQUENCE;
DROP SEQUENCE ENTITY_SEQUENCE; DROP SEQUENCE ENTITY_SEQUENCE;
DROP TABLE PROVIDED_ID_ENTITY;
CREATE TABLE dummy_entity CREATE TABLE dummy_entity
( (
@ -55,4 +56,8 @@ CREATE TABLE ENTITY_WITH_SEQUENCE
NAME VARCHAR(100) NAME VARCHAR(100)
); );
CREATE SEQUENCE ENTITY_SEQUENCE START WITH 1 INCREMENT BY 1 NO MAXVALUE; CREATE TABLE PROVIDED_ID_ENTITY
(
ID BIGINT PRIMARY KEY,
NAME VARCHAR(30)
);

6
spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-h2.sql

@ -48,3 +48,9 @@ CREATE TABLE ENTITY_WITH_SEQUENCE
); );
CREATE SEQUENCE ENTITY_SEQUENCE START WITH 1 INCREMENT BY 1 NO MAXVALUE; CREATE SEQUENCE ENTITY_SEQUENCE START WITH 1 INCREMENT BY 1 NO MAXVALUE;
CREATE TABLE PROVIDED_ID_ENTITY
(
ID BIGINT PRIMARY KEY,
NAME VARCHAR(30)
);

6
spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-hsql.sql

@ -48,3 +48,9 @@ CREATE TABLE ENTITY_WITH_SEQUENCE
); );
CREATE SEQUENCE ENTITY_SEQUENCE START WITH 1 INCREMENT BY 1 NO MAXVALUE; CREATE SEQUENCE ENTITY_SEQUENCE START WITH 1 INCREMENT BY 1 NO MAXVALUE;
CREATE TABLE PROVIDED_ID_ENTITY
(
ID BIGINT PRIMARY KEY,
NAME VARCHAR(30)
);

6
spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-mariadb.sql

@ -48,3 +48,9 @@ CREATE TABLE ENTITY_WITH_SEQUENCE
); );
CREATE SEQUENCE `ENTITY_SEQUENCE` START WITH 1 INCREMENT BY 1 NO MAXVALUE; CREATE SEQUENCE `ENTITY_SEQUENCE` START WITH 1 INCREMENT BY 1 NO MAXVALUE;
CREATE TABLE PROVIDED_ID_ENTITY
(
ID BIGINT PRIMARY KEY,
NAME VARCHAR(30)
);

7
spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-mssql.sql

@ -5,6 +5,7 @@ DROP TABLE IF EXISTS LEAF;
DROP TABLE IF EXISTS WITH_DELIMITED_COLUMN; DROP TABLE IF EXISTS WITH_DELIMITED_COLUMN;
DROP TABLE IF EXISTS ENTITY_WITH_SEQUENCE; DROP TABLE IF EXISTS ENTITY_WITH_SEQUENCE;
DROP SEQUENCE IF EXISTS ENTITY_SEQUENCE; DROP SEQUENCE IF EXISTS ENTITY_SEQUENCE;
DROP TABLE IF EXISTS PROVIDED_ID_ENTITY;
CREATE TABLE dummy_entity CREATE TABLE dummy_entity
( (
@ -56,3 +57,9 @@ CREATE TABLE ENTITY_WITH_SEQUENCE
); );
CREATE SEQUENCE ENTITY_SEQUENCE START WITH 1 INCREMENT BY 1 NO MAXVALUE; CREATE SEQUENCE ENTITY_SEQUENCE START WITH 1 INCREMENT BY 1 NO MAXVALUE;
CREATE TABLE PROVIDED_ID_ENTITY
(
ID BIGINT PRIMARY KEY,
NAME VARCHAR(30)
);

6
spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-mysql.sql

@ -43,3 +43,9 @@ CREATE TABLE WITH_DELIMITED_COLUMN
`ORG.XTUNIT.IDENTIFIER` VARCHAR(100), `ORG.XTUNIT.IDENTIFIER` VARCHAR(100),
STYPE VARCHAR(100) STYPE VARCHAR(100)
); );
CREATE TABLE PROVIDED_ID_ENTITY
(
ID BIGINT PRIMARY KEY,
NAME VARCHAR(30)
);

7
spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-oracle.sql

@ -5,6 +5,7 @@ DROP TABLE LEAF CASCADE CONSTRAINTS PURGE;
DROP TABLE WITH_DELIMITED_COLUMN CASCADE CONSTRAINTS PURGE; DROP TABLE WITH_DELIMITED_COLUMN CASCADE CONSTRAINTS PURGE;
DROP TABLE ENTITY_WITH_SEQUENCE CASCADE CONSTRAINTS PURGE; DROP TABLE ENTITY_WITH_SEQUENCE CASCADE CONSTRAINTS PURGE;
DROP SEQUENCE ENTITY_SEQUENCE; DROP SEQUENCE ENTITY_SEQUENCE;
DROP TABLE PROVIDED_ID_ENTITY CASCADE CONSTRAINTS PURGE;
CREATE TABLE DUMMY_ENTITY CREATE TABLE DUMMY_ENTITY
( (
@ -56,3 +57,9 @@ CREATE TABLE ENTITY_WITH_SEQUENCE
); );
CREATE SEQUENCE ENTITY_SEQUENCE START WITH 1 INCREMENT BY 1; CREATE SEQUENCE ENTITY_SEQUENCE START WITH 1 INCREMENT BY 1;
CREATE TABLE PROVIDED_ID_ENTITY
(
ID BIGINT PRIMARY KEY,
NAME VARCHAR(30)
);

7
spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-postgres.sql

@ -5,6 +5,7 @@ DROP TABLE LEAF;
DROP TABLE WITH_DELIMITED_COLUMN; DROP TABLE WITH_DELIMITED_COLUMN;
DROP TABLE ENTITY_WITH_SEQUENCE; DROP TABLE ENTITY_WITH_SEQUENCE;
DROP SEQUENCE ENTITY_SEQUENCE; DROP SEQUENCE ENTITY_SEQUENCE;
DROP TABLE PROVIDED_ID_ENTITY;
CREATE TABLE dummy_entity CREATE TABLE dummy_entity
( (
@ -56,3 +57,9 @@ CREATE TABLE ENTITY_WITH_SEQUENCE
); );
CREATE SEQUENCE "ENTITY_SEQUENCE" START WITH 1 INCREMENT BY 1 NO MAXVALUE; CREATE SEQUENCE "ENTITY_SEQUENCE" START WITH 1 INCREMENT BY 1 NO MAXVALUE;
CREATE TABLE PROVIDED_ID_ENTITY
(
ID BIGINT PRIMARY KEY,
NAME VARCHAR(30)
);

36
spring-data-relational/src/test/java/org/springframework/data/relational/core/conversion/DbActionExecutionExceptionUnitTests.java

@ -1,36 +0,0 @@
/*
* Copyright 2018-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.relational.core.conversion;
import org.junit.jupiter.api.Test;
import static org.mockito.Mockito.*;
/**
* Unit test for {@link DbActionExecutionException}.
*
* @author Jens Schauder
*/
public class DbActionExecutionExceptionUnitTests {
@Test // DATAJDBC-162
public void constructorWorksWithNullPropertyPath() {
DbAction<?> action = mock(DbAction.class);
new DbActionExecutionException(action, null);
}
}
Loading…
Cancel
Save