2024 02 12
2024-02-12¶
Kotlin Companion Object¶
참고: https://lannstark.tistory.com/141 참고: https://onlyfor-me-blog.tistory.com/441
- 개요
- 자바의 static 필드/메서드를 코틀린에서 쓰려면...?
- 코틀린 문법에서는 클래스 안에 이걸 둘 수는 없어 (static 없음)
- companion object 사용하세요! (오 Scala 같아!)
- 하나의 클래스에 하나의 Companion Object 사용 가능
-
Java => Kotlin
- Java
- Kotlin
JPA + Spring Batch - JpaRepository delete 쿼리가 안나감¶
참고: https://myvelop.tistory.com/116
-
Select 쿼리만 나감 => JPA 대량 데이터 삭제 글 후술
interface NoticeRepository: JpaRepository<Notice, Long> { fun deleteByIdBetween(startId: Long, endId: Long) }- 이건 Transactional 이 없어서 그래
- DB에 변경이 가해지려면 트랜잭션 안에서 이루어져야겠지?
- 현재 메서드에 트랜잭션을 열어주는 공간이 없다면, 변경에 대해서 DB에 커밋이 어려워
- 주로 Spring Boot에서는 Service에서 해줬지만,,, 배치에서는 레포단이나 그냥 전체에서 해도 괜찮을 듯
-
@Transactional붙임interface NoticeRepository: JpaRepository<Notice, Long> { @Transactional @Modifying fun deleteByIdBetween(startId: Long, endId: Long) }- 이제 delete 쿼리 나감
@Modifying은 무엇이고 하니...- Spring Data JPA에게 해당 쿼리가 DB의 레코드를 변경시킨다는 것을 알려주는 것
- 그냥 디폴트로 쓰는 CRUD Operation의 경우 (알아서 JPQL 만들어 주는 것)은
@Modifying없어도 OK - 하지만,
@Query써서 직접적으로 DB에 접근하는 경우, DELETE/UPDATE/INSERT 쓸 때에는@Modifying을 써주세요!!- 그래야 Spring Data JPA가 영속성 컨텍스트를 비워야겠구나~ 하는 시점을 알게 된 답니다
- 참고로,
@Modifying쿼리는Entity를 리턴할 수 없어- 왜냐면 해당 쿼리는 주로 영속성 컨텍스트에 엔티티 로딩하지 않고 수행되거든
- 트랜잭션 컨텍스트랑 같이 써줘요!
-
@Query작성interface NoticeRepository: JpaRepository<Notice, Long> { @Transactional @Modifying @Query("delete from notice n where n.id between :startId and :endId") fun deleteByIdBetween(startId: Long, endId: Long) }- 이게 위에 처럼 쓰니까, 아니 delete 쿼리를 id별로 한개씩 내보내네;;;
- 커스텀 JPQL로 쓰고,
@Modifying붙여주자!
JPA 대량 데이터 삭제 주의할 점¶
참고: https://jojoldu.tistory.com/235
- delete 문제점
- Spring Data JPA에서
deleteByXXX메서드는- 삭제 대상을 전부 조회하는 쿼리 1번 발생 (위에 서술한 select만 나갔던 이유. 트랜잭션 없으니 지울라니까 뇌절)
- 삭제 대상은 1건씩 삭제된다
cascase = CascadeType.DELETE로 하위 엔티티와 관계가 있다면 1건씩 삭제됨
- Spring Data JPA에서
- 해결책
- delete의 경우 직접 범위 조건의 삭제 쿼리를 생성하자!
JPA + Spring Batch - saveAll()이 벌크로 동작 안 하는 이유¶
참고: https://imksh.com/113 참고: https://sabarada.tistory.com/220 참고: https://medium.com/@tmdghk502/springdata-jpa-bulk-insert-4a3e58d883ad
- 개요
- saveAll 메서드의 Entity는 왜 벌크로 동작하지 않는가?
- saveAll() & save()
- saveAll()에 List
넣게 되면 반복문 돌면서 결국 save() - List
내가 돌면서 save()하나, 그냥 saveAll()에 박아두나 똑같음
- saveAll()에 List
- 자 여기서 PK(id) 전략에 따라 save()가 좀 다른데...
- MySQL에서 직접 PK 관리하도록 IDENTITY 전략을 쓴다면?!
- 영속성 컨텍스트에서 Entity Id 가져오고
- ID = null -> 아 새로운 엔티티구나!
- em.persist() 하려면 PK는 필수라서, 영속성 컨텍스트 등록을 위해 INSERT 쿼리가 바로 실행됨
- ID != null -> 아 있는 놈이구나!
- ID = null -> 아 새로운 엔티티구나!
- 그래서 결국 JPA에서는
- ID 전략이 IDENTITY 이면서 ID가 없는 친구는 일단 영속성 컨텍스트에 등록하려고만 해도 ID가 필요하니,
- INSERT가 그때그때 될것이야 (bulk 어려움)
- Hibernate 자체에서 IDENTITY인 경우, Bulk Insert 안 되도록 막아뒀어!!
- 저는 벌크로 넣고 싶은데요?
- JdbcTemplate의 rewriteBatchedStatements 옵션을 쓰란다
@Repository @RequiredArgsConstructor public class BulkInsertRepository { private final JdbcTemplate jdbcTemplate; public void saveAll(List<Dummy> dummies) { jdbcTemplate.batchUpdate("INSERT INTO dummy(name) values (?)", new BatchPreparedStatementSetter() { @Override public void setValues(PreparedStatement ps, int i) throws SQLException { ps.setString(1, dummies.get(i).getName()); } @Override public int getBatchSize() { return dummies.size(); } }); } }
- JdbcTemplate의 rewriteBatchedStatements 옵션을 쓰란다
- 다시 정리
- MySQL 사용 + ID auto_increment + JPA 사용 -> JPA 철학에 의거, bulk insert 못함. 채번 전략 바꿔야 함
- 대안으로 채번 전략을 바꾸던가 (Sequence, Table)
- jdbc batchUpdate를 직접 쓰던가
- MySQL 사용 + ID auto_increment + JPA 사용 -> JPA 철학에 의거, bulk insert 못함. 채번 전략 바꿔야 함
Access-Control-Allow-Credentials¶
- 개요
- Credentials: 쿠키, Authorization 인증 헤더, TLS 증명서 내포하는 자격 인증 정보
- 브라우저의 요청 API들은 별도 옵션 없이 브라우저 쿠키와 같은 인증 데이터 함부로 담지 않음
- 요청과 응답에 쿠키를 허용하고자 한다면, withCredentials 옵션으로 해결해보자!
- withCredentials
- 다른 도메인에 요청을 보낼 때 요청에 인증 정보를 담아서 보낼지를 결정하는 항목
- 클라이언트에서
withCredentials:true - 서버에서
Access-Control-Allow-Credentials:true
- 클라이언트에서
- 다른 도메인에 요청을 보낼 때 요청에 인증 정보를 담아서 보낼지를 결정하는 항목
-
클라이언트 처리
- axios
// 1. axios 전역 설정 axios.defaults.withCredentials = true; // withCredentials 전역 설정 // 2. axios 옵션 객체로 넣기 axios.post( 'https://example.com:1234/users/login', { profile: { username: username, password: password } }, { withCredentials: true } ).then(response => { console.log(response); console.log(response.data); })
- fetch
- axios
- 서버 처리
Access-Control-Allow-Credentials:trueAccess-Control-Allow-Origin: "*"는 안 됨! 보안상 취약!Access-Control-Allow-Methods: "*"는 안 됨! 보안상 취약!Access-Control-Allow-Headers: "*"는 안 됨! 보안상 취약!