Expert One-on-One J2EE Development without EJB中文版PDF下载

你的J2EE项目是否耗费了你太多的时间?它们是否难以调试?它们是否效率不彰?也许你还在使用传统的J2EE方案,然而这种主案太过复杂,而且并非真正面向对象。这里的很多问题都与EJB有关:EJB是一种复杂的技术,但它没有兑现自己曾经的承诺。 1. 站长评价 这是一本很古老的书,同时也是一本介绍Spring框架设计理念、出现缘由的书,也是一本介绍软件设计的书! 在Java开发领域,Spring框架应该说是久负盛名,而且是Java Web开发必备武器。但是,随着Spring的发展壮大, Spring涵盖的东西也越来越多:Spring Boot、Spring Cloud等等以Spring框架(Spring Framework)为基础的Spring生态系统。 所以,对于初学Spring的人而言,可能不知道从何入手。所以,推荐先阅读这本书,本书的作者也是Spring框架的发起者。他在本书中详细介绍了Spring框架的出现原因、Spring框架如何解决一系列企业级问题,如控制反转(IoC)、事务控制、远程调用等等。同时,他还详细阐述了Spring框架架构设计理念和技术抉择,对比当时流行的企业级框架EJB的种种缺陷,一一介绍了Spring框架如何采用轻量级的方式来解决企业级J2EE问题。总之,是一本深入了解Spring框架的经典著作。不论你是初学Spring,还是对Spring已经了如指掌,都可以从本书中学到很多东西。 本书的前5章都在讲述EJB相关的内容,如果不想了解EJB可以直接从第六章开始阅读。 丰富指数:☆☆☆☆ 难度指数:☆☆☆☆ 推荐指数:☆☆☆☆ 迫不及待想要阅读它了?点此立即下载本书的PDF版本(仅供可以学习研究使用,切勿用于商业用途)! 2. 内容简介 在这本实战手册中,你将看到另一种截然不同的方案:没有EJB,却可以创建质量更高的应用程序,所需的时间和成本则更低。你将学会如何充分利用各种实用的技巧和工具,包括时下流行的Spring框架和Hibernate两个开源工具。你将看到如何高效地解决企业级应用的核心问题,例如事务管理、持久化、远程调用和web设计。你将了解这种新的方案给可测试性、性能和可伸缩性带来怎样的影响,并亲身体验轻量级架构如何大幅降低项目开发所需的时间和工作量。 自从servlet、EJB、JSP等J2EE技术发布之初,本书作者Rod Johnson就一直在使用这些技术,他对于这些技术的优劣利弊了如指掌。现在,通过这本书,你将可以面对面地分享他的专家经验。 你将从本书学到…… 如何针对自己的应用程序找到 简单、 易维护的架构;在不使用EJB的情况下有效地管理事务;如何利用AOP和loC解决企业级软件开发中的常见问题;web层设计,以web层在设计良好的J2EE应用中的地位;J2EE应用中的数据访问技术,包括BC、Hibernate和O;如何利用开源产品提升生产率、减少编码量;如何从设计层面上改善性能和可伸缩性。 “传统的J2EE设计思路尤其是EJB日益让架构师和开发者们灰心丧气,我这本书正是为这些人而写的。本书将告诉读者,如何从现在开始用更清晰、更高效的方案去替代EJB,并开始迈向web应用的新时代。” 3. 作者简介 Rod Johnson,Spring框架的创始人,同时也是SpringSource的联合创始人。Spring是面向切面编程(AOP)和控制反转(IoC)的容器框架。Rod的畅销书Expert One-on-One J2EE Design and Development(2002年出版)是迄今为止J2EE领域最具影响力的书之一。 4. 目录 第1章 为什么要“j2ee without ejb” 聚光灯下的ejb j2ee还剩什么? 站在十字路口的j2ee 前行的路 主旋律 轻量级框架和容器 我们还应该使用ejb吗? 小结 第2章 目标 生产率 问题 传统j2ee方案解决生产率问题的办法 提升生产率更好的办法 oo 业务需求的重要性 经验过程的重要性 小结 第3章 各种架构 架构性构件 .业务服务层 向外部暴露业务对象 数据访问层,或eis层 j2ee架构 两种ejb架构 两种非ejb架构 j2ee架构实例 “经典的”j2ee远程ejb架构 本地ejb架构 特制的非ejb架构 “轻量级容器架构”:示例应用系统 确定是否采用应用服务器 小结 ...

