一、需求分析

使用Spring Batch对DB进行读写操作: 从一个表中读取数据, 然后批量的插入另外一张表中.

二、代码实现

1. 代码结构图:

2. applicationContext.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.1.xsd"> <!-- 配置spring扫描范围 -->
<context:component-scan base-package="com.zdp" /> <!-- 配置数据源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" abstract="false" scope="singleton">
<property name="driverClass" value="org.gjt.mm.mysql.Driver" />
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test? useUnicode=true&characterEncoding=UTF-8" />
<property name="user" value="root" />
<property name="password" value="root" />
<property name="checkoutTimeout" value="30000" />
<property name="maxIdleTime" value="120" />
<property name="maxPoolSize" value="100" />
<property name="minPoolSize" value="2" />
<property name="initialPoolSize" value="2" />
<property name="maxStatements" value="0" />
<property name="maxStatementsPerConnection" value="0" />
<property name="idleConnectionTestPeriod" value="30" />
</bean> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource" />
</bean> <bean id="jobRepository" class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean">
<property name="transactionManager" ref="transactionManager" />
</bean> <bean id="jobLauncher" class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
<property name="jobRepository" ref="jobRepository" />
</bean> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean> <tx:annotation-driven transaction-manager="transactionManager" />
</beans>

base-package: 扫描spring注解

jobLauncher: 启动Job

jobRepository: 为Job提供持久化操作

transactionManager: 提供事务管理操作

3. springBatch.xml

<?xml version="1.0" encoding="UTF-8"?>
<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"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/batch
http://www.springframework.org/schema/batch/spring-batch-2.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.1.xsd"> <!-- 引入spring核心配置文件 -->
<import resource="applicationContext.xml"/> <batch:job id="ledgerJob">
<!-- 监听job运行状态 -->
<batch:listeners>
<batch:listener ref="appJobExecutionListener" />
</batch:listeners>
<batch:step id="step">
<!-- 加入事务控制 -->
<batch:tasklet transaction-manager="transactionManager">
<batch:listeners>
<batch:listener ref="itemFailureLoggerListener" />
</batch:listeners>
<!-- commit-interval: 批量提交的条数; skip-limit: 指同意跳过记录数 -->
<batch:chunk reader="ledgerReader" writer="ledgerWriter" commit-interval="1000" skip-limit="1000">
<batch:skippable-exception-classes>
<batch:include class="java.lang.Exception"/> <!-- 出现exception或其子类, Job仍然会往后运行 -->
<batch:exclude class="java.io.FileNotFoundException"/> <!-- 出现这个异常, Job会立马停止 -->
</batch:skippable-exception-classes>
</batch:chunk>
</batch:tasklet>
</batch:step>
</batch:job> <!-- 从ledger表读取数据 -->
<bean id="ledgerReader" class="org.springframework.batch.item.database.JdbcCursorItemReader">
<property name="dataSource" ref="dataSource" />
<property name="sql" value="select * from ledger" />
<property name="rowMapper" ref="ledgerRowMapper" />
</bean> <bean id="jobParameterBulider" class="org.springframework.batch.core.JobParametersBuilder" /> <!-- 定时任务開始 -->
<bean id="ledgerJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject">
<!-- 定时运行类 -->
<ref bean="quartzLedgerJob" />
</property>
<property name="targetMethod">
<!-- 定时运行类的方法 -->
<value>execute</value>
</property>
</bean> <bean id="ledgerCronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean" >
<property name="jobDetail" >
<ref bean="ledgerJobDetail" />
</property>
<property name="cronExpression" >
<!-- 每天晚上22:30运行 -->
<value>0 30 22 ? * *</value>
</property>
</bean> <!-- 触发器工厂。将全部的定时任务都注入工厂-->
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<!-- 加入触发器 -->
<property name="triggers">
<list>
<!-- 将上面定义的測试定时任务注入(能够定义多个定时任务。同一时候注入)-->
<ref local="ledgerCronTrigger" />
</list>
</property>
</bean>
</beans>

4. AppJobExecutionListener.java

