728x90

 java stream에서 maptoobj 함수는 중간 연산이라 되어 있습니다. 길이 n짜리 배열을 obj object n개로 채우려고 합니다. obj 클래스에는 int 자료형만 하나 있고, 우리는 이 n개의 obj가 깊은 복사가 되어야 해요. 이걸 stream을 써서 할 때, Intstream의 range 메서드와, maptoObj를 사용하면 손쉽게 처리할 수 있습니다.

 


 

 

 mapToObj 메서드를 봅시다. Intstream 뿐만이 아니라, Longstream과 DoubleStream에도 있습니다. 설명을 보면, 스트림으로부터 해당 함수를 적용한 객체 값들의 stream을 반환한다고 되어 있어요. 즉 입력 스트림으로부터 무언가를 받아서, 새로운 결과 가지고 있는 스트림으로 변환합니다.

 

 n개의 크기를 가진 리스트에 깊은 복사한 Obj 오브젝트 n개를 채워야 한다고 해 볼게요. 그러면 단순하게 List를 새로 생성해서 Obj 객체를 추가해도 됩니다. 그런데, 조금 더 생각해 보면 아래와 같은 로직을 생각할 수 있습니다.

 

 

 

 1부터 5까지 있는 stream이 있어요. 이것을 아래와 같이 변환시키면 어떨까요?

 

 

 

 하나의 원소가 새로운 new Obj(3)으로 바뀌는 것입니다. mapToXXX류가 이러한 역할을 수행합니다. 이 경우 IntStream의 원소들을 다른 obj로 변환시키는 apply 작업을 수행했습니다.

 

 

 

 

 그림으로 그리면 이런 상황인 셈입니다. 즉, mapToXXX는 스트림의 요소들을 다른 요소로 바꾼 새로운 스트림을 돌려줍니다. 위 그림에서는 x를 new Obj(3)으로 바꾸었습니다. 따라서, 1 2 3 4 5로 이루어져 있던 것을 new Obj(3), ... , new Obj(3)으로 대체하게 됩니다.

 


 이제 문제 상황을 다시 봅시다. 저는 객체 Obj n개가 채워진 ArrayList를 원합니다. 객체 n개는 깊은 복사가 되어야 하고요. 객체 Obj는 int 필드 하나만 주어져 있습니다. n = 4라고 해 보겠습니다.

 

 

 

 당연하게도, setter가 있기 때문에, 불변 객체가 아닙니다. 어떻게 하면 될까요? 로직부터 설계해 봅시다. 일단, 이전에 배웠던 range는 1부터 n까지의 순서를 가지는 stream을 생성합니다. 고로, IntStream.range(1, 5)를 먼저 수행합니다.

 

 

 

 

 다음에, 해당 stream을 토대로 Obj로 이루어진 스트림을 새로 생성합니다. mapToObj로요.

 

 

 

 그러면, 1부터 5까지 순서로 이루어진 Stream이 new Obj(3)으로 이루어진 4개의 객체로 이루어 집니다. 참고로 각 원소별로 apply가 별개로 동작하므로 매번 새로운 객체가 생기게 됩니다.

 

 

 

 toList로 Stream을 List로 변환합니다.

 

 

 

 최종 코드는 20 ~ 21번째 줄에 나와 있습니다. 23번째 줄에 list의 0번째 원소의 x 값을 2로 바꾸어 봅시다. 만약에 저 객체들이 모두 얕은 복사가 되었다면, 모두 2가 출력되었을 겁니다.

 

 

 

 그런데 3이 출력되었습니다. 이유는 toList가 호출될 때 mapToObj에 있는 apply인 x -> new Obj(3)가 실행되기 때문입니다. 각각의 element에 대해 적용되기 때문에 별개의 새로운 오브젝트 Obj가 생성됩니다.

출처: https://codingdog.tistory.com/entry/java-stream-maptoobj-함수에-대해-알아봅시다 [강아지의 코딩공부:티스토리]

'Java' 카테고리의 다른 글

[Spring Batch] multiple nodes with MySQL 8.0.33  (0) 2024.05.03
자바 어플리케이션 inputstream 주의사항  (1) 2024.04.18
728x90

https://community.letsencrypt.org/t/android-7-0-cant-establish-ssl-connection/152050

 

Android 7.0 can't establish ssl connection

