热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

springbootstatic关键字真能提高Bean的优先级(厉害了)

这篇文章主要介绍了springbootstatic关键字真能提高Bean的优先级(厉害了),需要的朋友可以参考下

生命太短暂,不要去做一些根本没有人想要的东西。本文已被 https://www.yourbatman.cn 收录,里面一并有Spring技术栈、MyBatis、JVM、中间件等小而美的专栏供以免费学习。关注公众号【BAT的乌托邦】逐个击破,深入掌握,拒绝浅尝辄止。

前言

各位小伙伴大家好,我是A哥。关于Spring初始化Bean的顺序问题,是个老生常谈的话题了,结论可总结为一句话:全局无序,局部有序。Spring Bean整体上是无序的,而现实是大多数情况下我们真的无需关心,无序就无序呗,无所谓喽。但是(此处应该有但是哈),我有理由相信,对于有一定从业经验的Javaer来说,或多或少都经历过Bean初始化顺序带来的“困扰”,也许是因为没有对你的功能造成影响,也许可能是你全然“不知情”,所以最终就不了了之~

隐患终归隐患,依照墨菲定律来讲,担心的事它总归是会发生的。A哥经常“教唆”程序员要面向工资编程,虽然这价值观有点扭曲,但不可否认很多小伙伴真是这么想的(命中你了没有😄),稍加粉饰了而已。话粗理不粗哦,almost所有的Javaer都在用Spring,你凭什么工资比你身边同事的高呢?

Spring对Bean的(生命周期)管理是它最为核心的能力,同时也是很复杂、很难掌握的一个知识点。现在就可以启动你的工程,有木有这句日志:

"Bean 'xxx' of type [xxxx] is not eligible for getting processed by all BeanPostProcessors"
 + "(for example: not eligible for auto-proxying)"

这是一个典型的Spring Bean过早初始化问题,搜搜看你日志里是否有此句喽。这句日志是由Spring的BeanPostProcessorChecker这个类负责输出,含义为:你的Bean xxx不能被所有的BeanPostProcessors处理到(有的生命周期触达不到),提醒你注意。此句日志在低些的版本里是warn警告级别,在本文约定的版本里官方把它改为了info级别。

绝大多数情况下,此句日志的输出不会对你的功能造成影响,因此无需搭理。这也是Spring官方为何把它从warn调低为info级别的原因

我在CSDN上写过一篇“Spring Bean过早初始化导致的误伤”的文章,访问量达近4w:

从这个数据(访问量)上来看,这件事“并不简单”,遇到此麻烦的小伙伴不在少数且确实难倒了一众人。关于Spring Bean的顺序,全局是不可控的,但是局部上它提供了多种方式来方便使用者提高/降低优先级(比如前面的使用@AutoConfigureBefore调整配置顺序竟没生效?这篇文章),本文就聊聊static关键字对于提供Bean的优先级的功效。

版本约定

本文内容若没做特殊说明,均基于以下版本:

JDK:1.8Spring Framework:5.2.2.RELEASE

正文

本文采用从 问题提出-结果分析-解决方案-原理剖析 这4个步骤,层层递进的去感受static关键字在Spring Bean上的魅力~

警告一:来自BeanPostProcessorChecker

这是最为常见的一种警告,特别当你的工程使用了shiro做鉴权框架的时候。在我记忆中这一年来有N多位小伙伴问过我此问题,可见一斑。

@Configuration
class AppConfig {

 AppConfig() {
  System.out.println("AppConfig init...");
 }

 @Bean
 BeanPostProcessor postProcessor() {
  return new MyBeanPostProcessor();
 }
}

class MyBeanPostProcessor implements BeanPostProcessor {

 MyBeanPostProcessor() {
  System.out.println("MyBeanPostProcessor init...");
 }
}

运行程序,输出结果:

AppConfig init...
2020-05-31 07:40:50.979  INFO 15740 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'appConfig'
  of type [com.yourbatman.config.AppConfig$$EnhancerBySpringCGLIB$$29b523c8] is not eligible for getting
  processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
MyBeanPostProcessor init...
...

结果分析(问题点/冲突点):

