InnoDB Lock: REF
엔진확인
mysql> show engines;
mysql> show variables; (autocommit등의 Variables 확인)
Spring 의 @Transactional과 함께 사용하면 autcommit이 일반적으로는 자동으로 풀렸다가 다시 설정 된다.. REF(Stack-overFlow) REF
=======================================
Mysql에서 엔진이 innodb(요즘 보통다 이러함)일 경우, row level lock이 지원된다.REF
- start transaction -> 작업 -> commit 순으로 수행하면 된다.
start transaction;
select * from sales_item where id=99 lock in share mode;
commit;
transaction도중에 다른 작업이 또 들어오면
1. wait이 되거나 (위 REF 참조)
2. 자동으로 에러가 나서 거절이 되는데..
(1,2번 중 원하는 데로 선택을 어떻게 하는지 ... 연구 중)
select for update도 있긴한데.. 한 문장 밖에 안되므로 좀 활용도가 떨어지지만
spring의 @Transactional과 같이 사용하기에 유리하다. REF
일단 설정 파일에서
init_connect = 'set autocommit=0'
으로 설정하여 오토커밋을 해제합니다. 기본적으로 mySQL 설치 시엔 오토커밋일 설정되어 있습니다
innodb_lock_wait_timeout 확인 방법.
show variables like '%wait_timeout%';
MockMvc결과가 문자열 json일 때 쉽게 체크하는 법은 jsonPath를 사용하는 방법. REF
그러나, 결과가 Attribute내에 Object 등으로 오는 경우가 많은데..
이럴 경우에는 org.hamcrest.Matchers 를 사용하면 좋다.
<Attribute가 단순 String일 경우>
.andExpect(model().attribute("ReserveResult", org.hamcrest.Matchers.containsString("rtncd=0000")));
<(result내의 Model) Attribute가 Json Object일 경우> org.hamcrest.Matchers.CustomMatcher를 사용한다.
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
//Check if rtncd="0000"
Matcher< ResultClass > resultMatcher = new CustomMatcher< ResultClass >("") {
public boolean matches(Object object) {
return ((object instanceof ResultClass) && ((ResultClass) object).getRtncd().equals("00"));
}
};
mockMvc.perform(request)
.andDo(print())
.andExpect(status().is3xxRedirection())
.andExpect(model().attribute("reserveResult", resultMatcher));
========node와 연계해서 빌드도 가능===========REF
spring과 npm을 연계해서 빌드시에,
$npm run build:js 등으로 package.json을 이용해 직접 build명령을 내릴 수도 있다.
npm REF
- npm은 필요모듈 설치시, 글로벌설치/로컬설치 가능. 일반적으로는 로컬설치가 좋지만 선택이 어려울경우가 있다.
npm 환경설정 npm
각종 npm 패키지 명령: REF
- npm list browserify
- npm view browerify version ( 최신버전확인)
- npm remove browserify
- npm install (-g) browserify (-g: global)
<빌드 LifeCycle>: REF
default 빌드 LifeCycle은 다음과 같다.
- validate - validate the project is correct and all necessary information is available
- compile - compile the source code of the project
- test - test the compiled source code using a suitable unit testing framework. These tests should not require the code be packaged or deployed
- package - take the compiled code and package it in its distributable format, such as a JAR.
- verify - run any checks on results of integration tests to ensure quality criteria are met
- install - install the package into the local repository, for use as a dependency in other projects locally
- deploy - done in the build environment, copies the final package to the remote repository for sharing with other developers and projects.
아래와 같이 springBoot 실행도 가능.
$mvn springboot run REF
------------------------------------------------------------------------------------------------------------
=====maven 확인======== REF
$mvn -version
없으면 mac의 경우에는 brew install maven
=======BUILD+package=============== REF
$mvn package
빌드 에러메시지를 상세히 보고 싶다면
$mvn -e -X package
===기본설명===
spring 에서 pom.xmL을 이용해 maven 의존성 관리를 한다.
maven을 직접사용하는 방법도 있는데
maven 설치 후
$ mvn archetype:generate 해서 각종 값을 넣고 나면 (주로 package 명으로 넣으면된다)
pom.xml까지 자동 생성이 되며,
$ mvn compile exec:java -Dexec.mainClass=com.ky.App
으로 바로 커맨드 상에서 실행한다.
매우 유용하다.
=== MOJO ============
MOJO : Maven plain Old Java Object 이다. REF
- maven의 java-plugin을 만드는데 사용된다.
만들때는 @Mojo를 써서 간단히 만들 수 있다는데, 만들일 은 잘 없고.. 쓸 일은 많으니.. .. 쓸 때 위주로 보면.
groupId | This is the group ID for the plugin, and should match the common prefix to the packages used by the mojos |
artifactId | This is the name of the plugin |
version | This is the version of the plugin |
packaging | This should be set to "maven-plugin" |
dependencies | A dependency must be declared to the Maven Plugin Tools API to resolve "AbstractMojo" and related classes |
plugin내의 mojo를 실행시키려면
- "$mvn sample.plugin:hello-maven-plugin:1.0-SNAPSHOT:sayhi" 로도 가능하다.
($mvn groupId:artifactId:version:goal )
spring 컨트롤러나 서비스 등의 안에서, 웹 서비스를 접속할 필요가 있을경우 RestTemplate(혹은 RestOperation)을 이용하면 편리하다.
get/post
For
Object/Entity 의 형태로 함수명이 존재한다.
즉 결과를 Object형태로 받을 수도 있고, Entity형태로 받을 수도 있다.
파라미터로
-Object, Map, ClassType 등을 다양하게 이용할 수 있다.
patch/update/delete/option 함수들도 존재한다.
spring에서
@Cacheable
@Cacheevict
@Cacheput
을 이용해서 각종 조건을 지정하면서... 함수 리턴결과 등을 cache할 수 있다.
단, Cacheable등은 proxy형태의 AOP이므로, 별도 class를 만들어서 추가해야 한다.
@CacheConfig(cacheNames = CacheManagerConfig.DEFAULT_CACHE_NAME) public class ForCacheService {
@Cacheable(key = "'myCache'")
public Optional<Something> findSomething(){
return db.findSomething();
}
@CacheEvict(key = "'myCache'")
public void clearCache() {
log.info("clear cache: key=myCache");
}}
==> 음 Optional은 serialize가 안되서 Cache가 안되는 문제 발견.
일반 class 일 경우에도 implements Serializable을 해야 한다.
null Value가 cache가 안되도록 하려면 다음과 같이 #unless를 이용하면 된다. REF
(unless는 함수가 실행된 이후에 평가됨. 즉, cache가 있을때는 상관없이 pass.)
@Cacheable( key="'myCache'", unless="#result == null")
public Person findPerson(int pk) {
return getSession.getPerson(pk);
}
null Value도 cache가 되도록 하고 싶으면? ==>안됨.
REF-spring REF-etc Validataion-Group
spring 에는 annotation으로 form 필드를 자동으로 체크할 수가 있다.
일반적으로는
xxForm.java 파일을 하나 만들고 그 안에 Form과 일치하도록 모든 Field를 정의한 다음에...
각 필드별로 여러가지 constraint를 정의할 수 있다.
@Pattern : Regex패턴 체크.
@NotNull @Null
@Size(min=2, max=30)
@Past (지난 날짜) @Future
@Max @Min @DecimalMax @DecimalMin 2Digits
@AssertFalse @AssertTrue
<기본사용>
예제)
public class MyForm {
@NotNull(message = "{error.not_input}")
@Length(max = 3, message = "{error.max_length}")
private String age;
@NotNull(message = "{error.not_input}")
@Length(max = 255, message = "{error.max_length}")
private String name;
@Pattern(regexp = MyConstant.MAIL_ADDRESS, message = "{error.mail_address_format_error}")private String email;
}
컨트롤러에서 아래와 같은 형태로 값을 받는다.
public String checkPersonInfo(@Valid PersonForm personForm, BindingResult bindingResult)
==========1=====================
간단히 Override로 Custom Validator를 만들 수 있다.
@Data
@NoArgsConstructor
@CmsMemberMailValidator(newMailAddressField = "newMailAddress", mailConfirmField = "mailConfirm")
public class CmsMemberMailModifyForm {
private Long id;
private String displayName;
private String status;
private String organizationName;
private String mailAddress;
@NotNull(message = "{error.mail_address_null_error}")
@Pattern(regexp = WebConstantShared.MAIL_ADDRESS, message = "{error.mail_address_format_error}")
private String newMailAddress;
@NotNull(message = "{error.mail_address_null_error}")
private String mailConfirm;
public static CmsMemberMailModifyForm of(CmsMemberDetail cmsMemberDetail) {
CmsMemberMailModifyForm form = new CmsMemberMailModifyForm();
BeanUtils.copyProperties(cmsMemberDetail, form);
return form;
}
}
@Target({ TYPE }) @Documented | |
@Retention(RUNTIME) | |
@Constraint(validatedBy = Validator.class) | |
public @interface CmsMemberMailValidator { | |
String message() default "{error.mail_address_format_error}"; | |
Class<?>[] groups() default {}; | |
Class<? extends Payload>[] payload() default {}; | |
String newMailAddressField(); | |
String mailConfirmField(); | |
class Validator implements ConstraintValidator<CmsMemberMailValidator, Object> { | |
private String message; | |
private String newMailAddressField; | |
private String mailConfirmField; | |
@Override | |
public void initialize(CmsMemberMailValidator constraintAnnotation) { | |
message = constraintAnnotation.message(); | |
newMailAddressField = constraintAnnotation.newMailAddressField(); | |
mailConfirmField = constraintAnnotation.mailConfirmField(); | |
} | |
@Override | |
public boolean isValid(Object value, ConstraintValidatorContext context) { | |
BeanWrapper beanWrapper = new BeanWrapperImpl(value); | |
String newMailAddressValue = (String) beanWrapper.getPropertyValue(newMailAddressField); | |
String mailConfirmValue = (String) beanWrapper.getPropertyValue(mailConfirmField); | |
//check only different case (null & blank Error_Message is processed on @NotNull annotation) | |
if (newMailAddressValue != null && StringUtils.isNotBlank(newMailAddressValue) | |
&& mailConfirmValue != null && StringUtils.isNotBlank(mailConfirmValue) && !mailConfirmValue | |
.equals(newMailAddressValue)) { | |
context.disableDefaultConstraintViolation(); | |
context.buildConstraintViolationWithTemplate(message) | |
.addPropertyNode(mailConfirmField) | |
.addConstraintViolation(); | |
return false; | |
} | |
return true; | |
} | |
} | |
} |
==========2===================
위보단 약간 복잡하지만 좀 더 많은 기능이 있는 @InitBinder를 이용해
Custom Validator를 만들 수 있다.
Custom Validator: spring-REF Ref-InitBinder
Custom Validation Class를 만들 수도 있다.
.
< Valid vs Validated > REF1simple, REF2,
Validated는 spring 소속이고, Valid는 java소속인데
Validated가 Validataion-Group을 지정할 수 있다.
에러메시지도 출력가능하다. REF
javascript로 이메일 verification하는 스크립트가 왜케 복잡한 것만 있는지..
인터넷에 마음에 드는 게 없어서 새로 만들어 보았다.
//check if mail address is xx@xx.xx (xx: contains "." & "_" & "-" & "alphanumeric" )
function validateEmail(email) {
var re = new RegExp("^[-a-zA-Z0-9._]+@[-a-zA-Z0-9._]+\\.[-a-zA-Z0-9._]+$");
return re.test(email);
코멘트 처럼 xx@xx.xx 폼을 체크하는데 xx 는 - . _ 알파뉴메릭 으로 이루어진다.
조금 더 발전하면.. (이건 다른사람 꺼)
"[_A-Za-z0-9-\\+]+(\\.[_A-Za-z0-9-]+)*@[A-Za-z0-9-]+(\\.[A-Za-z0-9-]+)*(\\.[A-Za-z]{2,})";