Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/369.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 当@Version的类型为整型时休眠重复记录,但在使用基元类型int时不休眠重复记录_Java_Hibernate - Fatal编程技术网

Java 当@Version的类型为整型时休眠重复记录,但在使用基元类型int时不休眠重复记录

Java 当@Version的类型为整型时休眠重复记录,但在使用基元类型int时不休眠重复记录,java,hibernate,Java,Hibernate,给定一个JPA实体,我注意到代码中有一个有趣的问题: 当@Version字段的类型为Integer时,记录将重复 当@Version字段为基元类型int时,记录被正确存储 我使用Hibernate 4.3.11.Final上的Spring数据和内存中的HSQLDB 2.5.0数据库(但使用Hibernate 5.4.10.Final和Oracle 12数据库)在具有双向关系的父/子层次结构上重现了该问题(为了减少冗长,我使用了Lombok) 儿童班: @Entity @SequenceGen

给定一个JPA实体,我注意到代码中有一个有趣的问题:

  • @Version
    字段的类型为
    Integer
    时,记录将重复
  • @Version
    字段为基元类型
    int
    时,记录被正确存储
我使用Hibernate 4.3.11.Final上的Spring数据和内存中的HSQLDB 2.5.0数据库(但使用Hibernate 5.4.10.Final和Oracle 12数据库)在具有双向关系的父/子层次结构上重现了该问题(为了减少冗长,我使用了Lombok)

儿童班:

@Entity
@SequenceGenerator(name = "s1", allocationSize = 1, sequenceName = "S1db")
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode
@ToString(exclude = "parent")
class Child {
    @Id
    @Column
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "s1")
    private Long id;

    @Column
    private String name;

    @Version
    @Column
    private Integer version;

    @ManyToOne
    @JoinColumn
    private Parent parent;
}
父类:

@Entity
@Getter
@Setter
@NoArgsConstructor
@SequenceGenerator(name = "s2", allocationSize = 1, sequenceName = "s2db")
@ToString
class Parent {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "s2")
    @Column
    private Long id;

    @Column(nullable = false)
    private String name;

    @OneToMany(targetEntity = Child.class,
            mappedBy = "parent",
            cascade = CascadeType.ALL,
            orphanRemoval = true,
            fetch = FetchType.LAZY
    )
    @OnDelete(action = OnDeleteAction.CASCADE)
    private List<Child> children = new ArrayList<>();
}
@实体
@吸气剂
@塞特
@诺尔格构装师
@SequenceGenerator(name=“s2”,allocationSize=1,sequenceName=“s2db”)
@托斯特林
班级家长{
@身份证
@GeneratedValue(策略=GenerationType.SEQUENCE,generator=“s2”)
@纵队
私人长id;
@列(nullable=false)
私有字符串名称;
@OneToMany(targetEntity=Child.class,
mappedBy=“parent”,
cascade=CascadeType.ALL,
删除=真,
fetch=FetchType.LAZY
)
@OnDelete(action=OnDeleteAction.CASCADE)
private List children=new ArrayList();
}
存储库和Spring配置:

@Repository
@javax.transaction.Transactional
interface ChildRepository extends JpaRepository<Child, Long> {}

@javax.transaction.Transactional
@Repository
interface ParentRepository extends JpaRepository<Parent, Long> {}

@Configuration
@EnableJpaRepositories(basePackageClasses = ParentRepository.class)
@EntityScan(basePackageClasses = Parent.class)
class ConfigClass {
    @Bean
    public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
        JpaTransactionManager txManager = new JpaTransactionManager();
        txManager.setEntityManagerFactory(entityManagerFactory);
        return txManager;
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
        final DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("org.hsqldb.jdbcDriver");
        dataSource.setUrl("jdbc:hsqldb:mem:spring;sql.syntax_ora=true");
        dataSource.setUsername("sa");
        dataSource.setPassword("");

        final Properties properties = new Properties();
        properties.setProperty("hibernate.dialect", "org.hibernate.dialect.HSQLDialect");
        properties.setProperty("hibernate.hbm2ddl.auto", "create");
        properties.setProperty("hibernate.show_sql", "true");
        properties.setProperty("hibernate.format_sql", "true");
        properties.setProperty("hibernate.use_sql_comments", "true");
        properties.setProperty("properties.hibernate.jdbc.batch_size", "10");

