Hibernate:直接在bean中设置Id或调用load()或get()方法之间的区别?

以下是加载的示例: –

Stock stock = (Stock)session.load(Stock.class, new Integer(2)); StockTransaction stockTransactions = new StockTransaction(); //set stockTransactions detail stockTransactions.setStock(stock); session.save(stockTransactions); 

有什么区别,如果我直接设置id如下: –

 Stock stock =new Stock(); stock.setId(2); StockTransaction stockTransactions = new StockTransaction(); //set stockTransactions detail stockTransactions.setStock(stock); session.save(stockTransactions); 

因为我已经知道了股票表的Id。 你打电话给负载还是搞定?

有什么不同 …

您的第一个代码示例从数据库中获取对象,因此加载的对象将处于持久化状态。 您的第二个示例将尝试使用全新的 Stock存储StockTransaction 。 这可能会导致主键错误(如果库存ID唯一)或重复条目。 您应该根据您的要求选择使用哪种方式。 如果您需要StockTransaction与现有Stock (我认为这是你的情况,因为你写了你知道ID) – 你应该首先从数据库加载它。

你打电话给负载还是搞定?

如果数据库中没有此类对象(具有此类ID), Session.load()将返回具有空字段的代理。

如果没有具有此类id的对象, Session.get()将返回null。

使用哪一个取决于您和您的任务。 我个人更喜欢get()

对象create将处于持久状态。

  Stock stock = (Stock)session.load(Stock.class, new Integer(2)); 

对象创建将处于暂时状态。

 Stock stock =new Stock(); stock.setId(2); 

瞬态:

与Session无关的持久化类的新实例在数据库中没有表示,Hibernate没有标识符值被认为是瞬态的:

持久国家:

持久化实例在数据库中具有表示,标识符值并与会话相关联。 您可以通过将瞬态实例与会话关联来使其持久化:

参考

http://www.dineshonjava.com/p/transient-persistent-and-detached.html#.U4LKlHakrlc

虽然如果您只计划保存子实体(StockTransaction)并不是两种方法都会产生相同的结果,但这并不常见。 您将保持子项持久化,并且在刷新之后,父项将附加到当前会话。

我在GitHub上创建了一个测试:

 final Long parentId = cleanAndSaveParent(); transactionTemplate.execute(new TransactionCallback() { @Override public Void doInTransaction(TransactionStatus transactionStatus) { SetParent idOnlyParent = new SetParent(); idOnlyParent.setId(parentId); SetChild newChild = new SetChild(); newChild.setName("new"); newChild.setParent(idOnlyParent); entityManager.persist(newChild); entityManager.flush(); SetChild otherChild = new SetChild(); otherChild.setName("Other"); idOnlyParent.addChild(otherChild); entityManager.flush(); assertEquals(1, idOnlyParent.getChildren().size()); return null; } }); transactionTemplate.execute(new TransactionCallback() { @Override public Void doInTransaction(TransactionStatus transactionStatus) { SetParent parent = entityManager.find(SetParent.class, parentId); assertEquals(3, parent.getChildren().size()); return null; } }); 

调用flush()时,newChild对象将附加到当前Session。 但是父母不会被附加,因此父母方面的改变根本不会同步。

如果从DB中获取父级,则更改为父级将被“脏检查”并在刷新时同步。

即使有可能这样做,也不是真的可取。 它可能会让您产生错误的印象,即您仍在使用附加的父实体,而您只获得一个临时父实体。

为了正确地将对象状态与数据库同步,对象需要由hibernate 管理aka与持久化上下文相关联)。 在刷新时,它是持久化上下文的内容,它决定将什么内容刷新到数据库然后提交。 除此之外,始终在持久实体之间创建关系。 持久性本质可以是显式的(通过调用任何适当的API方法 – 在本机hibernate或它们的JPA对应物中保存,更新,合并等)或隐式(由于级联属性或由于通过适当的API调用加载,如load,得到等)。 实体持久化的另一个原因是后写事务性质,您可以继续修改对象的状态,并在事务提交时或显式刷新时将增量传播到数据库。 在对象图中,需要传播到数据库的内容取决于管理或持久的对象(这两个术语大多数时间都可互换使用)。 有一个分离对象的概念(对象的数据库标识符已设置,但无法保证代表数据库中的实际状态。实际上,任何数据都可能在事务外部过时)。 对于这些,您也可以选择重新连接/合并到持久化上下文(在本机hibernate中)或合并(在JPA中)。

此外,在创建双向关系时 – 需要考虑另一个概念 – 反向。 反面不负责创建关系,因此仅从反面设置关系不会导致关系通过外键保留在数据库中。

让我用这种方式解释一下:你的问题是合理的,并且有一个明确的答案 – 使用load() 。 为什么? 一般来说,我们有三种方法可以通过ID获得一个实例。

1)一个,极端的,事实上不恰当的,仅提到复杂性,将使用查询,例如对ID的限制。 此查询必须命中DB …

2)然后,我们有get() ,这是如何通过ID获取项目的最常见方式。 它始终命中DB,因为它的合同说( get ):

使用给定标识符返回给定实体类的持久实例,如果没有此类持久实例,则返回null

因此,为了确保该对象存在与否,必须击中DB。

3)最后,出于某种原因,还有第三个合同 load() 。 它永远不会命中DB来检查是否有这样的项目(提供ID) : load() :

假定实例存在,返回给定实体类的持久实例和给定标识符。

合同在这里期望。 另一方面,这个约定可以帮助我们解决此查询中描述的情况

如果我们确实有参考ID,并且我们知道它确实存在,我们shouuld使用load() 。 它将创建一个代理实例 – 使用提供的ID,并且在该根/持有者实体的INSERT或UPDATE期间,代理ID将用于创建正确的SQL语句。

总结: get()load()是我们的原因所在。 它们旨在支持不同的场景。 对于根实体的CRUD操作,我们应该通过get()接收它,以确保上层要求现有ID。 load()的用例是当我们有ID时,只想坚持……

也可以看看:

  • session.get()和session.load()之间有所不同
  • NHibernate – 获取,加载和通过id查询之间的区别