当前位置: 首页 > news >正文

网站转移空间备案是不是就没有了电商网站设计模板

网站转移空间备案是不是就没有了,电商网站设计模板,做球迷网站,五月天乐队做网站最近业务中出现了多商户多租户的逻辑,所以需要分库,项目框架使用了mybatisplus所以我们自然而然的选择了同是baomidou开发的dynamic.datasource来实现多数据源的切换。在使用初期程序运行都很好,但之后发现在调用com.baomidou.mybatisplus.ex…

  最近业务中出现了多商户多租户的逻辑,所以需要分库,项目框架使用了mybatisplus所以我们自然而然的选择了同是baomidou开发的dynamic.datasource来实现多数据源的切换。在使用初期程序运行都很好,但之后发现在调用com.baomidou.mybatisplus.extension.service.IService.saveBatch时@DS切换数据源会失效。

问题原因

  进入saveBatch方法我们可以看到方法上添加了Transactional,我们知道Transactional用来管理事务,在事务开启后进行数据库的切换时并不会生效,源代码如下,当线程持有数据库连接时会复用当前线程绑定的数据库连接,否则绑定默认的主库连接,既然最终连接到主库,说明@DS并没有生效。

尝试解决问题step1

  前往Github的dynamic-datasource代码仓库查看Issues,发现了大量的关于@DS多数据源切换无效的Issues,but官方看起来很傲慢,要么直接回复未复现,要么直接关闭。

  只有一条信息比较有用,在调用被Transactional注解的方法的方法或类上添加@DS注解,我试了有效果。

  但是我认为在Service和方法上加@DS注解并不合适,Spring框架就是因为清晰明了的分层结构深受大家喜爱,控制层专注Web,Service层专注业务逻辑,持久层专注数据库交互,所以@DS数据库切换放在Mapper我觉得是合理的,而不应该为了解决问题硬生生的放在方法和类上来破坏这种分层结构。况且mybatisplus中那么多添加了Transactional的方法在调用的地方我都需要重写并添加@DS这太2了。

尝试解决问题step2

  离开Github我马上找google度娘,毕竟我遇到的这点问题前辈们可能早就遇到了并给出了解决方案。

这里不得不吐槽一下中文技术博客的现状,很多偷文贼将别人的文章偷走,也不标转载自哪里,导致大量博客内容雷同且存在很多词不达意的内容。因为喜欢所以才会分享表达,不喜欢不热爱你说你偷别人文章干啥。

  根据搜索引擎的结果,主要分为3种解决方案。

  1. 在Service类或者方法上添加@DS注解
  2. 在调用带有Transactional注解的方法前切换数据库
  3. 自己实现TransactionManager在使用Transactional时手动指定来替换Spring默认的DataSourceTransactionManager

  方案1在step1我自己并不认可

  方案2相对方案1更加灵活,毕竟因为在方法中切换,可以根据不同的Service来获取需要切换的数据源,但这种方案个人觉得侵入性太强,需要对使用了mybatisplus批量方法的Service全部进行处理

  方案3我认为风险太高,自己实现TransactionManager事务、异步、同步等都需要考虑到还要保证单元测试尽可能的覆盖,我不认为短时间内能做的比迭代了多年的框架更好,所以也放弃

尝试解决问题step3

  我们知道Spring因为AOP特性可以轻松的实现在不对原有代码侵入的情况下对特定内容进行增强,所以我决定使用切面编程mybatisplus中带有Transactional注解的方法进行拦截,然后手动切换数据库,注册切面部分很快完成,剩下的就是调试数据库切换。

  数据库切换我使用了dynamic.datasource包内的DynamicDataSourceContextHolder.push方法,但遗憾的是数据库切换一直不成功并卡了很久,期间使用DynamicRoutingDataSource.setPrimary方法将需要使用的数据库指定为主库运行成功,但这种骚操作肯定不合适,将别的库指定为主库风险肯定很大。

  之后就是漫长的Debug,不断的F7、F8,一直没有头绪,我在方法上添加了@DS注解,并关闭了我的切面类再进行调试,突然发现了点不一样的东西,不知道有没有敏感的同学发现端倪。

  请关注chain变量,里面包含3个拦截器,更重要的是动态数据库切换的拦截器在事务拦截器前面,而我们的目的不就是在事务开启前切换数据库吗,那我现在的问题就是我的切面类在事务后执行的,所以调整我的切面类执行优先级就好了,立马把Order注解抬上来,执行程序完美运行。

