Springboot+Mybatis+Maven+Oracle+Cassandra+事務(Aop)+定時任務實現

本文將通過示例介紹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

7.實例演示


四.代碼地址

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章