My domain is: starline.ru I ran this command: android 7.0 can't connect It produced this output: Caused by: javax.net.ssl.SSLProtocolException: SSL handshake terminated: ssl=0x76a8eb8a00: Failure in SSL library, usually a protocol error error:10000410:SSL

community.letsencrypt.org

 

 

My domain is: starline.ru 4

I ran this command: android 7.0 can't connect

It produced this output:

 
Caused by: javax.net.ssl.SSLProtocolException: SSL handshake terminated: ssl=0x76a8eb8a00: Failure in SSL library, usually a protocol error error:10000410:SSL routines:OPENSSL_internal:SSLV3_ALERT_HANDSHAKE_FAILURE (external/boringssl/src/ssl/s3_pkt.c:641 0x76a8e2b0a0:0x00000001) error:1000009a:SSL routines:OPENSSL_internal:HANDSHAKE_FAILURE_ON_CLIENT_HELLO (external/boringssl/src/ssl/s3_clnt.c:800 0x76d2e2c253:0x00000000)
at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:364)

SSLV3 - wrapper string, actualy sslv3 not use

My web server is (include version):

 
nginx version: nginx/1.14.1
built with OpenSSL 1.1.0f  25 May 2017 (running with OpenSSL 1.1.0l  10 Sep 2019)
TLS SNI support enabled

The operating system my web server runs on is (include version): Debian GNU/Linux 9.13 (stretch)

