本文將通過示例介紹Springboot,mybatis,maven,oracle,cassandra,事務,定時任務等框架的集成,因此業務不會複雜,供學習使用。
一.基礎知識
1. Springboot
Spring Boot是由Pivotal團隊提供的全新框架,其設計目的是用來簡化新Spring應用的初始搭建以及開發過程。該框架使用了特定的方式來進行配置,從而使開發人員不再需要定義樣板化的配置。通過這種方式,Spring
Boot致力於在蓬勃發展的快速應用開發領域(rapid application development)成爲領導者。
Springboot特點:
1). 創建獨立的Spring應用程序
2). 嵌入的Tomcat,無需部署WAR文件
3). 簡化Maven配置
4). 自動配置Spring
5). 提供生產就緒型功能,如指標,健康檢查和外部配置
6). 絕對沒有代碼生成和對XML沒有要求配置
2. Mybatis
MyBatis 本是apache的一個開源項目iBatis,
2010年這個項目由apache software foundation 遷移到了google code,並且改名爲MyBatis 。2013年11月遷移到Github。
iBATIS一詞來源於“internet”和“abatis”的組合,是一個基於Java的持久層框架。iBATIS提供的持久層框架包括SQL
Maps和Data Access Objects(DAO)
mybatis特點:
1). MyBatis 是支持定製化 SQL、存儲過程以及高級映射的優秀的持久層框架。
2). MyBatis 避免了幾乎所有的 JDBC 代碼和手動設置參數以及獲取結果集。
3). MyBatis 可以對配置和原生Map使用簡單的 XML 或註解,將接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java對象)映射成數據庫中的記錄。
3. Cassandra
Cassandra 的名稱來源於希臘神話,是特洛伊的一位悲劇性的女先知的名字,因此項目的Logo是一隻放光的眼睛。
Cassandra是一個高可靠的大規模分佈式存儲系統。高度可伸縮的、一致的、分佈式的結構化key-value存儲方案,集Google BigTable的數據模型與Amazon Dynamo的完全分佈式的架構於一身。2007由facebook開發,2009年成爲Apache的孵化項目。
Cassandra使用了Google BigTable的數據模型,與面向行的傳統的關係型數據庫不同,這是一種面向列的數據庫,列被組織成爲列族(Column Family),在數據庫中增加一列非常方便。對於搜索和一般的結構化數據存儲,這個結構足夠豐富和有效。
Cassandra的系統架構與Dynamo一脈相承,是基於O(1)DHT(分佈式哈希表)的完全P2P架構,與傳統的基於Sharding的數據庫集羣相比,Cassandra可以幾乎無縫地加入或刪除節點,非常適於對於節點規模變化比較快的應用場景。
Cassandra的數據會寫入多個節點,來保證數據的可靠性,在一致性、可用性和網絡分區耐受能力(CAP)的折衷問題上,Cassandra比較靈活,用戶在讀取時可以指定要求所有副本一致(高一致性)、讀到一個副本即可(高可用性)或是通過選舉來確認多數副本一致即可(折衷)。這樣,Cassandra可以適用於有節點、網絡失效,以及多數據中心的場景。
1). 列表數據結構
在混合模式可以將超級列添加到5維的分佈式Key-Value存儲系統。
2). 模式靈活
使用Cassandra,你不必提前解決記錄中的字段。你可以在系統運行時隨意的添加或移除字段。
3). 真正的可擴展性
Cassandra是純粹意義上的水平擴展。爲給集羣添加更多容量,可以增加動態添加節點即可。你不必重啓任何進程,改變應用查詢,或手動遷移任何數據。
4). 多數據中心識別
你可以調整節點佈局來避免某一個數據中心起火,一個備用的數據中心將至少有每條記錄的完全複製。
5). 範圍查詢
如果你不喜歡全部的鍵值查詢,則可以設置鍵的範圍來查詢。
6). 分佈式寫操作
你以在任何地方任何時間集中讀或寫任何數據。並且不會有任何單點失敗。
4.Springboot集成框架
1).spring-boot-starter-data-cassandra
2).mybatis-spring-boot-starter
3).spring-boot-starter-aop
二.業務需求
定時同步cassandra數據庫數據到oracle數據庫
三.代碼示例
1. 代碼目錄
2.application.properties配置文件
# logger
logging.level.root=info
##########################mybatis#######################################
mybatis.config-locations=classpath:mybatis/mybatis-config.xml
mybatis.mapper-locations=classpath:mybatis/mapper/*.xml
##########################數據庫連接池#######################################
#單一數據源
spring.datasource.primary.url=jdbc:oracle:thin:@ip:1521/dwrac
spring.datasource.primary.username=root
spring.datasource.primary.password=root
spring.datasource.primary.driver-class-name=oracle.jdbc.driver.OracleDriver
spring.datasource.primary.min-idle=5
spring.datasource.primary.max-active= 10
spring.datasource.primary.max-idle=10
#測試連接語句
spring.datasource.primary.connection-test-query=SELECT 1 FROM DUAL
spring.datasource.primary.test-while-idle=true
spring.datasource.primary.test-on-borrow=false
##########################cassandra數據庫#######################################
spring.data.cassandra.keyspace-name=ups
#測試環境
spring.data.cassandra.contact-points=ip
spring.data.cassandra.username= casroot
spring.data.cassandra.port= 9042
spring.data.cassandra.password= root
################################定時任務信息#########################################
syncTask.cron=0 0 0/1 * * ?
注意:
1) 配置mybatis時,需要在相應路徑位置建立*.xml文件
3. oracle數據源配置
package com.lm.springboot_mybatis_oracle_cassandra.datasource;
import javax.sql.DataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
* 主數據源配置(可配多數據源)
*
* @author liangming.deng
* @date 2017年6月9日
*
*/
@Configuration
@MapperScan(basePackages = "com.lm.springboot_mybatis_oracle_cassandra.mapper", sqlSessionTemplateRef = "primarySqlSessionTemplate")
@EnableTransactionManagement
public class DataSourceConfig {
@Bean(name = "primaryDataSource")
@ConfigurationProperties(prefix = "spring.datasource.primary")
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "primarySqlSessionFactory")
public SqlSessionFactory primarySqlSessionFactory(@Qualifier("primaryDataSource") DataSource dataSource)
throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
bean.setMapperLocations(
new PathMatchingResourcePatternResolver().getResources("classpath:mybatis/mapper/*.xml"));
return bean.getObject();
}
@Bean(name = "primaryTransactionManager")
public DataSourceTransactionManager primaryTransactionManager(
@Qualifier("primaryDataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Bean(name = "primarySqlSessionTemplate")
public SqlSessionTemplate primarySqlSessionTemplate(
@Qualifier("primarySqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
注意:
1) 配置mapper自動掃描包:@MapperScan
2) 數據源name需要與properties中配置文件對應:name="primaryDataSource"
3. 事務Aop控制
package com.lm.springboot_mybatis_oracle_cassandra.datasource;
import java.util.Calendar;
import javax.sql.DataSource;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
/**
* aop事務控制
*
* @author liangming.deng
* @date 2017年6月9日
*
*/
@Aspect
@Configuration
public class TranscationAop {
private static Logger logger = LoggerFactory.getLogger(TranscationAop.class);
@Autowired
PlatformTransactionManager transactionManager;
/**
* 注入dataSource
*
* @param dataSource
* @return
*/
@Bean
public PlatformTransactionManager txManager(@Qualifier("primaryDataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
/**
* 定義事務掃描包
*/
@Pointcut("execution(* com.lm.springboot_mybatis_oracle_cassandra.service..*.*(..))")
public void service() {
}
/**
* 環繞通知 事務
*
* @param pjp
* @return
*/
@Around("service()")
public Object tran(ProceedingJoinPoint pjp) {
long startTimeLong = Calendar.getInstance().getTimeInMillis();
TransactionStatus transactionStatus = transactionManager.getTransaction(new DefaultTransactionDefinition());
String classInfo = getClassInfo(pjp);
try {
pjp.proceed();
} catch (Throwable throwable) {
logger.error(classInfo + " 異常 事務回滾 :" + throwable.getMessage());
transactionManager.rollback(transactionStatus);
return null;
}
transactionManager.commit(transactionStatus);
long endTimeLong = Calendar.getInstance().getTimeInMillis();
logger.info(classInfo + " 事務提交成功,耗時:" + (endTimeLong - startTimeLong));
return null;
}
/**
* 獲取className和method
*
* @param pjp
* @return
*/
private static String getClassInfo(ProceedingJoinPoint pjp) {
StringBuilder sBuilder = new StringBuilder();
if (null == pjp) {
return sBuilder.toString();
}
sBuilder.append(pjp.getTarget().getClass().getSimpleName()).append(" ").append(pjp.getSignature().getName());
return sBuilder.toString();
}
}
注意:
1) 注入指定的數據源
2) 環繞通知事務處理
4. cassandra獲取數據實現
package com.lm.springboot_mybatis_oracle_cassandra.dao.impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.cassandra.core.CassandraTemplate;
import org.springframework.stereotype.Repository;
import com.lm.springboot_mybatis_oracle_cassandra.dao.UpsCalendarCassandraDao;
import com.lm.springboot_mybatis_oracle_cassandra.entity.UpsCalendarEntity;
/**
* 獲取cassandra數據庫數據dao實現
* @author liangming.deng
* @date 2017年6月9日
*
*/
@Repository
public class UpsCalendarCassandraDaoImpl implements UpsCalendarCassandraDao {
@Autowired
private CassandraTemplate cassandraTemplate;
@Override
public List<UpsCalendarEntity> getAll() {
return cassandraTemplate.select(
"SELECT ID, NAME, DESCRIPTION, ORG_ID, IS_ACTIVE, CREATED, CREATEDBY, UPDATED,UPDATEDBY FROM UPS_CALENDAR",
UpsCalendarEntity.class);
}
}
注意:
1)通過CassandraTemplate實現數據獲取,具體可以查詢springboot-cassandra集成api
5.service數據業務
package com.lm.springboot_mybatis_oracle_cassandra.service.impl;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.lm.springboot_mybatis_oracle_cassandra.dao.UpsCalendarCassandraDao;
import com.lm.springboot_mybatis_oracle_cassandra.entity.UpsCalendarEntity;
import com.lm.springboot_mybatis_oracle_cassandra.mapper.UpsCalendarMapper;
import com.lm.springboot_mybatis_oracle_cassandra.service.UpsCalendarService;
@Service
public class UpsCalendarServiceImpl implements UpsCalendarService {
private static Logger logger = LoggerFactory.getLogger(UpsCalendarServiceImpl.class);
@Autowired
private UpsCalendarCassandraDao UpsCalendarCassandraDao;
@Autowired
private UpsCalendarMapper UpsCalendarMapper;
@Override
public void batchSaveCassandraToOracle() {
List<UpsCalendarEntity> UpsCalendars = null;
// 1.獲取cassandra數據
UpsCalendars = UpsCalendarCassandraDao.getAll();
// 2.刪除oracle數據
UpsCalendarMapper.delete();
// 3.批量增加oracle數據
UpsCalendarMapper.batchInsert(UpsCalendars);
logger.info("batchSaveCassandraToOracle finish");
}
@Override
public void batchSaveExceptionCassandraToOracle() {
List<UpsCalendarEntity> UpsCalendars = null;
// 1.獲取cassandra數據
UpsCalendars = UpsCalendarCassandraDao.getAll();
// 2.刪除oracle數據
UpsCalendarMapper.delete();
//手動給出異常
int j = 1 / 0;
// 3.批量增加oracle數據
UpsCalendarMapper.batchInsert(UpsCalendars);
logger.info("batchSaveCassandraToOracle finish");
}
}
注意:
batchSaveCassandraToOracle:正常邏輯
batchSaveExceptionCassandraToOracle:異常邏輯,事務回滾
6.定時任務
package com.lm.springboot_mybatis_oracle_cassandra.task;
import javax.annotation.PostConstruct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import com.lm.springboot_mybatis_oracle_cassandra.service.UpsCalendarService;
@Component
@Lazy(value = false)
public class SyncTask {
private static Logger LOGGER = LoggerFactory.getLogger(SyncTask.class);
@Autowired
private UpsCalendarService upsCalendarService;
@PostConstruct
@Scheduled(cron = "${syncTask.cron}")
public void syncCassandraToOracle() {
LOGGER.info("SyncTask syncCassandraToOracle start sync...");
upsCalendarService.batchSaveCassandraToOracle();
upsCalendarService.batchSaveExceptionCassandraToOracle();
LOGGER.info("SyncTask syncCassandraToOracle end sync...");
}
}
注意:1) 配置文件讀取定時任務cron: @Scheduled(cron = "${syncTask.cron}")
2) 啓動程序就執行定時任務:@PostConstruct