Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/jpa/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Hibernate JPA@ElementCollection神秘缓存_Hibernate_Jpa_Jpa 2.0_Hibernate Entitymanager_Guice Persist - Fatal编程技术网

Hibernate JPA@ElementCollection神秘缓存

Hibernate JPA@ElementCollection神秘缓存,hibernate,jpa,jpa-2.0,hibernate-entitymanager,guice-persist,Hibernate,Jpa,Jpa 2.0,Hibernate Entitymanager,Guice Persist,我的POJO(命名类别)有一个langMap(语言映射),它存储Locale->String映射。它的定义是: @Entity class Category implements Serializable { @ElementCollection @MapKeyColumn(name = "locale") @Column(name = "name") @CollectionTable(name = "CategoryName", joinColumns = @JoinColu

我的POJO(命名类别)有一个
langMap
(语言映射),它存储
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.

}
在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):

日志写入域对象(
类别
),而不是视图层。每次刷新都会触发POJO中的日志。所以我确信视图层没有缓存任何东西

似乎有一个过时的
langMap
没有从内存中清除,hibernate偶尔会得到这个版本。如果我再次修改它,将会有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
------------更新-----------------

出于好奇,我想知道
类别dao.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\u query\u cache
hibernate.cache.use\u second\u level\u 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
正确地存储到数据库并从数据库中检索。我看到SQL,每一个
get(id)
都会真正击中数据库

但实际上,此操作通常不会仅渲染一个类别对象。例如,我有其他查询获取
子类别
,或类别下的项目:

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);
Category-Category=categoryDao.get(id);
Map catMap=categoryDao.getSubCategories(category).stream()
.collect(Collectors.toMap(cat->cat,cat->categoryDao.getChildCount(cat));
List dataList=dataService.getDataList(类别、页面、计数);
这样的动作看起来还可以,离线测试也可以。但在线时,在更新类别的
langMap
后,神秘缓存的
langMap
有时会再次上浮(WTF!)。而且,
categoryDao.get(id)
也不总是命中DB


嗯,这里可能出了什么问题?

如果没有确切的代码,很难说到底出了什么问题

一些意见:

始终使用@Transactional(用于写访问)或@UnitOfWork(只读)。 @Transactional或@UnitOfWork之外的所有内容都不会有连接。如果没有连接,对象的任何字段都不会神奇地更新

因此,在忍者html模板中呈现Hibernate代理对象可能会出现严重错误。特别是如果代理未正确分离或同步。没有联系。模板可能知道也可能不知道如何处理特殊的代理属性

关于视图中的会话模式:我只知道它是反模式。虽然有一些理论方法可以让它在忍者中发挥作用,但我不推荐它。经验法则是只渲染pojo而不使用任何魔法。显著降低发生奇怪事情的百分比

除此之外,你的问题似乎更多地与guice persist(忍者使用)和忍者有关

以下是一些链接:


最后,我将
@Transactional
添加到我的DAO的
公共类别get(Serializable id)
,这些奇怪的行为消失了…我仍然感到奇怪…为什么阅读应该是事务性的…哎呀,我不得不收回我之前的评论。参见
update2
我发现摆脱神秘缓存的唯一方法是标记所有DAO的方法
@Transactional
(或者只标记DAO类
@Transactional
)。无论是阅读还是其他。C/U/D肯定是事务性的。但是我不喜欢标记reading
@Transactional
,因为它将使
@OneToMany
惰性
获取无效。我仍然希望有更好的解决办法。
    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
  public Result category(@Param("id") Long id ) {
    Category category = categoryDao.get(id);
    return Results.html()    
      .render("category" , category);
   }
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);