org.hibernate.HibernateException:数据库未返回本机生成的标识值 - Spring MultiReaderHibernateWriter 的批处理

org.hibernate.HibernateException: The database returned no natively generated identity value - Spring Batch for MultiReaderHibernateWriter

我正在从 link 开发“Multiresource ItemReader & HibernateItemWritter”:http://websystique.com/springbatch/spring-batch-multiresourceitemreader-hibernateitemwriter-example/。当我是 运行 主程序时,我遇到了以下错误:

    Jul 27, 2016 12:27:36 AM org.springframework.batch.core.launch.support.SimpleJobLauncher afterPropertiesSet
    INFO: No TaskExecutor has been set, defaulting to synchronous executor.
    Jul 27, 2016 12:27:37 AM org.springframework.batch.core.launch.support.SimpleJobLauncher run
    INFO: Job: [FlowJob: [name=examResultJob]] launched with the following parameters: [{}]
    ---------------------------------
    ExamResult Job starts at :2016-07-27T00:27:37.294+05:30
    Jul 27, 2016 12:27:37 AM org.springframework.batch.core.job.SimpleStepHandler handleStep
    INFO: Executing step: [step1]
    Processing result :ExamResult [id=0, studentName=Brian Burlet, dob=1985-02-01, percentage=76.0]
    Processing result :ExamResult [id=0, studentName=Jimmy Snuka, dob=1983-02-01, percentage=39.0]
    Processing result :ExamResult [id=0, studentName=Renard konig, dob=1970-02-01, percentage=61.0]
    Processing result :ExamResult [id=0, studentName=Kevin Richard, dob=2002-02-01, percentage=59.0]
    Processing result :ExamResult [id=0, studentName=Sam Disilva, dob=1992-05-01, percentage=76.0]
    Processing result :ExamResult [id=0, studentName=Bob corbet, dob=1990-07-10, percentage=29.0]
    Processing result :ExamResult [id=0, studentName=Rick Ricky, dob=1973-02-01, percentage=54.0]
    Processing result :ExamResult [id=0, studentName=Igor Watson, dob=1986-02-01, percentage=34.0]
    Processing result :ExamResult [id=0, studentName=Peet Sampras, dob=1978-02-01, percentage=97.0]
    Processing result :ExamResult [id=0, studentName=Rita Paul, dob=1993-02-01, percentage=92.0]
    Hibernate: insert into EXAM_RESULT (DOB, PERCENTAGE, STUDENT_NAME) values (?, ?, ?)
    Jul 27, 2016 12:18:09 AM 
org.springframework.batch.core.step.AbstractStep execute
    SEVERE: Encountered an error executing step step1 in job examResultJob
    org.hibernate.HibernateException: The database returned no natively generated identity value
        at org.hibernate.id.IdentifierGeneratorHelper.getGeneratedIdentity(IdentifierGeneratorHelper.java:91)
        at org.hibernate.id.IdentityGenerator$GetGeneratedKeysDelegate.executeAndExtract(IdentityGenerator.java:100)
        at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:58)
        at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3032)
        at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3558)
        at org.hibernate.action.internal.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:98)
        at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:490)
        at org.hibernate.engine.spi.ActionQueue.addResolvedEntityInsertAction(ActionQueue.java:195)
        at org.hibernate.engine.spi.ActionQueue.addInsertAction(ActionQueue.java:179)
        at org.hibernate.engine.spi.ActionQueue.addAction(ActionQueue.java:214)
        at org.hibernate.event.internal.AbstractSaveEventListener.addInsertAction(AbstractSaveEventListener.java:324)
        at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:288)
        at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:194)
        at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:125)
        at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:209)
        at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:194)
        at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:114)
        at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:90)
        at org.hibernate.internal.SessionImpl.fireSaveOrUpdate(SessionImpl.java:684)
        at org.hibernate.internal.SessionImpl.saveOrUpdate(SessionImpl.java:676)
        at org.hibernate.internal.SessionImpl.saveOrUpdate(SessionImpl.java:671)
        at org.springframework.batch.item.database.HibernateItemWriter.doWrite(HibernateItemWriter.java:140)
        at org.springframework.batch.item.database.HibernateItemWriter.write(HibernateItemWriter.java:113)
        at org.springframework.batch.core.step.item.SimpleChunkProcessor.writeItems(SimpleChunkProcessor.java:175)
        at org.springframework.batch.core.step.item.SimpleChunkProcessor.doWrite(SimpleChunkProcessor.java:151)
        at org.springframework.batch.core.step.item.SimpleChunkProcessor.write(SimpleChunkProcessor.java:274)
        at org.springframework.batch.core.step.item.SimpleChunkProcessor.process(SimpleChunkProcessor.java:199)
        at org.springframework.batch.core.step.item.ChunkOrientedTasklet.execute(ChunkOrientedTasklet.java:75)
        at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:406)
        at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:330)
        at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:133)
        at org.springframework.batch.core.step.tasklet.TaskletStep.doInChunkContext(TaskletStep.java:271)
        at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:81)
        at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:374)
        at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:215)
        at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:144)
        at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:257)
        at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:200)
        at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:148)
        at org.springframework.batch.core.job.flow.JobFlowExecutor.executeStep(JobFlowExecutor.java:64)
        at org.springframework.batch.core.job.flow.support.state.StepState.handle(StepState.java:67)
        at org.springframework.batch.core.job.flow.support.SimpleFlow.resume(SimpleFlow.java:169)
        at org.springframework.batch.core.job.flow.support.SimpleFlow.start(SimpleFlow.java:144)
        at org.springframework.batch.core.job.flow.FlowJob.doExecute(FlowJob.java:134)
        at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:306)
        at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:135)
        at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:50)
        at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:128)
        at com.websystique.springbatch.Main.main(Main.java:22)

