查询Hibernate脏检查

时间:2017-02-15 11:39:02

标签: java hibernate jpa

我正在阅读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();
        }
    }
}

1 个答案:

答案 0 :(得分:1)

假设在数据库中,您有firstNameFOO的记录。 在某些时候,此记录作为持久性实体加载,因此您现在拥有类型为User的Java对象,其中getFirstName()返回字符串"FOO"

当您使用setFirstName("BAR");修改持久对象时,下次提交时,将导致SQL UPDATE。这是因为Hibernate将“数据库状态”与“内存状态”进行比较,它会看到存在差异(FOO变为BAR)并且他将启动SQL更新。到目前为止所有的标准。

现在,Hibernate手册试图提出的一点是,这种比较是基于equals而不是==。在我们的示例中,它将检查字符串值FOOBAR是否相等(概念上为oldValue.equals(newValue)),而不是返回相同的String对象(oldValue == newValue)。

因此他们的示例:您可以返回new String(firstName)这是一个不同的String对象,但equals只是{。}}。

希望这有帮助。