1

내 POJO (카테고리)는 langMap (언어 맵)이며 Locale -> String 매핑을 저장합니다. 내가지도를 업데이트 할 때까지 그것은 잘 작동JPA @ ElementCollection이 신비하게 캐시 됨

@Entity 
class Category implements Serializable { 

    @ElementCollection 
    @MapKeyColumn(name = "locale") 
    @Column(name = "name") 
    @CollectionTable(name = "CategoryName", joinColumns = @JoinColumn(name = "category_id")) 
    private Map<Locale, String> langMap = new HashMap<>(); 

    // other fields skipped. 

} 

:이 정의되어 코드는 간단하다 :

public void replaceLangMap(Map<Locale, String> map) { 
    langMap.clear(); 
    langMap.putAll(map); 
    } 

지우기 모든 langMap 넣어 새 값. (물론, @Transactional merged())

그러나보기 레이어를 새로 고침 할 때 이전 맵의 결과가 표시되는 경우가 있습니다. 캐싱 레이어를 추가하지 않을 것이라고 확신합니다. 여기

제가보고 정의 : 예

, 올바르게 도시되어있는 MySQL

en -> Vocation 
de_DE -> Berufung 

저장 한 종류가있다 :

mysql> select * from CategoryName where category_id = 1; 
+-------------+----------+--------+ 
| category_id | name  | locale | 
+-------------+----------+--------+ 
|   1 | Berufung | de_DE | 
|   1 | Vocation | en  | 
+-------------+----------+--------+ 
2 rows in set (0.00 sec) 

하고 뷰 층

, 각 이름에 의도적으로 "X"를 추가했습니다.

enter image description here

투입 후에는 제대로 된지도를 교체하고 MySQL의의 값은 정말 수정 :

mysql> select * from CategoryName where category_id = 1; 
+-------------+-----------+--------+ 
| category_id | name  | locale | 
+-------------+-----------+--------+ 
|   1 | BerufungX | de_DE | 
|   1 | VocationX | en  | 
+-------------+-----------+--------+ 
2 rows in set (0.00 sec) 

을하지만 같은 페이지를 다시로드 할 때, 나는 가끔 (도시 고지도를 볼 수 없습니다 항상 50/50)

18:14:42.698 INFO models.Category - en -> VocationX 
18:14:42.698 INFO models.Category - de_DE -> BerufungX 

18:14:42.706 INFO models.Category - en -> VocationX 
18:14:42.706 INFO models.Category - de_DE -> BerufungX 

18:14:44.165 INFO models.Category - en -> Vocation 
18:14:44.165 INFO models.Category - de_DE -> Berufung 

로그가 아닌 뷰 층 도메인 오브젝트 (Category)에 기록된다. 모든 새로 고침은 POJO에서 로그를 트리거합니다. 따라서 뷰 레이어가 아무 것도 캐시하지 않는다고 확신합니다.

메모리에서이 제거되지 않고, 최대 절전 모드가 때때로 해당 버전을 얻는 것 같습니다. 다시 수정하면 무작위로 회전하는지도의 3 가지 버전이 있습니다 ... 이상합니다.

서버를 다시 시작하면 항상 올바른 langMap을 얻을 수 있습니다.

무엇이 잘못 될 수 있습니까?

환경 :

hibernate-jpa-2.1-api-1.0.0.Final 
Hibernate 4.3.1.Final 
MySQL 5.5.21 - MySQL Community Server 
Table is innodb 
mysql client library : mysql-connector-java 5.1.27 

------------ 호기심에서

------------ 업데이트, 내가 찾고 싶어요 여부를 CategoryDao.get(1) 정말 안타 db. 나는 hibernate.show_sql=true을 켜고 CategoryDao.get(1)에 일부 로깅을 추가 한 다음 프로세스를 다시 실행합니다.

@Override 
    public Category get(Serializable id) { 
    if (id == null) 
     throw new PersistenceException("id may not be null"); 
    Category obj = emp.get().find(Category.class, id); 
    logger.info("get id={} of object class {}", id, Category.class.getSimpleName()); 
    return obj; 
    } 

그리고 결과 :

select aaa as aaa , bbb as bbb , … // fields skipped 
    from 
     Category category0_ 
    left outer join 
     CategoryName langmap1_ 
      on category0_.id=langmap1_.category_id 
    where 
     category0_.id=? 
INFO d.CategoryDao$$EnhancerByGuice$$1904dfdf - get id=1 of object class Category 
INFO d.CategoryDao$$EnhancerByGuice$$1904dfdf - get id=1 of object class Category 
INFO d.CategoryDao$$EnhancerByGuice$$1904dfdf - get id=1 of object class Category 

