Browse Source

Introduced pessimistic locks for derived queries.

Methods which use the derive query functionality now can be annotated with `@Lock` to used a given `LockMode`. Right now there are two different modes `PESSIMISTIC_READ` and `PESSIMISTIC_WRITE`. Based on the dialect the right select is generated. For example for HSQLDB `Select ... FOR UPDATE`.

See #1041
Original pull request #1158
pull/1166/head
Diego Krupitza 4 years ago committed by Jens Schauder
parent
commit
e68c3557c0
No known key found for this signature in database
GPG Key ID: 45CC872F17423DBF
  1. 9
      spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/JdbcCountQueryCreator.java
  2. 15
      spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/JdbcQueryCreator.java
  3. 20
      spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/JdbcQueryMethod.java
  4. 39
      spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/Lock.java
  5. 7
      spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/PartTreeJdbcQuery.java
  6. 16
      spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryIntegrationTests.java
  7. 35
      spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/query/JdbcQueryMethodUnitTests.java
  8. 56
      spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/query/PartTreeJdbcQueryUnitTests.java

9
spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/JdbcCountQueryCreator.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2021 the original author or authors. * Copyright 2021-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -30,18 +30,21 @@ import org.springframework.data.relational.repository.query.RelationalParameterA
import org.springframework.data.repository.query.ReturnedType; import org.springframework.data.repository.query.ReturnedType;
import org.springframework.data.repository.query.parser.PartTree; import org.springframework.data.repository.query.parser.PartTree;
import java.util.Optional;
/** /**
* {@link JdbcQueryCreator} that creates {@code COUNT(*)} queries without applying limit/offset and {@link Sort}. * {@link JdbcQueryCreator} that creates {@code COUNT(*)} queries without applying limit/offset and {@link Sort}.
* *
* @author Mark Paluch * @author Mark Paluch
* @author Diego Krupitza
* @since 2.2 * @since 2.2
*/ */
class JdbcCountQueryCreator extends JdbcQueryCreator { class JdbcCountQueryCreator extends JdbcQueryCreator {
JdbcCountQueryCreator(RelationalMappingContext context, PartTree tree, JdbcConverter converter, Dialect dialect, JdbcCountQueryCreator(RelationalMappingContext context, PartTree tree, JdbcConverter converter, Dialect dialect,
RelationalEntityMetadata<?> entityMetadata, RelationalParameterAccessor accessor, boolean isSliceQuery, RelationalEntityMetadata<?> entityMetadata, RelationalParameterAccessor accessor, boolean isSliceQuery,
ReturnedType returnedType) { ReturnedType returnedType, Optional<Lock> lockMode) {
super(context, tree, converter, dialect, entityMetadata, accessor, isSliceQuery, returnedType); super(context, tree, converter, dialect, entityMetadata, accessor, isSliceQuery, returnedType, lockMode);
} }
@Override @Override

15
spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/JdbcQueryCreator.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2020-2021 the original author or authors. * Copyright 2020-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -18,6 +18,7 @@ package org.springframework.data.jdbc.repository.query;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.Optional;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort;
@ -57,6 +58,7 @@ import org.springframework.util.Assert;
* @author Mark Paluch * @author Mark Paluch
* @author Jens Schauder * @author Jens Schauder
* @author Myeonghyeon Lee * @author Myeonghyeon Lee
* @author Diego Krupitza
* @since 2.0 * @since 2.0
*/ */
class JdbcQueryCreator extends RelationalQueryCreator<ParametrizedQuery> { class JdbcQueryCreator extends RelationalQueryCreator<ParametrizedQuery> {
@ -69,6 +71,7 @@ class JdbcQueryCreator extends RelationalQueryCreator<ParametrizedQuery> {
private final RenderContextFactory renderContextFactory; private final RenderContextFactory renderContextFactory;
private final boolean isSliceQuery; private final boolean isSliceQuery;
private final ReturnedType returnedType; private final ReturnedType returnedType;
private final Optional<Lock> lockMode;
/** /**
* Creates new instance of this class with the given {@link PartTree}, {@link JdbcConverter}, {@link Dialect}, * Creates new instance of this class with the given {@link PartTree}, {@link JdbcConverter}, {@link Dialect},
@ -85,7 +88,7 @@ class JdbcQueryCreator extends RelationalQueryCreator<ParametrizedQuery> {
*/ */
JdbcQueryCreator(RelationalMappingContext context, PartTree tree, JdbcConverter converter, Dialect dialect, JdbcQueryCreator(RelationalMappingContext context, PartTree tree, JdbcConverter converter, Dialect dialect,
RelationalEntityMetadata<?> entityMetadata, RelationalParameterAccessor accessor, boolean isSliceQuery, RelationalEntityMetadata<?> entityMetadata, RelationalParameterAccessor accessor, boolean isSliceQuery,
ReturnedType returnedType) { ReturnedType returnedType, Optional<Lock> lockMode) {
super(tree, accessor); super(tree, accessor);
Assert.notNull(converter, "JdbcConverter must not be null"); Assert.notNull(converter, "JdbcConverter must not be null");
@ -102,6 +105,7 @@ class JdbcQueryCreator extends RelationalQueryCreator<ParametrizedQuery> {
this.renderContextFactory = new RenderContextFactory(dialect); this.renderContextFactory = new RenderContextFactory(dialect);
this.isSliceQuery = isSliceQuery; this.isSliceQuery = isSliceQuery;
this.returnedType = returnedType; this.returnedType = returnedType;
this.lockMode = lockMode;
} }
/** /**
@ -168,7 +172,12 @@ class JdbcQueryCreator extends RelationalQueryCreator<ParametrizedQuery> {
whereBuilder); whereBuilder);
selectOrderBuilder = applyOrderBy(sort, entity, table, selectOrderBuilder); selectOrderBuilder = applyOrderBy(sort, entity, table, selectOrderBuilder);
Select select = selectOrderBuilder.build(); SelectBuilder.BuildSelect completedBuildSelect = selectOrderBuilder;
if (this.lockMode.isPresent()) {
completedBuildSelect = selectOrderBuilder.lock(this.lockMode.get().value());
}
Select select = completedBuildSelect.build();
String sql = SqlRenderer.create(renderContextFactory.createRenderContext()).render(select); String sql = SqlRenderer.create(renderContextFactory.createRenderContext()).render(select);

20
spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/JdbcQueryMethod.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2020-2021 the original author or authors. * Copyright 2020-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -47,6 +47,7 @@ import org.springframework.util.StringUtils;
* @author Kazuki Shimizu * @author Kazuki Shimizu
* @author Moises Cisneros * @author Moises Cisneros
* @author Hebert Coelho * @author Hebert Coelho
* @author Diego Krupitza
*/ */
public class JdbcQueryMethod extends QueryMethod { public class JdbcQueryMethod extends QueryMethod {
@ -168,7 +169,6 @@ public class JdbcQueryMethod extends QueryMethod {
return StringUtils.hasText(annotatedName) ? annotatedName : super.getNamedQueryName(); return StringUtils.hasText(annotatedName) ? annotatedName : super.getNamedQueryName();
} }
/** /**
* Returns the class to be used as {@link org.springframework.jdbc.core.RowMapper} * Returns the class to be used as {@link org.springframework.jdbc.core.RowMapper}
* *
@ -245,6 +245,22 @@ public class JdbcQueryMethod extends QueryMethod {
return doFindAnnotation(Query.class); return doFindAnnotation(Query.class);
} }
/**
* @return is a {@link Lock} annotation present or not.
*/
public boolean hasLockMode() {
return lookupLockAnnotation().isPresent();
}
/**
* Looks up the {@link Lock} annotation from the query method.
*
* @return the {@link Optional} wrapped {@link Lock} annotation.
*/
Optional<Lock> lookupLockAnnotation() {
return doFindAnnotation(Lock.class);
}
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private <A extends Annotation> Optional<A> doFindAnnotation(Class<A> annotationType) { private <A extends Annotation> Optional<A> doFindAnnotation(Class<A> annotationType) {

39
spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/Lock.java

@ -0,0 +1,39 @@
/*
* Copyright 2022 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.jdbc.repository.query;
import org.springframework.data.annotation.QueryAnnotation;
import org.springframework.data.relational.core.sql.LockMode;
import java.lang.annotation.*;
/**
* Annotation to provide a lock mode for a given query.
*
* @author Diego Krupitza
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@QueryAnnotation
@Documented
public @interface Lock {
/**
* Defines which type of {@link LockMode} we want to use.
*/
LockMode value() default LockMode.PESSIMISTIC_READ;
}

7
spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/PartTreeJdbcQuery.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2020-2021 the original author or authors. * Copyright 2020-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -50,6 +50,7 @@ import org.springframework.util.Assert;
* *
* @author Mark Paluch * @author Mark Paluch
* @author Jens Schauder * @author Jens Schauder
* @author Diego Krupitza
* @since 2.0 * @since 2.0
*/ */
public class PartTreeJdbcQuery extends AbstractJdbcQuery { public class PartTreeJdbcQuery extends AbstractJdbcQuery {
@ -163,7 +164,7 @@ public class PartTreeJdbcQuery extends AbstractJdbcQuery {
RelationalEntityMetadata<?> entityMetadata = getQueryMethod().getEntityInformation(); RelationalEntityMetadata<?> entityMetadata = getQueryMethod().getEntityInformation();
JdbcCountQueryCreator queryCreator = new JdbcCountQueryCreator(context, tree, converter, dialect, JdbcCountQueryCreator queryCreator = new JdbcCountQueryCreator(context, tree, converter, dialect,
entityMetadata, accessor, false, processor.getReturnedType()); entityMetadata, accessor, false, processor.getReturnedType(), getQueryMethod().lookupLockAnnotation());
ParametrizedQuery countQuery = queryCreator.createQuery(Sort.unsorted()); ParametrizedQuery countQuery = queryCreator.createQuery(Sort.unsorted());
Object count = singleObjectQuery((rs, i) -> rs.getLong(1)).execute(countQuery.getQuery(), Object count = singleObjectQuery((rs, i) -> rs.getLong(1)).execute(countQuery.getQuery(),
@ -181,7 +182,7 @@ public class PartTreeJdbcQuery extends AbstractJdbcQuery {
RelationalEntityMetadata<?> entityMetadata = getQueryMethod().getEntityInformation(); RelationalEntityMetadata<?> entityMetadata = getQueryMethod().getEntityInformation();
JdbcQueryCreator queryCreator = new JdbcQueryCreator(context, tree, converter, dialect, entityMetadata, accessor, JdbcQueryCreator queryCreator = new JdbcQueryCreator(context, tree, converter, dialect, entityMetadata, accessor,
getQueryMethod().isSliceQuery(), returnedType); getQueryMethod().isSliceQuery(), returnedType, this.getQueryMethod().lookupLockAnnotation());
return queryCreator.createQuery(getDynamicSort(accessor)); return queryCreator.createQuery(getDynamicSort(accessor));
} }

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

@ -1,5 +1,5 @@
/* /*
* Copyright 2017-2021 the original author or authors. * Copyright 2017-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -51,6 +51,7 @@ import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice; import org.springframework.data.domain.Slice;
import org.springframework.data.jdbc.core.mapping.AggregateReference; import org.springframework.data.jdbc.core.mapping.AggregateReference;
import org.springframework.data.jdbc.repository.query.Lock;
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;
import org.springframework.data.jdbc.repository.support.JdbcRepositoryFactory; import org.springframework.data.jdbc.repository.support.JdbcRepositoryFactory;
@ -61,6 +62,7 @@ import org.springframework.data.jdbc.testing.TestDatabaseFeatures;
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.mapping.event.AfterLoadEvent; import org.springframework.data.relational.core.mapping.event.AfterLoadEvent;
import org.springframework.data.relational.core.sql.LockMode;
import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.core.NamedQueries; import org.springframework.data.repository.core.NamedQueries;
import org.springframework.data.repository.core.support.PropertiesBasedNamedQueries; import org.springframework.data.repository.core.support.PropertiesBasedNamedQueries;
@ -331,6 +333,13 @@ public class JdbcRepositoryIntegrationTests {
assertThat(repository.findAllByNamedQuery()).hasSize(1); assertThat(repository.findAllByNamedQuery()).hasSize(1);
} }
@Test
void findAllByFirstnameWithLock() {
DummyEntity dummyEntity = createDummyEntity();
repository.save(dummyEntity);
assertThat(repository.findAllByName(dummyEntity.getName())).hasSize(1);
}
@Test // GH-1022 @Test // GH-1022
public void findAllByCustomQueryName() { public void findAllByCustomQueryName() {
@ -574,7 +583,11 @@ public class JdbcRepositoryIntegrationTests {
interface DummyEntityRepository extends CrudRepository<DummyEntity, Long> { interface DummyEntityRepository extends CrudRepository<DummyEntity, Long> {
@Lock(LockMode.PESSIMISTIC_WRITE)
List<DummyEntity> findAllByName(String name);
List<DummyEntity> findAllByNamedQuery(); List<DummyEntity> findAllByNamedQuery();
@Query(name = "DummyEntity.customQuery") @Query(name = "DummyEntity.customQuery")
List<DummyEntity> findAllByCustomNamedQuery(); List<DummyEntity> findAllByCustomNamedQuery();
@ -624,6 +637,7 @@ public class JdbcRepositoryIntegrationTests {
List<DummyEntity> findByFlagTrue(); List<DummyEntity> findByFlagTrue();
List<DummyEntity> findByRef(int ref); List<DummyEntity> findByRef(int ref);
List<DummyEntity> findByRef(AggregateReference<DummyEntity, Long> ref); List<DummyEntity> findByRef(AggregateReference<DummyEntity, Long> ref);
} }

35
spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/query/JdbcQueryMethodUnitTests.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2020-2021 the original author or authors. * Copyright 2020-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -28,6 +28,7 @@ import org.junit.jupiter.api.Test;
import org.springframework.data.jdbc.core.mapping.JdbcMappingContext; import org.springframework.data.jdbc.core.mapping.JdbcMappingContext;
import org.springframework.data.projection.ProjectionFactory; import org.springframework.data.projection.ProjectionFactory;
import org.springframework.data.relational.core.sql.LockMode;
import org.springframework.data.repository.core.NamedQueries; import org.springframework.data.repository.core.NamedQueries;
import org.springframework.data.repository.core.RepositoryMetadata; import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.core.support.PropertiesBasedNamedQueries; import org.springframework.data.repository.core.support.PropertiesBasedNamedQueries;
@ -41,6 +42,7 @@ import org.springframework.jdbc.core.RowMapper;
* @author Oliver Gierke * @author Oliver Gierke
* @author Moises Cisneros * @author Moises Cisneros
* @author Mark Paluch * @author Mark Paluch
* @author Diego Krupitza
*/ */
public class JdbcQueryMethodUnitTests { public class JdbcQueryMethodUnitTests {
@ -120,6 +122,37 @@ public class JdbcQueryMethodUnitTests {
assertThat(queryMethod.getDeclaredQuery()).isEqualTo(null); assertThat(queryMethod.getDeclaredQuery()).isEqualTo(null);
} }
@Test // GH-1041
void returnsQueryMethodWithLock() throws NoSuchMethodException {
JdbcQueryMethod queryMethodWithWriteLock = createJdbcQueryMethod("queryMethodWithWriteLock");
JdbcQueryMethod queryMethodWithReadLock = createJdbcQueryMethod("queryMethodWithReadLock");
assertThat(queryMethodWithWriteLock.hasLockMode()).isTrue();
assertThat(queryMethodWithReadLock.hasLockMode()).isTrue();
}
@Test // GH-1041
void returnsQueryMethodWithCorrectLockType() throws NoSuchMethodException {
JdbcQueryMethod queryMethodWithWriteLock = createJdbcQueryMethod("queryMethodWithWriteLock");
JdbcQueryMethod queryMethodWithReadLock = createJdbcQueryMethod("queryMethodWithReadLock");
assertThat(queryMethodWithWriteLock.lookupLockAnnotation()).isPresent();
assertThat(queryMethodWithReadLock.lookupLockAnnotation()).isPresent();
assertThat(queryMethodWithWriteLock.lookupLockAnnotation().get().value()).isEqualTo(LockMode.PESSIMISTIC_WRITE);
assertThat(queryMethodWithReadLock.lookupLockAnnotation().get().value()).isEqualTo(LockMode.PESSIMISTIC_READ);
}
@Lock(LockMode.PESSIMISTIC_WRITE)
@Query
private void queryMethodWithWriteLock() {}
@Lock(LockMode.PESSIMISTIC_READ)
@Query
private void queryMethodWithReadLock() {}
@Query(value = QUERY, rowMapperClass = CustomRowMapper.class) @Query(value = QUERY, rowMapperClass = CustomRowMapper.class)
private void queryMethod() {} private void queryMethod() {}

56
spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/query/PartTreeJdbcQueryUnitTests.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2020-2021 the original author or authors. * Copyright 2020-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -42,6 +42,8 @@ import org.springframework.data.relational.core.dialect.H2Dialect;
import org.springframework.data.relational.core.mapping.Embedded; import org.springframework.data.relational.core.mapping.Embedded;
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.Table;
import org.springframework.data.relational.core.sql.In;
import org.springframework.data.relational.core.sql.LockMode;
import org.springframework.data.relational.repository.query.RelationalParametersParameterAccessor; import org.springframework.data.relational.repository.query.RelationalParametersParameterAccessor;
import org.springframework.data.repository.NoRepositoryBean; import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.Repository; import org.springframework.data.repository.Repository;
@ -58,6 +60,7 @@ import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
* @author Mark Paluch * @author Mark Paluch
* @author Jens Schauder * @author Jens Schauder
* @author Myeonghyeon Lee * @author Myeonghyeon Lee
* @author Diego Krupitza
*/ */
@ExtendWith(MockitoExtension.class) @ExtendWith(MockitoExtension.class)
public class PartTreeJdbcQueryUnitTests { public class PartTreeJdbcQueryUnitTests {
@ -96,6 +99,47 @@ public class PartTreeJdbcQueryUnitTests {
}); });
} }
@Test // GH-922
void createQueryWithPessimisticWriteLock() throws Exception {
JdbcQueryMethod queryMethod = getQueryMethod("findAllByFirstNameAndLastName", String.class, String.class);
PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod);
String firstname = "Diego";
String lastname = "Krupitza";
ParametrizedQuery query = jdbcQuery.createQuery(getAccessor(queryMethod, new Object[] { firstname, lastname }),
returnedType);
assertSoftly(softly -> {
softly.assertThat(query.getQuery().toUpperCase()).endsWith("FOR UPDATE");
softly.assertThat(query.getParameterSource().getValue("first_name")).isEqualTo(firstname);
softly.assertThat(query.getParameterSource().getValue("last_name")).isEqualTo(lastname);
});
}
@Test // GH-922
void createQueryWithPessimisticReadLock() throws Exception {
JdbcQueryMethod queryMethod = getQueryMethod("findAllByFirstNameAndAge", String.class, Integer.class);
PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod);
String firstname = "Diego";
Integer age = 22;
ParametrizedQuery query = jdbcQuery.createQuery(getAccessor(queryMethod, new Object[] { firstname, age }),
returnedType);
assertSoftly(softly -> {
// this is also for update since h2 dialect does not distinguish between lockmodes
softly.assertThat(query.getQuery().toUpperCase()).endsWith("FOR UPDATE");
softly.assertThat(query.getParameterSource().getValue("first_name")).isEqualTo(firstname);
softly.assertThat(query.getParameterSource().getValue("age")).isEqualTo(age);
});
}
@Test // DATAJDBC-318 @Test // DATAJDBC-318
public void shouldFailForQueryByList() throws Exception { public void shouldFailForQueryByList() throws Exception {
@ -213,7 +257,6 @@ public class PartTreeJdbcQueryUnitTests {
+ ".\"FIRST_NAME\" = :first_name)"); + ".\"FIRST_NAME\" = :first_name)");
} }
@Test // DATAJDBC-318 @Test // DATAJDBC-318
public void createsQueryToFindAllEntitiesByDateAttributeBetween() throws Exception { public void createsQueryToFindAllEntitiesByDateAttributeBetween() throws Exception {
@ -644,6 +687,12 @@ public class PartTreeJdbcQueryUnitTests {
@NoRepositoryBean @NoRepositoryBean
interface UserRepository extends Repository<User, Long> { interface UserRepository extends Repository<User, Long> {
@Lock(LockMode.PESSIMISTIC_WRITE)
List<User> findAllByFirstNameAndLastName(String firstName, String lastName);
@Lock(LockMode.PESSIMISTIC_READ)
List<User> findAllByFirstNameAndAge(String firstName, Integer age);
List<User> findAllByFirstName(String firstName); List<User> findAllByFirstName(String firstName);
List<User> findAllByHated(Hobby hobby); List<User> findAllByHated(Hobby hobby);
@ -758,7 +807,6 @@ public class PartTreeJdbcQueryUnitTests {
} }
static class Hobby { static class Hobby {
@Id @Id String name;
String name;
} }
} }

Loading…
Cancel
Save