AppConfig优先于MyBeanPostProcessor进行实例化常识是:MyBeanPostProcessor作为一个后置处理器理应是先被初始化的,而AppConfig仅仅是个普通Bean而已,初始化理应靠后

出现了BeanPostProcessorChecker日志:表示AppConfig这个Bena不能被所有的BeanPostProcessors处理,所以有可能会让它“错过”容器对Bean的某些生命周期管理,因此可能损失某些能力(比如不能被自动代理),存在隐患但凡只要你工程里出现了BeanPostProcessorChecker输出日志,理应都得引起你的注意,因为这属于Spring的警告日志(虽然新版本已下调为了info级别)

说明:这是一个Info日志,并非warn/error级别。绝大多数情况下你确实无需关注,但是如果你是一个容器开发者,建议请务必解决此问题(毕竟貌似大多数中间件开发者都有一定代码洁癖😄)

解决方案:static关键字提升优先级

基于上例,我们仅需做如下小改动:

AppConfig:

//@Bean
//BeanPostProcessor postProcessor() {
// return new MyBeanPostProcessor();
//}

// 方法前面加上static关键字
@Bean
static BeanPostProcessor postProcessor() {
 return new MyBeanPostProcessor();
}

运行程序,结果输出:

MyBeanPostProcessor init...
...
AppConfig init...
...

那个烦人的BeanPostProcessorChecker日志就不见了,清爽了很多。同时亦可发现AppConfig是在MyBeanPostProcessor之后实例化的,这才符合我们所想的“正常”逻辑嘛。

警告二:Configuration配置类增强失败

这个“警告”就比上一个严重得多了,它有极大的可能导致你程序错误,并且你还很难定位问题所在。

@Configuration
class AppConfig {

 AppConfig() {
  System.out.println("AppConfig init...");
 }

 @Bean
 BeanDefinitionRegistryPostProcessor postProcessor() {
  return new MyBeanDefinitionRegistryPostProcessor();
 }

	///////////////////////////////
 @Bean
 Son son(){
  return new Son();
 }
 @Bean
 Parent parent(){
  return new Parent(son());
 }

}

class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {

 MyBeanDefinitionRegistryPostProcessor() {
  System.out.println("MyBeanDefinitionRegistryPostProcessor init...");
 }

 @Override
 public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
 }

 @Override
 public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
 }
}

运行程序,结果输出:

AppConfig init...
MyBeanDefinitionRegistryPostProcessor init...
2020-05-31 07:59:06.363  INFO 37512 --- [           main] o.s.c.a.ConfigurationClassPostProcessor  : Cannot enhance
  @Configuration bean definition 'appConfig' since its singleton instance has been created too early. The typical
  cause is a non-static @Bean method with a BeanDefinitionRegistryPostProcessor return type: Consider declaring
  such methods as 'static'.
...
son init...hashCode() = 1300528434
son init...hashCode() = 1598434875
Parent init...

结果分析(问题点/冲突点):

  1. AppConfig竟然比MyBeanDefinitionRegistryPostProcessor的初始化时机还早,这本就不合理
  2. ConfigurationClassPostProcessor 的日志中可看到:AppConfig配置类enhance增强失败
  3. Son对象竟然被创建了两个不同的实例,这将会直接导致功能性错误

这三步结果环环相扣,因为1导致了2的增强失败,因为2的增强失败导致了3的创建多个实例,真可谓一步错,步步错。需要注意的是:这里ConfigurationClassPostProcessor输出的依旧是info日志(我个人认为,Spring把这个输出调整为warn级别是更为合理的,因为它影响较大)。

说明:对这个结果的理解基于对Spring配置类的理解,因此强烈建议你进我公众号参阅那个可能是写的最全、最好的Spring配置类专栏学习(文章不多,6篇足矣)

源码处解释:

ConfigurationClassPostProcessor:

