資料處理---Spring Batch之實踐
上面介紹了Spring Batch的基本概念和簡單的demo專案,顯然這些還是不夠實際使用的。下面我們來更多的程式碼實踐。
在上面的基礎專案上面,我們來更多的修改:
不用專案預設的hsql DB,用mysql,讓ItemReader,ItemWriter 支援mysql;
支援處理結果自定義儲存到資料庫,我們用專案裡面的JPA;
讓Quartz來定時呼叫spring batch的Job
可以讀取檔案,而不只是資料庫;
下面開始動手。
修改pom.xml,節選部分,實在太長了。
<spring.framework.version>3.2.0.RELEASE</spring.framework.version>
<spring.batch.version>2.1.7.RELEASE</spring.batch.version> <!-- 這個的版本和quartz的版本要注意,不然很容易在執行的時候出錯 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.23</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>1.3.2.RELEASE.rebuild</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>3.6.10.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>3.6.10.Final</version>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.1.7</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>3.2.0.RELEASE</version>
</dependency>
launch-context.xml定義需要用到的bean,
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="spring" />
<property name="dataSource" ref="dataSource" />
<property name="jpaDialect">
<bean class="com.test.batch.CustomHibernateJpaDialect" />
</property>
<property name="loadTimeWeaver">
<bean
class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" />
</property>
</bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url"
value="jdbc:mysql://localhost:3306/testbatch?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true" />
<property name="username" value="root" />
<property name="password" value="root" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="customerMapper" class="com.test.batch.CustomerMapper"></bean>
<bean id="lineTokenizer" class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer"></bean>
<!-- 這個可以讓spring batch和hibernate共用
<bean id="itemReader"
class="org.springframework.batch.item.database.HibernateCursorItemReader">
<property name="sessionFactory" ref="sessionFactory" />
<property name="queryString" value="from CustomerCredit" />
</bean>
-->
<bean id="itemReaderFile" class="org.springframework.batch.item.file.FlatFileItemReader" scope="step">
<property name="lineMapper">
<bean class="org.springframework.batch.item.file.mapping.DefaultLineMapper">
<property name="lineTokenizer" ref="lineTokenizer"/>
<property name="fieldSetMapper" ref="customerMapper"/>
</bean>
</property>
<!--<property name="resource" value="file:#{jobParameters['customFileAbPath']}"/> 配置讀取檔案的路徑,我固定了 -->
<property name="resource" value="file:D:/temp/testdata.txt"/>
</bean>
<bean id="itemReader" class="org.springframework.batch.item.database.JdbcCursorItemReader">
<property name="dataSource" ref="dataSource"/>
<property name="sql" value="select ID, NAME, CREDIT from CUSTOMER"/>
<property name="rowMapper">
<bean class="com.test.batch.CustomerCreditRowMapper"/>
</property>
<property name="fetchSize" value="100"></property>
<property name="maxRows" value="10000"></property>
</bean>
<jdbc:initialize-database data-source="dataSource">
<!-- <jdbc:script location="${batch.schema.script}" /> -->
<jdbc:script location="org/springframework/batch/core/schema-drop-mysql.sql" />
<jdbc:script location="org/springframework/batch/core/schema-mysql.sql" />
</jdbc:initialize-database
<!-- batch:job-repository id="jobRepository" / -->
<batch:job-repository id="jobRepository"
data-source="dataSource" transaction-manager="transactionManager"
isolation-level-for-create="SERIALIZABLE" table-prefix="BATCH_" />
<!-- 下面是Quartz呼叫spring batch 的job要用到的 -->
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list><ref bean="scheduledTrigger"></ref></list>
</property>
</bean>
<bean id="scheduledTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="jobDetail"/>
<property name="cronExpression">
<value>*/10 * * * * ?</value>
</property>
</bean>
<bean id="jobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<property name="jobClass" value="com.test.batch.JobLauncherDetails" />
<property name="jobDataAsMap">
<map>
<entry key="jobName" value="job1" /> <!--指定jobID -->
<entry key="jobLocator" value-ref="jobRegistry" />
<entry key="jobLauncher" value-ref="jobLauncher" />
<entry key="param1" value="p1" />
<entry key="param2" value="p2" />
</map>
</property>
<property name="durability" value="true" />
</bean>
<bean id="jobLauncher"
class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
<property name="jobRepository" ref="jobRepository" />
</bean>
<bean
class="org.springframework.batch.core.configuration.support.JobRegistryBeanPostProcessor">
<property name="jobRegistry" ref="jobRegistry" />
</bean>
<bean id="jobRegistry" class="org.springframework.batch.core.configuration.support.MapJobRegistry" />
<import resource="classpath:/META-INF/spring/module-context.xml" />
有幾個定製的東西,需要說下。
我們用到的domain物件是這樣的,很多不必要的都省略了
@Entity
@Table(name = "customer")
public class CustomerCredit {
public static final String TABLE_NAME = "customer";
@Column(name = "name", nullable = true, length = 12)
private String name;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", nullable = false)
private Integer id;
@Column(name = "credit", nullable = true, precision = 15, scale = 2)
private BigDecimal credit;
FlatFileItemReader 使用預設的DefaultLineMapper,裡面指定了lineTokenizer和fieldSetMapper,就是說要怎麼讀一行行的資料,讀了之後怎麼和Bean的欄位Mapper,這樣後面的步驟好繼續處理。
public class CustomerMapper implements FieldSetMapper<CustomerCredit> {
@Override
public CustomerCredit mapFieldSet(FieldSet fieldSet) throws BindException {
CustomerCredit lv = new CustomerCredit();
lv.setId(Integer.parseInt(fieldSet.readString(0)));
lv.setName(fieldSet.readString(1));
lv.setCredit(fieldSet.readBigDecimal(2));
return lv;
}
}
如果是讀資料庫呢?就是下面那個JdbcCursorItemReader,裡面指定了dataSource,sql,rowMapper,這些都類似檔案
public class CustomerCreditRowMapper implements RowMapper {
public static final String ID_COLUMN = "id";
public static final String NAME_COLUMN = "name";
public static final String CREDIT_COLUMN = "credit";
public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
CustomerCredit customerCredit = new CustomerCredit();
customerCredit.setId(rs.getInt(ID_COLUMN));
customerCredit.setName(rs.getString(NAME_COLUMN));
customerCredit.setCredit(rs.getBigDecimal(CREDIT_COLUMN));
return customerCredit;
}
}
還可以和hibernate結合來讀取資料,可以讀取儲存過程的資料,等等,具體可以參考spring batch文件
說好的自定義處理資料呢,比如我們把每個人的Credit加10.
@Component("customProcessor")
public class CustomProcessor implements
ItemProcessor<CustomerCredit, CustomerCredit> {
@PersistenceContext
private EntityManager em;
@Override
public CustomerCredit process(CustomerCredit item) throws Exception {
System.out.println(new Date().toString()+"start to process");
if (item == null) {
return null;
}
try {
item = em.find(CustomerCredit.class, item.getId());
item.setCredit(item.getCredit().add(new BigDecimal(10)));
//find by id才可以persist (否則出現detached entity passed to persist)
em.persist(item);
} catch (Exception e) {
e.printStackTrace();
}
return item;
}
}
每一步的處理,我們想看看結果,可以定製一個ItemReadListener
public class CustomStepListener implements ItemReadListener<CustomerCredit> 具體程式碼省略
修改module-context.xml
<batch:job id="job1">
<batch:step id="step1">
<batch:tasklet transaction-manager="transactionManager"
start-limit="100">
<batch:chunk reader="itemReade" writer="itemwriter" processor="customProcessor"
commit-interval="3" />
</batch:tasklet>
</batch:step>
</batch:job>
在META-INF下面加個persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0"
xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="spring" transaction-type="RESOURCE_LOCAL">
<!--
<class>com.test.jpatest.model.Customer</class>
<class>com.test.jpatest.model.Address</class>
-->
<provider>org.hibernate.ejb.HibernatePersistence</provider>
</persistence-unit>
</persistence>
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'exampleConfiguration': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire
field: private org.springframework.batch.core.repository.JobRepository com.test.batch.ExampleConfiguration.jobRepository; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jobRepository': Cannot resolve
reference to bean 'transactionManager' while setting bean property 'transactionManager'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionManager' defined in class path resource [launch-context.xml]:
Cannot resolve reference to bean 'entityManagerFactory' while setting bean property 'entityManagerFactory'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path
resource [launch-context.xml]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: No persistence unit with name 'spring' found
執行的時候遇到上面的錯誤,就是沒有上面的配置的原因
org.springframework.transaction.InvalidIsolationLevelException: Standard JPA does not support custom isolation levels - use a special JpaDialect for your JPA implementation
at org.springframework.orm.jpa.DefaultJpaDialect.beginTransaction(DefaultJpaDialect.java:66)
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.beginTransaction(HibernateJpaDialect.java:59)
遇到這樣的錯誤,是因為預設的JPA不支援自定義的事物隔離級別。可以自定義一個CustomHibernateJpaDialect extends HibernateJpaDialect,具體程式碼沒有列出,可以找下。
在用Quartz的時候遇到
Caused by: java.lang.IncompatibleClassChangeError: class org.springframework.scheduling.quartz.CronTriggerBean has interface org.quartz.CronTrigger as super class
這個是由於網上的很多例子都是quartz版本稍舊的原因,我用的是quartz 2.1.7
錯誤:Jobs added with no trigger must be durable
<property name="durability" value="true" />
坑真的是不少,需要一個個解決。最後測試一下,是不是定時執行我們的job:
public class App {
public static void main(String[] args) {
String springConfig = "launch-context.xml";
ApplicationContext context = new ClassPathXmlApplicationContext(
springConfig);
}
}
祝你好運,能夠成功,。
相關推薦
資料處理---Spring Batch之實踐
上面介紹了Spring Batch的基本概念和簡單的demo專案,顯然這些還是不夠實際使用的。下面我們來更多的程式碼實踐。 在上面的基礎專案上面,我們來更多的修改: 不用專案預設的hsql DB,用mysql,讓ItemReader,Item
資料處理---Spring Batch之基礎
Spring框架提供了強大的底層結構,基於此,Spring出現了很多方面的應用。Spring Batch就是其一,它是一個輕量級的,完全面向Spring的批處理框架,可以應用於企業級大量的資料處理系統。Spring Batch以POJO和大家熟知的Spring框
資料處理-Spring Batch Scaling and Parallel Processing
承蒙各位擡愛,鄙人的一篇關於Spring Batch的部落格《Spring Batch之進階》有很多人瀏覽。說明有很多人工作中用到這個spring batch框架進行批量任務處理,也說明對這個框架還有不少不熟悉的地方,鄙人也是。That is to say,我們
資料共享-spring batch(9)上下文處理
[TOC] > 在 Spring Batch 中進行資料及引數傳遞的方法。 ## 1 引言 本文是 Spring Batch 系列文章的第9篇,有興趣的可見文章: - [資料批處理神器-Spring Batch(1)簡介及使用場景](https://mp.weixin.qq.com/s/mH0k
Spring Batch 之 flow 介紹和使用
通過前文我們已經知道,Step 是一個獨立的、順序的處理步驟,包含完整的輸入、處理以及輸出。但是在企業應用中,我們面對的更多情況是多個步驟按照一定的順序進行處理。因此如何維護步驟之間的執行順序是我們需要考慮的。Spring Ba
Spring Batch 之 Job的建立和呼叫
在上一篇文章 Spring Batch 之 背景框架簡介 中,已經概述了Batch的基本架構組織,並且運行了簡易demo。 在接下來的篇幅中,將逐步介紹每個元件的使用方式,並結合業務進行批處理。
Spring Batch 之 背景框架簡介
Spring Batch 是一個輕量級的、全面的批處理框架,用於開發對企業系統的日常操作至關重要的健壯批處理應用程式。Spring Batch提供了處理大量記錄所必需的可重用功能,包括日誌/跟蹤、
核磁資料處理: FSL系列之flirt命令
flirt 是FSL的線性修正工具. 官方提供了非常豐富的呼叫方式: - 命令Flirt可以啟動FLIRT的GUI + InvertXFM, ApplyXFM, ConcatXFM - 命令flirt 是命令列工具 - misc flirt util
spring batch之三 配置和執行Job
4.6.3. JobOperator sping batch 提供了JobOperator對batch 操作進行重啟,總結,停止操作. public interface JobOperator { List<Long> getExecutions(long instanceI
核磁資料處理: FSL系列之segmentation工具FAST
fsl的segmentation工具: FAST (FMRIB’s Automated Segmentation Tool)將大腦組織的3D影響分解為不同的組織,比如灰質\白質\腦脊液等等, 同時還可以進行spatial intensity variations
python 資料處理學習pandas之DataFrame(三)
請原諒沒有一次寫完,本文是自己學習過程中的記錄,完善pandas的學習知識,對於現有網上資料的缺少和利用python進行資料分析這本書部分知識的過時,只好以記錄的形勢來寫這篇文章.最如果後續工作定下來有時間一定完善pandas庫的學習,請見諒!
spring batch之二 一個簡單的spring batch的例子.
在實際工作中我們可能需要快速的實現一個spring batch.本文作為一個參考例子。 主要使用maven ,STS tool. spring.framework.version 3.0.6.RELEASE. spring.batch.version 2.1.7.REL
Spring batch 之操作資料庫
common.xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://
史上最輕鬆入門之Spring Batch - 輕量級批處理框架實踐
從 MariaDB 一張表內讀 10 萬條記錄,經處理後寫到 MongoDB 。 Batch 任務模型 具體實現 1、新建 Spring Boot 應用,依賴如下: <!-- Web 應用 --> <dependency> <group
Spring Boot 之 Spring Batch 批處理實踐
#### 實踐內容 從 MariaDB 一張表內讀 10 萬條記錄,經處理後寫到 MongoDB 。 #### 具體實現 1、新建 Spring Boot 應用,依賴如下: ```xml
Spring Batch:將資料從Web服務處理到MongoDB
概觀 在這篇文章中,我們將介紹如何建立一個使用Web服務資料並將其插入MongoDB資料庫的Spring Batch應用程式。 要求 閱讀本文的開發人員必須熟悉Spring Batch(示例)和MongoDB。 環境 Mongo資料庫部署在MLab中。請按照本快速入門中的步驟操作。 批
薦書丨深度學習之美——AI時代的資料處理與最佳實踐
點選上方“程式人生”,選擇“置頂公眾號”第一時間關注程式猿(媛)身邊的故事零入門 | 高可讀|
大資料批處理框架Spring Batch 的全面解析
如今微服務架構討論的如火如荼。但在企業架構裡除了大量的OLTP交易外,還存在海量的批處理交易。在諸如銀行的金融機構中,每天有3-4萬筆的批處理作業需要處理。針對OLTP,業界有大量的開源框架、優秀的架構設計給予支撐;但批處理領域的框架確鳳毛麟角。是時候和我們一起來了解下批處理的世界哪些優秀的框架和設計了,今天
大量資料也不在話下,Spring Batch並行處理四種模式初探
# 1 前言 > 歡迎訪問[南瓜慢說 www.pkslow.com](https://www.pkslow.com/)獲取更多精彩文章! `Spring相關文章:`[Springboot-Cloud](https://www.pkslow.com/categories/springboot) 前
Spring Security應用開發(11) 並發控制之實踐
nag line then 9.png page 總結 -c ole for 本文分別介紹了四種不同情況下,Spring Security的Session管理和並發控制的不同配置的配置方法,以及所產生的效果。 (1)首先編寫了session_error.jsp頁面,用於