2021-06-15 · 3 min · 450 words · Hank

Spring扩展原理

Spring的扩展点很多,本文讨论Spring的 BeanPostProcessor、BeanFactoryPostProcessor、ApplicationListener 和 SmartInitializingSingleton 这四个扩展的基础类或接口。 1. Bean后置处理器 bean后置处理器用于bean创建对象初始化前后进行拦截工作,因此它是spring容器扩展必不可少的组件。 1.1. BeanPostProcessor 允许自定义修改新bean实例的工厂钩子,例如,检查标记接口或用代理包装bean。 通常,通过标记接口等填充bean的后处理器将在初始化前实现后处理,而使用代理包装bean的后处理器通常在初始化后实现后处理。 注册表 ApplicationContext 可以在其bean定义中自动检测 BeanPostProcessor bean,并将这些后处理器应用于随后创建的任何bean。一个普通的bean factory允许对后处理器进行编程注册,将它们应用于通过bean工厂创建的所有bean。 顺序 在 ApplicationContext 中自动检测到的 BeanPostProcessor bean将根据 org.springframework.core.PriorityOrdered 和 org.springframework.core.ordered 语义进行排序。相反,以编程方式向 BeanFactory 注册的 BeanPostProcessor bean将按注册顺序应用;通过实现 PriorityOrdered 或 Ordered 接口表示的任何排序语义对于以编程方式注册的后处理器都将被忽略。此外,BeanPostProcessor bean不考虑 @Order 注解。 public interface BeanPostProcessor { /** * 在传入的bean属性设置之后、初始化之前调用。在任何bean初始化回调(如initializengbean的 * afterPropertiesSet或自定义init方法)之前,将此BeanPostProcessor应用于给定的新bean实例。 * bean已经填充了属性值。返回的bean实例可以是原始实例的包装器。 * 默认实现按原样返回给定的bean。 */ @Nullable default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return bean; } /** * 在传入的bean初始化完成之后调用 * 在任何bean初始化回调(如initializengbean的afterPropertiesSet或自定义init方法)之后, * 将此BeanPostProcessor应用于给定的新bean实例。bean已经填充了属性值。 * 返回的bean实例可以是原始实例的包装器。 * 对于FactoryBean,将为FactoryBean实例和由FactoryBean创建的对象(从Spring 2.0开始)调用此回调。 * 后处理器可以通过FactoryBean检查的相应bean实例来决定是应用于FactoryBean还是创建的对象, * 或者两者都应用。此回调也将在InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation * 方法触发短路后调用,与所有其他BeanPostProcessor回调不同。 默认实现按原样返回给定的bean。 */ @Nullable default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { return bean; } } ...

2020-08-12 · 4 min · 804 words · Hank

给Spring中注册Bean的几种方式