有解决问题的建议吗? ExamResult.java

@Entity
@Table(name = "EXAM_RESULT")
public class ExamResult {

    @Id
    //@GeneratedValue(strategy = GenerationType.IDENTITY)
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    @Column(name = "STUDENT_NAME", nullable = false)
    private String studentName;

    @Column(name = "DOB", nullable = false)
    @Type(type="org.jadira.usertype.dateandtime.joda.PersistentLocalDate")
    private LocalDate dob;

    @Column(name = "PERCENTAGE", nullable = false)
    private double percentage;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getStudentName() {
        return studentName;
    }

    public void setStudentName(String studentName) {
        this.studentName = studentName;
    }

    public LocalDate getDob() {
        return dob;
    }

    public void setDob(LocalDate dob) {
        this.dob = dob;
    }

    public double getPercentage() {
        return percentage;
    }

    public void setPercentage(double percentage) {
        this.percentage = percentage;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + (int) (id ^ (id >>> 32));
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (!(obj instanceof ExamResult))
            return false;
        ExamResult other = (ExamResult) obj;
        if (id != other.id)
            return false;
        return true;
    }

    @Override
    public String toString() {
        return "ExamResult [id=" + id + ", studentName=" + studentName
                + ", dob=" + dob + ", percentage=" + percentage + "]";
    }
}

spring-批量-context.xml

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:batch="http://www.springframework.org/schema/batch" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/batch
        http://www.springframework.org/schema/batch/spring-batch.xsd
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <import resource="classpath:context-model.xml"/>


    <!-- JobRepository and JobLauncher are configuration/setup classes -->
    <bean id="jobRepository" class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean" />

    <bean id="jobLauncher"  class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
        <property name="jobRepository" ref="jobRepository" />
    </bean>

    <!-- =============  Multi Resource Item Reader  ================== -->
    <bean id="multiResourceItemReader" class="org.springframework.batch.item.file.MultiResourceItemReader">
        <property name="resources" value="classpath:csv/ExamResult*.txt" />
        <property name="delegate" ref="flatFileItemReader" />
    </bean>


    <!-- =========== ItemReader reads a complete line one by one from input file ============-->
    <bean id="flatFileItemReader" class="org.springframework.batch.item.file.FlatFileItemReader" scope="step">

        <property name="lineMapper">
            <bean class="org.springframework.batch.item.file.mapping.DefaultLineMapper">

                <property name="fieldSetMapper">
                    <!-- Mapper which maps each individual items in a record to properties in POJO -->
                    <bean class="com.websystique.springbatch.ExamResultFieldSetMapper" />
                </property>

                <property name="lineTokenizer">
                    <!-- A tokenizer class to be used when items in input record are separated by specific characters -->
                    <bean class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer">
                        <property name="delimiter" value="|" />
                    </bean>
                </property>
            </bean>
        </property>
    </bean>


    <!-- ItemWriter which writes data to database -->
    <bean id="databaseItemWriter" class="org.springframework.batch.item.database.HibernateItemWriter">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>


    <!-- Optional ItemProcessor to perform business logic/filtering on the input records -->
    <bean id="itemProcessor" class="com.websystique.springbatch.ExamResultItemProcessor" />

    <!-- Optional JobExecutionListener to perform business logic before and after the job -->
    <bean id="jobListener" class="com.websystique.springbatch.ExamResultJobListener" />


    <!-- =========== Actual Job =========== -->
    <batch:job id="examResultJob">
        <batch:step id="step1">
            <batch:tasklet transaction-manager="transactionManager">
                <batch:chunk reader="multiResourceItemReader" writer="databaseItemWriter"
                    processor="itemProcessor" commit-interval="10" />
            </batch:tasklet>
        </batch:step>
        <batch:listeners>
            <batch:listener ref="jobListener" />
        </batch:listeners>
    </batch:job>
</beans>

上下文-model.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:tx="http://www.springframework.org/schema/tx"
        xmlns:aop="http://www.springframework.org/schema/aop"
        xsi:schemaLocation="
        http://www.springframework.org/schema/beans  http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop  http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/tx   http://www.springframework.org/schema/tx/spring-tx.xsd"
                             default-autowire="byName"  default-init-method="init">

    <import resource="classpath:context-datasource.xml"/>

    <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean" >
        <property name="dataSource" ref="dataSource"/>
        <property name="packagesToScan">
            <list>
                <value>com.websystique.springbatch.model</value>
            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
                <prop key="hibernate.show_sql">true</prop>
                <!-- <prop key="hibernate.format_sql">true</prop> -->
            </props>
        </property>     
    </bean>

    <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager" />

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

只需像下面这样创建 exam_result:

CREATE TABLE `websystique`.`exam_result` (
  `ID` INT NOT NULL AUTO_INCREMENT,
  `STUDENT_NAME` VARCHAR(500) NULL,
  `DOB` DATE NULL,
  `PERCENTAGE` VARCHAR(500) NULL,
  PRIMARY KEY (`ID`));