BAEL-7509: An example with optimized referenceBy (#15988)
* BAEL-7509: An example with optimized referenceBy * BAEL-7509: Added query counting tests * BAEL-7509: Formatting fix
This commit is contained in:
parent
c1fe1fd285
commit
f7bd3d50f5
@ -76,6 +76,16 @@
|
|||||||
<artifactId>logback-classic</artifactId>
|
<artifactId>logback-classic</artifactId>
|
||||||
<version>${logback.version}</version>
|
<version>${logback.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.hypersistence</groupId>
|
||||||
|
<artifactId>hypersistence-utils-hibernate-62</artifactId>
|
||||||
|
<version>${hypersistence-utils.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.vladmihalcea</groupId>
|
||||||
|
<artifactId>db-util</artifactId>
|
||||||
|
<version>${db.util.version}</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
@ -130,6 +140,8 @@
|
|||||||
<properties>
|
<properties>
|
||||||
<hypersistance-utils-hibernate-55.version>3.7.0</hypersistance-utils-hibernate-55.version>
|
<hypersistance-utils-hibernate-55.version>3.7.0</hypersistance-utils-hibernate-55.version>
|
||||||
<postgresql.version>42.7.1</postgresql.version>
|
<postgresql.version>42.7.1</postgresql.version>
|
||||||
|
<db.util.version>1.0.7</db.util.version>
|
||||||
|
<hypersistence-utils.version>3.7.0</hypersistence-utils.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
</project>
|
</project>
|
@ -0,0 +1,51 @@
|
|||||||
|
package com.baeldung.spring.data.persistence.findvsget.entity;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.GenerationType;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.OneToMany;
|
||||||
|
import javax.persistence.OneToOne;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "group")
|
||||||
|
public class Group {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private Long id;
|
||||||
|
private String name;
|
||||||
|
@OneToOne
|
||||||
|
private User administrator;
|
||||||
|
@OneToMany(mappedBy = "id")
|
||||||
|
private Set<User> users = new HashSet<>();
|
||||||
|
public void addUser(User user) {
|
||||||
|
users.add(user);
|
||||||
|
}
|
||||||
|
public Set<User> getUsers() {
|
||||||
|
return users;
|
||||||
|
}
|
||||||
|
public void setUsers(Set<User> users) {
|
||||||
|
this.users = users;
|
||||||
|
}
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
public User getAdministrator() {
|
||||||
|
return administrator;
|
||||||
|
}
|
||||||
|
public void setAdministrator(User administrator) {
|
||||||
|
this.administrator = administrator;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
package com.baeldung.spring.data.persistence.findvsget.repository;
|
||||||
|
|
||||||
|
import com.baeldung.spring.data.persistence.findvsget.entity.Group;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
|
public interface GroupRepository extends JpaRepository<Group, Long> {
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,87 @@
|
|||||||
|
package com.baeldung.spring.data.persistence.findvsget;
|
||||||
|
|
||||||
|
import static com.vladmihalcea.sql.SQLStatementCountValidator.assertInsertCount;
|
||||||
|
import static com.vladmihalcea.sql.SQLStatementCountValidator.assertSelectCount;
|
||||||
|
import static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType;
|
||||||
|
import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
|
||||||
|
|
||||||
|
import com.baeldung.spring.data.persistence.findvsget.entity.Group;
|
||||||
|
import com.baeldung.spring.data.persistence.findvsget.entity.User;
|
||||||
|
import com.baeldung.spring.data.persistence.findvsget.repository.GroupRepository;
|
||||||
|
import com.baeldung.spring.data.persistence.findvsget.repository.SimpleUserRepository;
|
||||||
|
import io.hypersistence.utils.jdbc.validator.SQLStatementCountValidator;
|
||||||
|
import java.util.Optional;
|
||||||
|
import org.hibernate.LazyInitializationException;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.dao.DataIntegrityViolationException;
|
||||||
|
|
||||||
|
class AdditionalLookupIntegrationTest extends DatabaseConfigurationBaseIntegrationTest {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SimpleUserRepository userRepository;
|
||||||
|
@Autowired
|
||||||
|
private GroupRepository groupRepository;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void setup() {
|
||||||
|
SQLStatementCountValidator.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenEmptyGroup_whenAssigningAdministratorWithGetByReference_thenNoAdditionalLookupHappens() {
|
||||||
|
User user = userRepository.getReferenceById(1L);
|
||||||
|
Group group = new Group();
|
||||||
|
group.setAdministrator(user);
|
||||||
|
groupRepository.save(group);
|
||||||
|
assertSelectCount(0);
|
||||||
|
assertInsertCount(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenEmptyGroup_whenAssigningIncorrectAdministratorWithGetByReference_thenErrorIsThrown() {
|
||||||
|
User user = userRepository.getReferenceById(-1L);
|
||||||
|
Group group = new Group();
|
||||||
|
group.setAdministrator(user);
|
||||||
|
assertThatExceptionOfType(DataIntegrityViolationException.class)
|
||||||
|
.isThrownBy(() -> {
|
||||||
|
groupRepository.save(group);
|
||||||
|
});
|
||||||
|
assertSelectCount(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenEmptyGroup_whenAssigningAdministratorWithFindBy_thenAdditionalLookupHappens() {
|
||||||
|
Optional<User> optionalUser = userRepository.findById(1L);
|
||||||
|
assertThat(optionalUser).isPresent();
|
||||||
|
User user = optionalUser.get();
|
||||||
|
Group group = new Group();
|
||||||
|
group.setAdministrator(user);
|
||||||
|
groupRepository.save(group);
|
||||||
|
assertSelectCount(2);
|
||||||
|
assertInsertCount(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenEmptyGroup_whenAddingUserWithGetByReference_thenTryToAccessInternalsAndThrowError() {
|
||||||
|
User user = userRepository.getReferenceById(1L);
|
||||||
|
Group group = new Group();
|
||||||
|
assertThatExceptionOfType(LazyInitializationException.class)
|
||||||
|
.isThrownBy(() -> {
|
||||||
|
group.addUser(user);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenEmptyGroup_whenAddingUserWithFindBy_thenAdditionalLookupHappens() {
|
||||||
|
Optional<User> optionalUser = userRepository.findById(1L);
|
||||||
|
assertThat(optionalUser).isPresent();
|
||||||
|
User user = optionalUser.get();
|
||||||
|
Group group = new Group();
|
||||||
|
group.addUser(user);
|
||||||
|
groupRepository.save(group);
|
||||||
|
assertSelectCount(1);
|
||||||
|
assertInsertCount(1);
|
||||||
|
}
|
||||||
|
}
|
@ -4,7 +4,9 @@ import static com.baeldung.spring.data.persistence.findvsget.UserProvider.userSo
|
|||||||
import static org.assertj.core.api.Assumptions.assumeThat;
|
import static org.assertj.core.api.Assumptions.assumeThat;
|
||||||
|
|
||||||
import com.baeldung.spring.data.persistence.findvsget.entity.User;
|
import com.baeldung.spring.data.persistence.findvsget.entity.User;
|
||||||
|
import com.baeldung.spring.data.persistence.findvsget.repository.GroupRepository;
|
||||||
import com.baeldung.spring.data.persistence.findvsget.repository.SimpleUserRepository;
|
import com.baeldung.spring.data.persistence.findvsget.repository.SimpleUserRepository;
|
||||||
|
import com.baeldung.spring.data.persistence.util.TestConfig;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
@ -13,7 +15,7 @@ import org.junit.jupiter.params.provider.Arguments;
|
|||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
|
||||||
@SpringBootTest(classes = ApplicationConfig.class, properties = {
|
@SpringBootTest(classes = {ApplicationConfig.class, TestConfig.class}, properties = {
|
||||||
"spring.jpa.generate-ddl=true",
|
"spring.jpa.generate-ddl=true",
|
||||||
"spring.jpa.show-sql=false"
|
"spring.jpa.show-sql=false"
|
||||||
})
|
})
|
||||||
@ -22,7 +24,10 @@ abstract class DatabaseConfigurationBaseIntegrationTest {
|
|||||||
private static final int NUMBER_OF_USERS = 10;
|
private static final int NUMBER_OF_USERS = 10;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private SimpleUserRepository repository;
|
private SimpleUserRepository userRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private GroupRepository groupRepository;
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void populateDatabase() {
|
void populateDatabase() {
|
||||||
@ -30,13 +35,14 @@ abstract class DatabaseConfigurationBaseIntegrationTest {
|
|||||||
.map(Arguments::get)
|
.map(Arguments::get)
|
||||||
.map(s -> new User(((Long) s[0]), s[1].toString(), s[2].toString()))
|
.map(s -> new User(((Long) s[0]), s[1].toString(), s[2].toString()))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
repository.saveAll(users);
|
userRepository.saveAll(users);
|
||||||
assumeThat(repository.findAll()).hasSize(NUMBER_OF_USERS);
|
assumeThat(userRepository.findAll()).hasSize(NUMBER_OF_USERS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterEach
|
@AfterEach
|
||||||
void clearDatabase() {
|
void clearDatabase() {
|
||||||
repository.deleteAll();
|
groupRepository.deleteAll();
|
||||||
|
userRepository.deleteAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,36 @@
|
|||||||
|
package com.baeldung.spring.data.persistence.util;
|
||||||
|
|
||||||
|
import io.hypersistence.utils.logging.InlineQueryLogEntryCreator;
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
import net.ttddyy.dsproxy.listener.ChainListener;
|
||||||
|
import net.ttddyy.dsproxy.listener.DataSourceQueryCountListener;
|
||||||
|
import net.ttddyy.dsproxy.listener.logging.SLF4JQueryLoggingListener;
|
||||||
|
import net.ttddyy.dsproxy.support.ProxyDataSourceBuilder;
|
||||||
|
import org.springframework.beans.BeansException;
|
||||||
|
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class DataSourceWrapper implements BeanPostProcessor {
|
||||||
|
|
||||||
|
public Object postProcessBeforeInitialization(Object bean, String beanName) {
|
||||||
|
return bean;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||||
|
if (bean instanceof DataSource) {
|
||||||
|
DataSource originalDataSource = ((DataSource) bean);
|
||||||
|
ChainListener listener = new ChainListener();
|
||||||
|
SLF4JQueryLoggingListener loggingListener = new SLF4JQueryLoggingListener();
|
||||||
|
loggingListener.setQueryLogEntryCreator(new InlineQueryLogEntryCreator());
|
||||||
|
listener.addListener(loggingListener);
|
||||||
|
listener.addListener(new DataSourceQueryCountListener());
|
||||||
|
return ProxyDataSourceBuilder
|
||||||
|
.create(originalDataSource)
|
||||||
|
.name("DS-Proxy")
|
||||||
|
.listener(listener)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
return bean;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package com.baeldung.spring.data.persistence.util;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class TestConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public DataSourceWrapper dataSourceWrapper() {
|
||||||
|
return new DataSourceWrapper();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user