公司最近有需求,需要处理一批千万级别的数据,不过是一次性的,之前没碰到过,开发的过程中遇到不少问题,这里记录一下代码,主要使用的是spring-JdbcTemplate进行数据库操作,使用quartz定时任务进行启动,因为只需要运行一次,所有就设置了定时自启
业务代码
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
/**
* @author
* @Classname data
* @Date 2019/6/12 15:25
*/
public class data implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
}
public void executeA() throws JobExecutionException {
// TODO Auto-generated method stub
System.out.println("程序启动---------------------------------------");
dataServlet dataServlet = new dataServlet();
dataServlet.init();
}
}
具体业务代码如下 代码
.
import bsoft.lis.tools.UploadReportTools;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.context.ContextLoader;
import org.springframework.web.context.WebApplicationContext;
import java.util.*;
/**
* @author
* @Classname dataServlet
* @Date 2019/6/12 10:20
*/
public class dataServlet {
private static Log logger = LogFactory.getLog(PublicDispatcher.class);
//加载spring容器
private static WebApplicationContext ac = ContextLoader.getCurrentWebApplicationContext();
//获取jdbctemplate
private static JdbcTemplate jt = (JdbcTemplate) ac.getBean("jdbcTemplate");
/**
* 数据处理,将list集合中的对象转换成数组
*/
private List<Object[]> transform(List<patient> query) {
List<Object[]> list = new ArrayList<>();
Object[] objects = null;
for (bsoft.lis.serverlet.patient patient : query) {
objects = new Object[]{
patient.getREPORTID(),
patient.getJGID(),
(String) patient.getSAMPLENO(),
(String) patient.getDOCTADVISENO(),
(String) patient.getPlatId()
};
System.out.println(Arrays.toString(objects));
list.add(objects);
}
return list;
}
public void init() {
String sql1 = "INSERT INTO PATIENTINFO_";
String sql2 = " (" +
"REPORTID, JGID, SAMPLENO, DOCTADVISENO, PLATID," +
"VALUES (?, ?, ?, ?, ?, ?)";
//地市分表数组
String[] xzqh = {"3301", "3302", "3303", "3304", "3305", "3306", "3307", "3308", "3309", "3310", "3311"};
//时间分段
String[][] date = {{"2019-01-01 00:00:00", "2019-02-01 00:00:00"},
{"2019-02-01 00:00:00", "2019-03-01 00:00:00"},
{"2019-03-01 00:00:00", "2019-04-01 00:00:00"},
{"2019-04-01 00:00:00", "2019-05-01 00:00:00"},
{"2019-05-01 00:00:00", "2019-05-24 00:00:00"}};
for (int i = 0; i < date.length; i++) {
String id = map.get("id").toString();
//按照时间段进行筛选数据
String sql = "select * from labplat.patientinfo where checktime >= to_date('" + date[i][0] + "','yyyy-mm-dd hh24:mi:ss') and checktime < to_date('" + date[i][1] + "','yyyy-mm-dd hh24:mi:ss')";
List<patient> query = jt.query(sql, new BeanPropertyRowMapper<patient>(patient.class));
//循环判断插入地市分表
for (String s : xzqh) {
List<patient> plist = new ArrayList<>();
for (bsoft.lis.serverlet.patient patient : query) {
if (Objects.equals(s, patient.getPlatId.substring(0, 4))) {
patient.setPLATID(Integer.parseInt(sfzh.substring(0,6)));
plist.add(patient);
}
logger.info(patient.getREPORTID()+patient.getPLATID());
}
List<Object[]> transform = transform(plist);
String isql = sql1 + s + sql2;
jt.batchUpdate(isql, transform);
}
}
}
}
spring.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:dwr="http://www.directwebremoting.org/schema/spring-dwr"
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-2.0.xsd
http://www.directwebremoting.org/schema/spring-dwr http://www.directwebremoting.org/schema/spring-dwr-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<import resource="spring-hibernate.xml"/>
<context:component-scan base-package="bsoft.lis.service"></context:component-scan>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<!--配置JdbcTemplate-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean id="data" class="bsoft.lis.serverlet.data" />
<!--定时器任务配置(开始)-->
<!--配置JOB-->
<bean id="dataDetail"
class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="data" />
<property name="targetMethod" value="executeA" />
<!-- <property name="arguments" /> -->
</bean>
<!--配置Trigger-->
<bean id="dataTrigger"
class="org.springframework.scheduling.quartz.SimpleTriggerBean">
<property name="jobDetail" ref="dataDetail" />
<property name="startDelay" value="10000" />
<property name="repeatInterval" value="0" />
<property name="repeatCount" value="0" />
</bean>
<!--配置Scheduler-->
<bean id="schedulerFactory"
class="org.springframework.scheduling.quartz.SchedulerFactoryBean" autowire="no">
<property name="triggers">
<list>
<ref bean="dataTrigger" />
</list>
</property>
<property name="autoStartup" value="true"/>
</bean>
<!--定时器任务配置(结束)-->
</beans>
数据库连接用的是hibnreate,连接池使用的是Druid,相关配置就不往上贴了
问题总结
1.之前没有接触过比较大数据处理,所以也是从网上找思路,选用spring-JdbcTemplate的原因是进行批量插入操作的时候比原生jdbc和hibnreate或者Mybatis的效率高些,使用的过程中也选择batchUpdate()进行批量插入,减少连接数据库的次数,避免一次只插入一条的情况,这个要感谢网上的大神们提供的思路及代码。
2.因为使用spring容器加载jdbcTemplate,所以自动执行的时候会有问题,例如jdbcTemplate还没加载到,但是自启的方法已经开始执行了,所以在获取jdbcTemplate示例的时候需要注意。
3.处理数据将list数据转换为数组使用的时候需要注意一点,因为先从数据中查出结果后封装为对象,在转换的过程中使用get方法获取对应的数据需要进行数据转换,不然原来数据如果为空的话,在之后进行数据插入的过程中就会产生异常了。
4.最后还要说下效率问题,由于本身项目使用的是jdk7,所以有所限制,实际使用jdk8的话效率会更高,还有就是由于查询出来的数据都放在list集合了,所以需要注意内存溢出的问题。在查询的时候可以使用RowCallBackHandle()效率提高的同时也可以避免一定内存溢出的风险。
暂时就这么多了,当然实际开发过程中还遇到很多问题,这些是比较需要注意的问题