spring batch 中JpaNamedQueryProvider、JpaNativeQueryProvider两种查询方式对比
完整代码示例:对比两种查询方式
// Employee.java 实体类(包含命名查询)
@Entity
@NamedQuery(name = "Employee.findAllNamedQuery", 
            query = "SELECT e FROM Employee e ORDER BY e.id") // 定义命名查询
public class Employee {
    @Id
    private Long id;
    private String name;
    private Double salary;
    // getters/setters
}
// JobConfig.java 配置类
@Configuration
@EnableBatchProcessing
public class JobConfig {
    @Autowired
    private JobBuilderFactory jobBuilderFactory;
    @Autowired
    private StepBuilderFactory stepBuilderFactory;
    @Autowired
    private EntityManagerFactory entityManagerFactory;
    @Bean
    public Job employeeJob() {
        return jobBuilderFactory.get("employeeJob")
                .start(employeeStep1()) // 使用命名查询的步骤
                .next(employeeStep2())  // 使用原生查询的步骤
                .build();
    }
    // 使用JpaNamedQueryProvider的步骤
    @Bean
    public Step employeeStep1(JpaPagingItemReader<Employee> namedQueryReader) {
        return stepBuilderFactory.get("step1")
                .<Employee, Employee>chunk(10)
                .reader(namedQueryReader)
                .writer(items -> items.forEach(System.out::println))
                .build();
    }
    // 使用JpaNativeQueryProvider的步骤
    @Bean
    public Step employeeStep2(JpaPagingItemReader<Employee> nativeQueryReader) {
        return stepBuilderFactory.get("step2")
                .<Employee, Employee>chunk(10)
                .reader(nativeQueryReader)
                .writer(items -> items.forEach(System.out::println))
                .build();
    }
    // 命名查询配置
    @Bean
    public JpaPagingItemReader<Employee> namedQueryReader() {
        return new JpaPagingItemReaderBuilder<Employee>()
            .name("namedQueryReader")
            .entityManagerFactory(entityManagerFactory)
            .pageSize(50)
            .queryProvider(new JpaNamedQueryProvider("Employee.findAllNamedQuery"))
            .build();
    }
    // 原生查询配置
    @Bean
    public JpaPagingItemReader<Employee> nativeQueryReader() {
        return new JpaPagingItemReaderBuilder<Employee>()
            .name("nativeQueryReader")
            .entityManagerFactory(entityManagerFactory)
            .pageSize(50)
            .queryProvider(new JpaNativeQueryProvider<>(
                "SELECT e.id, e.name, e.salary FROM EMPLOYEE e ORDER BY e.id", // 原生SQL
                Employee.class, // 映射实体
                new String[]{"id", "name", "salary"} // 列名到属性的映射
            ))
            .build();
    }
}
// SpringBatchApplication.java 启动类
@SpringBootApplication
@EnableBatchProcessing
public class SpringBatchApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringBatchApplication.class, args);
    }
}
关键代码说明:
-  JpaNamedQueryProvider - 通过实体类上的@NamedQuery定义查询名称和JPQL语句
- 配置时直接传入命名查询名称
- 优势:符合JPA规范,编译时检查查询语法
 
- 通过实体类上的
-  JpaNativeQueryProvider - 处理原生SQL查询,需手动指定: 
    - SQL语句(注意表名与数据库实际表名一致)
- 目标实体类型
- 列名与实体属性的映射关系
 
- 适用场景:需要复杂SQL优化或使用数据库特定语法
 
- 处理原生SQL查询,需手动指定: 
    
-  JpaPagingItemReader - 核心分页读取器,自动处理分页逻辑: 
    - 使用entityManagerFactory连接数据库
- 通过pageSize控制每批数据量
- 支持事务管理(由Spring Batch自动处理)
 
- 使用
 
- 核心分页读取器,自动处理分页逻辑: 
    
-  JpaPagingItemReaderBuilder -  通过链式调用简化配置: new JpaPagingItemReaderBuilder<>() .name("readerName") .entityManagerFactory(...) .pageSize(50) .queryProvider(...) .build();
-  必须配置: entityManagerFactory、queryProvider、pageSize
 
-  
功能对比表格
| 类名称 | 功能描述 | 使用场景 | 关键配置参数 | 注意事项 | 
|---|---|---|---|---|
| JpaNamedQueryProvider | 基于实体类的命名查询管理 | 需要复用JPQL查询 | 查询名称(String) | 需与实体类的@NamedQuery一致 | 
| JpaNativeQueryProvider | 管理原生SQL查询,支持列名到实体属性的映射 | 需要执行原生SQL查询 | SQL语句、实体类型、属性列名映射数组 | 需确保列名与实体属性严格对应 | 
| JpaPagingItemReader | 分页读取数据的核心组件,支持数据库连接和分页逻辑 | 所有需要分页读取数据的场景 | entityManagerFactory、pageSize、查询提供者 | 需配合Spring Batch事务管理 | 
| JpaPagingItemReaderBuilder | 构建JpaPagingItemReader的辅助类,提供链式配置方式 | 需要简化配置流程 | name、entityManagerFactory、pageSize、查询提供者 | 所有参数必须显式配置 | 
使用要点总结:
- 命名查询:需在实体类上通过@NamedQuery定义,保证查询名称一致性
- 原生查询: 
  - 表名需与数据库实际表名一致(区分大小写)
- 列名必须与实体属性严格对应(如:id对应Employee.id)
 
- 分页性能: 
  - pageSize需根据数据库性能调整,建议50-1000之间
- 分页使用OFFSET时需注意数据库性能(如MySQL InnoDB的优化)
 
- 事务管理:Spring Batch会自动管理事务,但需确保EntityManagerFactory配置正确
- 数据映射:原生查询需手动指定列名映射,命名查询自动通过实体属性映射
