为什么在Hibernate 5.2中saveOrUpdate的行为不符合记录

问题描述 投票:0回答:1

在Hibernate 5.2中,org.hibernate.Session.saveOrUpdate()不会为分离的对象执行update,而是执行save

使用Hibernate 3.6时,它按预期工作。

这些是重现问题的文件:

  1. 实体Person.javapackage model; import javax.persistence.*; @Entity public class Person { @Id @GeneratedValue private Long id; @Column(unique = true) private String name; private Integer age; public void setName(String name) { this.name = name; } public void setAge(Integer age) { this.age = age; } }
  2. DAO接口HibernateTestDao.javapackage model; public interface HibernateTestDao { void test(); }
  3. 和DAO实施HibernateTestDaoImpl.javapackage model; import org.hibernate.SessionFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; @Transactional(readOnly = true) @Repository public class HibernateTestDaoImpl implements HibernateTestDao { @Autowired private SessionFactory sessionFactory; @Transactional(readOnly = false) @Override public void test() { Person person = new Person(); person.setName("Joe"); person.setAge(10); Long id = (Long)sessionFactory.getCurrentSession().save(person); sessionFactory.getCurrentSession().flush(); person = sessionFactory.getCurrentSession().get(Person.class, id); sessionFactory.getCurrentSession().clear(); person.setAge(11); sessionFactory.getCurrentSession().saveOrUpdate(person); sessionFactory.getCurrentSession().flush(); throw new RuntimeException(); } }
  4. 主要类HibernateTest.javapackage test; import org.springframework.context.support.ClassPathXmlApplicationContext; import model.HibernateTestDao; public class HibernateTest { public static void main(String[] args) { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:/applicationContext.xml"); HibernateTestDao dao = applicationContext.getBean(HibernateTestDao.class); dao.test();; applicationContext.close(); } }
  5. Spring配置文件applicationContext.xml<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:util="http://www.springframework.org/schema/util" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd"> <context:component-scan base-package="model"/> <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/hibernatetest" /> <property name="username" value="hibernatetest" /> <property name="password" value="hibernatetest" /> </bean> <bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean"> <property name="packagesToScan"> <list> <value>model</value> </list> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop> <prop key="hibernate.id.new_generator_mappings">false</prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.generate_statistics">false</prop> <prop key="hibernate.max_fetch_depth">3</prop> </props> </property> <property name="dataSource"> <ref bean="dataSource"/> </property> </bean> <tx:annotation-driven/> <bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory"/> </bean> </beans>
  6. 最后是pom.xml文件: <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>ProvaHibernate</groupId> <artifactId>ProvaHibernate</artifactId> <version>0.0.1-SNAPSHOT</version> <properties> <hibernate.version>5.2.12.Final</hibernate.version> <spring.version>4.3.12.RELEASE</spring.version> </properties> <build> <sourceDirectory>src</sourceDirectory> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.7.0</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>${hibernate.version}</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>5.3.4.Final</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.45</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-dbcp2</artifactId> <version>2.1.1</version> </dependency> </dependencies> </project>

执行时控制台显示:

    Hibernate: insert into Person (age, name) values (?, ?)
    Hibernate: insert into Person (age, name) values (?, ?)
    Dec 13, 2017 6:26:47 PM org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
    WARN: SQL Error: 1062, SQLState: 23000
    Dec 13, 2017 6:26:47 PM org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
    ERROR: Duplicate entry 'Joe' for key 'person_un'
    Exception in thread "main"
    org.hibernate.exception.ConstraintViolationException: could not execute statement
    ...
    Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException:
    Duplicate entry 'Joe' for key 'person_un'
    ...

如果我删除了sessionFactory.getCurrentSession().clear();中的HibernateTestDaoImpl.javastatement,让Person对象进入会话,那么控制台会显示:

    Hibernate: insert into Person (age, name) values (?, ?)
    Hibernate: update Person set age=?, name=? where id=?

Hibernate documentation声称saveOrUpdate将一个独立的对象重新附加到会话中:

这是一个Hibernate 5.2错误,我错过了一些东西。

hibernate
1个回答
0
投票

它不是Hibernate的错误。

在这个answer之后,我在integrate的方法JpaAnnotationsIntegrator上添加了一个句子,引发了这个问题。增加的句子是:

eventListenerRegistry.prependListeners(EventType.SAVE_UPDATE, new JpaSaveEventListener(callbackRegistry));

更新:我忘了说我没有使用任何监听器,只是安装服务。我无法理解为什么这会在saveOrUpdate中引发这种行为。如果我通过prependListeners改变appendListeners,那么事情就会正常进行。

© www.soinside.com 2019 - 2024. All rights reserved.