本文将通过示例介绍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.实例演示
四.代码地址
oschina:http://git.oschina.net/a123demi/springboot_mybatis_oracle_cassandra
csdn:http://download.csdn.net/detail/a123demi/9865580