精华内容
下载资源
问答
  • 2、转发机制:让沉默的大多数转发关注带来力量; 4、门户取代者; 5、品牌塑造着:经过真实的人塑造的品牌是最有生命力; 6、狗仔队最新做狗的手法; 7、最好的社交平台,扩大自己的粉丝群; 8、简单易用...
    • 1、传播平台:病毒式广播站式传播;
    • 2、转发机制:让沉默的大多数转发关注带来力量;
    • 4、门户取代者;
    • 5、品牌塑造着:经过真实的人塑造的品牌是最有生命力;
    • 6、狗仔队最新做狗的手法;
    • 7、最好的社交平台,扩大自己的粉丝群;
    • 8、简单易用:相对于强调版面布置的Blog来说,微博的内容组成只是由简单的只言片语组成;
    • 9、主动传播:还是相对于Blog来说,用户的关注属于一种“被动”的关注状态,写出来的内容其传播受众并不确定;而微博的关注则更为主动,只要轻点“follow”,即表示你愿意接受某位用户的即时更新信息;从这个角度上来说,对于商业推广、明星效应的传播更有研究价值。
             同时,对于普通人来说,微博的关注友人大多来自事实的生活圈子,用户的一言一行不但起到发泄感情,记录思想的作用,更重要的是维护了人际关系;
    • 10、微博与手机的结合:微博的主要发展运用平台应该是以手机用户为主,微博以电脑为服务器以手机为平台,把每个手机用户用无线的手机连在一起,让每个手机用户不用使用电脑就可以发表自己的最新信息,并和好友分享自己的快乐。
              微博之所以要限定140个字符,就是源于从手机发短信最多的字符就是140个(微博进入中国后普遍默认为140个汉字,随心微博333字)。可见微博从诞生之初就同手机应用密不可分,更是其在互联网形态中最大的亮点。微博对互联网的重大意义就在于建立手机和互联网应用的无缝连接,培养手机用户使用手机上网的习惯,增强手机端同互联网端的互动,从而使手机用户顺利过渡到无线互联网用户。

    如有朋友对微博营销感兴趣,不妨加我的微博进行互动交流,http://t.qq.com/daitengfei888

    转载于:https://www.cnblogs.com/daitengfei/archive/2011/03/18/1988028.html

    展开全文
  • 渲染机制包括内容: 什么是DOCTYPE及作用 浏览器渲染过程 面试经常会问:在浏览器中输入url,发生了哪些事情。其中有一部就是浏览器的渲染过程。 Reflow:重排 面试官问完了渲染机制,一般会紧接着问重排...

    这里写图片描述

    二面的内容:

    • 渲染机制

    • JS 运行机制

    • 页面性能

    • 错误监控

    本文接下来讲渲染机制。

    渲染机制包括的内容:

    • 什么是DOCTYPE及作用

    • 浏览器渲染过程

    面试经常会问:在浏览器中输入url,发生了哪些事情。其中有一部就是浏览器的渲染过程。

    • Reflow:重排

    面试官问完了渲染机制,一般会紧接着问重排Reflow,你可千万别说你没听过。

    • Repaint:重绘

    • Layout:布局

    这里的Layout指的是浏览器的Layout。

    什么是DOCTYPE及作用

    定义

    DTD(Document Type Definition):文档类型定义。

    是一系列的语法规则,用来定义XML或者(X)HTML文件类型。浏览器会使用DTD来判断文本类型,决定使用何种协议来解析,以及切换浏览器模式。(说白了就是:DTD就是告诉浏览器,我是什么文档类型,你要用什么协议来解析我)

    DOCTYPE:用来声明DTD规范。

    一个主要的用途便是文件的合法性验证。如果文件代码不合法,那么浏览器解析时便会出现一些差错。(说白了,DOCTYPE就是用来声明DTD的)

    常见的DOCTYPE声明有几种

    面试官紧接着会问,常见的 DOCTYPE 有哪些,以及 HTML5 的 DOCTYPE 怎么写。

    1、HTML 4.01 Strict:(严格的)

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">

    PS:该DTD包含所有的HTML元素和属性,但不包括展示性的和弃用的元素(比如 font、u下划线等,这些是被废弃了的)。

    2、HTML 4.01 Transitional:(传统的)

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    

    PS:该DTD包含所有的HTML元素和属性,但包括展示性的和弃用的元素(比如 font、u下划线等)。

    3、HTML 5:

    <!DOCTYPE html>

    总结:

    面试时,不会让你写出 HTML 4.01的写法,因为大家都记不住。但是要记住 HTML 5 的写法,别看它简单,知道的人还真不多。

    面试时,可以这样回答: HTML 4.01 中有两种写法,一种是严格的,一种是传统的;并且答出二者的区别。 HTML 5的写法是<!DOCTYPE html>

    浏览器的渲染过程

    浏览器的渲染过程非常复杂,但是面试只用说几句话就行了,不然太耗时间。如何快速简洁地描述清楚,是关键。

    这里先解释一下几个概念,方便大家理解:

    • DOM Tree:浏览器将HTML解析成树形的数据结构(DOM 树)。

    • CSS Rule Tree:浏览器将CSS解析成树形的数据结构。

    • Render Tree: DOM和CSSOM合并后生成Render Tree。(虽然有了Render Tree,但并不知道节点的位置,需要依靠接下来的layout)

    • layout: 有了Render Tree,浏览器已经能知道网页中有哪些节点、各个节点的CSS定义以及他们的从属关系,从而去计算出每个节点在屏幕中的位置(宽高、颜色等)。

    • painting:按照算出来的规则,通过显卡,把内容画到屏幕上。

    • display:打击看到的最终效果。

    参考链接:

    Reflow:重排

    定义

    重排 Reflow:DOM结果中的各个元素都有自己的盒子(模型),这些都需要浏览器根据各种样式来计算,并根据计算结果将元素放在它该出现的位置,这个过程称之为Reflow。

    什么时候触发 Reflow

    • 增加、删除、修改DOM节点时,会导致 Reflow 或 Repaint。

    • 移动DOM的位置,或是加个动画的时候

    • 修改CSS样式时(宽高、display 为none等,都是通过css样式来修改的)

    • 当用户Resize窗口时(移动端没有这个问题),或是滚动的时候,有可能会触发(具体要看浏览器的规则)。

    • 修改网页的默认字体时(这个影响非常严重)。

    面试总结:

    首先要答出 Reflow 定义;其次,什么时候触发,至少要答出两条。更进一步,面试官可能还会问你怎么避免reflow,这个自己去查查吧。

    Repaint:重绘

    定义

    Repaint重绘制:当各种盒子的位置、大小以及其他属性,例如颜色、字体大小等都确定下来后,浏览器便把这些元素都按照各自的特性绘制一遍,于是页面的内容出现了,这个过程称之为 Repaint。

    说白了,页面要呈现的内容,统统画在屏幕上,这就叫 Repaint。

    什么时候触发 Repaint

    • DOM改动

    • CSS改动

    其实,就是判断当前呈现的内容是否发生变化(无论这个变化是通过DOM改动还是CSS改动)。只要页面显示的内容不一样了,肯定要 Repaint。

    面试总结:

    面试官经常会问:“如何**尽量减少**Repaint的频率?”

    注意, reflow是问“怎么避免”,repaint是问“怎么减少”。Repaint是无法避免的,否则就成了静态页面了。

    答案

    (1)如果需要创建多个DOM节点,可以使用DocumentFragment创建完,然后一次性地加入document。(加一个节点,就repaint一次,不太好)

    (2)将元素的display设置为”none”,完成修改后再把display修改为原来的值。

    参考链接:如何减少浏览器repaint和reflow ?

    展开全文
  • SpringBoot中的事件机制

    千次阅读 2019-02-25 10:58:52
    文章内容 在这篇文章中聊一聊 Spring 中的扩展机制(一)中对Spring中的事件机制...在 SpringBoot 的启动过程中,会通过 SPI 机制去加载 spring.factories 下面的一些类,这里面就包括了事件相关的类。 SpringApp...

    阿里云幸运券
    在这篇文章中聊一聊 Spring 中的扩展机制(一)中对Spring中的事件机制进行了分析。那么对于 SpringBoot 来说,它在 Spring 的基础上又做了哪些拓展呢?本篇将来聊一聊 SpringBoot 中的事件。

    在 SpringBoot 的启动过程中,会通过 SPI 机制去加载 spring.factories 下面的一些类,这里面就包括了事件相关的类。

    SpringApplicationRunListener

    Run Listeners

    org.springframework.boot.SpringApplicationRunListener=
    org.springframework.boot.context.event.EventPublishingRunListener
    ApplicationListener

    Application Listeners

    org.springframework.context.ApplicationListener=
    org.springframework.boot.ClearCachesApplicationListener,
    org.springframework.boot.builder.ParentContextCloserApplicationListener,
    org.springframework.boot.context.FileEncodingApplicationListener,
    org.springframework.boot.context.config.AnsiOutputApplicationListener,
    org.springframework.boot.context.config.ConfigFileApplicationListener,
    org.springframework.boot.context.config.DelegatingApplicationListener,
    org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,
    org.springframework.boot.context.logging.LoggingApplicationListener,
    org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener
    SpringApplicationRunListener 类是 SpringBoot 中新增的类。SpringApplication 类 中使用它们来间接调用 ApplicationListener。另外还有一个新增的类是SpringApplicationRunListeners,SpringApplicationRunListeners 中包含了多个 SpringApplicationRunListener。

    SpringApplicationRunListener

    SpringApplicationRunListener 接口规定了 SpringBoot 的生命周期,在各个生命周期广播相应的事件,调用实际的 ApplicationListener 类。通过对 SpringApplicationRunListener 的分析,也可以对 SpringBoot 的整个启动过程的理解会有很大帮助。

    先来看下SpringApplicationRunListener 接口的代码:

    public interface SpringApplicationRunListener {
    //当run方法首次启动时立即调用。可用于非常早期的初始化。
    void starting();
    //在准备好环境后,但在创建ApplicationContext之前调用。
    void environmentPrepared(ConfigurableEnvironment environment);
    //在创建和准备好ApplicationContext之后,但在加载源之前调用。
    void contextPrepared(ConfigurableApplicationContext context);
    //在加载应用程序上下文后但刷新之前调用
    void contextLoaded(ConfigurableApplicationContext context);
    //上下文已刷新,应用程序已启动,但尚未调用commandlinerunner和applicationrunner。
    void started(ConfigurableApplicationContext context);
    //在运行方法完成之前立即调用,此时应用程序上下文已刷新,
    //并且所有commandlinerunner和applicationrunner都已调用。
    //2.0 才有
    void running(ConfigurableApplicationContext context);
    //在运行应用程序时发生故障时调用。2.0 才有
    void failed(ConfigurableApplicationContext context, Throwable exception);
    }
    SpringApplicationRunListeners
    上面提到,SpringApplicationRunListeners 是SpringApplicationRunListener的集合,里面包括了很多SpringApplicationRunListener实例;SpringApplication 类实际上使用的是 SpringApplicationRunListeners 类,与 SpringApplicationRunListener 生命周期相同,调用各个周期的 SpringApplicationRunListener 。然后广播相应的事件到 ApplicationListener。

    代码详见:SpringApplicationRunListeners.

    EventPublishingRunListener
    EventPublishingRunListener 类是 SpringApplicationRunListener接口的实现类 ,它具有广播事件的功能。其内部使用 ApplicationEventMulticaster在实际刷新上下文之前发布事件。下面来看下 EventPublishingRunListener 类生命周期对应的事件。

    ApplicationStartingEvent
    ApplicationStartingEvent 是 SpringBoot 启动开始的时候执行的事件,在该事件中可以获取到 SpringApplication 对象,可做一些执行前的设置,对应的调用方法是 starting()。

    ApplicationEnvironmentPreparedEvent
    ApplicationEnvironmentPreparedEvent 是SpringBoot 对应 Enviroment 已经准备完毕时执行的事件,此时上下文 context 还没有创建。在该监听中获取到 ConfigurableEnvironment 后可以对配置信息做操作,例如:修改默认的配置信息,增加额外的配置信息等。对应的生命周期方法是 environmentPrepared(environment);SpringCloud 中,引导上下文就是在这时初始化的。

    ApplicationContextInitializedEvent
    当 SpringApplication 启动并且准备好 ApplicationContext,并且在加载任何 bean 定义之前调用了 ApplicationContextInitializers 时发布的事件。对应的生命周期方法是contextPrepared()

    ApplicationPreparedEvent
    ApplicationPreparedEvent 是SpringBoot上下文 context 创建完成是发布的事件;但此时 spring 中的 bean 还没有完全加载完成。这里可以将上下文传递出去做一些额外的操作。但是在该监听器中是无法获取自定义 bean 并进行操作的。对应的生命周期方法是 contextLoaded()。

    ApplicationStartedEvent
    这个事件是在 2.0 版本才引入的;具体发布是在应用程序上下文刷新之后,调用任何 ApplicationRunner 和 CommandLineRunner 运行程序之前。
    腾讯云代金券

    ApplicationReadyEvent
    这个和 ApplicationStartedEvent 很类似,也是在应用程序上下文刷新之后之后调用,区别在于此时ApplicationRunner 和 CommandLineRunner已经完成调用了,也意味着 SpringBoot 加载已经完成。

    ApplicationFailedEvent
    SpringBoot 启动异常时执行的事件,在异常发生时,最好是添加虚拟机对应的钩子进行资源的回收与释放,能友善的处理异常信息。

    demo 及各个事件的执行顺序
    下面的各个事件对应的demo及打印出来的执行顺序。

    GlmapperApplicationStartingEventListener

    public class GlmapperApplicationStartingEventListener implements ApplicationListener {
    @Override
    public void onApplicationEvent(ApplicationStartingEvent applicationStartingEvent) {
    System.out.println(“execute ApplicationStartingEvent …”);
    }
    }
    GlmapperApplicationEnvironmentPreparedEvent

    public class GlmapperApplicationEnvironmentPreparedEvent implements ApplicationListener {
    @Override
    public void onApplicationEvent(ApplicationEnvironmentPreparedEvent applicationEnvironmentPreparedEvent) {
    System.out.println(“execute ApplicationEnvironmentPreparedEvent …”);
    }
    }
    GlmapperApplicationContextInitializedEvent

    public class GlmapperApplicationContextInitializedEvent implements ApplicationListener {
    @Override
    public void onApplicationEvent(ApplicationContextInitializedEvent applicationContextInitializedEvent) {
    System.out.println(“execute applicationContextInitializedEvent …”);
    }
    }
    GlmapperApplicationPreparedEvent

    public class GlmapperApplicationPreparedEvent implements ApplicationListener {
    @Override
    public void onApplicationEvent(ApplicationPreparedEvent applicationPreparedEvent) {
    System.out.println(“execute ApplicationPreparedEvent …”);
    }
    }
    GlmapperApplicationStartedEvent

    public class GlmapperApplicationStartedEvent implements ApplicationListener {
    @Override
    public void onApplicationEvent(ApplicationStartedEvent applicationStartedEvent) {
    System.out.println(“execute ApplicationStartedEvent …”);
    }
    }
    GlmapperApplicationReadyEvent

    public class GlmapperApplicationReadyEvent implements ApplicationListener {
    @Override
    public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) {
    System.out.println(“execute ApplicationReadyEvent …”);
    }
    }
    执行结果

    SpringBoot 中的事件体系
    这里围绕 SpringApplicationRunListener 这个类来说。在实现类 EventPublishingRunListener 中,事件发布有两种模式:

    通过 SimpleApplicationEventMulticaster 进行事件广播

    所有监听器交给相应的 Context

    所以EventPublishingRunListener 不仅负责发布事件,而且在合适的时机将 SpringApplication 所获取的监听器和应用上下文作关联。

    SimpleApplicationEventMulticaster
    SimpleApplicationEventMulticaster是 Spring 默认的事件广播器。来看下它是怎么工作的:

    @Override
    public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
    ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
    for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
    Executor executor = getTaskExecutor();
    if (executor != null) {
    executor.execute(() -> invokeListener(listener, event));
    }
    else {
    invokeListener(listener, event);
    }
    }
    }
    从上面的代码段可以看出,它是通过遍历注册的每个监听器,并启动来调用每个监听器的 onApplicationEvent 方法。

    下面再来看下 SimpleApplicationEventMulticaster 的类集成结构:

    这里的 AbstractApplicationContext 下面来聊,这个类实际上就负责了事件体系的初始化工作。
    事件体系的初始化
    事件体系的初始化对应在 SpringBoot启动过程的 refreshContext这个方法;refreshContext具体调用 AbstractApplicationContext.refresh()方法,最后调用 initApplicationEventMulticaster() 来完成事件体系的初始化,代码如下:

    用户可以为容器定义一个自定义的事件广播器,只要实现 ApplicationEventMulticaster 就可以了,Spring 会通过 反射的机制将其注册成容器的事件广播器,如果没有找到配置的外部事件广播器,Spring 就是默认使用 SimpleApplicationEventMulticaster 作为事件广播器。

    事件注册
    事件注册是在事件体系初始化完成之后做的事情,也是在 AbstractApplicationContext.refresh() 方法中进行调用的。

    这里干了三件事:
    首先注册静态指定的 listeners;这里包括我们自定义的那些监听器。

    调用 DefaultListableBeanFactory 中 getBeanNamesForType 得到自定义的 ApplicationListener bean 进行事件注册。

    广播早期的事件。

    事件广播
    事件发布伴随着 SpringBoot 启动的整个生命周期。不同阶段对应发布不同的事件,上面我们已经对各个事件进行了分析,下面就具体看下发布事件的实现:

    org.springframework.context.support.AbstractApplicationContext#publishEvent

    earlyApplicationEvents 中的事件是广播器未建立的时候保存通知信息,一旦容器建立完成,以后都是直接通知。

    广播事件最终还是通过调用 ApplicationEventMulticaster 的 multicastEvent 来实现。而 multicastEvent 也就就是事件执行的方法。

    事件执行
    上面 SimpleApplicationEventMulticaster 小节已经初步介绍了 multicastEvent 这个方法。补充一点, 如果有可用的 taskExecutor 会使用并发的模式执行事件,但是实际上 SimpleApplicationEventMulticaster 并没有提供线程池实现,默认请况下是使用同步的方式执行事件(org.springframework.core.task.SyncTaskExecutor),所以如果需要异步配置的话,需要自己去实现线程池。

    SpringBoot 启动过程中的事件阶段
    这里回到 SpringApplication的run方法,看下 SpringBoot 在启动过程中,各个事件阶段做了哪些事情。

    starting -> ApplicationStartingEvent
    这里 debug 到 starting 方法,追踪到 multicastEvent,这里 type为 ApplicationStartingEvent;对应的事件如下:

    LoggerApplicationListener:配置日志系统。使用logging.config环境变量指定的配置或者缺省配置

    BackgroundPreinitializer:尽早触发一些耗时的初始化任务,使用一个后台线程

    DelegatingApplicationListener:监听到事件后转发给环境变量context.listener.classes指定的那些事件监听器

    LiquibaseServiceLocatorApplicationListener:使用一个可以和 SpringBoot 可执行jar包配合工作的版本替换 liquibase ServiceLocator

    listeners.environmentPrepared->ApplicationEnvironmentPreparedEvent

    AnsiOutputApplicationListener:根据spring.output.ansi.enabled参数配置AnsiOutput

    ConfigFileApplicationListener:EnvironmentPostProcessor,从常见的那些约定的位置读取配置文件,比如从以下目录读取application.properties,application.yml等配置文件:

    也可以配置成从其他指定的位置读取配置文件。

    classpath:

    file:.

    classpath:config

    file:./config/

    ClasspathLoggingApplicationListener:对环境就绪事件ApplicationEnvironmentPreparedEvent/应用失败事件ApplicationFailedEvent做出响应,往日志DEBUG级别输出TCCL(thread context class loader)的 classpath。

    FileEncodingApplicationListener:如果系统文件编码和环境变量中指定的不同则终止应用启动。具体的方法是比较系统属性file.encoding和环境变量spring.mandatory-file-encoding是否相等(大小写不敏感)。

    listeners.contextPrepared->ApplicationContextInitializedEvent

    相关监听器参考上面的描述。
    listeners.contextLoaded->ApplicationPreparedEvent

    相关监听器参考上面的描述。
    refresh->ContextRefreshedEvent

    ConditionEvaluationReportLoggingListener:实际上实现的是 ApplicationContextInitializer接口,其目的是将 ConditionEvaluationReport 写入到日志,使用DEBUG级别输出。程序崩溃报告会触发一个消息输出,建议用户使用调试模式显示报告。它是在应用初始化时绑定一个ConditionEvaluationReportListener事件监听器,然后相应的事件发生时输出ConditionEvaluationReport报告。

    ClearCachesApplicationListener:应用上下文加载完成后对缓存做清除工作,响应事件ContextRefreshedEvent。

    SharedMetadataReaderFactoryContextInitializer: 向context注册了一个BeanFactoryPostProcessor:CachingMetadataReaderFactoryPostProcessor实例。

    ResourceUrlProvider:handling mappings处理

    started->ApplicationStartedEvent

    相关监听器参考上面的描述。
    running->ApplicationReadyEvent

    相关监听器参考上面的描述。
    BackgroundPreinitializer&DelegatingApplicationListener
    这两个贯穿了整个过程,这里拎出来单独解释下:

    BackgroundPreinitializer:对于一些耗时的任务使用一个后台线程尽早触发它们开始执行初始化,这是SpringBoot的缺省行为。这些初始化动作也可以叫做预初始化。可以通过设置系统属性spring.backgroundpreinitializer.ignore为true可以禁用该机制。该机制被禁用时,相应的初始化任务会发生在前台线程。

    DelegatingApplicationListener:监听应用事件,并将这些应用事件广播给环境属性context.listener.classes指定的那些监听器。

    小结
    到此,SpringBoot 中的事件相关的东西就结束了。本文从SpringApplicationRunListener这个类说起,接着介绍 SpringBoot 启动过程的事件以及事件的生命周期。最后介绍了 SpringBoot中的内置的这些 监听器在启动过程中对应的各个阶段。
    腾讯云代金券

    原文链接

    https://mp.weixin.qq.com/s/QnFK7RhhOQJI0iaqlxE-6w

    服务推荐

    展开全文
  • Spring有5种隔离级别,7种传播行为。这是面试常问的内容,也是代码中经常碰到...3.事务隔离机制都有哪些? 4.事务传播机制都有哪些? 5.查询语句需要开事务么? 6.private方法加事务注解有用么? 1、Spring的事务和数

    Spring有5种隔离级别,7种传播行为。这是面试常问的内容,也是代码中经常碰到的知识点。这些知识枯燥而且乏味,其中有些非常的绕。如果栽在这上面,就实在是太可惜了。
    在这里插入图片描述

    @Transactional(isloation=,propagation=,readOnly=,timeout=,rollbackFor=,noRollbackFor=,)
    
    • isloation的值:
      在这里插入图片描述

    • propagation的值:
      在这里插入图片描述

    在一些事务的基础上,再探讨几个容易淡忘的概念,从源码层面找原因,加深我们的理解,问题大概包括:

    1.Spring的事务和数据库的事务隔离是一个概念么?
    2.Spring是如何实现事务的?
    3.事务隔离机制都有哪些?
    4.事务传播机制都有哪些?
    5.查询语句需要开事务么?
    6.private方法加事务注解有用么?

    1、Spring的事务和数据库的事务隔离是一个概念么?

    先来第一个问题,Spring的事务隔离级别和数据的事务隔离级别,是一回事么?
    其实,数据库一般只有4种隔离机制,Spring抽象出一种default,根据数据设置来变动。
    在这里插入图片描述

    1.read uncommitted(未提交读)
    2.read committed(提交读、不可重复读)
    3.repeatable read(可重复读)
    4.serializable(可串行化)
    5.default (PlatformTransactionManager默认的隔离级别,使用的就是数据库默认的)
    

    这是因为,Spring只提供统一事务管理接口,具体实现都是由各数据库自己实现(如MySQL)。Spring会在事务开始时,根据当前环境中设置的隔离级别,调整数据库隔离级别,由此保持一致。在DataSourceUtils文件中,代码详细的输出了这个过程。

    // Apply specific isolation level, if any.
    Integer previousIsolationLevel = null;
    if (definition != null && definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
    	if (logger.isDebugEnabled()) {
    		logger.debug("Changing isolation level of JDBC Connection [" + con + "] to " +
    				definition.getIsolationLevel());
    	}
    	int currentIsolation = con.getTransactionIsolation();
    	if (currentIsolation != definition.getIsolationLevel()) {
    		previousIsolationLevel = currentIsolation;
    		con.setTransactionIsolation(definition.getIsolationLevel());
    	}
    }
    

    结论:三种情况:

    1. 如果Spring没有指定事务隔离级别,则会采用数据库默认的事务隔离级别;
    2. 当Spring指定了事务隔离级别,则会在代码里将事务隔离级别修改为指定值;
    3. 当数据库不支持这种隔离级别,效果则以数据库的为准(比如采用了MyISAM引擎)

    我们会使用如下的方式进行声明。如果不是有性能和需求问题,就不要瞎改。事务处理弄不好是会锁表的,而锁表在大并发的情况下是会死人的。

    @Transactional(isolation = Isolation.READ_UNCOMMITTED)
    

    2、Spring事务的7种传播机制

    只要写代码,代码总会存在嵌套,或者循环,造成了事务的嵌套或者循环。那么事务在这些情况下,根据配置会有不同的反应。
    在这里插入图片描述

    1. REQUIRED
      这是默认的。表示当前方法必须在一个具有事务的上下文中运行,如有客户端有事务在进行,那么被调用端将在该事务中运行,否则的话重新开启一个事务。(如果被调用端发生异常,那么调用端和被调用端事务都将回滚)
    2. REQUIRE_NEW
      表示当前方法必须运行在它自己的事务中。如果存在当前事务,在该方法执行期间,当前事务会被挂起
    3. NESTED
      如果当前方法正有一个事务在运行中,则该方法应该运行在一个嵌套事务中,被嵌套的事务可以独立于被封装的事务中进行提交或者回滚。如果封装事务存在,并且外层事务抛出异常回滚,那么内层事务必须回滚,反之,内层事务并不影响外层事务。如果封装事务不存在,则同required的一样
    4. SUPPORTS
      表示当前方法不必需要具有一个事务上下文,但是如果有一个事务的话,它也可以在这个事务中运行
    5. NOT_SUPPORTED
      表示该方法不应该在一个事务中运行。如果有一个事务正在运行,他将在运行期被挂起,直到这个事务提交或者回滚才恢复执行
    6. MANDATORY
      表示当前方法必须在一个事务中运行,如果没有事务,将抛出异常
    7. NEVER
      表示当方法务不应该在一个事务中运行,如果存在一个事务,则抛出异常
      在这里插入图片描述

    一般用得比较多的是REQUIRED , REQUIRES_NEW,用到其他的,你就要小心了,搞懂再用。
    最怕如果这俩字了,它会将事情搞的很复杂,尤其是代码量大的时候,你永远不知道你写的service会被谁用到。这就很尴尬了。
    我们会采用下面的方式进行声明。鉴于Spring的事务传播非常的绕,如果功能满足需求,那么就用默认的就好,否则会引起不必要的麻烦。

    @Transactional(propagation=Propagation.REQUIRED) 
    

    3、事务传播机制是怎么实现的?

    事务传播机制看似神奇,实际上是使用简单的ThreadLocal的机制实现的。所以,如果调用的方法是在新线程调用的,事务传播实际上是会失效的。这不同于我们以前讲到的透传,Spring并没有做这样的处理。
    所以事务传播机制,只有翻一遍源代码,才能印象深刻。仅靠文字去传播,很多东西会变得不可描述。
    在这里插入图片描述

    如图,PlatformTransactionManager只有简单的三个抽象接口,定义了包含JDBC在内的Spring所有的事务操作。
    在这里插入图片描述

    我们平常说的JDBC,只是占到其中一部分。
    实现的方式,依然是使用AOP来实现的,具体的实现类是由TransactionAspectSupport来实现的。可以看到,代码定义了一个叫做transactionInfoHolder的ThreadLocal变量,当用到它的时候,就能够确保在同一个线程下,获取的变量是一致的。

    /**
        * Holder to support the {@code currentTransactionStatus()} method,
    	* and to support communication between different cooperating advices
    	* (e.g. before and after advice) if the aspect involves more than a
    	* single method (as will be the case for around advice).
    */
    private static final ThreadLocal<TransactionInfo> transactionInfoHolder =
    		new NamedThreadLocal<>("Current aspect-driven transaction");
    

    具体的业务逻辑,是在invokeWithinTransaction中实现的。如果你继续向下跟踪的话,会找到AbstractPlatformTransactionManager类中的getTransaction方法。

    @Override
    public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
    		throws TransactionException {
    
    	// Use defaults if no transaction definition given.
    	TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());
    
    	Object transaction = doGetTransaction();
    	boolean debugEnabled = logger.isDebugEnabled();
    
    	if (isExistingTransaction(transaction)) {
    		// Existing transaction found -> check propagation behavior to find out how to behave.
    		return handleExistingTransaction(def, transaction, debugEnabled);
    	}
    
    	// Check definition settings for new transaction.
    	if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
    		throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout());
    	}
    
    	// No existing transaction found -> check propagation behavior to find out how to proceed.
    	if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
    		throw new IllegalTransactionStateException(
    				"No existing transaction found for transaction marked with propagation 'mandatory'");
    	}
    	else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
    			def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
    			def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
    		SuspendedResourcesHolder suspendedResources = suspend(null);
    		if (debugEnabled) {
    			logger.debug("Creating new transaction with name [" + def.getName() + "]: " + def);
    		}
    		try {
    			return startTransaction(def, transaction, debugEnabled, suspendedResources);
    		}
    		catch (RuntimeException | Error ex) {
    			resume(null, suspendedResources);
    			throw ex;
    		}
    	}
    	else {
    		// Create "empty" transaction: no actual transaction, but potentially synchronization.
    		if (def.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
    			logger.warn("Custom isolation level specified but no actual transaction initiated; " +
    					"isolation level will effectively be ignored: " + def);
    		}
    		boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
    		return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);
    	}
    }
    

    不用我做过多解释了吧,一切明显的逻辑,都在代码里。事务就是在这里创建的。

    4、查询方法可以不开启事务么?

    事务有个readonly,控制了事务的只读属性,和事务是否开启没半毛钱关系。
    在以前的一篇文章中,谈到通过设置readonly属性来控制语句的路由:”MySQL官方驱动“主从分离的神秘面纱(扫盲篇),这其中就用到了事务的其中一个属性readonly,它最终是体现在数据库连接层面的。

    connection.setReadOnly(true);
    

    在Spring中的使用方式如下:

    @Transactional(readOnly=true)
    

    值得注意的是,这个属性设置之后,并不是每个底层的数据库都支持。中间层的ORM或者驱动,也可能会拿这个属性做一些文章,所以与其说这个readonly是功能性的,不如说是一种暗示。
    拿MySQL来说,有两种提交模式:

    SET AUTOCOMMIT=0 禁止自动提交
    SET AUTOCOMMIT=1 开启自动提交
    

    这都是实打实的SQL语句,所以如果开启了事务,AUTOCOMMIT要为false。我们可以看到Spring做了以下几个操作。

    con.setAutoCommit(false);
    

    如果是只读事务,还不忘手动设置一下。

    if (isEnforceReadOnly() && definition.isReadOnly()) {
    	try (Statement stmt = con.createStatement()) {
    		stmt.executeUpdate("SET TRANSACTION READ ONLY");
    	}
    }
    

    这种操作是很昂贵的,如果不加Transaction注解,默认是不开启事务的。单条的查询语句也是没有必要开启事务的,数据库默认的配置就能满足需求。
    但如果你一次执行多条查询语句,例如统计查询,报表查询,在这种场景下,多条查询SQL必须保证整体的读一致性,否则,在前条SQL查询之后,后条SQL查询之前,数据被其他用户改变,就会造成数据的前后不一。也仅有在这种情况下,要开启读事务。

    5、private方法加事务注解有用么?

    @Transaction注解加在private上,并没有什么卵用。
    这倒不是事务处理的代码去写的特性。由于事务的这些功能,是通过AOP方式强加进去的,所以受收到动态代理的控制。
    privatefinal修饰的方法,不会被代理。
    但是,你却可以把private方法放在带有事务功能的public方法里。这样,它看起来也有了事务的一些功能特性,但它并没有。

    本文转自

    展开全文
  • 那么拦截器拦截MyBatis中的哪些内容呢? 概述 MyBatis 允许你在已映射语句执行过程中的某一点进行拦截调用。默认情况下,MyBatis允许使用插件来拦截的方法调用包括: Executor (update, query, flushStatements, ...
  • MYSQL MVCC 实现机制

    2017-10-10 22:57:37
    SQL标准定义了4类隔离级别,包括了一些具体规则,用来限定事务内外的哪些改变是可见的,哪些是不可见的。低级别的隔离级一般支持更高的并发处理,并拥有更低的系统开销。 Read Uncommitted(读取未提交内容)  在...
  • mysql 事务隔离机制

    2016-01-11 16:38:48
    SQL标准定义了4类隔离级别,包括了一些具体规则,用来限定事务内外的哪些改变是可见的,哪些是不可见的。低级别的隔离级一般支持更高的并发处理,并拥有更低的系统开销。本文将以具体的例子来讲解这4类隔离级别。 ...
  • Android APK安装与卸载机制

    千次阅读 2016-07-18 12:49:20
    主要内容包括以下内容: 安装和卸载APK的方法有哪些,每种方法实现的原理是什么?APK安装和卸载过程中,系统数据发生了哪些变化?Android App端常用的Package Manager使用方法简介。 注:本文是在本人阅读、、...
  • Spring内部机制内容较多,所以打算多分几个阶段来写。 本章仅探索Spring容器启动做了哪些事; 前言: 都说Spring容器就像一台构造精妙的机器,此话一点不假,我们通过配置文件向机器传达控制信息,机器就能够...
  • 文章目录 前言 一、pandas是什么? 二、使用步骤 1.... 2....提示:这里可以添加本文要记录的大概内容: 例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了...二、Handler包括哪些部分 1...
  • Mac OS X下的网络编程(socket)的机制

    千次阅读 2015-07-18 20:56:05
    对于socket的机制来说,应该都是差不多的 如果用C来写的话,我给出一个简要说明 1.1 什么是Socket?...1.2 Socket包括哪些内容? 一个特殊的通信域,比如一个网络连接 一个特殊的通信类型,比如流或者数据
  • SQL标准定义了4类隔离级别,包括了一些具体规则,用来限定事务内外的哪些改变是可见的,哪些是不可见的。低级别的隔离级一般支持更高的并发处理,并拥有更低的系统开销。 1、Read Uncommitted(读取未提交内容) ...
  • 在前面的几篇中,我们已经详细学习了Class字节码文件的结构,包含哪些内容已经内容的含义,下面几篇我们将研习一下类的加载。虚拟机的类加载机制: 虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验,...
  • SQL标准定义了4类隔离级别,包括了一些具体规则,用来限定事务内外的哪些改变是可见的,哪些是不可见的。低级别的隔离级一般支持更高的并发处理,并拥有更低的系统开销。 1.Read Uncommitted(读取未提交内容)  ...
  • 它的内容包括 告诉别人,我是谁 告诉别人,我能做什么 (有点面试的感觉了) Python 是一门动态语言,有了自省,就能让程序在运行时能够获知对象的类型以及该对象下有哪些方法等。 1. 学习 Python 模块的入口 help...
  • 浏览器输入url按回车背后经历了哪些? 1、首先,在浏览器地址栏中输入url,先解析url,检测url地址是否合法 2、浏览器先查看浏览器缓存-系统缓存-路由器缓存,如果缓存中有,会直接在屏幕中显示页面内容。若没有,...
  • JavaSE的内容包括:环境搭建、基础语法、面向对象、数组、集合、常用类、IO流、反射机制、网络编程……… 第二:MySQL数据库 搞定一门数据库相关的课程,例如:MySQL、Oracle,搞定一个就可以了,目前互联网公司,...
  • JavaSE的内容包括:环境搭建、基础语法、面向对象、数组、集合、常用类、IO流、反射机制、网络编程…….. 第二:MySQL数据库 搞定一门数据库相关的课程,例如:MySQL、Oracle,搞定一个就可以了,目前互联网公司,...
  • 刺激战场春节版都更新了哪些内容?刺激战场年兽的位置都在哪?刺激战场年兽什么时候出?自从上次圣诞模式雪地地图大更新后,今天刺激战场迎来了春节版的更新,其中大家最关心的除了新版更新内容、调整机制,就是年兽...
  • C/C++头文件中内容

    2009-03-23 21:35:00
    以下经验说明哪些可以,哪些不可以放在头文件中,不是语言要这么做,而是对#include机制使用方法的一个合理建议。 头文件一般可包括: 1 类型声明,如 enum COLOR {//...} 2 函数声明,如 extern int fn(char s)...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 382
精华内容 152
关键字:

机制包括哪些内容