2017-02-15 2 views
1

私はHibernate 2nd EditionでJava Persistenceを読んでいます。私は私がはっきりしない本から下の引用を見つけました。Hibernateのダーティチェックのクエリ

もう1つの問題は、汚れチェックです。自動的にHibernate は、更新された状態をデータベース と同期させるために状態の変化を検出します。通常、Hibernateによってsetterに渡されたインスタンスよりも、getterメソッドの から別のインスタンスを返すことは安全です。 Hibernateは、オブジェクトのIDではなく値を比較して、 の属性の永続状態を更新する必要があるかどうかを判断します。 たとえば、次のgetterメソッドは、不必要なSQL アップデートでなりません。

public String getFirstName(){ 
    return new String(firstName); 
} 

私の質問新しいStringオブジェクトを返すことは、不必要なSQLの更新をすることはありません理由で、どのようにちょうど戻ってからも異なっていますファーストネーム?

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(); 
     } 
    } 
} 

答えて

1

、あなたはfirstNameFOOあるレコードを持っています。 ある時点では、このレコードは永続エンティティとしてロードされるため、タイプUserのJavaオブジェクトがあります。ここで、getFirstName()は文字列"FOO"を返します。

setFirstName("BAR");を使用して永続オブジェクトを変更すると、次回このコミット時にSQL UPDATEが発生します。これは、Hibernateが "データベース状態"と "メモリ状態"を比較するため、差異(FOOBARになっている)が表示され、SQL UPDATEを起動するためです。これまでのすべての標準。

ここでは、Hibernate Manualが作成しようとしている点は、equalsではなく==に基づいていることです。この例では、文字列値FOOBARが等しい(oldValue.equals(newValue)、概念的に)かどうかをチェックし、同じStringオブジェクトが返された場合(oldValue == newValue)はチェックしません。

したがって、例:new String(firstName)は別のStringオブジェクトですが、同じものはequalsになります。

希望します。

+0

答えをくれてありがとう。しかし、この例のように、新しいStringオブジェクトを返すことはSQLの更新を避けることができます。私は何かが足りない。私が試してみる疑似コードを表示してください。 – zilcuanu

+0

更新を避けない*更新を引き起こさない*更新は、現在の永続エンティティのプロパティがデータベース内のものと等しくない場合にのみ発生します。この例は、 'equal'値を持つ別のオブジェクトが更新を起こさないことを実証するための人工的な例です。 – geert3

+0

実際には心配する必要はありません。 – geert3