Ehache로 추가하고 삭제하고.. 글이 참 많지만

모든 캐시들을 삭제하는 건 글이 별로 없기에 작성한다!

 

Ehcache에 대한 설명과 Config 만드는 법은 아래 글을 참고!

https://kagoon.tistory.com/56

 

spring cache 를 사용 하기 위한 ehcache 사용법

강준한 입니다. 감동을 줄 뻔한 이야기로 시작해보죠. 아들이 치매에 걸린 아버지와 같이 있습니다. 아버지는 멀리 있는 새를 보고 아들에게 물었습니다, 저게 무어냐? 아들이 말하죠... 까마귀

kagoon.tistory.com

 

Class 안에 아래 코드를 적어준다!

 

@Autowired
    private CacheConfig ehcacheManager;

    public void cacheClear () {
    
        CacheManager cacheManager = ehcacheManager.EhcacheManager();
        cacheManager.getCacheNames().forEach(cacheName -> cacheManager.getCache(cacheName).clear());
        
    }

 

그럼 만들어둔 캐싱을 하나씩 불러와 결론적으로 전체 삭제가 되는 것을 확인할 수 있다!

필자의 경우 혹시 모를 실패나 성공 여부를 확인하기 위해 cacheClaer메소드 안을 try catch로 잡았고,

String을 리턴값으로 줘 확인 가능하도록 코드를 구성했다 ㅎㅎ

반응형

뒤로가기 막는 방법이 아니라

지금 페이지가 뒤로가기로 왔는지 아는 방법을 써보려고 한다!

 

// onpageshow의 경우 page 호출되면 무조건 실행됨

window.onpageshow = function (event){

    //뒤로가기로 페이지 접근했는지 확인
    if(event.persisted || (window.performance && window.performance.navigation.type == 2)){

        //쓰고 싶은 코드
        
    }
}

 

이렇게 하면 지금 해당 페이지가 뒤로가기로 접근했는지 확인할 수 있다!

하지만 막상 코드를 입력해보면 navigation.type == 2 부분이 deprecated 되어 취소선이 그어져있는 걸 볼 수 있다.

그대로 써도 기능은 하지만 영 찝찝하다면 밑에 내용으로 쓰면 된다!

 

// onpageshow의 경우 page 호출되면 무조건 실행됨

window.onpageshow = function (event){     //뒤로가기로 페이지 접근했는지 확인
    if(event.persisted || (window.performance && window.performance.navigation.type == 2) || (window.performance.getEntriesByType("navigation")[0].type == "back_forward")){

        //쓰고 싶은 코드
        
    }
}

 

if문 안에 새롭게 window.performance.getEntriesByType("navigation")[0].type == "back_forward" 가 추가된 걸 볼 수 있다.

window.performance.getEntriesByType("navigation")[0].type은 웹페이지의 탐색유형을 반환하는 코드이고,

back_foward는 해당 페이지가 뒤로가기나 앞으로가기로 왔는지 인식해준다!

 

반응형

개발중에 작은 오류 하나에 ... 헛방을 키다 기록용으로 남겨 놓습니다.

mybatis 를 이용한 DB 쿼리 조회에서 

select 안에 join 한 다른 테이블의 리스트 형을 처리 하고자 mybatis의 collection을 이용 하고 있습니다

 

<resultMap type="testVo" id="Map">
    <id property="seq" column="seq"/>
    <result property="userId" column="userId"/>
    <result property="userPw" column="userPw" />
    <collection property="info" javaType="List" ofType="myVo">
        <result property="nameSeq" column="nameSeq"/>
        <result property="testId" column="testId"/>
    </collection>
</resultMap>

resultMap 을 사용 해야 하고 컬렉션 안에는 조인 결과가 많은 리스트로 생성 됩니다

 

실행 결과는 argument type mismatch.....

 

이는 VO 와 DB테이블과 무언가의 변수차이가 난다는 에러 이므로 저와 같은 상황에서는 

myVo 에 info 라는 변수가 존재 해야 하고 info 는 List 타입이어야 해결 됬습니다.

 

반응형

강준한입니다.