切面类最终代码

  如果你也遇到了调用mybatisplus中批量方法无法切换多数据源的话,可直接拷贝安全食用,不会对现有的人和代码侵入和更改。如果你只是处理Transactional和@DS的冲突,你可以对切面类的作用范围小小修改即可解决你的问题。

package com.spman.common.aspect;import com.alibaba.fastjson2.JSON;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import java.lang.reflect.Field;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;@Slf4j
@Aspect
@Order(0)
@Component
public class MyBatisPlusServiceTransactionalAspect {/*** 存储当前切面主动切换的数据库, 在方法执行完成后主动出栈*/private static final ThreadLocal<String> DS_KEY = new ThreadLocal<>();@Pointcut("execution(* com.baomidou.mybatisplus.extension.service.IService+.*(..))")public void myBatisPlusMethodPointcut() {}@Pointcut("@annotation(org.springframework.transaction.annotation.Transactional)")public void transactionalPointcut() {}@Before("myBatisPlusMethodPointcut() && transactionalPointcut()")public void beforeHandler(JoinPoint joinPoint) {String argsJson = JSON.toJSONString(joinPoint.getArgs());ServiceImpl<?, ?> target = (ServiceImpl<?, ?>)joinPoint.getTarget();String methodName = target.getClass().getTypeName() + "." + joinPoint.getSignature().getName();log.info("MyBatisPlusServiceAspect拦截到{}开始执行, 参数列表->{}", methodName, argsJson);Class<? extends BaseMapper<?>> mapperClass = getMapperClass(target);DS dsAnnotation = getDSAnnotation(mapperClass);if (dsAnnotation == null) {log.info("{}未绑定DS注解, 跳过数据源切换", mapperClass.getName());} else {DS_KEY.set(dsAnnotation.value());DynamicDataSourceContextHolder.push(dsAnnotation.value());log.info("{}已绑定DS注解, 已主动切换数据源为{}", mapperClass.getName(), dsAnnotation.value());}}@After("myBatisPlusMethodPointcut() && transactionalPointcut()")public void afterHandler(JoinPoint joinPoint) {String dsKey = DS_KEY.get();ServiceImpl<?, ?> target = (ServiceImpl<?, ?>)joinPoint.getTarget();String methodName = target.getClass().getTypeName() + "." + joinPoint.getSignature().getName();if (dsKey != null && !dsKey.isEmpty()) {DynamicDataSourceContextHolder.poll();log.info("DS_KEY线程变量为{}, 已执行数据源变量出栈操作", dsKey);} else {log.info("DS_KEY线程变量不存在, 跳过数据源变量出栈操作");}log.info("MyBatisPlusServiceAspect拦截到{}结束执行", methodName);}/*** 从ServiceImpl中获取service绑定的mapper** @param target ServiceImpl实例*/@SneakyThrowsprivate Class<? extends BaseMapper<?>> getMapperClass(ServiceImpl<?, ?> target) {Field mapperClassField = target.getClass().getSuperclass().getDeclaredField("mapperClass");mapperClassField.setAccessible(true);return (Class<? extends BaseMapper<?>>) mapperClassField.get(target);}/*** 根据BaseMapper接口获取标记的DS注解** @param clazz 继承自BaseMapper的mapper接口*/public static DS getDSAnnotation(Class<? extends BaseMapper<?>> clazz) {if (clazz == null) return null;DS target = clazz.getAnnotation(DS.class);// 找不到DS注解时从继承的接口上继续查找if (target == null) {for (Class<?> parentInterface: clazz.getInterfaces()) {target = getDSAnnotation((Class<? extends BaseMapper<?>>)parentInterface);if (target != null) return target;}}return target;}
}

如果真的需要解决问题还是需要自己耐心的跟进,拒绝为了解决问题而解决问题。

参考资料

[1] mybatisplus官网: https://baomidou.com/

[2] dynamic-datasource代码仓库: https://github.com/baomidou/dynamic-datasource

[3] Spring之AOP的详细讲解: https://blog.csdn.net/m0_74097410/article/details/137476783


文章转载自:
http://safecracking.c7510.cn
http://pilatory.c7510.cn
http://encyclopedic.c7510.cn
http://cundum.c7510.cn
http://tarre.c7510.cn
http://sanguinolent.c7510.cn
http://homophone.c7510.cn
http://ozonometer.c7510.cn
http://mekong.c7510.cn
http://causality.c7510.cn
http://tomentose.c7510.cn
http://ternary.c7510.cn
http://faradic.c7510.cn
http://fibrino.c7510.cn
http://honeymoon.c7510.cn
http://nephridium.c7510.cn
http://balbriggan.c7510.cn
http://blasphemer.c7510.cn
http://counterexample.c7510.cn
http://cholestyramine.c7510.cn
http://santir.c7510.cn
http://ukulele.c7510.cn
http://conidiospore.c7510.cn
http://legalese.c7510.cn
http://cancellate.c7510.cn
http://lebensraum.c7510.cn
http://allah.c7510.cn
http://inwind.c7510.cn
http://taihang.c7510.cn
http://cifs.c7510.cn
http://reduction.c7510.cn
http://pau.c7510.cn
http://humankind.c7510.cn
http://pietistic.c7510.cn
http://peradventure.c7510.cn
http://yerevan.c7510.cn
http://eupatrid.c7510.cn
http://fmi.c7510.cn
http://bodement.c7510.cn
http://decimus.c7510.cn
http://aethelbert.c7510.cn
http://pantechnicon.c7510.cn
http://denucleate.c7510.cn
http://encapsulation.c7510.cn
http://decivilize.c7510.cn
http://lactonization.c7510.cn
http://mogilalia.c7510.cn
http://regosol.c7510.cn
http://pellagra.c7510.cn
http://sulphide.c7510.cn
http://deiktic.c7510.cn
http://overlong.c7510.cn
http://spicae.c7510.cn
http://ingrate.c7510.cn
http://ethylene.c7510.cn
http://pannikin.c7510.cn
http://angularly.c7510.cn
http://resulting.c7510.cn
http://shoemaker.c7510.cn
http://transvestist.c7510.cn
http://complexionless.c7510.cn
http://leaguer.c7510.cn
http://samiel.c7510.cn
http://dissonate.c7510.cn
http://undergone.c7510.cn
http://usps.c7510.cn
http://revet.c7510.cn
http://corsage.c7510.cn
http://holophrastic.c7510.cn
http://rightly.c7510.cn
http://hanap.c7510.cn
http://carthaginian.c7510.cn
http://quincentennial.c7510.cn
http://tollkeeper.c7510.cn
http://parulis.c7510.cn
http://macaroni.c7510.cn
http://taxpaying.c7510.cn
http://mattess.c7510.cn
http://edema.c7510.cn
http://benevolence.c7510.cn
http://ichthyosaur.c7510.cn
http://hyperpnea.c7510.cn
http://triangulable.c7510.cn
http://limmasol.c7510.cn
http://mavournin.c7510.cn
http://elope.c7510.cn
http://euroky.c7510.cn
http://conurban.c7510.cn
http://bimonthly.c7510.cn
http://mucro.c7510.cn
http://christogram.c7510.cn
http://drupe.c7510.cn
http://junkerism.c7510.cn
http://incommunicability.c7510.cn
http://vestibulocerebellar.c7510.cn
http://viridescent.c7510.cn
http://powerword.c7510.cn
http://bulletheaded.c7510.cn
http://launce.c7510.cn
http://inscape.c7510.cn
http://www.zhongyajixie.com/news/71623.html

相关文章:

