私のPOJO(Categoryという名前)には、マッピングlangMap
を格納する (Language Map) があります。Locale -> String
次のように定義されています。
@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() です)
しかし、ビューレイヤーを更新すると、古いマップの結果が表示されることがあります。キャッシュレイヤーを追加していないと確信しています。
ここに私が見るものがあります:
たとえば、 を格納するカテゴリが 1 つあります。
en -> Vocation
de_DE -> Berufung
mysqlでは正しく表示されます:
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」を追加しました。
コミット後、古いマップが正しく置き換えられ、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 でログがトリガーされます。したがって、ビューレイヤーは何もキャッシュしていないと確信しています。
メモリから消去されていない古いものがあるようでlangMap
、休止状態は時々そのバージョンを取得します。もう一度修正すると、ランダムにローテーションする 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 ログが表示されません。彼らはデータベースにアクセスしていないようです。最新のデータに SQL ログが表示されないことがあります。とにかく、SQLコードが表示されれば、結果は間違いなく最新です。
これはキャッシュの問題のようです。ただし、ここではキャッシュ (ehcahce を含む) を使用していません。hibernate.cache.use_query_cache
とhibernate.cache.use_second_level_cache
を false に設定しましたが、無駄でした。
ここで何が間違っている可能性がありますか?
------------ 更新 2 ------------
@Transactional
コメントで、 DAOのget(id)
方法を紹介することで問題を解決できると思いました。ただし、(Web の) アクション全体がカテゴリのみを取得する場合にのみ機能します。たとえば、次は問題ありません。
public Result category(@Param("id") Long id ) {
Category category = categoryDao.get(id);
return Results.html()
.render("category" , category);
}
カテゴリをどのように変更しても、正常に機能langMap
しlangMap
、 db に正しく保存され、 db から取得されます。SQL が表示されます。すべてget(id)
が実際にデータベースにヒットします。
しかし実際には、このアクションは通常、1 つのカテゴリ オブジェクトをレンダリングするだけではありません。たとえば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。しかし、オンラインの場合、カテゴリの を更新した後langMap
、不思議なことにキャッシュされlangMap
た が再び浮き上がることがあります (WTF!)。また、categoryDao.get(id)
常に DB にヒットするとは限りません。
さて、ここで何が間違っているのでしょうか?