스트리밍 버전으로 메모리를 적게 사용 된다고 하는 SXSSF를 이용하여 대용량 엑셀 다운로드 를 사용 했습니다

 

SXSSFWorkbook wb = null;
FileOutputStream fos = null;
SXSSFSheet sheet;
SXSSFRow row;
SXSSFCell cell;
try {
    //크롬 인코딩
    fileName = new String(fileName.getBytes("UTF-8"),"ISO-8859-1");
    wb = new SXSSFWorkbook(100); //메모리 누적 해가면 DISK 에 저장 하는 기준 사이즈
    fos = new FileOutputStream("경로");
    wb.setCompressTempFiles(true);

    sheet = wb.createSheet("Sheet1");

    int position = 0;
    row = sheet.createRow(position);

//          컬럼명
    for (int i = 0; i < columns.length; ++i) {
        cell = row.createCell(i);
        cell.setCellValue(columns[i]);
    }

//          데이터
    for (int i = 0; i < tmpData.size(); i++) {
        position++;
        row = sheet.createRow(position);
        int k = 0;
        for (int column = 0; column < columns.length; ++column) {
            cell = row.createCell(k);
            if (tmpData.get(i).get(columns[k]) != null) {
                cell.setCellValue(tmpData.get(i).get(columns[k]).toString());
            }
            k++;
        }
    }
    res.setContentType("application/vnd.ms-excel");
    // 엑셀 파일명 설정
    res.setHeader("Content-Disposition", "attachment;filename="+파일이름+".xlsx");
    wb.write(res.getOutputStream());

} catch (Exception e) {
    log.error(e.getMessage(), e);

} finally {
    try {
        wb.close();
        wb.dispose();
        if (fos != null) {
            fos.close();
        }
    } catch (IOException e) {
        log.error(e.getMessage(), e);
    }
}

이 방식은 그저 엑셀을 생성 하는 부분이라는 점임니다.

 

주로 엑셀을 다운로드 할 상황은 쿼리를 보내 ROW 를 가져와 엑셀을 만드는 형태입니다.

엑셀의 생성에는 문제 없으나 쿼리가 몇십만 ROW 이다 보니 거기에서 서버가 힘을 내지 못하는 상황이 었습니다.

 

쿼리를 조금씩 가져와 엑셀에 쌓는 방법은 없을까 고민 하다가

org.apache.ibatis 에 괜찮은 기능을 찾았습니다.

 

ResultRowDataHandler

 

주로 mybatis 에서 쿼리를 조회 해오면 리스트에 담아 오는 형태인데 핸들러라는 말이 들어간거 보니 ROW 단위로 DATA를 핸들링 하는 느낌이 들어 심도있게 파봤습니다.

 

public class  ResultRowDataHandler implements ResultHandler {
    private final SXSSFWorkbook workbook;
    private final SXSSFSheet sheet;
    SXSSFRow row;
    SXSSFCell cell;
    FileOutputStream fileOutputStream;
    private final String[] columns;

    public ResultRowDataHandler(Map<String, Object> params, String[] col, Map<String, Object> getConfig) throws FileNotFoundException {
        // 현재 날짜 구하기
        LocalDate now = LocalDate.now();
        // 포맷 정의
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
        // 포맷 적용
        String formatedNow = now.format(formatter);

        workbook = new SXSSFWorkbook(10000);
        workbook.setCompressTempFiles(true);
        sheet = workbook.createSheet("Sheet1");

        row = sheet.createRow(0);
        columns = col;
        //컬럼명
        for (int i = 0; i < columns.length; ++i) {
            cell = row.createCell(i);
            cell.setCellValue(columns[i]);
           
        }

        String savePath = params.get("path").toString() + "/" + formatedNow+"_"+params.get("SaveFileName").toString() + ".xlsx";
        fileOutputStream = new FileOutputStream(savePath);

    }

    @Override
    public void handleResult(ResultContext resultContext) {
        Map<String, Object> result = (Map<String, Object>) resultContext.getResultObject();
        //데이터
        row = sheet.createRow(resultContext.getResultCount());
        int k = 0;
        for (int column = 0; column < columns.length; ++column) {
            cell = row.createCell(k);
            if (result.get(columns[k]) != null) {
                cell.setCellValue(result.get(columns[k]).toString());
            }
            k++;
        }
    }

