在Spring-Batch的上下文中持久化实体jpa的问题,该实体是一个联接表,带有一些额外的字段

如何解决在Spring-Batch的上下文中持久化实体jpa的问题,该实体是一个联接表,带有一些额外的字段

读取两个表,对其进行修改并将其写回到外部数据库(socio_db)的批处理是微服务演示项目的一部分。 Spring-Batch的数据库更新按计划运行(每个24小时),仅修改两个字段(布尔值和枚举)。

(要修改的表格属于类似于Facebook的应用程序,社交在此注册并添加其他社交作为关联的社交):

socio_db schema

在显示代码和错误消息之前:

  1. 我已经使用其自己的数据源配置了批处理元数据数据库(socio_batch_meta_data_db),因此它与作为目标数据库的socio_db分开了。
  2. 我将不包括有关两个DB字段的逻辑,因为它与SocioAssociatedSocio类的读取器-处理程序-写入器流程无关;
  3. 仅查找三个相关实体(Socio,SocioAssociatedSocio,SocioAssociatedSocioId)的代码。

错误消息:

2020-08-19 10:51:25,141 ERROR [restartedMain] org.springframework.batch.core.step.AbstractStep: Encountered an error executing step associatedsociodbsociowriteStep in job batchdbsociowriteJob
java.lang.IllegalArgumentException: Unable to invoke method: [public void com.artsgard.sociodbbatch.readers.AssociatedSocioReader.before(org.springframework.batch.core.StepExecution)] on object: [com.artsgard.sociodbbatch.readers.AssociatedSocioReader@9e233ce] with arguments: [[StepExecution: id=1178,version=1,name=associatedsociodbsociowriteStep,status=STARTED,exitStatus=EXECUTING,readCount=0,filterCount=0,writeCount=0 readSkipCount=0,writeSkipCount=0,processSkipCount=0,commitCount=0,rollbackCount=0,exitDescription=]]
    at org.springframework.batch.support.SimpleMethodInvoker.invokeMethod(SimpleMethodInvoker.java:112)
    at org.springframework.batch.core.listener.MethodInvokerMethodInterceptor.invoke(MethodInvokerMethodInterceptor.java:69)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
    at com.sun.proxy.$Proxy111.beforeStep(Unknown Source)

Caused by: java.lang.reflect.InvocationTargetException: null
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.batch.support.SimpleMethodInvoker.invokeMethod(SimpleMethodInvoker.java:108)
    ... 39 common frames omitted
Caused by: org.springframework.dao.InvalidDataAccessResourceUsageException: could not extract ResultSet; SQL [n/a]; nested exception is org.hibernate.exception.SQLGrammarException: could not extract ResultSet
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:281)
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:255)
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:528)
    at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61)


Caused by: org.hibernate.exception.SQLGrammarException: could not extract ResultSet
    at org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:103)
    at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42)
    at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:113)

Caused by: org.postgresql.util.PSQLException: ERROR: no existe la columna socioassoc0_.associatedsocioid
  Hint: Probablemente quiera hacer referencia a la columna «socioassoc0_.associated_socio_id».
  Position: 8
    at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2497)
    at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2233)
    at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:310)

Pom和属性文件:

<?xml version="1.0" encoding="UTF-8"?>
<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">
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.2.RELEASE</version>
    </parent>
    
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.artsgard</groupId>
    <artifactId>sociodbbatch</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-batch</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency> 
            <groupId>org.springframework.boot</groupId> 
            <artifactId>spring-boot-starter-validation</artifactId> 
        </dependency>
         <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.batch</groupId>
            <artifactId>spring-batch-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

app.datasource.batch.url=jdbc:postgresql://localhost:5432/socio_batch_meta_data_db
app.datasource.batch.driverClassName=org.postgresql.Driver
app.datasource.batch.username=postgres
app.datasource.batch.password=Candita123

app.datasource.db.url=jdbc:postgresql://localhost:5432/socio_db
app.datasource.db.driverClassName=org.postgresql.Driver
app.datasource.db.username=postgres
app.datasource.db.password=Candita123

spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true

spring.batch.initialize-schema=always

#86400000
batch.delay= 5000

spring.jpa.hibernate.ddl-auto=none
spring.datasource.initialization-mode=never
spring.datasource.initialize=false

数据库和JobRepositoy配置:

@Configuration
public class BatchDbMetaDataRepoConfig {
    
    @Primary
    @Bean(name = "batchDataSourceProperties")
    @ConfigurationProperties("app.datasource.batch")
    public DataSourceProperties dataSourceProperties() {
        return new DataSourceProperties();
    }

    @Primary
    @Bean(name = "batchDataSource")
    @ConfigurationProperties("app.datasource.batch.hikari")
    public DataSource dataSource(@Qualifier("batchDataSourceProperties") DataSourceProperties dataSourceProperties) {
        return dataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
    }
}

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = {"com.artsgard.sociodbbatch.repository","com.artsgard.sociodbbatch.config" },entityManagerFactoryRef = "dbEntityManagerFactory",transactionManagerRef = "dbTransactionManager")

public class BatchDbRepoConfig {
    
    @Bean(name = "dbDataSourceProperties")
    @ConfigurationProperties("app.datasource.db")
    public DataSourceProperties dataSourceProperties() {
        return new DataSourceProperties();
    }

    @Bean(name = "dbDataSource")
    @ConfigurationProperties("app.datasource.db.hikari")
    public DataSource dataSource(@Qualifier("dbDataSourceProperties") DataSourceProperties dataSourceProperties) {
        return dataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class)
                .build();
    }
    
    @Bean(name = "dbEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(
            EntityManagerFactoryBuilder builder,@Qualifier("dbDataSource") DataSource dataSource) {
        return builder
                    .dataSource(dataSource)
                    .packages("com.artsgard.sociodbbatch.model")
                    .persistenceUnit("db")
                    .build();
    }

    @Bean(name = "dbTransactionManager")
    public PlatformTransactionManager transactionManager(
            @Qualifier("dbEntityManagerFactory") EntityManagerFactory entityManagerFactory) {
        return new JpaTransactionManager(entityManagerFactory);
    }
}

public class JobRepositoryConfig extends DefaultBatchConfigurer {
    
    @Autowired
    private PlatformTransactionManager transactionManager;
    
    @Autowired
    @Qualifier("batchDataSource")
    private DataSource datasource;

    
    @Override
    protected JobRepository createJobRepository() throws Exception {
        JobRepositoryFactoryBean factoryBean = new JobRepositoryFactoryBean();
        factoryBean.setDatabaseType(DatabaseType.POSTGRES.getProductName());
        factoryBean.setTablePrefix("BATCH_");
        factoryBean.setIsolationLevelForCreate("ISOLATION_READ_COMMITTED");
        factoryBean.setDataSource(datasource);
        factoryBean.setTransactionManager(transactionManager);
        factoryBean.afterPropertiesSet();
        return factoryBean.getObject();
    }
}

三个实体:

@Data
@NoArgsConstructor
@Entity
@Table(name = "socio") //,catalog = "socio_db"),schema = "socio_db"),schema = "socio_db")
public class SocioModel implements Serializable { // UserDetails

    public SocioModel(Long id,String username,String password,String firstName,String lastName,String email,Boolean active,List<LanguageModel> socioLanguages,List<AddressModel> socioAddresses) {
        this.id = id;
        this.password = password;
        this.username = username;
        this.firstName = firstName;
        this.lastName = lastName;
        this.email = email;
        this.active = active;
        this.socioLanguages = socioLanguages;
        this.socioAddresses = socioAddresses;
    }

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

    @NotNull
    @Column(name = "username",nullable = false,unique = true)
    private String username;

    @NotNull
    @Column(name = "password",nullable = false)
    private String password;

    @Column(name = "first_name",nullable = true)
    private String firstName;

    @NotNull
    @Column(name = "last_name",nullable = true)
    private String lastName;

    @NotNull
    @Column(name = "email",unique = true)
    private String email;

