728x90
2023.12.26 - [DB(MySQL, MongoDB, Redis, Kafka)/MySQL] - MySQL 테스트를 위한 SNS서비스 회원정보 등록
2023.12.26 - [DB(MySQL, MongoDB, Redis, Kafka)/MySQL] - MySQL 테스트를 위한 SNS서비스 회원정보 조회
앞서 만든 내용에 회원 이름이 변경 가능하도록만 수정하고, 변경이력 조회를 진행했습니다.
public void changeNickname(String other) {
validateNickname(other);
nickname = other;
}
닉네임이 변경가능하도록 member 객체에 changeNickname 메서드를 따로 만들면 됩니다.
public void changeNickname(Long id, String nickname) {
var member = memberRepository.findById(id)
.orElseThrow(() -> new IllegalArgumentException("해당하는 회원이 없습니다."));
member.changeNickname(nickname);
memberRepository.save(member);
}
WriteService에서는 리포지토리에 id값으로 조회를 한 뒤, 닉네임을 바꾸고 다시 저장하게 됩니다.
private Member update(Member member) {
var sql = "update " + TABLE_NAME + " set nickname = :nickname where id = :id";
SqlParameterSource params = new BeanPropertySqlParameterSource(member);
namedParameterJdbc.update(sql, params);
return member;
}
리포지토리에 update메서드를 통해 sql쿼리로 update된 member객체를 반환합니다.
@PostMapping("/members/{id}/nickname")
public MemberDto changeNickname(@PathVariable Long id, @RequestBody String nickname) {
memberWriteService.changeNickname(id, nickname);
return memberReadService.getMember(id);
}
}
Controller는 WriteService를 통해 수정하고, ReadService를 통해 조회한 값을 반환합니다.
회원이름 변경내역
create table Member
(
id int auto_increment,
email varchar(20) not null,
nickname varchar(20) not null,
birthdate date not null,
createdAt datetime not null,
constraint member_id_uindex
primary key (id)
);
create table MemberNicknameHistory
(
id int auto_increment,
memberId int not null,
nickname varchar(20) not null,
createdAt datetime not null,
constraint memberNicknameHistory_id_uindex
primary key (id)
);
변경이력은 기존의 회원정보 테이블과 데이터 중복을 피하기 위해 분리했습니다.
다만, 변경이력의 memberId는 member테이블의 id를 참조하고 있는데도 FK로 지정하고 있지 않습니다.
필수는 아니지만 데이터의 무결성을 위해 지정하는 것이 좋을 것 같습니다.
@Getter
public class MemberNickNameHistory {
private final Long id;
private final Long memberId;
private final String nickname;
private final LocalDate createdAt;
@Builder
public MemberNickNameHistory(Long id, Long memberId, String nickname, LocalDate createdAt) {
this.id = id;
this.memberId = Objects.requireNonNull(memberId);
this.nickname = Objects.requireNonNull(nickname);
this.createdAt = createdAt == null ? LocalDate.now() : createdAt; // 로그를 위해 생성시간 추가
}
public record NickNameHistoryDto (
Long id,
Long memberId,
String nickname,
LocalDate createdAt
){
}
엔티티와 Dto는 기존 member와 같은 형식으로 작성했습니다.
@Repository
@RequiredArgsConstructor
public class MemberNickNameHistoryRepository {
private final NamedParameterJdbcTemplate namedParameterJdbc;
private static final String TABLE_NAME = "MemberNickNameHistory";
public static final RowMapper<MemberNickNameHistory> rowMapper = (rs, rowNum) -> MemberNickNameHistory
.builder()
.id(rs.getLong("id"))
.memberId(rs.getLong("memberId"))
.nickname(rs.getString("nickname"))
.createdAt(rs.getObject("createdAt", LocalDate.class))
.build();
public List<MemberNickNameHistory> findAllByMemberId(Long memberId) {
/*
select * from Member where memberId = :memberId;
*/
var sql = "select * from " + TABLE_NAME + " where memberId = :memberId";
var params = new MapSqlParameterSource()
.addValue("memberId", memberId);
return namedParameterJdbc.query(sql, params, rowMapper);
}
public MemberNickNameHistory save(MemberNickNameHistory memberNickNameHistory) {
if (memberNickNameHistory.getId() == null) {
return insert(memberNickNameHistory);
}
throw new IllegalArgumentException("MemberNickNameHistory는 수정할 수 없습니다.");
}
private MemberNickNameHistory insert(MemberNickNameHistory memberNickNameHistory) {
SimpleJdbcInsert simpleJdbcInsert = new SimpleJdbcInsert(namedParameterJdbc.getJdbcTemplate())
.withTableName(TABLE_NAME)
.usingGeneratedKeyColumns("id");
SqlParameterSource params = new BeanPropertySqlParameterSource(memberNickNameHistory);
var id = simpleJdbcInsert.executeAndReturnKey(params).longValue();
return MemberNickNameHistory.builder()
.id(id)
.memberId(memberNickNameHistory.getMemberId())
.nickname(memberNickNameHistory.getNickname())
.createdAt(memberNickNameHistory.getCreatedAt())
.build();
}
}
Repository에서 데이터 액세스하는 메서드를 구현하고 있습니다.
sql쿼리가 실행되고 그 결과가 RowMapper를 통해 객체로 반환됩니다.
Insert 역시 SimpleJdbcInsert를 사용하여 데이터를 삽입하고 있습니다.
그리고 생성된 id 키값을 가져와 MemberNickNameHistory객체를 빌더패턴으로 설정하고 있습니다.
Read 및 Write 서비스에서는 동일한 방식으로 기능을 구현하고 Controller를 통해 HTTP요청을 받고 있습니다.
'DB(MySQL, MongoDB, Redis, Kafka) > MySQL' 카테고리의 다른 글
MySQL 조회 최적화를 위한 인덱스 테스트 [EazyRandom] (0) | 2023.12.29 |
---|---|
MySQL 테스트를 위한 SNS서비스 팔로우 (2) | 2023.12.27 |
MySQL 테스트를 위한 SNS서비스 회원정보 조회 (0) | 2023.12.26 |
MySQL 테스트를 위한 SNS서비스 회원정보 등록 (0) | 2023.12.26 |
MySQL 정규화와 반정규화(비정규화) (0) | 2023.12.25 |