Spring Boot定时任务排程器(DAY13)

我: 哇~ 同学你有好多资源是怎麽来的啊?

同学: 你猜猜看,猜错的话我就要检查你大脑发育有没有正常喔~~(冷笑

我: 难道是你自己花很多时间抓的 ? ( 觉得同学怪怪的,向後退了一步

同学: No~ 我设排程让系统自己跑的。你猜错了,所以过来让我看看你发育有没有正常~!! (强拉

我: ㄚㄚㄚ,不要阿~~


在现代社会中,时间就是金钱,能够让机器自己去跑我们就坚决不自己做,像是证交所API
有一个功能是上市个股每 5 秒委托成交统计,我们总不能请一位工程师在电脑前每五秒点一次查询吧!

Spring Boot本身就有提供排程让大家去设定,以下有两个规则需要注意

  • the method should typically have a void return type (if not, the returned value will be ignored)
  • the method should not expect any parameters

1.方法皆不会回传值,有回传值也会被忽略

2.方法不会有条件参数需求

好的,这次我们要写一个排程功能是每天下午5点会对API请求一次,取得资料後会存在资料库中,
让我们先新建一个资料库表单

CREATE TABLE `daily_tranction_stock_data` (
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `CODE` varchar(45) DEFAULT NULL COMMENT '证券代号',
  `NAME` varchar(45) DEFAULT NULL COMMENT '证券名称',
  `TRADE_VOLUME` int(11) DEFAULT NULL COMMENT '成交股数',
  `TRADE_VALUE` bigint(20) DEFAULT NULL COMMENT '成交金额',
  `OPENING_PRICE` decimal(10,2) DEFAULT NULL COMMENT '开盘价',
  `HIGHEST_PRICE` decimal(10,2) DEFAULT NULL COMMENT '最高价',
  `LOWEST_PRICE` decimal(10,2) DEFAULT NULL COMMENT '最低价',
  `CHANGE_GAP` decimal(10,2) DEFAULT NULL COMMENT '涨跌价差',
  `CLOSING_PRICE` decimal(10,2) DEFAULT NULL COMMENT '收盘价',
  `TRANSACTION_COUNT` int(11) DEFAULT NULL COMMENT '成交笔数',
  `CREATE_TIME` timestamp NOT NULL DEFAULT current_timestamp() COMMENT '建立时间',
  PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=1141 DEFAULT CHARSET=utf8mb4 COMMENT='上市个股日成交资讯';

再来我们更新一下 model-DailyTranctionStockData 的属性型别

package com.stockAPI.model;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Timestamp;

import com.fasterxml.jackson.annotation.JsonProperty;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@Getter
@Setter
@ToString
public class DailyTranctionStockData {
	
	//上市个股日成交资讯

//	{
//		  "Code": "string", //证券代号
//		  "Name": "string", //证券名称
//		  "TradeVolume": "string", //成交股数
//		  "TradeValue": "string", //成交金额
//		  "OpeningPrice": "string", //开盘价
//		  "HighestPrice": "string", //最高价
//		  "LowestPrice": "string", //最低价
//		  "ClosingPrice": "string", //收盘价
//		  "Change": "string", //涨跌价差
//		  "Transaction": "string" //成交笔数
//		}
	
	private Integer id;
	private Timestamp create_time;
	
	@JsonProperty(value="Code")
	private String code;
	
	@JsonProperty(value="Name")
	private String name;
	
	@JsonProperty(value="TradeVolume")
	private Integer trade_volume;
	
	@JsonProperty(value="TradeValue")
	private BigInteger trade_value;
	
	@JsonProperty(value="OpeningPrice")
	private BigDecimal opening_price;
	
	@JsonProperty(value="HighestPrice")
	private BigDecimal highest_price;
	
	@JsonProperty(value="LowestPrice")
	private BigDecimal lowest_price;
	
	@JsonProperty(value="ClosingPrice")
	private BigDecimal closing_price;
	
	@JsonProperty(value="Change")
	private BigDecimal change_gap;
	
	@JsonProperty(value="Transaction")
	private Integer transaction_count;
	
	public DailyTranctionStockData() {
		
	}

	public DailyTranctionStockData(String code, String name, Integer trade_volume, BigInteger trade_value,
			BigDecimal opening_price, BigDecimal highest_price, BigDecimal lowest_price, BigDecimal closing_price,
			BigDecimal change_gap, Integer transaction_count) {
		super();
		this.code = code;
		this.name = name;
		this.trade_volume = trade_volume;
		this.trade_value = trade_value;
		this.opening_price = opening_price;
		this.highest_price = highest_price;
		this.lowest_price = lowest_price;
		this.closing_price = closing_price;
		this.change_gap = change_gap;
		this.transaction_count = transaction_count;
	}

}

我们在repository里面新增一个 DailyTranctionStockDataRepository 然後里面新增一个批量新增资料的功能

@Repository
public class DailyTranctionStockDataRepository {
	
	@Autowired
	JdbcTemplate jdbcTemplate;

	@Autowired
	NamedParameterJdbcTemplate namedParameterJdbcTemplate;

	public int[] batchAdd(DailyTranctionStockData[] dailyTranctionStockData_array) {
		List<DailyTranctionStockData> dailyTranctionStockData_list = new ArrayList<DailyTranctionStockData>();
		for(DailyTranctionStockData dailyTranctionStockData:dailyTranctionStockData_array) {
			dailyTranctionStockData_list.add(dailyTranctionStockData);
		}
		 String sql = " INSERT INTO stockapi.daily_tranction_stock_data ( "
				   + " CODE, NAME, TRADE_VOLUME, TRADE_VALUE, OPENING_PRICE, HIGHEST_PRICE,
				   + LOWEST_PRICE, CLOSING_PRICE, CHANGE_GAP, TRANSACTION_COUNT )"   
				   + " VALUES ( :code, :name, :trade_volume, :trade_value, :opening_price, 
				   + :highest_price, :change_gap, :transaction_count "  
				   + " :lowest_price, :closing_price, ) " ;
        SqlParameterSource[] batch =                                                                     SqlParameterSourceUtils.createBatch(dailyTranctionStockData_list.toArray());
		int[] updateCounts = namedParameterJdbcTemplate.batchUpdate(sql, batch);
		return updateCounts;
		
	}
}

然後在TWSIOpenService新增一个功能

package com.stockAPI.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.stockAPI.enumsave.TWSIOpenAPIUrl;
import com.stockAPI.model.DailyTranctionStockData;
import com.stockAPI.repository.DailyTranctionStockDataRepository;
import com.stockAPI.util.TWSIOpenAPIUtil;

@Service
public class TWSIOpenService {
	
	@Autowired
	DailyTranctionStockDataRepository dailyTranctionStockDataRepository;
	
	public DailyTranctionStockData[] getDailyTranctionStockData(){
		DailyTranctionStockData[] resultList =
		TWSIOpenAPIUtil.send(
				TWSIOpenAPIUrl.EXCHANGE_REPORT_STOCK_DAY_ALL.getUrl(),
				TWSIOpenAPIUrl.EXCHANGE_REPORT_STOCK_DAY_ALL.getMethod(),
				DailyTranctionStockData[].class);
		return	resultList;
	}
	
//新增transaction注解可以防止出错时资料还继续写到资料库内
	@Transactional(rollbackFor = Exception.class)
	public void schedule_AddDailyTranctionStockData() {
		DailyTranctionStockData[] dailyTranctionStockData_array = getDailyTranctionStockData();
		dailyTranctionStockDataRepository.batchAdd(dailyTranctionStockData_array);
	}

}

新增一个package -schedule ,然後新建一个DailySchedule类别

package com.stockAPI.schedule;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import com.stockAPI.service.TWSIOpenService;

@Component
public class DailySchedule {
	
	 private final Logger logger = LoggerFactory.getLogger(this.getClass());
	 
	 @Autowired
	 TWSIOpenService tWSIOpenService;
	 
	 //上市个股日成交资讯-存入 下午五点写入
	 @Scheduled(cron = "0 0 17 * * ?") 
	 public void saveDailyTranctionStockData() {
		 tWSIOpenService.schedule_AddDailyTranctionStockData();
		 logger.info("上市个股日成交资讯-存入 下午五点写入");
	 }
}

一个cron表示式有至少6个(也可能7个)有空格分隔的时间元素。

按顺序依次为

  • 秒(0~59)
  • 分钟(0~59)
  • 小时(0~23)  
  • 天(月)(0~31,但是你需要考虑你月的天数)
  • 月(0~11)  
  • 星期(1~7 1=SUN 或 SUN,MON,TUE,WED,THU,FRI,SAT)
  • "*" 字元代表所有可能的值
  • "?" 使用在月&天两处,表示不指定值

这样我们的写入排程就完成罗!!


<<:  Day15_附录A.控制项(A.12运作安全)

>>:  [Day28] BERT(一)

16. 从Code review体现公司文化

前言 这篇有两个主题:公司文化与code review,而讲者特别强调的是要如何将这两件事情中间做...

Day1 写程序的前置工作!

安装环境第一步骤 App Store 搜寻Xcode并下载 下载後并创立一个专案 进入後系统帮我们预...

django新手村4 -----templates

再来说说templates 先修改在noob1 中的setting.py,找到TEMPLATES,修...

Day7-在认识 useMemo 前,先认识 React.memo

今天介绍的是避免重新渲染的 HOC(Higher Order Component) React.me...

android studio 30天学习笔记-day 21 -获得日期

一般在使用资料库新增资料的时候,都会看到新建资料的日期跟时间,今天会再sqllite上加入日期。 我...