// 对Full模式的配置类尝试使用CGLIB字节码提升
public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
	...
	// 对Full模式的配置类有个判断/校验
	if (ConfigurationClassUtils.CONFIGURATION_CLASS_FULL.equals(configClassAttr)) {
		if (!(beanDef instanceof AbstractBeanDefinition)) {
			throw new BeanDefinitionStoreException("Cannot enhance @Configuration bean definition '" +
					beanName + "' since it is not stored in an AbstractBeanDefinition subclass");
		}

		// 若判断发现此时该配置类已经是个单例Bean了(说明已初始化完成)
		// 那就不再做处理,并且输出警告日志告知使用者(虽然是info日志)
		else if (logger.isInfoEnabled() && beanFactory.containsSingleton(beanName)) {
			logger.info("Cannot enhance @Configuration bean definition '" + beanName +
					"' since its singleton instance has been created too early. The typical cause " +
					"is a non-static @Bean method with a BeanDefinitionRegistryPostProcessor " +
					"return type: Consider declaring such methods as 'static'.");
		}
		configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
	}
	...
}

由于配置类增强是在BeanFactoryPostProcessor#postProcessBeanFactory()声明周期阶段去做的,而BeanDefinitionRegistryPostProcessor它会优先于该步骤完成实例化(其实主要是优先级比BeanFactoryPostProcessor高),从而间接带动 AppConfig提前初始化导致了问题,这便是根本原因所在。

提问点:本处使用了个自定义的BeanDefinitionRegistryPostProcessor模拟了效果,那如果你是使用的BeanFactoryPostProcessor能出来这个效果吗???答案是不能的,具体原因留给读者思考,可参考:PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors这段流程辅助理解。

解决方案:static关键字提升优先级

来吧,继续使用static关键字改造一下:

AppConfig:

//@Bean
//BeanDefinitionRegistryPostProcessor postProcessor() {
// return new MyBeanDefinitionRegistryPostProcessor();
//}

@Bean
static BeanDefinitionRegistryPostProcessor postProcessor() {
 return new MyBeanDefinitionRegistryPostProcessor();
}

运行程序,结果输出:

MyBeanDefinitionRegistryPostProcessor init...
...
AppConfig init...
son init...hashCode() = 2090289474
Parent init...
...

完美。

警告三:非静态@Bean方法导致@Autowired等注解失效

@Configuration
class AppConfig {

 @Autowired
 private Parent parent;
 @PostConstruct
 void init() {
  System.out.println("AppConfig.parent = " + parent);
 }


 AppConfig() {
  System.out.println("AppConfig init...");
 }

 @Bean
 BeanFactoryPostProcessor postProcessor() {
  return new MyBeanFactoryPostProcessor();
 }

 @Bean
 Son son() {
  return new Son();
 }
 @Bean
 Parent parent() {
  return new Parent(son());
 }
}

class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

 MyBeanFactoryPostProcessor() {
  System.out.println("MyBeanFactoryPostProcessor init...");
 }

 @Override
 public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

 }
}

运行程序,结果输出:

AppConfig init...
2020-05-31 08:28:06.550  INFO 1464 --- [           main] o.s.c.a.ConfigurationClassEnhancer       : @Bean method
  AppConfig.postProcessor is non-static and returns an object assignable to Spring's BeanFactoryPostProcessor
  interface. This will result in a failure to process annotations such as @Autowired, @Resource and
  @PostConstruct within the method's declaring @Configuration class. Add the 'static' modifier to
  this method to avoid these container lifecycle issues; see @Bean javadoc for complete details.
MyBeanFactoryPostProcessor init...
...
son init...hashCode() = 882706486
Parent init...

结果分析(问题点/冲突点):

  • AppConfig提前于MyBeanFactoryPostProcessor初始化
  • @Autowired/@PostConstruct等注解没有生效,这个问题很大

需要强调的是:此时的AppConfig是被enhance增强成功了的,这样才有可能进入到BeanMethodInterceptor拦截里面,才有可能输出这句日志(该拦截器会拦截Full模式配置列的所有的@Bean方法的执行)

这句日志由ConfigurationClassEnhancer.BeanMethodInterceptor输出,含义为:你的@Bean标注的方法是非static的并且返回了一个BeanFactoryPostProcessor类型的实例,这就导致了配置类里面的@Autowired, @Resource,@PostConstruct等注解都将得不到解析,这是比较危险的(所以其实这个日志调整为warn级别也是阔仪的)。

小细节:为毛日志看起来是ConfigurationClassEnhancer这个类输出的呢?这是因为BeanMethodInterceptor是它的静态内部类,和它共用的一个logger

源码处解释:

