public boolean isUserNotExist(long id) {
String readSql = "SELECT * FROM user WHERE id = ?";
return jdbcTemplate.query(readSql, (rs, rowNum) -> 0, id).isEmpty();
}
자바진영의 ORM(Object-Relational Mapping)
객체와 테이블을 짝지어 데이터를 영구적으로 저장할 수 있도록 정해진 Java규칙
이를 구현하여 코드로 작성한 것이 HIBERNATE
User테이블에 대응되는 Entity Class를 만들어 사용해보겠습니다.
User테이블(MySQL)
CREATE TABLE IF NOT EXISTS user
(
id bigint AUTO_INCREMENT,
name varchar(25),
age int,
primary key (id)
);
Entity Class
@Id
이 필드를 primary key로 간주한다.
@GeneratedValue
primary key는 자동 생성되는 값이다. GenerationType.IDENTITY은 MySQL의 AUTO_INCREMENT속성에 대응된다.
다른 DB를 사용해도 자동으로 속성을 맞춰준다.
@Column
객체필드와 Table필드를 매핑한다 null여부, 길이 제한, DB에서의 이름 등등을 속성으로 지정한다. 객체필드의 컬럼명과 테이블의 컬럼명이 같으면 따로 DB에서의 이름을 지정하지 않아도 된다.
application.yml에 다음을 추가
spring:
jpa:
hibernate:
ddl-auto: none
properties:
hibernate:
show_sql: true
format_sql: true
dialect: org.hibernate.dialect.MySQL8Dialect
// UserServiceV1.java
import com.group.libraryapp.dto.user.request.UserCreateRequest;
import com.group.libraryapp.dto.user.request.UserUpdateRequest;
import com.group.libraryapp.dto.user.response.UserResponse;
import com.group.libraryapp.repository.user.UserJdbcRepository;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserServiceV1 {
private final UserJdbcRepository userJdbcRepository;
public UserServiceV1(UserJdbcRepository userJdbcRepository) {
this.userJdbcRepository = userJdbcRepository;
}
public void updateUser(UserUpdateRequest request) {
if (userJdbcRepository.isUserNotExist(request.getId())) {
throw new IllegalArgumentException();
}
userJdbcRepository.updateUserName(request.getName(), request.getId());
}
public void saveUser(UserCreateRequest request) {
userJdbcRepository.saveUser(request.getName(), request.getAge());
}
public List<UserResponse> getUsers() {
return userJdbcRepository.getUsers();
}
}
// UserJdbcRepository.java
import com.group.libraryapp.dto.user.response.UserResponse;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public class UserJdbcRepository {
private final JdbcTemplate jdbcTemplate;
public UserJdbcRepository(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public void updateUserName(String name, long id) {
String sql = "UPDATE user SET name = ? WHERE id = ?";
jdbcTemplate.update(sql, name, id);
}
public boolean isUserNotExist(Long id){
String readSql = "SELECT * FROM user WHERE name = ?";
return jdbcTemplate.query(readSql, (rs, rowNum) -> 0, id).isEmpty();
}
public boolean isUserNotExist(String name) {
String readSql = "SELECT * FROM user WHERE name = ?";
return jdbcTemplate.query(readSql, (rs, rowNum) -> 0, name).isEmpty();
}
public void saveUser(String name, Integer age) {
String sql = "INSERT INTO user (name, age) VALUES(?, ?)";
jdbcTemplate.update(sql, name, age);
}
public List<UserResponse> getUsers() {
String sql = "SELECT * FROM user";
return jdbcTemplate.query(sql, (rs, rowNum) -> {
long id = rs.getLong("id");
String name = rs.getString("name");
int age = rs.getInt("age");
return new UserResponse(id, name, age);
});
}
}
JpaRepository를 상속받는 UserRepository 인터페이스를 생성한다.
// UserRepository.java
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<User, Long> {}
// UserResponse.java
// User객체를 받는 생성자를 만들어 코드를 간편하게 바꾸도록한다.
import com.group.libraryapp.domain.user.User;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
@Getter
@AllArgsConstructor
public class UserResponse {
private long id;
private String name;
private Integer age;
public UserResponse(User user) {
this.id = user.getId();
this.name = user.getName();
this.age = user.getAge();
}
public UserResponse(long id, User user) {
this.id = id;
this.name = user.getName();
this.age = user.getAge();
}
}
// UserServiceV2.java
import com.group.libraryapp.domain.user.User;
import com.group.libraryapp.domain.user.UserRepository;
import com.group.libraryapp.dto.user.request.UserCreateRequest;
import com.group.libraryapp.dto.user.request.UserUpdateRequest;
import com.group.libraryapp.dto.user.response.UserResponse;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class UserServiceV2 {
private final UserRepository userRepository;
public UserServiceV2(UserRepository userRepository) {
this.userRepository = userRepository;
}
public void saveUser(UserCreateRequest request) {
User u = userRepository.save(new User(request.getName(), request.getAge()));
}
public List<UserResponse> getUsers() {
return userRepository.findAll().stream()
.map(UserResponse::new)
.collect(Collectors.toList());
}
public void updateUser(UserUpdateRequest request){
// SELECT * FROM user WHERE id = ?;
// Optional<User>
User user = userRepository.findById(request.getId())
.orElseThrow(IllegalArgumentException::new);
user.updateName(request.getName());
userRepository.save(user);
}
}
UserResponse에 생성자를 추가하므로써
UserResponse::new가
user -> new UserResponse(user.getId(), user.getName(), user.getAge()) 코드를 대체할 수 있게되었다.
위 Jpa에서는 findById처럼 Id값으로만 대상을 찾고있다. 다른 값으로 원하는 대상을 찾도록 수정해보자
// UserRepository.java
public interface UserRepository extends JpaRepository<User, Long> {
User findByName(String name);
}
findByName?
find는 하나만 찾습니다 By뒤에 붙는 필드이름으로 SELECT쿼리의 WHERE문이 작성됩니다. 위의 경우엔 "SELECT * FROM user WHERE name = ?"가 됩니다.
인터페이스의 위 처럼 객체에 맞는 값을 찾는 메소드를 작성한다.
이를 이용해 유저를 삭제하는 코드를 작성해보자
// UserServiceV2.java
public void deleteUser(String name) {
User user = userRepository.findByName(name);
if(user == null) { // 유저 존재 여부
throw new IllegalArgumentException();
}
userRepository.delete(user);
}
find : 1건을 가져온다. 반환타입은 객체가 될수도 Optional<타입>일 수도있다.
findAll : 쿼리의 결과물이 N개인 경우 사용. List<타입> 반환
exists : 쿼리 결과가 존재하는지 확인. 반환 타입은 boolean
count : SQL 결과의 개수를 센다. 반환 타입은 long.
// SELECT * FROM user WHERE name = ? AND age = ?;
List<User> findAllByNameAndAge(String name, int age);
GreaterThan : 초과
GreaterThanEqual : 이상
LessThan : 미만
LessThanEqual : 이하
Between : 사이에
StartsWith : ~로 시작하는
EndsWith : ~로 끝나는
// SELECT * FROM user WHERE age BETWEEN ? AND ?;
List<User> findAllByAgeBetween(int startAge, int endAge);