    public void close() {
        try{
            workbook.write(fileOutputStream);
            workbook.dispose();
            workbook.close();
            fileOutputStream.close();
        }catch (Exception e){
            log.error("ERROR : ", e);
        }
    }
}

우선 핸드러를 여기저기 구글링 하여 여차 저차 작성 했습니다.

가져온 데이터를 앞서 작성해본 엑셀에 차차 쌓는 형식의 헨들링 파일을 작성하고

 

핸들러를 호출 합니다 

다오에서 매퍼로 넘길때까지 핸들러를 같이 넘겨 쿼리를 실행하며 엑셀을 생성 합니다.

30만 ROW 까지는 끄떡없지만 ... 많이 느리네요

반응형

한때 아메리칸 드림을 꿈꾸며 해외 사업에 잠시 몸 담았던 적이 있다

프로젝트를 진행하며 수많은 고난과 역경을 겪었지만
그중 가장 곤란했던 문제는 달러 상품 가격을 설정하는 과정에서 발생했다.

소수점 단위의 숫자들을 연산하는 과정에서 미세한 수치지만 오차가 발생했고,

해결 방법을 열심히 찾아본 결과 이 오차는 부동소수점을 사용하는 double 자료형의 문제점인 것으로 확인했다.


오차가 왜 생겼을까?

컴퓨터는 0과 1로 이루어진 2진법을 사용하여 연산을 수행한다.
그렇기 때문에 10진법으로 이루어진 수를 2진법으로 변환하는 과정에서 오차가 발생할 확률이 존재한다.

0.2 를 2진법으로 변환할 경우
0.001100110011... 과 같이 0011 이 무한으로 반복되는 수가 된다.
0.3 을 2진법으로 변환할 경우도 마찬가지로
0.01001100110011... 과 같이 0011 이 무한으로 반복되어
컴퓨터는 0.2 0.3 과 같은 숫자들을 정확한 값으로 저장하지 않고 근사치로 저장하게 된다.

이때 double을 이용하여 이 둘을 연산할 경우

double salePrice = 0.3;
double discountPrice = 0.2;
System.out.println(salePrice - discountPrice);

 

 

위와 같은 오차가 발생하게 된다.

그렇다면 우리는 이러한 오차를 감수해야할까?


해결 방법은?

오차를 제거할 수 있는 방법 2가지를 찾았다.

가장 간단한 해결 방법은 소수점 연산을 하지 않는 것이다.
소수점 자리만큼 10^n 값을 곱해주고 나눠주는 연산을 통해 간단한 문제는 해결할 수 있다.

double salePrice = 0.3;
double discountPrice = 0.2;
System.out.println( ((salePrice*10) - (discountPrice*10)) /10 );

 


그러나 좀 더 정확한 연산을 위해서는 부동소수점인 float나 double 자료형이 아닌 BigDecimal 자료형을 사용해야 한다.

 

BigDecimal

BigDecimal의 초기화 방법은 다음과 같다.

BigDecimal salePrice = new BigDecimal("0.3");

초기화 과정에서 파라미터를 String 형태로 넘겨주는 것이 중요한데,

다른 숫자 형태의 파라미터로도 BigDecimal 초기화는 가능하지만 이때는 앞선 double 형태의 연산과 마찬가지로 오차가 발생할 수 있다.

따라서, 파라미터를 String 형태로 넘겨주는 것이 중요하다.

 

BigDecimal 연산

연산하는 방법은 다음과 같다

double salePrice = 0.3;
double discountPrice = 0.2;


BigDecimal salePrice2 = new BigDecimal(String.valueOf(salePrice));
BigDecimal discountPrice2 = new BigDecimal(String.valueOf(discountPrice));

// 덧셈 연산
System.out.println(salePrice2.add(discountPrice2));
// 뺄셈 연산
System.out.println(salePrice2.subtract(discountPrice2));
// 곱셈 연산
System.out.println(salePrice2.multiply(discountPrice2));

나눗셈의 경우는 추가적으로 옵션을 설정해주어야 하는데