1. 使用@Bean定义单个Bean 基于 @Bean 注解导入单个Bean。这种方式跟xml中 <bean> 标签等价,可以添加外部自定义Bean,但是需要自己创建Bean实例,而且只能导入单个Bean。注解定义如下: @Bean注解定义 @Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Bean { // 自定义bean的名称 @AliasFor("name") String[] value() default {}; // 同value属性,自定义bean的名称 @AliasFor("value") String[] name() default {}; // 设置当前注入的bean是否可用于自动注入,默认是true。 // 如果设置为false,那么即使该bean注入到Spring了,在自动注入时也会找不到bean而抛出NoSuchBeanDefinitionException异常。 // 5.1版本新增 boolean autowireCandidate() default true; (1) // 自定义Bean的初始化方法名称,Spring 在Bean初始化时会调用该方法 String initMethod() default ""; // 自定义Bean的销毁方法名称,Spring在容器关闭时会调用该方法进行自定义Bean销毁工作 String destroyMethod() default AbstractBeanDefinition.INFER_METHOD; } 1 功能与 @Primary 注解相关,都用于自动注入时Bean的选择,而 @Primary 用于指定注入时存在多个Bean实例时优先用哪个,而 autowireCandidate 属性则是设置Bean是否参与自动注入,true 则参与,false 则不参与(即使有Bean实例也可能在自动注入时抛出 NoSuchBeanDefinitionException 异常) ...

2020-05-07 · 4 min · 825 words · Hank

Spring IoC容器实现原理

1. IOC容器接口设计 Spring IOC容器接口设计如下图所示: Figure 1. Spring IoC容器接口设计 IOC容器两个核心的接口为BeanFacotry 和ApplicationContext,前者提供容器管理Bean的基本功能,后者则扩展 BeanFactory,提供了容器级的强大功能,如国际化支持、资源加载、事件、应用上下文环境等。 2. BeanFactory BeanFactory ,即bean工厂,定义IOC容器的基本规范,提供管理容器Bean的基本功能,如获取bean、判断单例、原型、判断包含bean、获取bean类型和别名等。下边有三个子接口 ListableBeanFactory、HierarchicalBeanFactory、AutowireCapableBeanFactory,他们具备不同的功能。 ListableBeanFactory 扩展 BeanFacoty ,增加了列举容器中bean的功能,BeanFactory 提供查询单个Bean的方法,而 ListableBeanFactory 可以查询多个Bean,如获取 BeanDefinition 的名称、数量、按类型查询bean和bean的名称等。 HierarchicalBeanFactory 在 BeanFactory 的基础上增加了父级 BeanFactory 的功能,即 BeanFacotry 可以有层级关系了。 AutowireCapableBeanFactory 在 BeanFactory 的基础上增加自动注入相关的功能。 ConfigurableBeanFactory 这是一个配置接口,扩展 HierarchicalBeanFactory,用于给 BeanFactory 提供各种配置功能,如配置 parentBeanFactory、beanClassLoader 添加后置处理器等等。 ConfigurableListableBeanFactory 这是一个配置接口,提供了大量方法来扩展 ConfigurableBeanFactory 和 ListableBeanFactory ,大多数可列举的bean工厂都需要实现它,除了 ConfigurableBeanFactory 的配置功能外,它还具备分析和修改bean定义以及预实例化单例bean的的能力。 3. ApplicationContext BeanFactory 提供了管理bean的基础功能,而 ApplicationContext 则在其基础上有用强大的容器特性。ApplicationContext 作为应用上下文,是Spring IOC容器的核心接口,具备 BeanFactory 基础管理bean的功能,还继承了 EnvironmentCapable 、 MessageSource 、 ResourceLoader 、 ApplicationEventPublisher ,具有资源加载、国际化支持、容器事件支持、系统环境支持等能力。 ...

2020-04-08 · 3 min · 627 words · Hank

Spring Bean自动扫描原理

Spring 基于注解的Bean自动扫描是由后置处理器 ConfigurationClassPostProcessor 来实现的。 1. ConfigurationClassPostProcessor类 ConfigurationClassPostProcessor 是一个 BeanDefinitionRegistryPostProcessor 实现,它的核心功能就是在容器启动时处理Spring的Java代码配置类(被 @Configuration 注解标记)。而且该类实现了 PriorityOrdered 接口,表示它是一个高优先级的后置处理器,会首先被执行。 ConfigurationClassPostProcessor 的定义如下: public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor, PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware { // 省略代码 } 2. 注册bean定义 创建 AnnotationConfigApplicationContext 时,其构造函数如下: AnnotationConfigApplicationContext构造函数 public AnnotationConfigApplicationContext(Class<?>... componentClasses) { this(); register(componentClasses); refresh(); } 首先,会调用 this() 方法调用构造函数: public AnnotationConfigApplicationContext() { this.reader = new AnnotatedBeanDefinitionReader(this); this.scanner = new ClassPathBeanDefinitionScanner(this); } 此时会创建 AnnotatedBeanDefinitionReader 和 ClassPathBeanDefinitionScanner 对象,前者用来读取配置类(@Configuration 注解标注)所定义的Bean定义信息,而后者用来扫描*classpath*下的bean定义信息。 AnnotatedBeanDefinitionReader 内部创建实例时会执行: ...

2020-03-10 · 9 min · 1827 words · Hank

Spring IoC容器启动过程

1. 容器启动入口 一般而言,都使用 ApplicationContext 容器实现,这里使用了基于注解的 AnnotationConfigApplicationContext 实现。 要跟踪Spring的源码,可能需要结合不同的功能测试代码,以便跟踪源码时查看Spring具体的功能实现。比如:要了解Spring @ComponentScan 注解的原理,则首先需要编写一个配置类(@Configuration),然后定义组件扫描。 本文的跟踪代码的过程可能涉及多个部分的测试代码,但是容器启动的代码都类似,详细的代码见 Github。 容器启动测试代码[1] AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(ScopeConfig.class); (1) System.out.println("IOC容器创建完成..."); User user = applicationContext.getBean(User.class); User aUser = applicationContext.getBean(User.class); System.out.println(user == aUser); 1 构造一个 AnnotationConfigApplicationContext 对象。 AnnotationConfigApplicationContext 的构造函数如下: AnnotationConfigApplicationContext构造函数 public AnnotationConfigApplicationContext(Class<?>... componentClasses) { this(); register(componentClasses); refresh(); } 1.1. ApplicationContext 类实现关系 AnnotationConfigApplicationContext 扩展了 GenericApplicationContext,增加了基于java配置类的支持,而 GenericApplicationContext 内部持有一个 DefaultListableBeanFactory 实例,而且仅允许刷新一次容器: GenericApplicationContext构造函数 public GenericApplicationContext() { this.beanFactory = new DefaultListableBeanFactory(); } ...

2020-02-06 · 7 min · 1345 words · Hank

使用Spring的RestTemplate发送GET请求,并支持传递Request body参数

最近在使用Spring Boot实现微服务,都是使用RESTful风格的Api接口,服务间使用RestTemplate来进行HTTP通信,遇到这样一个需求:开发一个查询请求Api,参数使用JSON格式的字符串来提交。 1. 请求格式 希望的请求格式如下: GET /pointCard/ HTTP/1.1 Host: localhost:8100 Content-Type: application/json;charset=UTF-8 Content-Length: 114 {"iColumns":7,"iDisplayLength":10,"iDisplayStart":0,"iSortingCols":0,"sColumns":"","sEcho":1,"subjectId":"11227"} 在RESTful下,这样的设计是合理的,GET请求表示从服务器获取资源,但需要将查询参数以JSON格式来提交。但是,这违背了传统的GET请求的规范,我们都知道,GET请求只能将请求参数拼接URI后边,而不能单独传递request body参数,除非你改用POST。 2. 代码实现 我们先来编一个上述请求的API,然后进行测试。 1、编写一个API: @GetMapping(value = "/") public Response getById(@RequestBody @Valid PointCardQuery query) throws Exception { Assert.notNull(query,"查询条件不能为空!"); …… return Response.success(pointCardPurePager, "积分卡获取成功!"); } 上边的代码片段处于一个Restcontroller,要求使用GET方法,并且使用了@RequestBody注解来获取request body参数。 2、我们使用RestTemplate来测试一下: @Test public void testGetWithBody() { RestTemplate restTemplate = new RestTemplate(); String p = "{\"iColumns\":7,\"iDisplayLength\":10,\"iDisplayStart\":0,\"iSortingCols\":0,\"sColumns\":\"\",\"sEcho\":1,\"subjectId\":\"11227\"}"; String url = "http://localhost:8100/pointCard/"; HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON)); HttpEntity<String> httpEntity = new HttpEntity<>(p, headers); ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.GET, httpEntity, String.class); String body = responseEntity.getBody(); System.out.println(body); System.out.println(responseEntity.getStatusCode()); System.out.println(responseEntity.getStatusCodeValue()); System.out.println(responseEntity); } ...

