java 单机接口限流处理方案
545
2022-09-21
SpringBoot+Mybatis plus实现多数据源整合的实践
SpringBoot 版本为1.5.10.RELEASE,Mybatis plus 版本为2.1.8。
第一步:填写配置信息:
spring:
aop:
proxy-target-class: true
auto: true
datasource:
druid:
# 数据库 1
db1:
url: jdbc:mysql://localhost:3306/db1?useUnicode=true&characterEncoding=utf8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
initialSize: 5
minIdle: 5
maxActive: 20
# 数据库 2
db2:
url: jdbc:mysql://localhost:3306/db2?useUnicode=true&characterEncoding=utf8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
initialSize: 5
minIdle: 5
maxActive: 20
第二步: 数据源配置:
@Configuration
@MapperScan({"com.warm.system.mapper*"})
public class MybatisPlusConfig {
/**
* mybatis-plus分页插件
* 文档:http://mp.baomidou.com
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
//paginationInterceptor.setLocalPage(true);// 开启 PageHelper 的支持
return paginationInterceptor;
}
/**
* mybatis-plus SQL执行效率插件【生产环境可以关闭】
*/
@Bean
public PerformanceInterceptor performanceInterceptor() {
return new PerformanceInterceptor();
}
@Bean(name = "db1")
@ConfigurationProperties(prefix = "spring.datasource.druid.db1" )
public DataSource db1 () {
return DruidDataSourceBuilder.create().build();
}
@Bean(name = "db2")
@ConfigurationProperties(prefix = "spring.datasource.druid.db2" )
public DataSource db2 () {
return DruidDataSourceBuilder.create().build();
}
/**
* 动态数据源配置
* @return
*/
@Bean
@Primary
public DataSource multipleDataSource (@Qualifier("db1") DataSource db1,
@Qualifier("db2") DataSource db2 ) {
DynamicDataSource dynamicDataSource = new DynamicDataSource();
Map< Object, Object > targetDataSources = new HashMap<>();
targetDataSources.put(DBTypeEnum.db1.getValue(), db1 );
targetDataSources.put(DBTypeEnum.db2.getValue(), db2);
dynamicDataSource.setTargetDataSources(targetDataSources);
dynamicDataSource.setDefaultTargetDataSource(db1);
return dynamicDataSource;
}
@Bean("sqlSessionFactory")
public SqlSessionFactory sqlSessionFactory() throws Exception {
MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean();
sqlSessionFactory.setDataSource(multipleDataSource(db1(),db2()));
//sqlSessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:/mapper/*/*Mapper.xml"));
MybatisConfiguration configuration = new MybatisConfiguration();
//configuration.setDefaultScriptingLanguage(MybatisXMLLanguageDriver.class);
configuration.setJdbcTypeForNull(JdbcType.NULL);
configuration.setMapUnderscoreToCamelCase(true);
configuration.setCacheEnabled(false);
sqlSessionFactory.setConfiguration(configuration);
sqlSessionFactory.setPlugins(new Interceptor[]{ //PerformanceInterceptor(),OptimisticLockerInterceptor()
paginationInterceptor() //添加分页功能
});
sqlSessionFactory.setGlobalConfig(globalConfiguration());
return sqlSessionFactory.getObject();
}
@Bean
public GlobalConfiguration globalConfiguration() {
GlobalConfiguration conf = new GlobalConfiguration(new LogicSqlInjector());
conf.setLogicDeleteValue("-1");
conf.setLogicNotDeleteValue("1");
conf.setIdType(0);
conf.setMetaObjectHandler(new MyMetaObjectHandler());
conf.setDbColumnUnderline(true);
conf.setRefresh(true);
return conf;
}
}
第三步:利用AOP进行数据源的动态切换:
@Component
@Aspect
@Order(-100) //这是为了保证AOP在事务注解之前生效,Order的值越小,优先级越高
@Slf4j
public class DataSourceSwitchAspect {
@Pointcut("execution(* com.warm.system.service.db1..*.*(..))")
private void db1Aspect() {
}
@Pointcut("execution(* com.warm.system.service.db2..*.*(..))")
private void db2Aspect() {
}
@Before( "db1Aspect()" )
public void db1() {
log.info("切换到db1 数据源...");
DbContextHolder.setDbType(DBTypeEnum.db1);
}
@Before("db2Aspect()" )
public void db2 () {
log.info("切换到db2 数据源...");
DbContextHolder.setDbType(DBTypeEnum.db2);
}
}
public class DbContextHolder {
private static final ThreadLocal contextHolder = new ThreadLocal<>();
/**
* 设置数据源
* @param dbTypeEnum
*/
public static void setDbType(DBTypeEnum dbTypeEnum) {
contextHolder.set(dbTypeEnum.getValue());
}
/**
* 取得当前数据源
* @return
*/
public static String getDbType() {
return (String) contextHolder.get();
}
/**
* 清除上下文数据
*/
public static void clearDbType() {
contextHolder.remove();
}
}
public enum DBTypeEnum {
db1("db1"), db2("db2");
private String value;
DBTypeEnum(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
public class DynamicDataSource extends AbstractRoutingDataSource {
/**
* 取得当前使用哪个数据源
* @return
*/
@Override
protected Object determineCurrentLookupKey() {
return DbContextHolder.getDbType();
}
}
OK!写个单元测试来验证一下:
@SpringBootTest
@RunWith(SpringJUnit4ClassRunner.class)
public class DataTest {
@Autowired
private UserService userService;
@Autowired
private OrderService orderService;
@Test
public void test() {
userService.getUserList().stream().forEach(item -> System.out.println(item));
orderService.getOrderList().stream().forEach(item -> System.out.println(item));
}
}
如图所示,证明数据源能动态切换了。
具体项目结构和代码参考github。
踩坑记录:
直接调用Mybatis plus 的service方法AOP不会生效,即数据源不会动态切换,解决方法:在自己的service层中封装一下,调用自定义的service方法AOP即能正常生效了,如下所示:
@Service
public class UserServiceImpl extends ServiceImpl
@Override
public List
return selectList(null);
}
}
application.yml 定义的mybatis plus 配置信息不生效,如:
#MyBatis
mybatis-plus:
mapper-locations: classpath:/mapper/*/*Mapper.xml
#实体扫描,多个package用逗号或者分号分隔
typeAliasesPackage: com.jinhuatuo.edu.sys.entity
global-config:
#主键类型 0:"数据库ID自增", 1:"用户输入ID",2:"全局唯一ID (数字类型唯一ID)", 3:"全局唯一ID UUID";
id-type: 0
#字段策略 0:"忽略判断",1:"非 NULL 判断"),2:"非空判断"
field-strategy: 2
#驼峰下划线转换
db-column-underline: true
#刷新mapper 调试神器
refresh-mapper: true
#数据库大写下划线转换
#capital-mode: true
#序列接口实现类配置
#key-generator: com.baomidou.springboot.xxx
#逻辑删除配置
#logic-delete-value: 0
#logic-not-delete-value: 1
#自定义填充策略接口实现
meta-object-handler: com.jinhuatuo.edu.config.mybatis.MyMetaObjectHandler
#自定义SQL注入器
#sql-injector: com.baomidou.springboot.xxx
configuration:
map-underscore-to-camel-case: true
cache-enabled: false
解决方法: 所有这些配置在MybatisPlusConfig 类中用代码的方式进行配置,分页插件亦是如此,否则统计列表总数的数据会拿不到,参考代码即可。
在application.yml配置
logging:
level: debug
控制台也不会打印Mybatis 执行的SQL语句,解决方法:自定义日志输出方案,如在classpath下直接引入日志配置文件如logback-spring.xml即可,同时application.yml无需再配置日志信息。
logback-shttp://pring.xml配置参考:
[ %-5level] [%date{yyyy-MM-dd HH:mm:ss}] %logger{96} [%line] - %msg%n
[ %-5level] [%date{yyyy-MM-dd HH:mm:ss}] %logger{96} [%line] - %msg%n
[ %-5level] [%date{yyyy-MM-dd HH:mm:ss}] %logger{96} [%line] - %msg%n
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~