BigDecimal a = new BigDecimal("0.3");
BigDecimal b = new BigDecimal("0.2");

System.out.println(b.divide(a));

위와같이 나누어지지 않는 수를 나누려 할 경우에 다음과 같은 에러가 발생한다.

Non-terminating decimal expansion; no exact representable decimal result.
java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.

 

따라서 나눗셈에는 다음과 같은 옵션이 추가된다.

System.out.println(b.divide(a, 2, RoundingMode.UP));

2번째 매개변수는 표현할 소수점 자리수, 3번째 매개변수는 처리방식을 나타낸다.

상황에 따라 적절히 옵션을 이용하여 사용하면 될 것이다.

 

BigDecimal 비교

compareTo 메서드를 이용하여 BigDecimal 간의 비교를 할 수 있다.

비교하려는 수가 비교되는 수 보다 클 경우 1, 같을 경우 0, 작을 경우 -1 을 리턴한다.

BigDecimal a = new BigDecimal("2");
BigDecimal b = new BigDecimal("1");
BigDecimal c = new BigDecimal("1");

System.out.println(a.compareTo(b));
System.out.println(b.compareTo(a));
System.out.println(b.compareTo(c));


 

글을 작성하다보니 옛 생각이 새록새록 떠오릅니다.

부족한 글이지만 도움이 되길 바랍니다.

 

감사합니다.

반응형

사내 프로젝트 고도화 중 우편번호 검색을 맡게 되었다.

보통의 경우 주소 API를 쓰겠지만

사내 DB에 매달 업데이트 되는 전국주소테이블을 써야했기에 쿼리를 만들어 테스트해봤다.

 

헌데..

이게 무슨 일이고???

필요한 칼럼들 like or like or ... 하니 3.9초나 걸리네??

이건 도저히 못 써먹는 수준 아닌가..

심지어 인덱싱 걸려있는 칼럼들도 있는데 ㅠㅠㅠ

 

도저히 안 되겠다 싶어서 우리의 친구 구글에 이것저것 검색해보니

FULLTEXT가 나와서 적용해보기로 했다!

 

1. FULLTEXT 만드는 법!

ALTER TABLE 테이블명 ADD FULLTEXT INDEX 인덱스명 (컬럼명) WITH PARSER ngram;

 

사용할 테이블에 위의 방식대로 생성하게 되면 FULLTEXT 인덱스가 만들어진다!

 

만약 나처럼 여러개의 칼럼을 같이 검색하고 싶다면

 

ALTER TABLE 테이블명 ADD FULLTEXT INDEX 인덱스명 (컬럼명, 컬럼명, 컬럼명 .....) WITH PARSER ngram;

 

() 안에 넣고 싶은 칼럼들을 넣으면 생성이 완료된다!

 

ex)

-aaa테이블에 aos라는 칼럼을 bbb라는 인덱스이름으로 만들고 싶을 때

ALTER TABLE aaa ADD FULLTEXT INDEX bbb (aos) WITH PARSER ngram;

-aaa테이블에 aos, bos, cos라는 칼럼을 ccc라는 인덱스이름으로 만들고 싶을 때

ALTER TABLE aaa ADD FULLTEXT INDEX ccc (aos, bos, cos) WITH PARSER ngram;

 

 

 

1-1) WITH PARSER ngram > ??

 

ngram은 한글이 지원하며 2글자 단위로 토큰화 해준다!

     ex) 탈개를 꿈꾸다 > ["탈개", "개를", "꿈꾸", "꾸다"]

 

한글 지원해주니 꼭 이거 써주면 된다 ㅎㅎ

기본값이 2여서 2글자 단위로 토큰화 해주는데

만약 3글자, 4글자부터 시작하는 검색을 구현하고 싶으면 따로 설정 해주면 된다!

- 단 이 경우 3글자 미만인 글자들은 파싱 안해주니 주의!

ex) "함께 가즈아"를 3글자 단위로 토큰화하면 '함께'는 파싱 안해줌

 

2. FULLTEXT 쓰는 법!

바쁜 현대사회인을 위해 다 생략하고 바로 적용하기 좋은 걸 알려주자면

 

