我正在阅读Hibernate第二版的Java Persistence。我从书中找到了以下引用,我不清楚。
要考虑的另一个问题是脏检查。自动休眠 检测状态更改以便与更新状态同步 数据库。从中返回不同的实例通常是安全的 getter方法比Hibernate传递给setter的实例。 Hibernate按值而非对象标识来比较它们来确定 是否需要更新属性的持久状态。对于 例如,以下getter方法不会导致不必要的SQL 更新:
public String getFirstName(){
return new String(firstName);
}
我的问题是为什么返回一个新的String对象不会产生不必要的SQL UPDATE,它与返回firstName有何不同?
当我尝试运行getFirstName时,我没有看到任何更新查询被触发。
请告诉我,因为我不清楚。
以下是代码:
package org.prashdeep.model;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@Entity
public class User {
protected Long id;
@Id
@GeneratedValue()
public Long getId() { // Optional but useful
return id;
}
protected String firstName;
protected String lastName;
public void setId(Long id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
System.out.println("Called from the setter of lastname");
this.lastName = lastName;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", firstName='" + firstName + '\'' +
", lastName='" + lastName + '\'' +
'}';
}
}
SaveUserEntity.java
package org.prashdeep.executor;
import bitronix.tm.resource.jdbc.PoolingDataSource;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataBuilder;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Environment;
import org.hibernate.resource.transaction.backend.jta.internal.JtaTransactionCoordinatorBuilderImpl;
import org.hibernate.service.ServiceRegistry;
import org.prashdeep.common.DatabaseProduct;
import org.prashdeep.model.User;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.transaction.Status;
import javax.transaction.UserTransaction;
import java.util.List;
public class SaveUserEntity {
protected Context context;
protected PoolingDataSource dataSource;
public static String DATASOURCE_NAME = "myDS";
public DatabaseProduct databaseProduct;
public UserTransaction getUserTransaction() {
try {
return (UserTransaction) context.lookup("java:comp/UserTransaction");
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
public void rollback() {
UserTransaction tx = getUserTransaction();
try {
if (tx.getStatus() == Status.STATUS_ACTIVE ||
tx.getStatus() == Status.STATUS_MARKED_ROLLBACK)
tx.rollback();
} catch (Exception ex) {
System.err.println("Rollback of transaction failed, trace follows!");
ex.printStackTrace(System.err);
}
}
protected SessionFactory createSessionFactory() throws Exception{
this.dataSource = new PoolingDataSource();
dataSource.setUniqueName(DATASOURCE_NAME);
dataSource.setMinPoolSize(1);
dataSource.setMaxPoolSize(5);
dataSource.setPreparedStatementCacheSize(10);
dataSource.setIsolationLevel("READ_COMMITTED");
dataSource.setClassName("org.h2.jdbcx.JdbcDataSource");
dataSource.setAllowLocalTransactions(true);
dataSource.getDriverProperties().put(
"URL",
"jdbc:h2:mem:test"
);
dataSource.getDriverProperties().put("user", "sa");
context = new InitialContext();
dataSource.init();
/*
This builder helps you create the immutable service registry with
chained method calls.
*/
StandardServiceRegistryBuilder serviceRegistryBuilder =
new StandardServiceRegistryBuilder();
/*
Configure the services registry by applying settings.
*/
serviceRegistryBuilder
.applySetting("hibernate.connection.datasource", "myDS")
.applySetting("hibernate.format_sql", "true")
.applySetting("hibernate.show_sql", "true")
.applySetting("hibernate.hbm2ddl.auto", "create-drop");
// Enable JTA (this is a bit crude because Hibernate devs still believe that JTA is
// used only in monstrous application servers and you'll never see this code).
serviceRegistryBuilder.applySetting(
Environment.TRANSACTION_COORDINATOR_STRATEGY,
JtaTransactionCoordinatorBuilderImpl.class
);
ServiceRegistry serviceRegistry = serviceRegistryBuilder.build();
/*
You can only enter this configuration stage with an existing service registry.
*/
MetadataSources metadataSources = new MetadataSources(serviceRegistry);
/*
Add your persistent classes to the (mapping) metadata sources.
*/
metadataSources.addAnnotatedClass(
org.prashdeep.model.User.class
);
// Add hbm.xml mapping files
// metadataSources.addFile(...);
// Read all hbm.xml mapping files from a JAR
// metadataSources.addJar(...)
MetadataBuilder metadataBuilder = metadataSources.getMetadataBuilder();
Metadata metadata = metadataBuilder.build();
SessionFactory sessionFactory = metadata.buildSessionFactory();
return sessionFactory;
}
public static void main(String args[]) throws Exception {
SaveUserEntity obj = new SaveUserEntity();
SessionFactory sessionFactory = obj.createSessionFactory();
try {
{
/*
Get access to the standard transaction API <code>UserTransaction</code> and
begin a transaction on this thread of execution.
*/
UserTransaction tx = obj.getUserTransaction();
tx.begin();
/*
Whenever you call <code>getCurrentSession()</code> in the same thread you get
the same <code>org.hibernate.Session</code>. It's bound automatically to the
ongoing transaction and is closed for you automatically when that transaction
commits or rolls back.
*/
Session session = sessionFactory.getCurrentSession();
User user = new User();
user.setFirstName("Pradeep");
user.setLastName("Kumar");
/*
The native Hibernate API is very similar to the standard Java Persistence API and most methods
have the same name.
*/
session.persist(user);
/*
Hibernate synchronizes the session with the database and closes the "current"
session on commit of the bound transaction automatically.
*/
tx.commit();
}
{
UserTransaction tx = obj.getUserTransaction();
tx.begin();
/*
A Hibernate criteria query is a type-safe programmatic way to express queries,
automatically translated into SQL.
*/
List<User> users =
sessionFactory.getCurrentSession().createCriteria(
User.class
).list();
// SELECT * from MESSAGE
users.get(0).setFirstName("Praveen");
System.out.println(users.get(0).getFirstName());
tx.commit();
}
} finally {
obj.rollback();
}
}
}
答案 0 :(得分:1)
假设在数据库中,您有firstName
为FOO
的记录。
在某些时候,此记录作为持久性实体加载,因此您现在拥有类型为User
的Java对象,其中getFirstName()
返回字符串"FOO"
。
当您使用setFirstName("BAR");
修改持久对象时,下次提交时,将导致SQL UPDATE。这是因为Hibernate将“数据库状态”与“内存状态”进行比较,它会看到存在差异(FOO
变为BAR
)并且他将启动SQL更新。到目前为止所有的标准。
现在,Hibernate手册试图提出的一点是,这种比较是基于equals
而不是==
。在我们的示例中,它将检查字符串值FOO
和BAR
是否相等(概念上为oldValue.equals(newValue)
),而不是返回相同的String对象(oldValue == newValue
)。
因此他们的示例:您可以返回new String(firstName)
这是一个不同的String对象,但equals
只是{。}}。
希望这有帮助。