/**
* 监听job执行状态
*/
@Component("appJobExecutionListener")
public class AppJobExecutionListener implements JobExecutionListener {
private final static Logger logger = Logger.getLogger(AppJobExecutionListener.class); public void afterJob(JobExecution jobExecution) {
if (jobExecution.getStatus() == BatchStatus.COMPLETED) {
logger.info("Job completed: " + jobExecution.getJobId());
} else if (jobExecution.getStatus() == BatchStatus.FAILED) {
logger.info("Job failed: " + jobExecution.getJobId());
}
} public void beforeJob(JobExecution jobExecution) {
if (jobExecution.getStatus() == BatchStatus.COMPLETED) {
logger.info("Job completed: " + jobExecution.getJobId());
} else if (jobExecution.getStatus() == BatchStatus.FAILED) {
logger.info("Job failed: " + jobExecution.getJobId());
}
}
}

5. ItemFailureLoggerListener.java

/**
* 检查是读出错还是写出错
*/
@Component("itemFailureLoggerListener")
public class ItemFailureLoggerListener extends ItemListenerSupport<Object, Object> {
private final static Logger LOG = Logger.getLogger(ItemFailureLoggerListener.class); public void onReadError(Exception ex) {
LOG.error("Encountered error on read", ex);
} public void onWriteError(Exception ex, Object item) {
LOG.error("Encountered error on write", ex);
} }

6. Ledger.java

public class Ledger implements Serializable {
private static final long serialVersionUID = 1L;
private int id;
private Date receiptDate;
private String memberName;
private String checkNumber;
private Date checkDate;
private String paymentType;
private double depositAmount;
private double paymentAmount;
private String comments; // getter and setter
}

7. LedgerRowMapper.java

/**
* ledger行的映射类
*/
@SuppressWarnings("rawtypes")
@Component("ledgerRowMapper")
public class LedgerRowMapper implements RowMapper {
public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
Ledger ledger = new Ledger();
ledger.setId(rs.getInt("ID"));
ledger.setReceiptDate(rs.getDate("RECEIPT_DATE"));
ledger.setMemberName(rs.getString("MEMBER_NAME"));
ledger.setCheckNumber(rs.getString("MEMBER_NAME"));
ledger.setCheckDate(rs.getDate("CHECK_DATE"));
ledger.setPaymentType(rs.getString("PAYMENT_TYPE"));
ledger.setDepositAmount(rs.getDouble("DEPOSIT_AMOUNT"));
ledger.setPaymentAmount(rs.getDouble("PAYMENT_AMOUNT"));
ledger.setComments(rs.getString("COMMENTS"));
return ledger;
}
}

8. LedgerDao.java

public interface LedgerDao {
public void save(final Ledger item) ;
}

9. LedgerDaoImpl.java

/**
* ledger数据操作类
*/
@Repository
public class LedgerDaoImpl implements LedgerDao { private static final String SAVE_SQL = "INSERT INTO LEDGER_TEMP (RECEIPT_DATE, MEMBER_NAME, CHECK_NUMBER, CHECK_DATE, PAYMENT_TYPE, DEPOSIT_AMOUNT, PAYMENT_AMOUNT, COMMENTS) VALUES(?,? ,? ,?,? ,?,? ,?)"; @Autowired
private JdbcTemplate jdbcTemplate; @Override
public void save(final Ledger item) {
jdbcTemplate.update(SAVE_SQL, new PreparedStatementSetter() {
public void setValues(PreparedStatement stmt) throws SQLException {
stmt.setDate(1, new java.sql.Date(item.getReceiptDate().getTime()));
stmt.setString(2, item.getMemberName());
stmt.setString(3, item.getCheckNumber());
stmt.setDate(4, new java.sql.Date(item.getCheckDate().getTime()));
stmt.setString(5, item.getPaymentType());
stmt.setDouble(6, item.getDepositAmount());
stmt.setDouble(7, item.getPaymentAmount());
stmt.setString(8, item.getComments());
}
});
}
}

10. LedgerWriter.java