select * from 테이블명 where match(풀텍스트인덱스를 한 칼럼명) against ('검색어' in boolean mode);

 

이 방식대로 쓰면 된다!

 

ex)

- 예시로 들었던 bbb인덱스 사용법

select * from aaa where match(aos) against ('검색어' in boolean mode);

- 예시로 들었던 ccc인덱스 사용법

select * from aaa where match(aos, bos, cos) against ('검색어' in boolean mode);

 

 

ngram이 2글자 단위로 토큰화 되니

먼저 2글자로 검색해보면!

 

무려 71ms로 단축됐다!!

 

똑같은 두글자로 검색했는데

약 3.9s에서 71ms로 단축됐으니.. 이 얼마나 엄청난 성능차이인지 ㅠㅠㅠ

헌데 여기서 끝나면 안된다!!

 

2-1) 검색어가 3글자 이상일 때 처리하는 방법!

특정 검색어가 3글자 이상일 경우 느려지는 현상이 있을 것이다.

이건 ngram이 2글자 단위로 파싱해줘서 생긴 문제다.

이것에 대한 해결법은

- 검색어가 "풀텍스트 검색"일 경우

select * from aaa where match(aos) against ('+풀텍 +텍스+ +스트 +검색' in boolean mode);

 

이렇게 하면 다시 빠릿하게 검색되는 게 느껴질 것이다!

검색어를 저렇게 넘기는 건 알고리즘을 짜주면 된다

필자의 경우 for문과 substring을 활용해서 넘겨주었다 ㅎㅎ

 

3. FULLTEXT 주의사항!

위에 예시로 들었던

 

ALTER TABLE aaa ADD FULLTEXT INDEX ccc (aos, bos, cos) WITH PARSER ngram;

 

ccc 인덱스를 아래와 같이

 

select * from aaa where match(aos, bos) against ('검색어' in boolean mode);

써도 될까?!

정답은 X다!

 

ccc 인덱스에 aos,bos,cos 칼럼을 걸어놨으니 무조건

(aos,bos,cos) 3개를 다 써야한다!

만약 aos, bos만 쓰고 싶다면 aos,bos를 쓰는 FULLTEXT Index를 새로 만들어주면 된다 ㅎㅎㅎ

 

 

 

 

 

 

 

출처 및 글 인용 --

https://inpa.tistory.com/entry/MYSQL-%F0%9F%93%9A-%ED%92%80%ED%85%8D%EC%8A%A4%ED%8A%B8-%EC%9D%B8%EB%8D%B1%EC%8A%A4Full-Text-Index-%EC%82%AC%EC%9A%A9%EB%B2%95
https://kabkee.github.io/mysql/mysql-full-text-search/
https://m.blog.naver.com/jjdo1994/222348191751
https://gongzza.github.io/database/mysql-fulltext-search/

반응형

강준한 입니다.

감동을 줄 뻔한 이야기로 시작해보죠.

아들이 치매에 걸린 아버지와 같이 있습니다.

아버지는 멀리 있는 새를 보고 아들에게 물었습니다,

저게 무어냐?

 아들이 말하죠...

까마귀요...

잠시 뒤, 치매에 걸린 아버지가 다시 물었습니다,

저게 무어냐?

아들이 다시 말하죠...

까마귀 라니까요

아버지는 잠시 뒤 다시 물었습니다

 저게 뭐라고?

아들은 짜증이 났습니다.

 까마귀라고요. 까!!마!!귀!!

아버지는 잠시 뒤 다시 물었습니다

저게 무어냐?

아들은 화를내며 큰소리로 말합니다.

까마귀라고요! 까마귀. 왜 자꾸 같은 SELECT를 반복하세요!!

 

그렇습니다 ... 아들에게는 cache가 적용되어 있지 않았던 것입니다. 

그래서 화(부하)가 발생했던 것입니다.

 

cache는 이런 간단하고 반복된 답을 줘야 하는 내용을 어느 한켠에 저장 했다가

바로 꺼내어 줄수 있는 방법입니다.

 

스프링에서는 아주 간단하게 사용이 가능 합니다.