ConfigurationClassEnhancer.BeanMethodInterceptor:

	if (isCurrentlyInvokedFactoryMethod(beanMethod)) {
		if (logger.isInfoEnabled() && BeanFactoryPostProcessor.class.isAssignableFrom(beanMethod.getReturnType())) {
			logger.info(String.format("@Bean method %s.%s is non-static and returns an object " +
							"assignable to Spring's BeanFactoryPostProcessor interface. This will " +
							"result in a failure to process annotations such as @Autowired, " +
							"@Resource and @PostConstruct within the method's declaring " +
							"@Configuration class. Add the 'static' modifier to this method to avoid " +
							"these container lifecycle issues; see @Bean javadoc for complete details.",
					beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName()));
		}
		return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);
	}

解释为:如果当前正在执行的@Bean方法(铁定不是static,因为静态方法它也拦截不到嘛)返回类型是BeanFactoryPostProcessor类型,那就输出此警告日志来提醒使用者要当心。

解决方案:static关键字提升优先级

AppConfig:

//@Bean
//BeanFactoryPostProcessor postProcessor() {
// return new MyBeanFactoryPostProcessor();
//}

@Bean
static BeanFactoryPostProcessor postProcessor() {
 return new MyBeanFactoryPostProcessor();
}

运行程序,结果输出:

MyBeanFactoryPostProcessor init...
AppConfig init...
son init...hashCode() = 1906549136
Parent init...
// @PostConstruct注解生效喽
AppConfig.parent = com.yourbatman.bean.Parent@baf1bb3
...

世界一下子又清爽了有木有。

原因总结

以上三个case是有共同点的,粗略的讲导致它们的原因甚至是同一个:AppConfig这个Bean被过早初始化。然而我们的解决方案似乎也是同一个:使用static提升Bean的优先级。

那么为何AppConfig会被提前初始化呢?为何使用static关键字就没有问题了呢?根本原因可提前剧透:static静态方法属于类,执行静态方法时并不需要初始化所在类的实例;而实例方法属于实例,执行它时必须先初始化所在类的实例。听起来是不是非常的简单,JavaSE的东西嘛,当然只知晓到这个层次肯定是远远不够的,限于篇幅原因,关于Spring是如何处理的源码级别的分析我放在了下篇文章,请别走开哟~

static静态方法一定优先执行吗?

看完本文,有些小伙伴就忍不住跃跃欲试了,甚至很武断的得出结论:static标注的@Bean方法优先级更高,其实这是错误的,比如你看如下示例:

@Configuration
class AppConfig2 {

 AppConfig2(){
  System.out.println("AppConfig2 init...");
 }

 @Bean
 Son son() {
  return new Son();
 }
 @Bean
 Daughter daughter() {
  return new Daughter();
 }
 @Bean
 Parent Parent() {
  return new Parent();
 }
}

运行程序,结果输出:

AppConfig2 init...
son init...
Daughter init...
Parent init...

这时候你想让Parent在Son之前初始化,因此你想着在用static关键字来提升优先级,这么做:

AppConfig2:

//@Bean
//Parent Parent() {
// return new Parent();
//}
@Bean
static Parent Parent() {
 return new Parent();
}

结果:你徒劳了,static貌似并没有生效,怎么回事?

原因浅析

为了满足你的好奇心,这里给个浅析,道出关键因素。我们知道@Bean方法(不管是静态方法还是实例方法)最终都会被封装进ConfigurationClass实例里面,使用Set beanMethods存储着,关键点在于它是个LinkedHashSet所以是有序的(存放顺序),而存入的顺序底层是由clazz.getDeclaredMethods()来决定的,由此可知@Bean方法执行顺序和有无static没有半毛钱关系。

说明:clazz.getDeclaredMethods()得到的是Method[]数组,是有序的。这个顺序由字节码(定义顺序)来保证:先定义,先服务。

由此可见,static并不是真正意义上的提高Bean优先级,对于如上你的需求case,你可以使用@DependsOn注解来保证,它也是和Bean顺序息息相关的一个注解,在本专栏后续文章中将会详细讲到。

所以关于@Bean方法的执行顺序的正确结论应该是:在同一配置类内,在无其它“干扰”情况下(无@DependsOn、@Lazy等注解),@Bean方法的执行顺序遵从的是定义顺序(后置处理器类型除外)。