    @NotNull
    @Column(name = "register_date",nullable = false)
    private Timestamp registerDate;
    
    @NotNull
    @Column(name = "last_checkin_date",nullable = false)
    private Timestamp lastCheckinDate;

    @NotNull
    @Column(name = "active",nullable = false)
    private Boolean active;
 
    @JsonIgnore
    @OneToMany(targetEntity=SocioAssociatedSocio.class,mappedBy="socio")
    private List<SocioAssociatedSocio> socios;
    
    @JsonIgnore
    @OneToMany(targetEntity=SocioAssociatedSocio.class,mappedBy="socio") //associatedSocio
    private List<SocioAssociatedSocio> associatedSocios;
    
    @ManyToMany
    @JoinTable(name = "socio_role",joinColumns = @JoinColumn(name = "socio_id"),inverseJoinColumns = @JoinColumn(name = "role_id"))
    private List<RoleModel> socioRoles;

    @NotNull
    @ManyToMany()
    @JoinTable(name = "socio_language",inverseJoinColumns = @JoinColumn(name = "language_id"))
    private List<LanguageModel> socioLanguages;

    @OneToMany(mappedBy = "socio",cascade = CascadeType.REMOVE)
    private List<AddressModel> socioAddresses;
}

@Entity(name = "SocioAssociatedSocio")
@Table(name = "socio_associated_socio") //,schema = "socio_db")
@IdClass(SocioAssociatedSocioId.class)
public class SocioAssociatedSocio implements Serializable {

    private SocioAssociatedSocio() { }

    public SocioAssociatedSocio(Long socioId,Long associatedSocioId,SocioModel socio,SocioModel associatedSocio,AssociatedSocioState associatedSocioState,Timestamp associatedSocioDate) {
        this.socioId = socioId;
        this.associatedSocioId = associatedSocioId;
        this.socio = socio;
        this.associatedSocio = associatedSocio;
        this.associatedSocioState = associatedSocioState;
        this.associatedSocioDate = associatedSocioDate;
    }
    
    @Id
    private Long socioId;
    
    @Id
    private Long associatedSocioId;
    
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "socioId",updatable = false,insertable = false,referencedColumnName = "id")
    private SocioModel socio;
    
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "associatedSocioId",referencedColumnName = "id")
    private SocioModel associatedSocio;
    
    public enum AssociatedSocioState {
        PENDING,EXPIRED,ACCEPTED,DENIED
    }

    @Column(name = "associated_socio_state",length = 100)
    @Enumerated(EnumType.STRING)
    private AssociatedSocioState associatedSocioState;
    
    @Column(name = "associated_socio_date",nullable = true)
    private Timestamp associatedSocioDate;

    public long getSocioId() {
        return socioId;
    }

    public void setSocioId(long socioId) {
        this.socioId = socioId;
    }

    public long getAssociatedSocioId() {
        return associatedSocioId;
    }

    public void setAssociatedSocioId(long associatedSocioId) {
        this.associatedSocioId = associatedSocioId;
    }

    public SocioModel getSocio() {
        return socio;
    }

    public void setSocio(SocioModel socio) {
        this.socio = socio;
    }

    public SocioModel getAssociatedSocio() {
        return associatedSocio;
    }

    public void setAssociatedSocio(SocioModel associatedSocio) {
        this.associatedSocio = associatedSocio;
    }

    public AssociatedSocioState getAssociatedSocioState() {
        return associatedSocioState;
    }

    public void setAssociatedSocioState(AssociatedSocioState associatedSocioState) {
        this.associatedSocioState = associatedSocioState;
    }

    public Timestamp getAssociatedSocioDate() {
        return associatedSocioDate;
    }

    public void setAssociatedSocioDate(Timestamp associatedSocioDate) {
        this.associatedSocioDate = associatedSocioDate;
    }
}

public class SocioAssociatedSocioId implements Serializable {
    private SocioAssociatedSocioId() { }
    private Long socioId;
    private Long associatedSocioId;

    @Override
    public int hashCode() {
        return (int) (socioId + associatedSocioId);
    }