이 모든 get() 예상 될 것이었다으로, 이전 데이터는 SQL 로그를 표시되지 않는, 로거를 트리거하지만. 그들은 DB를 치지 않는 것 같습니다. 때로는 최신 데이터가 SQL 로그를 표시하지 않습니다. 어쨌든 SQL 코드를 보여 주면 그 결과는 확실히 최신입니다.

이것은 캐시 문제로 보입니다. 하지만 여기에 ehcahce를 포함하여 어떤 캐시도 사용하지 않습니다. 심지어 hibernate.cache.use_query_cachehibernate.cache.use_second_level_cache을 false로 설정했지만 헛수고입니다.

무엇이 잘못 될 수 있습니까?

은 ------------ 주석에서 업데이트 2 ------------

, 나는 내가 DAO의 get(id)@Transactional을 도입하여 문제를 해결할 생각했다 방법. 그러나 전체 (웹) 액션이 카테고리를 검색 할 때만 작동합니다. 그것은 아무리 내가 수정하는 방법, 잘 작동하지

public Result category(@Param("id") Long id) { 
    Category category = categoryDao.get(id); 
    return Results.html()  
     .render("category" , category); 
    } 

범주의 langMaplangMap가 제대로 DB에 저장하고 DB에서 검색한다 : 예를 들어, 다음은 OK입니다. 나는 SQL을보고, 모든 get(id)은 실제로 DB를 쳤다.

그러나 실제로이 작업은 일반적으로 하나의 범주 개체를 렌더링하지 않습니다. 예를 들어, 나는 범주 아래에 다른 subCategories를 가져 오는 쿼리, 또는 항목이 있습니다

Category category = categoryDao.get(id); 
Map<Category , Long> catMap = categoryDao.getSubCategories(category).stream() 
    .collect(Collectors.toMap(cat -> cat, cat -> categoryDao.getChildCount(cat))); 

List<DataDto> dataList = dataService.getDataList(category , page , count); 

이러한 조치는, OK 보인다 오프라인 테스트도 OK입니다. 그러나 온라인에서 카테고리의 langMap을 업데이트 한 후 신비하게 캐시 된 langMap은 때때로 다시 뜨다 (WTF!). 그리고 categoryDao.get(id)이 항상 DB를 치는 것은 아닙니다.

글쎄, 여기에 무슨 문제가있을 수 있습니까?

+0

, 나는 Transactional' @ 내 DAO의'공공 부문 얻을 (직렬화 ID)', 그리고 이상한 행동에'추가 : 여기

몇 가지 링크입니다 사라졌습니다 ... 나는 여전히 이상하게 느껴집니다 ... 왜 읽는 것이 거래가되어야합니까 ... – smallufo

+0

죄송합니다, 이전 코멘트를 철회해야합니다. 'Update 2'를보십시오. – smallufo

+0

신비한 캐싱을 제거하는 유일한 방법은 모든 DAO의 메소드'@ Transactional'을 표시하는 것입니다 (또는 DAO 클래스'@ Transactional'을 표시하는 것입니다). 아무거나 독서 또는 다른 사람. C/U/D는 틀림없이'@ Transactional'입니다. 그러나'@ TransactionTo'를 읽는 것을 좋아하지 않습니다. 왜냐하면'@ OneToMany'를'LAZY' 페칭으로 무효화 할 것이기 때문입니다. 나는 여전히 더 나은 해결책을 찾고있다. – smallufo

답변

1

정확한 코드가 없으면 잘못되었다고 말하는 것이 정말 어렵습니다.

일부 관찰 :

는 항상 또는 @UnitOfWork (읽기 전용) (액세스를 쓰기 위해) @Transactional 중 하나를 사용하십시오. @Transactional 또는 @UnitOfWork 밖에있는 모든 것은 연결되지 않습니다. 아무 연결도없는 경우에 당신의 목표의 분야는 마술로 새롭게 할 것이다.

따라서 Ninja HTML 템플릿에서 Hibernate 프록시 객체를 렌더링하는 것은 잘못 될 수 있습니다. 특히 프록시가 분리되거나 제대로 동기화되지 않은 경우 연결이 없습니다. 그리고 템플릿은 특수 프록시 속성을 처리하는 방법을 알고있을 수도 있고 모를 수도 있습니다.

조회수의 세션 패턴 : 나는 반 패턴으로 만 알고 있습니다. Ninja에서 작동하도록 만드는 이론적 방법은 있지만 권장하지는 않습니다. 엄지 손가락의 규칙은 마술없이 POJO 만 렌더링하는 것입니다. 이상한 일이 극적으로 발생하는 비율을 줄입니다.

귀하의 질문은 guice-persist (닌자가 사용) 및 Ninja와 더 관련이있는 것으로 보입니다.마지막으로