/**
* ledger写入数据
*/
@Component("ledgerWriter")
public class LedgerWriter implements ItemWriter<Ledger> { @Autowired
private LedgerDao ledgerDao; /**
* 写入数据
* @param ledgers
*/
public void write(List<? extends Ledger> ledgers) throws Exception {
for (Ledger ledger : ledgers) {
ledgerDao.save(ledger);
}
} }

11. QuartzLedgerJob.java

/**
* 定时调度类
*/
@Component("quartzLedgerJob")
public class QuartzLedgerJob { private static final Logger LOG = LoggerFactory.getLogger(QuartzLedgerJob.class); @Autowired
private JobLauncher jobLauncher; @Autowired
private Job ledgerJob; @Autowired
JobParametersBuilder jobParameterBulider; private static long counter = 0l; /**
* 运行业务方法
* @throws Exception
*/
public void execute() throws Exception {
/**
* Spring Batch Job同一个job instance,成功运行后是不同意又一次运行的,
* 失败后是否同意重跑,可通过配置Job的restartable參数来控制,默认是true,假设须要又一次运行。能够变通处理,
* 加入一个JobParameters构建类,以当前时间作为參数,保证其它參数同样的情况下是不同的job instance
*/
LOG.debug("start...");
StopWatch stopWatch = new StopWatch();
stopWatch.start();
jobParameterBulider.addDate("date", new Date());
jobLauncher.run(ledgerJob, jobParameterBulider.toJobParameters());
stopWatch.stop();
LOG.debug("Time elapsed:{},Execute quartz ledgerJob:{}", stopWatch.prettyPrint(), ++counter);
}
}

12. StartQuartz.java

/**
* 启动定时调度
* 需求描写叙述: 定时从表ledger读取数据, 然后批量写入表ledger_temp
*/
public class StartQuartz {
public static void main(String[] args) throws FileNotFoundException {
new ClassPathXmlApplicationContext("/com/zdp/resources/springBatch.xml");
}
}

13. sql:

create table ledger(
ID int(10) not null AUTO_INCREMENT PRIMARY KEY,
RECEIPT_DATE date,
MEMBER_NAME varchar(10) ,
CHECK_NUMBER varchar(10) ,
CHECK_DATE date,
PAYMENT_TYPE varchar(10) ,
DEPOSIT_AMOUNT double(10,3),
PAYMENT_AMOUNT double(10,3),
COMMENTS varchar(100)
); create table ledger_temp(
ID int(10) not null AUTO_INCREMENT PRIMARY KEY,
RECEIPT_DATE date,
MEMBER_NAME varchar(10) ,
CHECK_NUMBER varchar(10) ,
CHECK_DATE date,
PAYMENT_TYPE varchar(10) ,
DEPOSIT_AMOUNT double(10,3),
PAYMENT_AMOUNT double(10,3),
COMMENTS varchar(100)
);