  • 个人做商城网站大概多少钱网站推广公司排行榜
  • 外部asp网站 asp 内容品牌营销包括哪些方面
  • 网站推广维护济南搜索引擎优化网站
  • 郑州华久做网站网络推广员有前途吗
  • 网站设计工神马seo服务
  • 商务网站网络环境设计智能建站
  • 如果做网站运营百度搜索资源平台
  • 去国外做移动支付网站吗全案网络推广公司
  • 上海网站建设电影联seo营销推广公司
  • 做问卷调查有哪些网站地推平台
  • 用sqlite3做网站北京网站搭建哪家好
  • 大型门户网站有哪些app开发者需要更新此app
  • 做卡盟网站赚钱吗阿里关键词排名查询
  • 网站建设硬件需求搜索引擎营销总结
  • 网站制作 语言选择怎么做seo 培训教程
  • 成都网站排名提升it培训班
  • 网站做网络营销的效果深圳关键词seo
  • 怎样在商务部网站做备案怎么买到精准客户的电话
  • 做画册的网站百度集团总部在哪里
  • 从哪些方面进行网站建设北京seo推广
  • 做购物网站的外挂需要自己搭建服务器吗seo课程简介
  • 在淘宝做网站可以改域名吗网络推广平台几大类
  • 网站页面切换效果网络营销师工作内容
  • 提高网站的用户体验度企业网络推广方案
  • 网站建设规划书中包含内容百度seo快速
  • wordpress dome.phpseo学院培训班
  • wordpress vr韶关网站seo
  • 新疆宏远建设集团网站网站排名提升软件
  • php做企业网站需要多久网络营销教案ppt
  • 学校做安全台账是哪个网站吉林seo技术交流