spring JdbcTemplate实现千万级数据的处理

spring JdbcTemplate实现千万级数据的处理

公司最近有需求,需要处理一批千万级别的数据,不过是一次性的,之前没碰到过,开发的过程中遇到不少问题,这里记录一下代码,主要使用的是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()效率提高的同时也可以避免一定内存溢出的风险。
暂时就这么多了,当然实际开发过程中还遇到很多问题,这些是比较需要注意的问题

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
可以参考以下代码: // 引入相关包 import org.springframework.jdbc.core.JdbcTemplate; import javax.sql.DataSource; import java.util.List; // 定义一个类 public class UserDao { // 定义一个 JdbcTemplate 对象 private JdbcTemplate jdbcTemplate; // 构造方法,传入数据源 public UserDao(DataSource dataSource) { this.jdbcTemplate = new JdbcTemplate(dataSource); } // 查询所有用户 public List<User> findAll() { String sql = "SELECT * FROM user"; return jdbcTemplate.query(sql, new UserRowMapper()); } // 根据 ID 查询用户 public User findById(Long id) { String sql = "SELECT * FROM user WHERE id=?"; return jdbcTemplate.queryForObject(sql, new Object[]{id}, new UserRowMapper()); } // 新增用户 public void save(User user) { String sql = "INSERT INTO user(name, age) VALUES(?, ?)"; jdbcTemplate.update(sql, user.getName(), user.getAge()); } // 更新用户 public void update(User user) { String sql = "UPDATE user SET name=?, age=? WHERE id=?"; jdbcTemplate.update(sql, user.getName(), user.getAge(), user.getId()); } // 删除用户 public void delete(Long id) { String sql = "DELETE FROM user WHERE id=?"; jdbcTemplate.update(sql, id); } } // 定义一个 User 类 public class User { private Long id; private String name; private Integer age; // 省略 getter 和 setter 方法 } // 定义一个 UserRowMapper 类,用于将查询结果映射为 User 对象 public class UserRowMapper implements RowMapper<User> { @Override public User mapRow(ResultSet rs, int rowNum) throws SQLException { User user = new User(); user.setId(rs.getLong("id")); user.setName(rs.getString("name")); user.setAge(rs.getInt("age")); return user; } }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值