implementation group: 'org.springframework.boot', name: 'spring-boot-starter-cache', version: '2.7.9'

종속성을 먼저 추가 한 후에 사용 하시면 됩니다.

물론 예시라서 따라 치면 오류납니다.

이 캐시의 어노테이션의 종류는 5가지 정도가 있습니다.

 

@Cacheable : 동일한 파리 미터로 메서드를 호출 이력과 반환 결과가 캐시에 저장되어 있으면

@CacheEvict : 캐시에 저장된 호출 이력 및 결과 값을 삭제

@CachePut : 캐시에 저장된 결괏값을 업데이트

@Caching : 여러 개의 캐시 어노테이션 옵션을 동시에 활성화하고자 할 때 사용

@CacheConfig : 캐시 옵션을 메서드 단위가 아닌 클래스 단위로 설정하고자 할 때 사용

 

그림에서 사용한 @Cacheable 키 벨류로 데이터를 저장하고 사용 되겠죠 마치 맵과 같네요

키를 안쓰면 뭐 그 안의 알고리즘으로 자동 생성 된다고 합니다.

 

선언후에 삭제 하거나 변경하는 작업을 주로 쓰겠죠? 사용 시점에 잘 분배해서 사용 하시면 될 것같습니다.

주로 많이 사용 하는 게시판을 예로 들면 리스트를 불러올때 @Cacheable 을 선언할 것이고

insert나 업데이트를 할때 캐시를 업데이트 할테고 ... delete 할때는 캐시를 비웠다가 다시 리스트를 불러올때 선언 하겠죠? ( 맞을까? )

 

하지만 사용 하다보면 각 상황에 맞는 포인트를 찾기 쉽지 않아 제때 알아서 한번씩 비워주고 다시 생성 됬으면 합니다.

물론 자동으로요 

 

여기저기 구글링을 하다 보니 ehcache 라는 녀석이 눈에 띕니다. redis 캐시도 눈에 뛰구요

하지만 과하게 가지 않고 로컬에 저장되고 사용되길 원하니 ehcache 를 사용 해봅니다. 종속성을 추가 해줍니다

 

implementation group: 'org.ehcache', name: 'ehcache', version: '3.10.0'

 

/***
private String soliloquy() throws Exception {

    return "속으론 여러번 고민한게 있었는데 이거는 그냥 쓸데없는거같지만 뭐랄까....
    메모리를 사용하는 레디스 캐시를 사용하면 1유저의 세션을 저장한다고 했을때 용량산정에 
    대한?? 이게 고민 할 문제가 맞을까요 ...? .. 암튼";
}
***/

 

버전은 자유겠지요 ... 저는 https://mvnrepository.com/ 에서 종속성을 검색한 후에 최근 몇개월간 중 많이 사용된 버전을 주로 사용 합니다. 전세계 테스터들이 좋으니까 썻겟죠?

 

ehcache 설정은 많이 검색해봤지만 xml 설정 만 나오는 거같아요

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://www.ehcache.org/ehcache.xsd"
         updateCheck="true"
         monitoring="autodetect"
         dynamicConfig="true">

    <diskStore path="io.dveamer.sample.ehcache"/>

    <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            overflowToDisk="true"
            maxElementsOnDisk="10000000"
            diskPersistent="false"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU"
    />

</ehcache>

전부 모르겠고 중요해 보이는 

maxElementsInMemory : 수치는 모르겠지만 찾아보니 바이트 단위 인듯 합니다

timeToIdleSeconds : 120초 동안 재요청이 없으면 비우고
timeToLiveSeconds : 120초 동안 살려 놓는다는 뜻인가 보네요

 

xml 설정은 JAVA CONFIG로 변경 해봅니다

import org.ehcache.config.CacheConfiguration;
import org.ehcache.config.builders.CacheConfigurationBuilder;
import org.ehcache.config.builders.ExpiryPolicyBuilder;
import org.ehcache.config.builders.ResourcePoolsBuilder;
import org.ehcache.config.units.MemoryUnit;
import org.ehcache.jsr107.Eh107Configuration;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.cache.CacheManager;
import javax.cache.Caching;
import javax.cache.spi.CachingProvider;
import java.time.Duration;