小提问:如果是垮@Configuration配置类的情况,顺序如何界定呢?那么这就不是同一层级的问题了,首先考虑的应该是@Configuration配置类的顺序问题,前面有文章提到过配置类是支持有限的的@Order注解排序的,具体分析请依旧保持关注A哥后续文章详解哈...

static关键字使用注意事项

在同一个@Configuration配置类内,对static关键字的使用做出如下说明,供以参考:

对于普通类型(非后置处理器类型)的@Bean方法,使用static关键字并不能改变顺序(按照方法定义顺序执行),所以别指望它static关键字一般有且仅用于@Bean方法返回为BeanPostProcessorBeanFactoryPostProcessor等类型的方法,并且建议此种方法请务必使用static修饰,否则容易导致隐患,埋雷

static关键字不要滥用(其实任何关键字皆勿乱用),在同一配置类内,与其说它是提升了Bean的优先级,倒不如说它让@Bean方法静态化从而不再需要依赖所在类的实例即可独立运行。另外我们知道,static关键还可以修饰(内部)类,那么如果放在类上它又是什么表现呢?同样的,你先思考,下篇文章我们接着聊~

说明:使用static修饰Class类在Spring Boot自动配置类里特别特别常见,所以掌握起来很具价值

思考题:

今天的思考题比较简单:为何文首三种case的警告信息都是info级别呢?是否有级别过低之嫌?

总结

本文还是蛮干的哈,不出意外它能够帮你解决你工程中的某些问题,排除掉一些隐患,毕竟墨菲定律被验证了你担心的事它总会发生,防患于未然才能把自己置于安全高地嘛。

你可能诧异,A哥竟能把static关键字在Spring中的应用都能写出个专栏出来,是的,这不是就是本公众号的定位么 ,小而美和拒绝浅尝辄止嘛。对于一些知识(比如本文的static关键字的使用)我并不推崇强行记忆,因为那真的很容易忘,快速使用可以简单记记,但真想记得牢(甚至成为永久记忆),那必须得去深水区看看。来吧,下文将授之以渔~

很多小伙伴去强行记忆Spring Boot支持的那17种外部化配置,此时你应该问自己:现在你可能记得,一周以后呢?一个月以后呢?所以你需要另辟蹊径,那就持续关注我吧😄

到此这篇关于springboot static关键字真能提高Bean的优先级(厉害了)的文章就介绍到这了,更多相关spring boot static关键字内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!