2018-10-31 · 2 min · 341 words · Hank

Spring事务管理四:声明式事务

编程式事务虽然可以精确控制事务,但是事务控制代码必须侵入业务逻辑代码中,耦合度高,后期难以维护。一般而言,不需要精确控制事务,所以采用的更多的是Spring的声明式事务。 Spring声明式事务基于AOP实现,有两种事务定义方式:xml配置和注解定义,前者使用tx命名空间,后者使用@Transactional注解。 1. 事务属性 在定义事务之前,需要了解一些事务的参数,正如前边TransactionDefinition类定义的,包括传播机制、隔离级别、是否只读、事务超时等,还包括回滚规则定义等参数。 1.1. 传播机制 传播机制(propagation)定义了客户端与被调用方法之间的事务界限。简单而言,就是一个方法调用其他一个或多个方法来实现业务逻辑时,这些方法间的事务如何进行传播,这就由传播机制来决定。 Spring提供了7中传播机制,如下表所示: Table 1. 事务的7种传播机制 传播行为 说明 REQUIRED 业务方法需要在一个事务中运行。如果方法运行时,已经处在一个事务中,那么加入到该事务,否则为自己创建一个新的事务 NOT_SUPPORTED 声明方法不需要事务。如果方法没有关联到一个事务,容器不会为它开启事务。如果方法在一个事务中被调用,该事务会被挂起,在方法调用结束后,原先的事务便会恢复执行 REQUIRES_NEW 属性表明不管是否存在事务,业务方法总会为自己发起一个新的事务。如果方法已经运行在一个事务中,则原有事务会被挂起,新的事务会被创建,直到方法执行结束,新事务才算结束,原先的事务才会恢复执行 MANDATORY 该属性指定业务方法只能在一个已经存在的事务中执行,业务方法不能发起自己的事务。如果业务方法在没有事务的环境下调用,容器就会抛出异常。 SUPPORTS 这一事务属性表明,方法可以受事务控制,也可以不。如果业务方法在某个事务范围内被调用,则方法成为该事务的一部分。如果业务方法在事务范围外被调用,则方法在没有事务的环境下执行 NEVER 指定业务方法绝对不能在事务范围内执行。如果业务方法在某个事务中执行,容器会抛出异常,只有业务方法没有关联到任何事务,才能正常执行 NESTED 如果一个活动的事务存在,则运行在一个嵌套的事务中. 如果没有活动事务, 则按REQUIRED属性执行.它使用了一个单独的事务, 这个事务拥有多个可以回滚的保存点。内部事务的回滚不会对外部事务造成影响。它只对DataSourceTransactionManager事务管理器起效 注意REQUIRES_NEW和NESTED两者的区别; PROPAGATION_REQUIRES_NEW启动一个新的, 不依赖于环境的 "内部" 事务. 这个事务将被完全 commited 或 rolled back 而不依赖于外部事务, 它拥有自己的隔离范围, 自己的锁, 等等. 当内部事务开始执行时, 外部事务将被挂起, 内务事务结束时, 外部事务将继续执行. PROPAGATION_NESTED 开始一个 "嵌套的" 事务, 它是已经存在事务的一个真正的子事务. 潜套事务开始执行时, 它将取得一个 savepoint. 如果这个嵌套事务失败, 我们将回滚到此 savepoint. 潜套事务是外部事务的一部分, 只有外部事务结束后它才会被提交. ...