springbatch操作DB的更多相关文章

  1. [Android] Android 使用 Greendao 操作 db sqlite(2)-- 封装DaoUtils类

    继续接上文: Android 使用 Greendao 操作 db sqlite(1)-- 直接在MainActivity中调用 布局文件同上文一致,这里就不贴了. 一.封装DaoUtils类 User ...

  2. [Android] Android 使用 Greendao 操作 db sqlite(1)-- 直接在MainActivity中调用

    继续接上文: Android 使用 Greendao 操作 db sqlite 布局文件: activity_test_green.xml <?xml version="1.0&quo ...

  3. [Android] Android 使用 Greendao 操作 db sqlite

    Android 使用 Greendao 操作 db sqlite GreenDAO是一个开源的安卓ORM框架,能够使SQLite数据库的开发再次变得有趣.它减轻开发人员处理低级数据库需求,同时节省开发 ...

  4. Atitit.软件按钮与仪表盘(13)--全文索引操作--db数据库子系统mssql2008

    Atitit.软件按钮与仪表盘(13)--全文索引操作--db数据库子系统mssql2008 全文索引操作 4.全文索引和like语句比较 1 5.倒排索引 inverted index 1 2.SQ ...

  5. 对SQLite数据库操作 操作db文件

    sqlite数据库就是一个DB文件.  程序每操作一次数据库都要读一次 .DB  文件 .  这个文件就是这个SQLite数据库. 如果需要依赖包的可以联系我 工具类: package com.hot ...

  6. Atitit.软件button和仪表板(13)--全文索引操作--db数据库子系统mssql2008

    Atitit.软件button和仪表板(13)--全文索引操作--db数据库子系统mssql2008 全文索引操作 4.全文索引和like语句比較 1 5.倒排索引 inverted index 1 ...

  7. springbatch操作CSV文件

    一.需求分析 使用Spring Batch对CSV文件进行读写操作: 读取一个含有四个字段的CSV文件(id, name, age, score), 对文件做简单的处理, 然后输出到还有一个csv文件 ...

  8. thinkphp 和 laravel使用sql语句操作db和源码浅析

    thinkphp 和 laravel是phper开发中用的比较多的两个框架,无所谓好坏,看个人习惯及喜爱! 前言对于一个PHP应用,可能最多的就是操作数据,以致于初学者有时只把php当做数据库增删查改 ...

  9. 20. Spring Boot 默认、自定义数据源 、配置多个数据源 jdbcTemplate操作DB

    Spring-Boot-2.0.0-M1版本将默认的数据库连接池从tomcat jdbc pool改为了hikari,这里主要研究下hikari的默认配置 0.  创建Spring Boot项目,选中 ...

随机推荐

  1. C# this.Hide()

    C# this.Hide() 第一次用的时候是在_Load函数里: BookSystem bs = new BookSystem();             bs.ShowDialog();     ...

  2. 求x>0时,y=x^3-6x^2+15的极值

    解: 当x→∞时,y也→∞,所以y没有最大值. y=x3-6x2+15=-4*(x/2)*(x/2)*(6-x)+15 而根据几何平均数小于等于算术平均数的定理,(x/2)*(x/2)*(6-x)在x ...

  3. Storm---DirectGroup(直接分组)

    以单词分割计数为例实现Storm的DirectGroup分组: 1.Spout实现 Spout是Storm数据源头,使用DirectGroup方式将Spout数据发送指定的Bolt,需注意: 1).S ...

  4. IBM-ETP 实训项目前一天

    明天就要开始项目了,实训项目,虽然之前做了几个项目,但是明天就要被一个有着8年项目经验的大牛带着做这个项目了.心中还是不免有点兴奋的.希望能学到更多的东西,来充实自己. 自己也搭建了一个小的demo ...

  5. FIFO、LRU、LFU的含义和原理(转)

    题目:请简要介绍FIFO.LRU.LFU的含义和原理   含义: FIFO:First In First Out,先进先出LRU:Least Recently Used,最近最少使用 LFU:Leas ...

  6. BroadcastReceiver应用详解——广播

    转自:http://blog.csdn.net/liuhe688/article/details/6955668 BroadcastReceiver也就是“广播接收者”的意思,顾名思义,它就是用来接收 ...

  7. Android低功耗蓝牙(BLE)使用详解

    代码地址如下:http://www.demodashi.com/demo/13390.html 与普通蓝牙相比,低功耗蓝牙显著降低了能量消耗,允许Android应用程序与具有更严格电源要求的BLE设备 ...

  8. MAC-Zsh安装与使用——终极Shell

    前言:Zsh可配置性强,用户可以自定义配置,个性化强.Zsh tab补全更强大,该功能可以让我们节约很多时间.Zsh 还有代码高亮功能,使得代码更好看了,显得逼格更高.Zsh 还有很多强大的功能,这里 ...

  9. spring中的AOP 以及各种通知 配置

    理解了前面动态代理对象的原理之后,其实还是有很多不足之处,因为如果在项目中有20多个类,每个类有100多个方法都需要判断是不是要开事务,那么方法调用那里会相当麻烦. spring中的AOP很好地解决了 ...

  10. python 高级语法

    #coding:utf-8 #定义一个装饰器函数 def doc_func(func): #包裹函数(闭包) def warpfunc(): #做一些额外的事情 print "%s call ...