推荐阅读
  • GPT-3发布,动动手指就能自动生成代码的神器来了!
    近日,OpenAI发布了最新的NLP模型GPT-3,该模型在GitHub趋势榜上名列前茅。GPT-3使用的数据集容量达到45TB,参数个数高达1750亿,训练好的模型需要700G的硬盘空间来存储。一位开发者根据GPT-3模型上线了一个名为debuid的网站,用户只需用英语描述需求,前端代码就能自动生成。这个神奇的功能让许多程序员感到惊讶。去年,OpenAI在与世界冠军OG战队的表演赛中展示了他们的强化学习模型,在限定条件下以2:0完胜人类冠军。 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • 本文详细介绍了云服务器API接口的概念和作用,以及如何使用API接口管理云上资源和开发应用程序。通过创建实例API、调整实例配置API、关闭实例API和退还实例API等功能,可以实现云服务器的创建、配置修改和销毁等操作。对于想要学习云服务器API接口的人来说,本文提供了详细的入门指南和使用方法。如果想进一步了解相关知识或阅读更多相关文章,请关注编程笔记行业资讯频道。 ... [详细]
  • 生成对抗式网络GAN及其衍生CGAN、DCGAN、WGAN、LSGAN、BEGAN介绍
    一、GAN原理介绍学习GAN的第一篇论文当然由是IanGoodfellow于2014年发表的GenerativeAdversarialNetworks(论文下载链接arxiv:[h ... [详细]
  • 如何用UE4制作2D游戏文档——计算篇
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了如何用UE4制作2D游戏文档——计算篇相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 本文介绍了2019年上半年内蒙古计算机软考考试的报名通知和考试时间。考试报名时间为3月1日至3月23日,考试时间为2019年5月25日。考试分为高级、中级和初级三个级别,涵盖了多个专业资格。报名采取网上报名和网上缴费的方式进行,报考人员可登录内蒙古人事考试信息网进行报名。详细内容请点击查看。 ... [详细]
  • Tomcat/Jetty为何选择扩展线程池而不是使用JDK原生线程池?
    本文探讨了Tomcat和Jetty选择扩展线程池而不是使用JDK原生线程池的原因。通过比较IO密集型任务和CPU密集型任务的特点,解释了为何Tomcat和Jetty需要扩展线程池来提高并发度和任务处理速度。同时,介绍了JDK原生线程池的工作流程。 ... [详细]
  • 闭包一直是Java社区中争论不断的话题,很多语言都支持闭包这个语言特性,闭包定义了一个依赖于外部环境的自由变量的函数,这个函数能够访问外部环境的变量。本文以JavaScript的一个闭包为例,介绍了闭包的定义和特性。 ... [详细]
  • Go GUIlxn/walk 学习3.菜单栏和工具栏的具体实现
    本文介绍了使用Go语言的GUI库lxn/walk实现菜单栏和工具栏的具体方法,包括消息窗口的产生、文件放置动作响应和提示框的应用。部分代码来自上一篇博客和lxn/walk官方示例。文章提供了学习GUI开发的实际案例和代码示例。 ... [详细]
  • 本文介绍了一种处理AJAX操作授权过期的全局方式,以解决Asp.net MVC中Session过期异常的问题。同时还介绍了基于WebImage的图片上传工具类。详细内容请参考链接:https://www.cnblogs.com/starluck/p/8284949.html ... [详细]
  • 如何提高PHP编程技能及推荐高级教程
    本文介绍了如何提高PHP编程技能的方法,推荐了一些高级教程。学习任何一种编程语言都需要长期的坚持和不懈的努力,本文提醒读者要有足够的耐心和时间投入。通过实践操作学习,可以更好地理解和掌握PHP语言的特异性,特别是单引号和双引号的用法。同时,本文也指出了只走马观花看整体而不深入学习的学习方式无法真正掌握这门语言,建议读者要从整体来考虑局部,培养大局观。最后,本文提醒读者完成一个像模像样的网站需要付出更多的努力和实践。 ... [详细]
  • 从高级程序员到CTO的4次能力跃迁!如何选择适合的技术负责人?
    本文讲解了从高级程序员到CTO的4次能力跃迁,以及如何选择适合的技术负责人。在初创期、发展期、成熟期的每个阶段,创业公司需要不同级别的技术负责人来实现复杂功能、解决技术难题、提高交付效率和质量。高级程序员的职责是实现复杂功能、编写核心代码、处理线上bug、解决技术难题。而技术经理则需要提高交付效率和质量。 ... [详细]
  • MySQL中的MVVC多版本并发控制机制的应用及实现
    本文介绍了MySQL中MVCC的应用及实现机制。MVCC是一种提高并发性能的技术,通过对事务内读取的内存进行处理,避免写操作堵塞读操作的并发问题。与其他数据库系统的MVCC实现机制不尽相同,MySQL的MVCC是在undolog中实现的。通过undolog可以找回数据的历史版本,提供给用户读取或在回滚时覆盖数据页上的数据。MySQL的大多数事务型存储引擎都实现了MVCC,但各自的实现机制有所不同。 ... [详细]
  • 本文讨论了微软的STL容器类是否线程安全。根据MSDN的回答,STL容器类包括vector、deque、list、queue、stack、priority_queue、valarray、map、hash_map、multimap、hash_multimap、set、hash_set、multiset、hash_multiset、basic_string和bitset。对于单个对象来说,多个线程同时读取是安全的。但如果一个线程正在写入一个对象,那么所有的读写操作都需要进行同步。 ... [详细]
  • svnWebUI:一款现代化的svn服务端管理软件
    svnWebUI是一款图形化管理服务端Subversion的配置工具,适用于非程序员使用。它解决了svn用户和权限配置繁琐且不便的问题,提供了现代化的web界面,让svn服务端管理变得轻松。演示地址:http://svn.nginxwebui.cn:6060。 ... [详细]
author-avatar
好咯午睡了_740
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有