2018-03-08 · 2 min · 401 words · Hank

Spring事务管理三:编程式事务

前边提到,编写程序式的事务管理可以清楚的定义事务的边界,可以实现细粒度的事务控制,比如你可以通过程序代码来控制你的事务何时开始,何时结束等,它可以实现细粒度的事务控制。 1. TransactionTemplate Spring提供了TransactionTemplate对象来控制事务,它使用了一种回调机制,通过回调来修改事务状态,继承关系如下: TransactionOperations接口定义了基础的事务的执行操作execute(),该接口便于后续扩展,一般不直接使用。 在使用TransactionTemplate之前,需要声明bean: <!--JDBC事务管理器--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!--编程式事务配置--> <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate"> <property name="transactionManager" ref="transactionManager"/> </bean> TransactionTemplate使用PlatformTransactionManager的实现来管理事务,这里注入的是JDBC的事务管理器。事务控制代码如下: public void add(User user) throws Exception{ // Spring编码式事务,回调机制 transactionTemplate.execute(new TransactionCallback<Object>() { @Override public Object doInTransaction(TransactionStatus status) { try { userMapper.insertSelective(user); } catch (Exception e) { // 异常,设置为回滚 status.setRollbackOnly(); throw e; } return null; } }); } 调用TransactionTemplate的execute()方法,传递一个TransactionCallback接口的实现,执行其doInTransaction()方法,该方法会回传事务状态对象TransactionStatus,如果有异常,则调用status.setRollbackOnly()将事务状态标记为回滚,否则doInTransaction方法正常返回,事务则会提交。 如果事务控制的方法不需要返回值,那么可以使用TransactionCallback接口的抽象实现类TransactionCallbackWithoutResult: @Override public void add(User user) throws Exception { // Spring编码式事务,回调机制 transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus status) { try { userMapper.insertSelective(user); } catch (Exception e) { // 异常,设置为回滚 status.setRollbackOnly(); throw e; } } }); } ...

