Hibernate查找方法有问题

时间:2010-01-27 12:53:47

标签: hibernate spring jpa caching

更新:清除示例 我将举例说明正在发生的事情,以澄清我的Spring + Hibernate应用程序中的情况。 想象一下,我有这两个实体(假设存在getter和setter)

@Entity
public class Class1(){
  private Integer id;

  @OneToOne
  private Class2 object2;
}

@Entity
public class Class2(){
  private Integer id;

  @OneToOne
  private Class1 object2;
}

所以在我的数据库中,我有两个表来映射每个对象的每个实例。假设我在数据库中存储了这些对象:

  • objectA(class Class1):id = 1,object2 = objectB
  • objectB(class Class2):id = 2,object2 = objectA
  • objectC(class Class2):id = 3,object2 = null 这意味着A和B是相连的。假设现在我想将objectA链接到objectC。这意味着我也必须删除objectB中的链接。

为此,我按照以下步骤进行操作:

//I get the objectA from database
Class1 storedObjectA = myservice.find(objectAId);
//Now in storedObject1 I have the same as what it is stored as objectA

//I change only the object2 attribute of it
storedObject1.setObject2(objectC);

//I search again in the database to see objectA
Class1 reStoredObjectA = myservice.find(objectAId);

restoredObjectA现在是:

  • restoredObjectA(class = Class1)id = 1,object2 = objectC

虽然在数据库中有:

  • restoredObjectA(class = Class1)id = 1,object2 = objectB

方法find没有在数据库中搜索过,虽然我的查询和二级缓存已禁用,但我已经获得了之前的搜索。方法find只发送到它在entityManager.find上执行的DAO(Class1.class,id) 如何在数据库中进行第二次搜索?

由于


(完整解释)

您好,

我有一个使用Spring 3和Hibernate的应用程序。我有一个名为Class1的实体存储在数据库中。此实体具有指向另一个名为Class2的实体的OneToOne链接。 Class2具有另一个到Class1的OneToOne链接,并且两个链接都将唯一属性设置为true。

我的控制器中有以下代码:

//I have an object called dataFromUser which is instance of Class1 and
// it is obtained via @ModelAttribute annotation from a form

Integer id = dataFromUser.getId();

//I get correctly the stored object from the database
Class1 storedData = myService.find(id); //this will call em.find of hibernate

//I set to the stored data the attribute I want to change
storedData.setObject2();

//I save again the object
myService.save(storedData);

myService中的方法save将使用实体管理器来持久保存数据,但在此之前,它将检查Class1对象和Class2对象之间的先前关联,以便在新的Class2对象设置为Class1的实例时将其删除。出于这个原因,我必须再次调用find方法来查看我的数据库中的内容

在服务中:

@Transactional
public void save(Class1 object1){
   Class1 objectFromDB =  myDAO.find(object1.getId());
   // ....  update the old object and save
}

问题是Service中的objectFromDB与我在控制器中执行myService.find(id)时的不一样。问题是它不是在数据库中查找它,而是在内存中搜索。我知道,因为在调用第二个find()方法时没有记录SQL语句。正如我在storedData对象上做了setObject2(),当我第二次调用find方法时,我得到了这个对象,而数据库不包含它,因为它还没有被保存。

我试图在我的配置中禁用缓存只是为了尝试,但它仍然在发生。我有一个配置此配置的ehCache:

在persistence.xml中我有这个属性(我已将两个缓存设置为false):

    <properties>
     <!-- Hibernate 3.5.0 - try org.hibernate.cache.* package -->
  <property name="hibernate.cache.provider_class"
               value="net.sf.ehcache.hibernate.SingletonEhCacheProvider" />
   <property name="hibernate.cache.use_query_cache" value="false" />
  <property name="hibernate.cache.use_second_level_cache" value="false" />
  <property name="hibernate.generate_statistics" value="true" />
  <property name="hibernate.cache.use_structured_entries" value="false" />
  <property name="hibernate.format_sql" value="true" />
  <!-- http://www.jroller.com/eyallupu/entry/hibernate_s_hbm2ddl_tool -->
  <!-- create, create-drop, update, validate -->
  <property name="hibernate.hbm2ddl.auto" value="update" />
    </properties>  

在我的ehcache.xml中,我设置为0 maxElementsInMemory,overflowToDisk设置为false以禁用它。

 

有没有办法避免这种情况?

感谢。

2 个答案:

答案 0 :(得分:0)

我不确定我是否理解正确,但以防万一...


两种加载对象的方法。如果对象不在当前内存上下文中,则会有所不同:

  • 确定数据库,如果存在则返回实例,否则返回null。
  • 另一个只是创建一个具有正确id的Proxy,而不是立即进入数据库,并将在以后的操作中按需要处理它(可能在刷新时)。

您似乎正在使用第二个,也许您可​​以尝试第一个,看看它是否解决了您的问题?

答案 1 :(得分:0)

好的,我发现了。问题是hibernate在数据库中搜索之前在其Session中查找对象。所以我必须在修改它之前将对象分离到会话。要在休眠中这样做:

    //being em my EntityManager instance
    Session session = (Session) em.getDelegate();
    session.evict(plan); 
    //Now the find object will not get the object wich is in session 
    //but the one in database