Hibernate 5.x和Spring Data 2.x:如何使用服务保存方法更新原始对象 [英] Hibernate 5.x and Spring Data 2.x : how to make the original object updated in a service save method

查看:98
本文介绍了Hibernate 5.x和Spring Data 2.x:如何使用服务保存方法更新原始对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



Spring(MVC)4.2.9.RELEASE,Hibernate 4.3.8.Final和1.7.1.RELEASE



to



Spring(MVC)5.0.2.RELEASE,Hibernate 5.2.12.Final和Spring Data 2.0.2.RELEASE。



Web应用程序在Windows和MS SQL Server 2014 Enterprise上运行。



升级并未迫使我更改Hibernate和JPA的设置。然而,现在这个程序的行为非常不同,这在下面进行了解释。

以下是应用程序中的一种典型服务方法,它保存一个新的Account对象,然后更新它的价值,如果它是一个新的对象,然后返回它。 Account对象有一个ID字段,定义如下:

pre $ $ b $ @ @ $
@GeneratedValue(strategy = GenerationType.IDENTITY)
私人长ID;

这是服务方式:

  @Override 
@Transactional
public Account saveAccount(Account acc){

// Step 1
// save method from Spring Data
accountRepository.save(acc);

// stringId仅手动设置一次,仅在创建新的accout对象时设置
if(acc.getStringId()== null){

//第2步
acc.setStringId(some_string_id);
}

return acc;
}

这是升级前的行为:



第1步:acc是保存后的同一个对象。保存后,它的id字段从null更新为Long值。第2步:新值自动序列化到数据库。请注意,没有明确的数据库调用save方法。



以下是升级后的行为:



步骤1:仅使用 accountRepository.save(acc)不会更新acc对象。要获得带有新ID的对象,我必须按照以下方法进行操作:

  acc = accountRepository.save(acc)

第二步:字符串ID不会保存为新对象。



我正在寻找方法使系统在升级之前正常工作。原因是应用程序不是微不足道的,而且我在应用程序中遵循了编程模式(好或坏)。我想避免很多更改和重新测试。



以下是相关配置:

 <?xml version = 1.0encoding =UTF-8standalone =no?> 
< beans xmlns =http://www.springframework.org/schema/beans
xmlns:p =http://www.springframework.org/schema/p
xmlns:tx =http://www.springframework.org/schema/tx
xmlns:aop =http://www.springframework.org/schema/aop
xmlns:上下文=http://www.springframework.org/schema/context
xmlns:jpa =http://www.springframework.org/schema/data/jpa
xmlns:jdbc = http://www.springframework.org/schema/jdbc
xmlns:xsi =http://www.w3.org/2001/XMLSchema-instance
xsi:schemaLocation =
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http:// www。 springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/data/ jpa
http://www.springframework.org/schema/data/jpa/spring-jpa-1.1.xs d
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http:/ /www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd\">

< bean id =dataSourceclass =com.zaxxer.hikari.HikariDataSourcedestroy-method =close>
< constructor-arg ref =hikariConfig/>
< / bean>

< bean id =hikariConfigclass =com.zaxxer.hikari.HikariConfig>
< property name =poolNamevalue =derek6HikariCP/>
< property name =connectionTestQueryvalue =$ {jdbc.connectionTestQuery}/>
< property name =dataSourceClassNamevalue =$ {jdbc.dataSourceClassName}/>
< property name =maximumPoolSizevalue =$ {jdbc.maximumPoolSize}/>
< property name =minimumIdlevalue =$ {jdbc.minimumIdle}/>
< property name =idleTimeoutvalue =$ {jdbc.idleTimeout}/>
< property name =connectionTimeoutvalue =$ {jdbc.connectionTimeout}/>
< property name =dataSourceProperties>
<道具>
< prop key =url> $ {jdbc.url}< / prop>
< prop key =user> $ {jdbc.username}< / prop>
< prop key =password> $ {jdbc.password}< / prop>
< /道具>
< / property>
< / bean>

< bean id =jdbcTemplateclass =org.springframework.jdbc.core.JdbcTemplate>
< constructor-arg ref =dataSource/>
< / bean>

< bean id =entityManagerFactoryname =emfclass =org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean>
< property name =dataSourceref =dataSource/>
< property name =jpaVendorAdapter>
< bean class =org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter/>
< / property>
< property name =packagesToScanvalue =myproject.entity/>
< property name =jpaProperties>
<道具>
< prop key =hibernate.dialect> $ {hibernate.dialect}< / prop>
< prop key =hibernate.show_sql> $ {hibernate.show_sql}< / prop>
< prop key =hibernate.hbm2ddl.auto> $ {hibernate.hbm2ddl.auto}< / prop>
< prop key =hibernate.max_fetch_depth> $ {hibernate.max_fetch_depth}< / prop>
< prop key =hibernate.jdbc.fetch_size> $ {hibernate.jdbc.fetch_size}< / prop>
< prop key =hibernate.jdbc.batch_size> $ {hibernate.jdbc.batch_size}< / prop>
< /道具>
< / property>
< / bean>

< bean id =transactionManagerclass =org.springframework.orm.jpa.JpaTransactionManager>
< property name =entityManagerFactoryref =emf/>
< / bean>

