springboot学习笔记:9.springboot+mybatis+通用mapper+多数据源
请确保根据上一篇文章的源代码完成所有测试之后,再跟随本文,继续配置多数据源;
1.数据库准备
数据库表我们在springboot-mybatis数据之外,新建数据库springboot-mybatis2;
springboot-mybatis数据库中有t_class表;
springboot-mybatis2数据库中有t_teacher表;
2.配置文件增加新数据源连接配置信息:
spring.datasource2.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource2.driver-class-name=com.mysql.jdbc.Driver
spring.datasource2.url=jdbc:mysql://localhost:3306/springboot-mybatis2?useUnicode=true&characterEncoding=utf-8
spring.datasource2.username=root
spring.datasource2.password=root
3.注意第二个数据源DataSource2对应的数据表实体及mapper和service的包结构:
两套数据源对应的mapper、service包与第一个数据源是平行的
4.DruidConfig.java中增加新数据源:dataSource2(加粗部分)
package com.zjt.config; import com.alibaba.druid.filter.Filter;
import com.alibaba.druid.filter.stat.StatFilter;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import com.alibaba.druid.wall.WallConfig;
import com.alibaba.druid.wall.WallFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary; import javax.sql.DataSource;
import java.util.ArrayList;
import java.util.List; /**
* Druid配置
*
* @author zhaojiatao
*/
@Configuration
public class DruidConfig {
private Logger logger = LoggerFactory.getLogger(DruidConfig.class); @Value("${spring.datasource.url:#{null}}")
private String dbUrl;
@Value("${spring.datasource.username: #{null}}")
private String username;
@Value("${spring.datasource.password:#{null}}")
private String password;
@Value("${spring.datasource.driverClassName:#{null}}")
private String driverClassName; @Value("${spring.datasource2.url:#{null}}")
private String dbUrl2;
@Value("${spring.datasource2.username: #{null}}")
private String username2;
@Value("${spring.datasource2.password:#{null}}")
private String password2;
@Value("${spring.datasource2.driverClassName:#{null}}")
private String driverClassName2; @Value("${spring.datasource.initialSize:#{null}}")
private Integer initialSize;
@Value("${spring.datasource.minIdle:#{null}}")
private Integer minIdle;
@Value("${spring.datasource.maxActive:#{null}}")
private Integer maxActive;
@Value("${spring.datasource.maxWait:#{null}}")
private Integer maxWait;
@Value("${spring.datasource.timeBetweenEvictionRunsMillis:#{null}}")
private Integer timeBetweenEvictionRunsMillis;
@Value("${spring.datasource.minEvictableIdleTimeMillis:#{null}}")
private Integer minEvictableIdleTimeMillis;
@Value("${spring.datasource.validationQuery:#{null}}")
private String validationQuery;
@Value("${spring.datasource.testWhileIdle:#{null}}")
private Boolean testWhileIdle;
@Value("${spring.datasource.testOnBorrow:#{null}}")
private Boolean testOnBorrow;
@Value("${spring.datasource.testOnReturn:#{null}}")
private Boolean testOnReturn;
@Value("${spring.datasource.poolPreparedStatements:#{null}}")
private Boolean poolPreparedStatements;
@Value("${spring.datasource.maxPoolPreparedStatementPerConnectionSize:#{null}}")
private Integer maxPoolPreparedStatementPerConnectionSize;
@Value("${spring.datasource.filters:#{null}}")
private String filters;
@Value("{spring.datasource.connectionProperties:#{null}}")
private String connectionProperties; @Bean
@Primary
public DataSource dataSource(){
DruidDataSource datasource = new DruidDataSource(); datasource.setUrl(this.dbUrl);
datasource.setUsername(username);
datasource.setPassword(password);
datasource.setDriverClassName(driverClassName);
//configuration
if(initialSize != null) {
datasource.setInitialSize(initialSize);
}
if(minIdle != null) {
datasource.setMinIdle(minIdle);
}
if(maxActive != null) {
datasource.setMaxActive(maxActive);
}
if(maxWait != null) {
datasource.setMaxWait(maxWait);
}
if(timeBetweenEvictionRunsMillis != null) {
datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
}
if(minEvictableIdleTimeMillis != null) {
datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
}
if(validationQuery!=null) {
datasource.setValidationQuery(validationQuery);
}
if(testWhileIdle != null) {
datasource.setTestWhileIdle(testWhileIdle);
}
if(testOnBorrow != null) {
datasource.setTestOnBorrow(testOnBorrow);
}
if(testOnReturn != null) {
datasource.setTestOnReturn(testOnReturn);
}
if(poolPreparedStatements != null) {
datasource.setPoolPreparedStatements(poolPreparedStatements);
}
if(maxPoolPreparedStatementPerConnectionSize != null) {
datasource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
} if(connectionProperties != null) {
datasource.setConnectionProperties(connectionProperties);
} List<Filter> filters = new ArrayList<>();
filters.add(statFilter());
filters.add(wallFilter());
datasource.setProxyFilters(filters); return datasource;
} @Bean
public DataSource dataSource2(){
DruidDataSource datasource = new DruidDataSource(); datasource.setUrl(this.dbUrl2);
datasource.setUsername(username2);
datasource.setPassword(password2);
datasource.setDriverClassName(driverClassName2);
//configuration
if(initialSize != null) {
datasource.setInitialSize(initialSize);
}
if(minIdle != null) {
datasource.setMinIdle(minIdle);
}
if(maxActive != null) {
datasource.setMaxActive(maxActive);
}
if(maxWait != null) {
datasource.setMaxWait(maxWait);
}
if(timeBetweenEvictionRunsMillis != null) {
datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
}
if(minEvictableIdleTimeMillis != null) {
datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
}
if(validationQuery!=null) {
datasource.setValidationQuery(validationQuery);
}
if(testWhileIdle != null) {
datasource.setTestWhileIdle(testWhileIdle);
}
if(testOnBorrow != null) {
datasource.setTestOnBorrow(testOnBorrow);
}
if(testOnReturn != null) {
datasource.setTestOnReturn(testOnReturn);
}
if(poolPreparedStatements != null) {
datasource.setPoolPreparedStatements(poolPreparedStatements);
}
if(maxPoolPreparedStatementPerConnectionSize != null) {
datasource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
} if(connectionProperties != null) {
datasource.setConnectionProperties(connectionProperties);
} List<Filter> filters = new ArrayList<>();
filters.add(statFilter());
filters.add(wallFilter());
datasource.setProxyFilters(filters); return datasource;
} @Bean
public ServletRegistrationBean druidServlet() {
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*"); //控制台管理用户,加入下面2行 进入druid后台就需要登录
//servletRegistrationBean.addInitParameter("loginUsername", "admin");
//servletRegistrationBean.addInitParameter("loginPassword", "admin");
return servletRegistrationBean;
} @Bean
public FilterRegistrationBean filterRegistrationBean() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(new WebStatFilter());
filterRegistrationBean.addUrlPatterns("/*");
filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
filterRegistrationBean.addInitParameter("profileEnable", "true");
return filterRegistrationBean;
} @Bean
public StatFilter statFilter(){
StatFilter statFilter = new StatFilter();
statFilter.setLogSlowSql(true); //slowSqlMillis用来配置SQL慢的标准,执行时间超过slowSqlMillis的就是慢。
statFilter.setMergeSql(true); //SQL合并配置
statFilter.setSlowSqlMillis(1000);//slowSqlMillis的缺省值为3000,也就是3秒。
return statFilter;
} @Bean
public WallFilter wallFilter(){
WallFilter wallFilter = new WallFilter();
//允许执行多条SQL
WallConfig config = new WallConfig();
config.setMultiStatementAllow(true);
wallFilter.setConfig(config);
return wallFilter;
}
}
5.增加MybatisDatasource2Config.java配置dataSource2对应的mapper扫描包路径、sqlSessionFactory2、以及事务管理器transactionManager2
package com.zjt.config; import com.zjt.util.MyMapper;
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.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager; import javax.sql.DataSource; /**
* @author <a href="zhaojiatao"></a>
* @version 1.0, 2017/11/24
* @description
*/
@Configuration
// 精确到 mapper 目录,以便跟其他数据源隔离
@MapperScan(basePackages = "com.zjt.mapper2", markerInterface = MyMapper.class, sqlSessionFactoryRef = "sqlSessionFactory2")
public class MybatisDatasource2Config { @Autowired
@Qualifier("dataSource2")
private DataSource ds; @Bean
public SqlSessionFactory sqlSessionFactory2() throws Exception {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(ds);
//指定mapper xml目录
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
factoryBean.setMapperLocations(resolver.getResources("classpath:mapper2/*.xml"));
return factoryBean.getObject(); } @Bean
public SqlSessionTemplate sqlSessionTemplate2() throws Exception {
SqlSessionTemplate template = new SqlSessionTemplate(sqlSessionFactory2()); // 使用上面配置的Factory
return template;
} //关于事务管理器,不管是JPA还是JDBC等都实现自接口 PlatformTransactionManager
// 如果你添加的是 spring-boot-starter-jdbc 依赖,框架会默认注入 DataSourceTransactionManager 实例。
//在Spring容器中,我们手工注解@Bean 将被优先加载,框架不会重新实例化其他的 PlatformTransactionManager 实现类。
@Bean(name = "transactionManager2")
@Primary
public DataSourceTransactionManager masterTransactionManager() {
//MyBatis自动参与到spring事务管理中,无需额外配置,只要org.mybatis.spring.SqlSessionFactoryBean引用的数据源
// 与DataSourceTransactionManager引用的数据源一致即可,否则事务管理会不起作用。
return new DataSourceTransactionManager(ds);
} }
6.增加TxAdvice2Interceptor.java配置datasource2数据源对应的事务配置
package com.zjt.interceptor; import org.aspectj.lang.annotation.Aspect;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
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.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.interceptor.*; import java.util.Collections;
import java.util.HashMap;
import java.util.Map; /**
* @author <a href="zhaojiatao"></a>
* @version 1.0, 2017/11/29
* @description
* 注解声明式事务
*/
@Aspect
@Configuration
public class TxAdvice2Interceptor {
private static final int TX_METHOD_TIMEOUT = 50000;//单位秒
private static final String AOP_POINTCUT_EXPRESSION = "execution (* com.zjt.service2.*.*(..))"; @Autowired
@Qualifier("transactionManager2")
private PlatformTransactionManager transactionManager; @Bean
public TransactionInterceptor txAdvice2() {
NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
/*只读事务,不做更新操作*/
RuleBasedTransactionAttribute readOnlyTx = new RuleBasedTransactionAttribute();
readOnlyTx.setReadOnly(true);
readOnlyTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED );
/*当前存在事务就使用当前事务,当前不存在事务就创建一个新的事务*/
RuleBasedTransactionAttribute requiredTx = new RuleBasedTransactionAttribute();
requiredTx.setRollbackRules(
Collections.singletonList(new RollbackRuleAttribute(Exception.class)));
requiredTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
requiredTx.setTimeout(TX_METHOD_TIMEOUT);
Map<String, TransactionAttribute> txMap = new HashMap<>();
txMap.put("add*", requiredTx);
txMap.put("save*", requiredTx);
txMap.put("insert*", requiredTx);
txMap.put("update*", requiredTx);
txMap.put("delete*", requiredTx);
txMap.put("get*", readOnlyTx);
txMap.put("select*", readOnlyTx);
txMap.put("query*", readOnlyTx);
source.setNameMap( txMap );
TransactionInterceptor txAdvice = new TransactionInterceptor(transactionManager, source);
return txAdvice;
} @Bean
public Advisor txAdviceAdvisor2() {
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression(AOP_POINTCUT_EXPRESSION);
return new DefaultPointcutAdvisor(pointcut, txAdvice2());
}
}
7.编写TeacherController实现教师业务控制器
package com.zjt.web; import com.zjt.entity.Teacher;
import com.zjt.model.PageRusult;
import com.zjt.model.QueryTeacherList;
import com.zjt.service2.TeacherService;
import com.zjt.util.Page;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import tk.mybatis.mapper.util.StringUtil; import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map; @Controller
@RequestMapping("/teacher")
public class TeacherController { @Autowired
@Qualifier("teacherServiceImpl")
private TeacherService teacherService; @ResponseBody
@RequestMapping("/queryTeacherList")
public PageRusult selectByPages(Page<QueryTeacherList> page){
List<Teacher> teacherList=teacherService.queryTeacherList(page);
PageRusult<Teacher> pageRusult =new PageRusult<Teacher>(teacherList);
pageRusult.setCode(0);
return pageRusult;
} @ResponseBody
@RequestMapping("/saveOrUpdateTeacher")
public Map<String,Object> saveOrUpdateTeacher(Teacher teacher){
LinkedHashMap<String,Object> resultMap=new LinkedHashMap<String,Object>();
try {
return teacherService.saveOrUpdateTeacher(teacher);
}catch (Exception e){
resultMap.put("state","fail");
resultMap.put("message","操作失败");
return resultMap;
}
} @ResponseBody
@RequestMapping("/deleteTeacher")
public Map<String,Object> deleteTeacher(String id){
LinkedHashMap<String,Object> resultMap=new LinkedHashMap<String,Object>();
try {
if(StringUtil.isNotEmpty(id)){
teacherService.delete(id);
resultMap.put("state","success");
resultMap.put("message","删除班级成功");
return resultMap;
}else{
resultMap.put("state","fail");
resultMap.put("message","删除班级失败");
return resultMap;
}
}catch (Exception e){
resultMap.put("state","fail");
resultMap.put("message","操作异常,删除班级失败");
return resultMap;
}
} }
8.启动项目验证:
8.1查询验证
8.2事务验证:
在TeacherServiceImpl.java的saveOrUpdateTeacher方法的更新操作(updateNotNull(teacher))后认为添加1/0,抛出运行时异常,看看是否回滚;
在TClassServiceImpl.java的saveOrUpdateTClass方法的更新操作(updateNotNull(tclass))后认为添加1/0,抛出运行时异常,看看是否回滚;
可以验证出两个数据源的事务均回滚成功,打开druid监控也可以看到两个数据源的事务均执行了回滚:
9.项目源代码:
https://github.com/zhaojiatao/springboot-zjt-chapter09-springboot-mybatis-datasources.git
springboot学习笔记:9.springboot+mybatis+通用mapper+多数据源的更多相关文章
- springboot+mybatis+通用mapper+多数据源(转载)
1.数据库准备 数据库表我们在springboot-mybatis数据之外,新建数据库springboot-mybatis2: springboot-mybatis数据库中有t_class表: spr ...
- springboot学习笔记-5 springboot整合shiro
shiro是一个权限框架,具体的使用可以查看其官网 http://shiro.apache.org/ 它提供了很方便的权限认证和登录的功能. 而springboot作为一个开源框架,必然提供了和sh ...
- SpringBoot学习笔记(9)----SpringBoot中使用关系型数据库以及事务处理
在实际的运用开发中,跟数据库之间的交互是必不可少的,SpringBoot也提供了两种跟数据库交互的方式. 1. 使用JdbcTemplate 在SpringBoot中提供了JdbcTemplate模板 ...
- SpringBoot学习笔记(6) SpringBoot数据缓存Cache [Guava和Redis实现]
https://blog.csdn.net/a67474506/article/details/52608855 Spring定义了org.springframework.cache.CacheMan ...
- springboot学习笔记-6 springboot整合RabbitMQ
一 RabbitMQ的介绍 RabbitMQ是消息中间件的一种,消息中间件即分布式系统中完成消息的发送和接收的基础软件.这些软件有很多,包括ActiveMQ(apache公司的),RocketMQ(阿 ...
- 【转】SpringBoot学习笔记(7) SpringBoot整合Dubbo(使用yml配置)
http://blog.csdn.net/a67474506/article/details/61640548 Dubbo是什么东西我这里就不详细介绍了,自己可以去谷歌 SpringBoot整合Dub ...
- SpringBoot学习笔记(16)----SpringBoot整合Swagger2
Swagger 是一个规范和完整的框架,用于生成,描述,调用和可视化RESTful风格的web服务 http://swagger.io Springfox的前身是swagger-springmvc,是 ...
- SpringBoot学习笔记(15)----SpringBoot使用Druid
直接访问Druid官网wiki,有详细教程,地址如下: SpringBoot支持Druid地址:https://github.com/alibaba/druid/tree/master/druid-s ...
- SpringBoot学习笔记(11)-----SpringBoot中使用rabbitmq,activemq消息队列和rest服务的调用
1. activemq 首先引入依赖 pom.xml文件 <dependency> <groupId>org.springframework.boot</groupId& ...
随机推荐
- spark on yarn 安装笔记
yarn版本:hadoop2.7.0 spark版本:spark1.4.0 0.前期环境准备: jdk 1.8.0_45 hadoop2.7.0 Apache Maven 3.3.3 1.编译spar ...
- MyBatis整体架构
Mybatis整体架构 基础支持层 反射模块 Java中的反射很强大,但是还是需要封装的.MyBatis专门提供了反射模块,对元素的反射进行了封装,提供了简洁的API,对反射进行了优化,例如缓存了类的 ...
- DFS+BFS(广度优先搜索弥补深度优先搜索遍历漏洞求合格条件总数)--09--DFS+BFS--蓝桥杯剪邮票
题目描述 如下图, 有12张连在一起的12生肖的邮票.现在你要从中剪下5张来,要求必须是连着的.(仅仅连接一个角不算相连) 比如,下面两张图中,粉红色所示部分就是合格的剪取. 请你计算,一共有多少 ...
- Javascript里EQ、NE、GT、LT、GE、LE含义
EQ 就是 EQUAL等于 NE就是 NOT EQUAL不等于 GT 就是 GREATER THAN大于 LT 就是 LESS THAN小于 GE 就是 GREATER THAN OR EQUAL ...
- The 2019 China Collegiate Pro gramming Contest Harbin Site (F. Fixing Banners)
F. Fixing Banners time limit per test 1 second memory limit per test 512 megabytes input standard in ...
- ✨vue引入组件 axios和icont矢量图标
axios 在vue项目开发中,我们使用axios进行ajax请求,很多人一开始使用axios的方式,会当成vue-resoure的使用方式来用,即在主入口文件引入import VueResource ...
- POJ - 2976 Dropping tests(01分数规划---二分(最大化平均值))
题意:有n组ai和bi,要求去掉k组,使下式值最大. 分析: 1.此题是典型的01分数规划. 01分数规划:给定两个数组,a[i]表示选取i的可以得到的价值,b[i]表示选取i的代价.x[i]=1代表 ...
- Cavace 自定义View绘制
一.开发资料与实例教程1.跟囧猫学之Canvas.Matrix 倒影实例教程 http://www.eoeandroid.com/thread-158506-1-1.html 2.Gridview 控 ...
- UML-设计对象时涉及的制品有哪些?
1.SSD.系统操作.交互图--->用例实现 1).通信图 2).顺序图 将SSD中的系统操作作为领域层控制器对象的起始消息.这是关键. 2.用例--->用例实现 在整个开发过程中,业务人 ...
- Java学习十六
学习内容: 1.做毕设 2.Java异常类 3.Java包装类 1.System.exit(1):终止程序运行,终止final执行方法 2.throws抛出异常类型,throw抛出异常对象 用法:th ...