|
32 | 32 | import java.util.Collections;
|
33 | 33 | import java.util.List;
|
34 | 34 | import java.util.Map;
|
| 35 | +import java.util.function.Consumer; |
35 | 36 |
|
36 | 37 | import javax.sql.DataSource;
|
37 | 38 |
|
| 39 | +import org.assertj.core.data.Index; |
38 | 40 | import org.junit.jupiter.api.BeforeEach;
|
39 | 41 | import org.junit.jupiter.api.Test;
|
40 | 42 |
|
41 | 43 | import org.springframework.dao.DataAccessException;
|
| 44 | +import org.springframework.dao.DuplicateKeyException; |
42 | 45 | import org.springframework.dao.InvalidDataAccessApiUsageException;
|
43 | 46 | import org.springframework.jdbc.BadSqlGrammarException;
|
44 | 47 | import org.springframework.jdbc.CannotGetJdbcConnectionException;
|
@@ -799,6 +802,55 @@ void testBatchUpdateWithCollectionOfObjects() throws Exception {
|
799 | 802 | verify(this.connection, atLeastOnce()).close();
|
800 | 803 | }
|
801 | 804 |
|
| 805 | + @Test |
| 806 | + void testBatchUpdateWithBatchFailingHasUpdateCounts() throws Exception { |
| 807 | + test3BatchesOf2ItemsFailing(exception -> assertThat(exception).cause() |
| 808 | + .isInstanceOfSatisfying(AggregatedBatchUpdateException.class, ex -> { |
| 809 | + assertThat(ex.getSuccessfulUpdateCounts()).hasDimensions(1, 2) |
| 810 | + .contains(new int[] { 1, 1 }, Index.atIndex(0)); |
| 811 | + assertThat(ex.getUpdateCounts()).contains(-3, -3); |
| 812 | + })); |
| 813 | + } |
| 814 | + |
| 815 | + @Test |
| 816 | + void testBatchUpdateWithBatchFailingMatchesOriginalException() throws Exception { |
| 817 | + test3BatchesOf2ItemsFailing(exception -> assertThat(exception).cause() |
| 818 | + .isInstanceOfSatisfying(AggregatedBatchUpdateException.class, ex -> { |
| 819 | + BatchUpdateException originalException = ex.getOriginalException(); |
| 820 | + assertThat(ex.getMessage()).isEqualTo(originalException.getMessage()); |
| 821 | + assertThat(ex.getCause()).isEqualTo(originalException.getCause()); |
| 822 | + assertThat(ex.getSQLState()).isEqualTo(originalException.getSQLState()); |
| 823 | + assertThat(ex.getErrorCode()).isEqualTo(originalException.getErrorCode()); |
| 824 | + assertThat((Exception) ex.getNextException()).isSameAs(originalException.getNextException()); |
| 825 | + assertThat(ex.getSuppressed()).isEqualTo(originalException.getSuppressed()); |
| 826 | + })); |
| 827 | + } |
| 828 | + |
| 829 | + void test3BatchesOf2ItemsFailing(Consumer<Exception> exception) throws Exception { |
| 830 | + String sql = "INSERT INTO NOSUCHTABLE values (?)"; |
| 831 | + List<Integer> ids = Arrays.asList(1, 2, 3, 2, 4, 5); |
| 832 | + int[] rowsAffected = new int[] {1, 1}; |
| 833 | + |
| 834 | + given(this.preparedStatement.executeBatch()).willReturn(rowsAffected).willThrow(new BatchUpdateException( |
| 835 | + "duplicate key value violates unique constraint \"NOSUCHTABLE_pkey\" Detail: Key (id)=(2) already exists.", |
| 836 | + "23505", 0, new int[] { -3, -3 })); |
| 837 | + mockDatabaseMetaData(true); |
| 838 | + |
| 839 | + ParameterizedPreparedStatementSetter<Integer> setter = (ps, argument) -> ps.setInt(1, argument); |
| 840 | + JdbcTemplate template = new JdbcTemplate(this.dataSource, false); |
| 841 | + |
| 842 | + assertThatExceptionOfType(DuplicateKeyException.class) |
| 843 | + .isThrownBy(() -> template.batchUpdate(sql, ids, 2, setter)) |
| 844 | + .satisfies(exception); |
| 845 | + verify(this.preparedStatement, times(4)).addBatch(); |
| 846 | + verify(this.preparedStatement).setInt(1, 1); |
| 847 | + verify(this.preparedStatement, times(2)).setInt(1, 2); |
| 848 | + verify(this.preparedStatement).setInt(1, 3); |
| 849 | + verify(this.preparedStatement, times(2)).executeBatch(); |
| 850 | + verify(this.preparedStatement).close(); |
| 851 | + verify(this.connection, atLeastOnce()).close(); |
| 852 | + } |
| 853 | + |
802 | 854 | @Test
|
803 | 855 | void testCouldNotGetConnectionForOperationOrExceptionTranslator() throws SQLException {
|
804 | 856 | SQLException sqlException = new SQLException("foo", "07xxx");
|
|
0 commit comments