< tx:注解驱动的事务管理器=transactionManager/>

< context:annotation-config />

< jpa:repositories base-package =myproject.entity
entity-manager-factory-ref =emftransaction-manager-ref =transactionManager/>

< / beans>

非常感谢您的帮助!

解决方案

我想这是由于冲洗策略。你应该看看: https:// vladmihalcea.com/how-does-the-auto-flush-work-in-jpa-and-hibernate/ 。更好地理解。

在这两个版本更改之间,可能会发生它们已更改其刷新策略默认值。所以首先阅读上面的文档&根据需要配置您的代码。

I am upgrading a web application from:

Spring (MVC) 4.2.9.RELEASE, Hibernate 4.3.8.Final, and 1.7.1.RELEASE

to

Spring (MVC) 5.0.2.RELEASE, Hibernate 5.2.12.Final, and Spring Data 2.0.2.RELEASE.

The web application runs on Windows and MS SQL Server 2014 Enterprise.

The upgrade did not force me to change the settings for Hibernate and JPA. However, now the program behaves very differently, which is explained below.

The following is a typcial service method in the application, which saves a new Account object, and then updates its value if it is a new object, then return it. The Account object has an ID field defined as follows:

@Id
@GeneratedValue( strategy = GenerationType.IDENTITY )
private Long id;

This is the servie method:

@Override
@Transactional
public Account saveAccount(Account acc) {

    //Step 1
    //save method from Spring Data
    accountRepository.save(acc); 

    //stringId is set manually only once and it is set only when a new accout object is created
    if (acc.getStringId() == null) { 

        //Step 2
        acc.setStringId("some_string_id");
    }

    return acc;
}

Here is the behavior BEFORE the upgrade:

Step 1: acc is the same object after the save. Its id field is updated from null to a Long value after the save.

Step 2: The new value is automatically serialized to database. Note that there is no explicit database call to the save method.

Here is the behavior AFTER the upgrade:

Step 1: Using accountRepository.save(acc) only does not update the acc object. To get the object with new id, I have to do it the following way:

acc = accountRepository.save(acc)

Step 2: the string id is not saved for a new object.

I am looking for ways to make the system work the way before it was upgrade. The reason is that the application is not trivial, and I have followed the programming pattern (good or bad) throught the application. I would like to avoid lots of changes and re-tests.

Here is the related configuration

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:jpa="http://www.springframework.org/schema/data/jpa"
       xmlns:jdbc="http://www.springframework.org/schema/jdbc"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
          http://www.springframework.org/schema/beans
          http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
          http://www.springframework.org/schema/context
          http://www.springframework.org/schema/context/spring-context-3.2.xsd
          http://www.springframework.org/schema/data/jpa    
          http://www.springframework.org/schema/data/jpa/spring-jpa-1.1.xsd                              
          http://www.springframework.org/schema/tx
          http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
          http://www.springframework.org/schema/jdbc 
          http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd">

    <bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">
        <constructor-arg ref="hikariConfig" />
    </bean> 

    <bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig">
        <property name="poolName" value="derek6HikariCP" />
        <property name="connectionTestQuery" value="${jdbc.connectionTestQuery}" />
        <property name="dataSourceClassName" value="${jdbc.dataSourceClassName}" />
        <property name="maximumPoolSize" value="${jdbc.maximumPoolSize}" />
        <property name="minimumIdle" value="${jdbc.minimumIdle}" />
        <property name="idleTimeout" value="${jdbc.idleTimeout}" />
        <property name="connectionTimeout" value="${jdbc.connectionTimeout}" />
        <property name="dataSourceProperties">
            <props>
                <prop key="url">${jdbc.url}</prop>
                <prop key="user">${jdbc.username}</prop>
                <prop key="password">${jdbc.password}</prop>
            </props>
        </property>     
    </bean>

    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <constructor-arg ref="dataSource"/>
    </bean>

    <bean  id="entityManagerFactory" name="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
        </property>
        <property name="packagesToScan" value="myproject.entity" />
        <property name="jpaProperties">
            <props>
                <prop key="hibernate.dialect">${hibernate.dialect}</prop>
                <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
                <prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
                <prop key="hibernate.max_fetch_depth">${hibernate.max_fetch_depth}</prop>                                 
                <prop key="hibernate.jdbc.fetch_size">${hibernate.jdbc.fetch_size}</prop>
                <prop key="hibernate.jdbc.batch_size">${hibernate.jdbc.batch_size}</prop>
            </props>
        </property>
    </bean>     

    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="emf" />
    </bean>

    <tx:annotation-driven transaction-manager="transactionManager"/>   

    <context:annotation-config />  

    <jpa:repositories base-package="myproject.entity"
        entity-manager-factory-ref="emf" transaction-manager-ref="transactionManager" />  

</beans>

Thanks so much for any help!

解决方案

I guess that is due to the flush strategy. You should look into : https://vladmihalcea.com/how-does-the-auto-flush-work-in-jpa-and-hibernate/. to understand better.

Between this 2 version changes, it might happen that they have changed their flush strategy default. so first read the above document & configure your code as you want.

这篇关于Hibernate 5.x和Spring Data 2.x:如何使用服务保存方法更新原始对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