    @Override
    public boolean equals(Object object) {
        if (object instanceof SocioAssociatedSocioId) {
            SocioAssociatedSocioId otherId = (SocioAssociatedSocioId) object;
            return (otherId.socioId == this.socioId)
                    && (otherId.associatedSocioId == this.associatedSocioId);
        }
        return false;
    }
}

批处理流

@Configuration
@EnableBatchProcessing
public class BatchFlowConfig {
    
    @Autowired
    @Qualifier("dbTransactionManager") 
    private PlatformTransactionManager transactionManager;
    
    @Autowired
    private JobBuilderFactory jobBuilders;

    @Autowired
    private StepBuilderFactory stepBuilders;
    
    @Autowired
    private JobRepository jobRepository;
    
    @Autowired
    private SocioProcessor socioProcessor;

    @Autowired
    private SocioReader socioReader;

    @Autowired
    private SocioWriter socioWriter;
    
    @Autowired
    private AssociatedSocioProcessor associatedProcessor;

    @Autowired
    private AssociatedSocioReader associatedReader;

    @Autowired
    private AssociatedSocioWriter associatedWriter;

    @Bean(name = "sociojob")
    public Job userDbJob() throws Exception {
        return jobBuilders.get("batchdbsociowriteJob")
                .repository(jobRepository)
                .start(socioStep())
                .next(associatedSocioStep())
                .build();
    }

    @Bean
    public Step socioStep() throws Exception {
        return stepBuilders.get("sociobatchdbsociowriteStep")
                .<SocioModel,SocioModel>chunk(20)
                .reader(socioReader)
                .processor(socioProcessor)
                .writer(socioWriter)
                .transactionManager(transactionManager)
                .build();
    }
    
    @Bean
    public Step associatedSocioStep() throws Exception {
        return stepBuilders.get("associatedsociodbsociowriteStep")
                .<SocioAssociatedSocio,SocioAssociatedSocio>chunk(20)
                .reader(associatedReader)
                .processor(associatedProcessor)
                .writer(associatedWriter)
                .transactionManager(transactionManager)
                .build();
    }
}

阅读器:

@Component
public class AssociatedSocioReader implements ItemReader<SocioAssociatedSocio> {
   
    @Autowired
    private AssociatedSocioRepository repo;

    private Iterator<SocioAssociatedSocio> associatedSocioIterator;

    @BeforeStep
    public void before(StepExecution stepExecution) {
        associatedSocioIterator = repo.findAll().iterator();
    }

    @Override
    public SocioAssociatedSocio read() {
        if (associatedSocioIterator != null && associatedSocioIterator.hasNext()) {
            return associatedSocioIterator.next();
        } else {
            return null;
        }
    }
}

处理器:

@Component
public class AssociatedSocioProcessor implements ItemProcessor<SocioAssociatedSocio,SocioAssociatedSocio> {

    @Autowired
    private AssociatedSocioRepository repo;

    @Override
    public SocioAssociatedSocio process(SocioAssociatedSocio associated) throws Exception {
        associated.setAssociatedSocioState(SocioAssociatedSocio.AssociatedSocioState.EXPIRED);
        // logic not displayed
        return associated;
    }
}

作家:

@Component
public class AssociatedSocioWriter implements ItemWriter<SocioAssociatedSocio> {
    
    @Autowired
    private AssociatedSocioRepository repo;
    
    @Override
    public void write(List<? extends SocioAssociatedSocio> associated) throws Exception {
        List<SocioAssociatedSocio> list = new ArrayList();
        
        for (SocioAssociatedSocio scs: associated) {
            if(scs != null) {
                list.add(scs);
            }
        }
        repo.saveAll(list);
    }
}

最终评论: 有效的Socio读取器-处理器-写入器与上面显示的相同。问题在于,作为联接表(具有额外字段)的SocioAssociatedSocio与社会实体(常规实体)不同。

我相信交易管理和实体经理(工厂)存在一些问题。

任何帮助,欢迎改进评论。

感谢您对此的关注 威廉

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-