The problem is that one day we discovered that if we're saving an object in spring boot repository, another objects that are changed in the same method are also updated and persisted in the database.
The curiosity is massive to find out why does this actually happen. I created sample project using Spring Initializr and some template code to show the actual situation (tried to keep the number of dependencies as low as possible).
Using Spring boot version 1.5.11 (SNAPSHOT) and project has following dependencies:
dependencies {
compile('org.springframework.boot:spring-boot-starter-data-jpa')
compile('org.springframework.boot:spring-boot-starter-web')
compile('org.mariadb.jdbc:mariadb-java-client:2.1.0')
testCompile('org.springframework.boot:spring-boot-starter-test')
}
Now to the point:
Project has two entities, Pet
:
@Entity
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id", scope = Pet.class)
public class Pet {
@Id
@GeneratedValue
private long id;
private String type;
public Pet() {}
public String getType() { return type; }
public void setType(String type) { this.type = type; }
}
and User
:
@Entity
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id", scope = User.class)
public class User {
@Id
@GeneratedValue
private long id;
private String name;
public User() {}
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}
Both entities also have repositories, Pet
:
@Repository
public interface PetRepository extends CrudRepository<Pet, Long> {
Pet findPetById(Long id);
}
User
:
@Repository
public interface UserRepository extends CrudRepository<User, Long> {
User findUserById(Long id);
}
And one simple service where the magic actually happens ( I have pre-saved one Pet
and one User
object, with different name and type)
@Service
public class UserService {
@Autowired
UserRepository userRepository;
@Autowired
PetRepository petRepository;
public User changeUserAndPet() {
User user = userRepository.findUserById(1L);
Pet pet = petRepository.findPetById(1L);
user.setName("Kevin");
pet.setType("Cow");
userRepository.save(user);
return user;
}
}
Right after calling userRepository.save(user);
the Pet object is also updated in the database with new type of 'Cow'. Why exactly does this happen if I only saved the User
object? Is this intended to be like this?
There's also one simple controller and simple test endpoint to call the service method which most likely is not important to the question, but I'll still add it here for the sake of completeness.
@RestController
public class UserController {
@Autowired
UserService userService;
@RequestMapping(value = "/test", method = RequestMethod.GET)
public User changeUserAndPet() {
return userService.changeUserAndPet();
}
}
Any explanation / tips are appreciated and feel free to ask extra information / code in github.