@EnableCaching
@Configuration
public class CacheConfig {
    @Bean
    public CacheManager EhcacheManager() {

        CacheConfiguration<String, Object> cachecConfig = CacheConfigurationBuilder
                .newCacheConfigurationBuilder(String.class,
                        Object.class,
                        ResourcePoolsBuilder.newResourcePoolsBuilder()
                                .offheap(10, MemoryUnit.MB)
                                .build())
                .withExpiry(ExpiryPolicyBuilder.timeToIdleExpiration(Duration.ofSeconds(3600)))
                .build();

        CachingProvider cachingProvider = Caching.getCachingProvider();
        CacheManager cacheManager = cachingProvider.getCacheManager();

        javax.cache.configuration.Configuration<String, Object> configuration = Eh107Configuration.fromEhcacheCacheConfiguration(cachecConfig);
        cacheManager.createCache("test", configuration);
        return cacheManager;
    }
}

여기서는 offheap 에 10 메가로 설정했고

재요청이 3600초 동안 없으면 지우는 걸로 설정 했어요 

.withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofSeconds(3600))));

을 추가 하기 전에 이걸로 테스트 해보려 합니다 . 재요청이 계속 있으면 죽이 않는지 ..

 

그리고 나서 케시 이름을 지정하여 생성 해줍니다 

저는 test를 만들어놓고 사용해봅니다

 

위에

이렇게 사용 벨류에 케시 이름으로 만들어논 캐시 영역을 사용 하시면 됩니다.

 

지금까지 테스트는 잘되고 잘 캐싱이 되고 있는데 

문제가 생기면 같은걸로 다시 포스팅 해보겠습니다.

 

그럼 이만

반응형

저번에 들른 오문창 순대국밥집

20대에 주로 순대국밥이라 함은 응당 농민순대 or 광천순대 였지만

여기도 유명 하다고 해서 먹어보았다.

점심식사 시간이 아닌 2시 즈음에 방문 했는데도 꽉 차있는 식당안 뭔가 기대 하게 한다.


주위 말론 볶음도 맛잇고 순대도 맛잇다지만 ... 해장의 의미로 순대국밥으로만 하자


비주얼은 여느 다른 순대국밥과 다른건 없다. 이상하게 대전 순대국밥 하면 좀전에 언급한 돼지국밥집은 돼지의 비릿한 냄새가 조금씩 낫는데 이건 좀 약하다. 비린거 못먹는 녀석도 약간 입에 대는거 보니

대전의 순대국밥집 가본곳은 모두 토렴을 해서 인지 밥알에 간이 딱 베어있다 여기도 마찬가지인듯한 느낌을 받았음


난 양념파 추가


다먹엇다. 솔직한 후기로는 잡내가 별로 안나고 맛은 보통정도? 가격은 역시 착하고 어린애들도 많은거 보니 모두 즐길수 있는 곳인것 같다. 



반응형

친구 집들이로 대전에 들르면서 요즘 떠오르는 성심당을 방문 했다.



그냥 은행동에 사람이 많은건줄 알앗고 그늘에서 쉬는줄 알앗지만 빵집에 들어가려고 줄을 선 천막 발견

아울렛에서 명품가방 사러 들어가는 사람들 줄스는 것도 충격인데 이또한 신선한 충격


영자언니가 선택한 빵킷리스트 때문인 효과인듯하다 명란젓은 겁나 짠데... 비린맛도 있고 근데 빵이랑...

궁금하다 맛이...


입구에서 상단한 줄이 보이는데 들어가자마자 왼쪽으로 오면 명란 바게트 사려는 줄이 있는데 2층을 침범하여 줄을 선다.

오른쪽줄도 길어서 보니 그건 튀김소보루 줄이란다.


고작 빵의 인기가 ... 2층계단을 뺑 둘러 돌아올 정도로 줄을 섯다.

더 기대된다.



고지가 가까울무렵

바게트 떨어져서 다시 나오는데 1시간 걸린덴다. ㅠ



결국 먹지 않았다.... 1시간을 빵따위에게 허락하지 않는다 ....

반응형

+ Recent posts