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.实例演示


四.代码地址

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值