        final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(dataSource);
        em.setPackagesToScan(Parent.class.getPackage().getName());

        final JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        em.setJpaVendorAdapter(vendorAdapter);
        em.setJpaProperties(properties);

        return em;
    }
}
@存储库
@javax.transaction.Transactional
接口子存储库扩展了JpaRepository{}
@javax.transaction.Transactional
@存储库
接口ParentRepository扩展了JpaRepository{}
@配置
@EnableJpaRepositories(basePackageClasses=ParentRepository.class)
@EntityScan(basePackageClasses=Parent.class)
类配置类{
@豆子
公共平台transactionManager transactionManager(EntityManager工厂EntityManager工厂){
JpaTransactionManager txManager=新的JpaTransactionManager();
txManager.setEntityManagerFactory(entityManagerFactory);
返回txManager;
}
@豆子
public LocalContainerEntityManagerFactoryBean entityManagerFactory(){
final DriverManager数据源dataSource=新DriverManager数据源();
setDriverClassName(“org.hsqldb.jdbcDriver”);
setUrl(“jdbc:hsqldb:mem:spring;sql.syntax_ora=true”);
dataSource.setUsername(“sa”);
dataSource.setPassword(“”);
最终属性=新属性();
properties.setProperty(“hibernate.dialent”、“org.hibernate.dialent.hsqldialent”);
properties.setProperty(“hibernate.hbm2ddl.auto”、“create”);
setProperty(“hibernate.show_sql”,“true”);
setProperty(“hibernate.format_sql”,“true”);
setProperty(“hibernate.use_sql_comments”,“true”);
setProperty(“properties.hibernate.jdbc.batch_size”,“10”);
最终LocalContainerEntityManagerFactoryBean em=新的LocalContainerEntityManagerFactoryBean();
em.setDataSource(数据源);
em.setPackagesToScan(Parent.class.getPackage().getName());
final JpaVendorAdapter vendorAdapter=new HibernateJpaVendorAdapter();
em.setjpavendor适配器(供应商适配器);
em.setJpaProperties(属性);
返回em;
}
}
最后是测试课:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=ConfigClass.class)
@Transactional
public class ParentRepositoryTest {
    @Autowired
    private ParentRepository parentRepository;
    @Autowired
    private ChildRepository childRepository;

    @Test
    public void test() {
        // cleanup database
        childRepository.deleteAll();
        parentRepository.deleteAll();

        // Given a parent without child
        Parent p = new Parent();
        p.setName("Alice");
        p = parentRepository.saveAndFlush(p);

        // When I add 3 children
        for (int i=0; i<3; i++) {
            Child c = new Child();
            c.setParent(p);
            c.setName("child " + i);
            c.setVersion(0); // <===== this is the main issue
            // When Child.version is an int => will persist 3 elements
            // When Child.version is an Integer => will persist 6 elements
            p.getChildren().add(c);
        }
        for (Child c : p.getChildren()) {
            childRepository.save(c);
        }

        // Then the database contains 3 children
        Assertions.assertThat(childRepository.findAll()).hasSize(3); // Ouch! will persist 6 children
    }
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(类=ConfigClass.class)
@交易的
公共类ParentRepositoryTest{
@自动连线
私有父存储库父存储库;
@自动连线
私人儿童知识库;
@试验
公开无效测试(){
//清理数据库
deleteAll();
parentRepository.deleteAll();
//给一个没有孩子的父母
父级p=新父级();
p、 设置名称(“Alice”);
p=parentRepository.saveAndFlush(p);
//当我加上3个孩子
对于(int i=0;我将保留6个元素)
p、 getChildren().add(c);
}
for(Child c:p.getChildren()){
保存(c);
}
//然后数据库包含3个子项
Assertions.assertThat(childRepository.findAll()).hasSize(3);//哎哟!将保留6个孩子
}
}
结论是:

  • Child.version
    为原始类型
    int
    时,测试通过
  • Child.version
    Integer
    类型时,测试失败
虽然解决这个问题很容易(我只需要将类型设置为
int
),但我想知道为什么这会产生不同

有人能解释一下为什么
@Version
字段类型会有所不同吗