Previously, the RSA private key was generated. And everything worked.
Now a private key has been generated as EC and application (with okhttp3 https://square.github.io/okhttp 12 or direct use ssl) on Android 7.0 - cannot connect (application using android webclient backend is working).

 Solved by rnz in post #10
 
Once again I regenerated the certificate with the RSA, since ApplePay also had problems.

 

 

You're almost certainly running into this issue:

W…

The only way to fix this is by NOT using an EC certificate. Right now you can work around by switching to P-256, but as the future E1 intermediate is P-384, that's not a long term solution.

 


요약

Android Side 에서 SSL Connection Handshake 가 날 때에 인증에 EC 인증서를 사용하면 안된다는 이야기이다. 즉, 안드로이 측면에서 고치려면 RSA 를 강제하고 인증서를 넘기면 된다.

728x90

Improve replication friendliness of the MySQL schema

 

Status quo

The table BATCH_JOB_EXECUTION_PARAMS currently has no primary key.

For a single node MySQL deployment, this does not cause any issue. For a setup of multiple nodes with replication, this is however not ideal as it causes performance problems with row-based replication and leads to ambiguity when calculating check sums over tables to validate the integrity of the replication.

To prevent such issues, MySQL 8 offers the system variable sql_require_primary_key. If set to ON, it is currently not possible to deploy the Spring Batch schema.

Suggestion

As job parameters are handled by Spring Batch internally as maps, it already works with the assumption that job parameter keys are unique for each job execution. This allows to declare a primary key on BATCH_JOB_EXECUTION_PARAMS consisting of JOB_EXECUTION_ID and KEY_NAME.

It would be nice if this (or any other) primary key were defined on BATCH_JOB_EXECUTION_PARAMS in the MySQL schema.

The tables BATCH_JOB_SEQ, BATCH_JOB_EXECUTION_SEQ, BATCH_STEP_EXECUTION_SEQ also do not have a primary key. As they contain only a single row, respectively, this is not a problem in practice. But if the column UNIQUE_KEY were to be declared as primary key, this would allow a seamless deployment to a MySQL instance with sql_require_primary_key=ON.

 

 


BATCH_JOB_EXECUTION_PARAMS

CREATE TABLE BATCH_JOB_EXECUTION_PARAMS  (
	JOB_EXECUTION_ID BIGINT NOT NULL ,
	TYPE_CD VARCHAR(6) NOT NULL ,
	KEY_NAME VARCHAR(100) NOT NULL ,
	STRING_VAL VARCHAR(250) ,
	DATE_VAL DATETIME(6) DEFAULT NULL ,
	LONG_VAL BIGINT ,
	DOUBLE_VAL DOUBLE PRECISION ,
	IDENTIFYING CHAR(1) NOT NULL ,
    PRIMARY KEY (JOB_EXECUTION_ID, KEY_NAME)
	constraint JOB_EXEC_PARAMS_FK foreign key (JOB_EXECUTION_ID)
	references BATCH_JOB_EXECUTION(JOB_EXECUTION_ID)
) ENGINE=InnoDB;

 

Other meta tables

CREATE TABLE BATCH_STEP_EXECUTION_SEQ (
	ID BIGINT NOT NULL,
	UNIQUE_KEY CHAR(1) NOT NULL,
    PRIMARY KEY(UNIQUE_KEY),
	constraint UNIQUE_KEY_UN unique (UNIQUE_KEY)
) ENGINE=InnoDB;

INSERT INTO BATCH_STEP_EXECUTION_SEQ (ID, UNIQUE_KEY) select * from (select 0 as ID, '0' as UNIQUE_KEY) as tmp where not exists(select * from BATCH_STEP_EXECUTION_SEQ);

CREATE TABLE BATCH_JOB_EXECUTION_SEQ (
	ID BIGINT NOT NULL,
	UNIQUE_KEY CHAR(1) NOT NULL,
    PRIMARY KEY(UNIQUE_KEY),
	constraint UNIQUE_KEY_UN unique (UNIQUE_KEY)
) ENGINE=InnoDB;

INSERT INTO BATCH_JOB_EXECUTION_SEQ (ID, UNIQUE_KEY) select * from (select 0 as ID, '0' as UNIQUE_KEY) as tmp where not exists(select * from BATCH_JOB_EXECUTION_SEQ);

CREATE TABLE BATCH_JOB_SEQ (
	ID BIGINT NOT NULL,
	UNIQUE_KEY CHAR(1) NOT NULL,
    PRIMARY KEY(UNIQUE_KEY),
	constraint UNIQUE_KEY_UN unique (UNIQUE_KEY)
) ENGINE=InnoDB;

INSERT INTO BATCH_JOB_SEQ (ID, UNIQUE_KEY) select * from (select 0 as ID, '0' as UNIQUE_KEY) as tmp where not exists(select * from BATCH_JOB_SEQ);

 

[important]

Do not create generated key in PARAMS table like below;

https://docs.spring.io/spring-batch/reference/schema-appendix.html

 

Meta-Data Schema :: Spring Batch

The Spring Batch Metadata tables closely match the domain objects that represent them in Java. For example, JobInstance, JobExecution, JobParameters, and StepExecution map to BATCH_JOB_INSTANCE, BATCH_JOB_EXECUTION, BATCH_JOB_EXECUTION_PARAMS, and BATCH_ST

docs.spring.io

 

'Java' 카테고리의 다른 글

[method] java stream mapToObj  (0) 2024.05.07
자바 어플리케이션 inputstream 주의사항  (1) 2024.04.18
728x90
Spring Batch 에서는 meta table이라고 해서 Batch 의 작업을 도와주는 테이블이 있는데...

 

 

 

 

여하튼 서론은 막론하고 MySQL 8.0 버전을 올리면서 이후부터는 System Variable 로 sql_require_primary_key 가 true 가 걸려있게 되는 경우 application.yml 에서 설정을 해도 작동을 하지 않는다 이말이다

 

전통적으로는 spring.batch.jdbc.

initialize-schema: always

 

이렇게 때려박아 주고 있는데, 여하튼 이거랑 별도로 환경변수에서 저렇게 잡아놓으면 데이터베이스가 생성하고 싶어도 생성할 수가 없다.

 

 

그렇다면 Spring Batch 공식문서로 가보자


The BATCH_JOB_EXECUTION_PARAMS Table

The BATCH_JOB_EXECUTION_PARAMS table holds all information relevant to the JobParameters object. It contains 0 or more key/value pairs passed to a Job and serves as a record of the parameters with which a job was run. For each parameter that contributes to the generation of a job’s identity, the IDENTIFYING flag is set to true. Note that the table has been denormalized. Rather than creating a separate table for each type, there is one table with a column indicating the type, as the following listing shows:

CREATE TABLE BATCH_JOB_EXECUTION_PARAMS  (
	JOB_EXECUTION_ID BIGINT NOT NULL ,
	PARAMETER_NAME VARCHAR(100) NOT NULL ,
	PARAMETER_TYPE VARCHAR(100) NOT NULL ,
	PARAMETER_VALUE VARCHAR(2500) ,
	IDENTIFYING CHAR(1) NOT NULL ,
	constraint JOB_EXEC_PARAMS_FK foreign key (JOB_EXECUTION_ID)
	references BATCH_JOB_EXECUTION(JOB_EXECUTION_ID)
);
 

The following list describes each column:

  • JOB_EXECUTION_ID: Foreign key from the BATCH_JOB_EXECUTION table that indicates the job execution to which the parameter entry belongs. Note that multiple rows (that is, key/value pairs) may exist for each execution.
  • PARAMETER_NAME: The parameter name.
  • PARAMETER_TYPE: The fully qualified name of the type of the parameter.
  • PARAMETER_VALUE: Parameter value
  • IDENTIFYING: Flag indicating whether the parameter contributed to the identity of the related JobInstance.

Note that there is no primary key for this table. This is because the framework has no use for one and, thus, does not require it. If need be, you can add a primary key with a database generated key without causing any issues to the framework itself.


 

간단하게 요약하자면 원래 이 테이블에는 Primary Key 따위는 없는 것인데, 네놈이 꼴린다면 generated Key 를 생성해서 그 키를 Primary Key로 쓸 수 있다 이말씀이다.

 

참고로 MySQL에서 SEQUENCE 를 생성해서 사용하려고 해도 PRIMARY KEY 때문에 작동하지 않을 것이므로 

 

여하튼 데이터베이스를 알게된 이래로 generated key 라는 놈은 처음 들어봣는데

 

 

내용을 잘 살펴보아하자니 프로세스가 진행될 때마다 증가하면서 자동으로 생성되는 놈이라하니 꼭 AI 를 박아놓은 친구처럼 생겼다.

 

그래서 만들어보았다 generated key

CREATE TABLE BATCH_JOB_EXECUTION_PARAMS (
    PARAM_ID BIGINT AUTO_INCREMENT PRIMARY KEY,
    JOB_EXECUTION_ID BIGINT NOT NULL,
    TYPE_CD VARCHAR(6) NOT NULL,
    KEY_NAME VARCHAR(100) NOT NULL,
    STRING_VAL VARCHAR(250),
    DATE_VAL DATETIME(6) DEFAULT NULL,
    LONG_VAL BIGINT,
    DOUBLE_VAL DOUBLE PRECISION,
    IDENTIFYING CHAR(1) NOT NULL,
    CONSTRAINT JOB_EXEC_PARAMS_FK FOREIGN KEY (JOB_EXECUTION_ID)
        REFERENCES BATCH_JOB_EXECUTION(JOB_EXECUTION_ID)
) ENGINE=InnoDB;

INSERT INTO BATCH_STEP_EXECUTION_SEQ (ID, UNIQUE_KEY) select * from (select 0 as ID, '0' as UNIQUE_KEY) as tmp where not exists(select * from BATCH_STEP_EXECUTION_SEQ);
CREATE TABLE BATCH_STEP_EXECUTION_SEQ (
                                        SEQ_ID  BIGINT  AUTO_INCREMENT  PRIMARY KEY ,
                                          ID BIGINT NOT NULL,
                                          UNIQUE_KEY CHAR(1) NOT NULL,
                                          constraint UNIQUE_KEY_UN unique (UNIQUE_KEY)
) ENGINE=InnoDB;


CREATE TABLE BATCH_JOB_EXECUTION_SEQ (
                                         SEQ_ID  BIGINT  AUTO_INCREMENT  PRIMARY KEY ,
                                         ID BIGINT NOT NULL,
                                         UNIQUE_KEY CHAR(1) NOT NULL,
                                         constraint UNIQUE_KEY_UN unique (UNIQUE_KEY)
) ENGINE=InnoDB;

INSERT INTO BATCH_JOB_EXECUTION_SEQ (ID, UNIQUE_KEY) select * from (select 0 as ID, '0' as UNIQUE_KEY) as tmp where not exists(select * from BATCH_JOB_EXECUTION_SEQ);

CREATE TABLE BATCH_JOB_SEQ (
                               SEQ_ID  BIGINT  AUTO_INCREMENT  PRIMARY KEY ,
                               ID BIGINT NOT NULL,
                               UNIQUE_KEY CHAR(1) NOT NULL,
                               constraint UNIQUE_KEY_UN unique (UNIQUE_KEY)
) ENGINE=InnoDB;

INSERT INTO BATCH_JOB_SEQ (ID, UNIQUE_KEY) select * from (select 0 as ID, '0' as UNIQUE_KEY) as tmp where not exists(select * from BATCH_JOB_SEQ);

 

이러면 쌈뽕하게 작동한다

+ Recent posts