2018-03-08 · 1 min · 103 words · Hank

Spring事务管理二:Spring事务管理器

前边简单介绍了事务的概念和其ACID特性,现在让我们看看Spring是如何实现对事务的支持的。 1. Spring事务管理器结构 Spring并不直接管理事务,而是提供多种事务管理器,将管理事务的责任委托给JTA或相应的持久性机制所提供的某个特定平台的事务实现。 Spring对事务管理器的抽象: Spring提供了顶层接口PlatformTransactionManager,并提供了扩展接口ResourceTransactionManager和抽象实现类AbstractPlatformTransactionManager。PlatformTransactionManager下的所有接口和实现类如图所示: 一般而言,每一种事务实现的类图如下: PlatformTransactionManager是Spring事务管理器的核心,接口定义如下: public interface PlatformTransactionManager { // 返回一个已经激活的事务或创建一个新的事务(根据给定的TransactionDefinition类型参数定义的事务属性), // 返回的是TransactionStatus对象代表了当前事务的状态,其中该方法抛出TransactionException(未检查异常) // 表示事务由于某种原因失败。 TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException; // 提交给定的事务,检查其状态。如果事务被标记为rollback-only,则执行回滚。 // 如果事务不是新的事务,则忽略提交周围适当的事务。如果先前的事务被挂起,则在提交新事务后恢复先前的事务。 void commit(TransactionStatus status) throws TransactionException; // 执行给定事务的回滚。如果事务不是一个新的事务,将其周边适当的事务标记为rollback-only。 // 如果先前的事务被挂起,则在回滚新事务后恢复先前的事务。 void rollback(TransactionStatus status) throws TransactionException; } TransactionDefinition接口定义如下: public interface TransactionDefinition { // 返回事务传播行为 int getPropagationBehavior(); // 返回事务隔离级别 int getIsolationLevel(); // 返回事务超时时间 int getTimeout(); // 返回事务是否只读 boolean isReadOnly(); // 返回事务的名称 String getName(); } ...

2018-03-07 · 1 min · 200 words · Hank

Spring事务管理一:Spring事务简介

1. 定义 在软件开发领域, 全有或全无的操作被称为事务(transaction)。 事物允许将几个操作组合成一个要么全部发生要么全部不发生的工作单元。发生和不发生两者只能选择其一,而不可能两者都选择。事务确保了数据和资源免于处在不一致的状态。 让我们继续使用最简单有效的转账例子来说明事务: A给B转100元,这个过程大概需要两步: step1、从A的账户扣除100元; step2、给B的账户增加100元。 这两步必须要么全部执行成功要么都不成功并且还原账户的金钱为初始值,否则转账失败。如果step1成功而step2失败,那么A账户少了100元,但是B却没收到钱;如果step1失败而step2成功,B账户会多出100元。这两种情况都是不允许发生的。 所以,step1和step2必须处于同一事务中,我们就说事务把这两个操作组合为要么都成功要么都失败的工作单元。整个操作成功,那么转账成功,结果是A账户扣了100元而B账户多了100元;如果整个过程失败,那么A和B的账户的金额恢复到转账前的状态,即未发生任何变化,就像转账操作从未发生过一样。 2. ACID特性 Atomic(原子性):确保所有操作要么都发生,要么都不发生。 Consistent(一致性):事务前后,数据均处于正确状态,数据不应该被破坏。 Isolated(隔离性):事务彼此隔离,用户间操作不相混淆。 Durable(持久性):事务一旦完成,结果应该持久化,例如保存到数据库中。 上边转账的例子中,两步操作必须要么成功要么都失败,确保了原子性;而原子性保证账户中的金额不会处于不一致或者说部分完成,保证了一致性;转账过程与其他转账过程互不影响,遵循隔离性;转账成功后,结果必须持久化保存,防止事务结果丢失。 3. Spring对事务管理的支持 Spring提供两者事务管理方式:编程式事务管理和声明式事务管理。 3.1. 编程式事务管理 编写程序式的事务管理可以清楚的定义事务的边界,可以 实现细粒度的事务控制,比如你可以通过程序代码来控制你的事务何时开始,何时结束等,与后面介绍的声明式事务管理相比,它可以实现细粒度的事务控制。 3.2. 声明式事务管理 如果你并不需要细粒度的事务控制,你可以使用声明式事务,在Spring中,你只需要在Spring配置文件中做一些配置,即可将操作纳入到事务管理中, 解除了和代码的耦合, 这是 对应用代码影响最小的选择,从这一点再次验证了Spring关于 AOP的概念。当你不需要事务管理的时候,可以直接从Spring配置文件中移除该设置。 Spring通过回调机制将实际的事务实现从事务性代码中抽象出来。如果应用只使用一种持久化资源,那么可以使用持久化机制本身的事务性支持(JDBC、Hibernate、JPA等);如果应用事务跨多个资源,那么Spring会使用第三方的JTA(JAVA事务API)实现来支持分布式(XA)事务。 使用声明式事务还是编程式事务管理,在很大程度上是 细粒度和易用性之间权衡。一般情况下,不需要精确控制事务,采用声明式事务不仅易用性高,而且降低了事务与其他业务代码的耦合性。 4. 总结 在软件开发领域,全有或全无的操作被称为事务。事务必须具备ACID特性,在Spring中,除了编程来精确控制事务,还可以使用AOP来配置低耦合度的声明式事务控制。

2018-03-07 · 1 min · 38 words · Hank