在初始化应用程序上下文时,Spring遇到带有@Transactional标记的类时会创建代理。 @Transactional可以应用于类级别或方法级别。 在类级别应用它意味着该类中定义的所有公共方法都是事务性的。 Spring创建的代理类型,即Jdk代理或CGLIB代理,取决于将方法标记为事务性的类。 如果该类实现了至少一个接口,则Spring将创建一个Jdk动态代理。 该代理实现与原始类相同的接口,并使用事务维护逻辑拦截接口方法。 它将调用委托给其中组成的原始对象。 假设该类未实现任何接口,Spring将创建一个CGLIB代理。 该代理扩展了原始类并覆盖了公共方法。 我们将尽快对此进行仔细研究。 假设我们有一个这样定义的类:

public interface BookDao{void buyBook(String isbn) throws BookNotFoundException;Book findByIsbn(String isbn);int deductStock(Book book);
}public class JdbcBookDao implements BookDao{void buyBook(String isbn) throws BookNotFoundException{Book book = findByIsbn(isbn);if(book == null){throw new BookNotFoundException();}deductStock(book);}@Transactional(propagation=Propagation.REQUIRES_NEW)Book findByIsbn(String isbn){Book book = getJdbcTemplate().queryForObject("SELECT * FROM BOOK WHERE ISBN=?",ParameterizedBeanPropertyRowMapper.newInstance(Book.class), isbn);return book;}@Transactional(propagation=Propagation.REQUIRES_NEW)int deductStock(Book book){String sql = "UPDATE BOOK_STOCK SET STOCK=STOCK-1 WHERE BOOK_ID=?";return getJdbcTemplate().update(sql, stockIncrement, book.getId());}
}

现在,Spring是否会通过从main方法调用bookDao的findByIsbn自动创建交易? 否。我们必须在xml配置中声明这一点:

<tx:annotation-driven>

因此,如果它不创建事务,是否会引发错误? 答案还是不是。Spring非事务地执行此语句。

按照我们的预期,一旦声明了‹tx:annotation-driven›,Spring就会在该类实现接口时为JdbcBookDao创建一个Jdk动态代理。 现在说,我们调用JdbcBookDao的buyBook方法,Spring创建了多少个事务?

  1. 二:1用于findByIsbn,另外1用于deductStock。
  2. 一:在同一笔交易中同时找到findByIsbn和deductStock。
  3. 完全没有交易!

答案是(3)。 交易的默认交易模式是“代理”。 这意味着Spring仅考虑通过代理进行的方法调用进行自动事务管理。 现在,如果您仔细观察,buyBook方法不会标记为事务性的。 因此,当创建事务代理时,此方法不会被事务管理逻辑拦截,因为它没有标记为@Transactional。 简而言之,buyBook不会在代理中被覆盖。 因此,该方法直接在原始对象上调用。 因此,其他两个方法也将在原始对象上调用。 请记住,只有PROXY包含事务管理代码。 因此,当其他方法也被原始对象调用时,Spring根本不会创建事务。 现在,如果我们将buyBook标记为@Transactional,是否可以解决问题? Spring是否会为每个findByIsbn和deductStock方法创建两个单独的事务?

不会。在调用buyBook()时,Spring仅创建一个事务。 由于不会在原始对象本身而非代理上调用各个方法,因此不会进一步创建任何新事务。 那么如何解决这个问题呢?

我们可以要求Spring创建一个CGLIB proxy()吗? 现在,由于代理是具有重写的公共事务方法的子类,因此它为每个方法调用创建一个新事务? 再次没有。 CGLIB代理不会直接在超类上调用该方法。 这是一个大概的实现方法。

import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;public class MyInterceptor implements MethodInterceptor {private Object realObject;public MyInterceptor(Object original) {this.realObject = original;}// This method will be called every time the object proxy calls any of its methodspublic Object intercept(Object o, Method method, Object[] args,MethodProxy methodProxy) throws Throwable {/*** Transaction Management Code*/// Invoke the method on the real object with the given paramsObject res = method.invoke(realObject, args);/*** Transaction Management Code*/return res;}
}import net.sf.cglib.proxy.Enhancer;public class ProxyCreator(){public static T createProxy(T original){// Enhancer is CGLIB class which builds a dynamic proxy with new capabilitiesEnhancer e = new Enhancer();e.setSuperclass(original.getClass());// We have to declare the interceptor whose 'intercept' will be called when methods are called on proxy.e.setCallback(new MyInterceptor(original));T proxy = (T) e.create();return proxy;}
}

因此,如您在此处看到的,代理扩展了原始类并由其对象组成。 因此,当我们调用buyBook时,代理会创建一个事务并将该调用委托给原始对象。 从原始对象的buyBook中调用findByIsbn和deductStock不会,因此不会创建新交易。

一个快速的周转解决方案是,因为JdbcBookDao是一个单例,请从应用程序上下文中获取此对象。 现在,与其直接在对象上调用方法,不如使用引用来调用它(以确保调用代理),这就是方法的外观。

public class JdbcBookDao implements BookDao, ApplicationContextAware{private ApplicationContext context;private BookDao bookDao;public void setApplicationContext(ApplicationContext context){this.context = context;}public BookDao getBookDao(){bookDao = (BookDao)context.getBean("jdbcBookDao");}void buyBook(String isbn) throws BookNotFoundException{Book book = getBookDao().findByIsbn(isbn);if(book == null){throw new BookNotFoundException();}getBookDao().deductStock(book);}.....
}

刚刚实施了一个粗略的版本来使它正常工作。 我们绝对可以改进其设计方式。 与其直接将应用程序上下文注入DAO中,不如说我们可以使用一种辅助类来实现。 或完成此任务的另一种选择是使用程序化事务。

最后要注意的一点是,Spring仅在将公共方法标记为事务性时才管理事务。 对于私有,受保护和程序包私有的方法,Spring不提供事务管理支持。 对于动态代理,当它们实现接口时,所有事务处理方法都是公共的。 因此,无需担心非公开方法。 对于CGLIB代理,在创建子类时仅覆盖公共方法。 因此,即使在这里,也不会考虑非公开方法。

让我以一个问题结束这次讨论。 当我尝试使用‹tx:annotation-driven proxy-target-class =” true” /›代理目标类时,它实际上不起作用,即未创建CGLIB代理 。 为此,我必须进行一些小改动。 正如Spring文档明确指出的那样,如果在‹tx:annotation驱动的›,‹aop:config›或‹aop:aspectj-autoproxy›中的任何一个上启用了代理目标类,Spring将在容器上启用CGLIB代理创建。 因此,我刚刚创建了一个空的‹aop:config proxy-target-class =“ true” /›。 不用担心,它开始起作用! 不知道这是否是Spring本身的错误。 高度赞赏,如果有人可以回答这个问题。

参考: Spring交易可见性来自prasanthnath博客上的JCG合作伙伴 Prasanth Gullapalli。

翻译自: https://www.javacodegeeks.com/2013/11/spring-transactions-visibility.html

Spring交易可见性相关推荐

  1. spring和spring_Spring交易可见性

    spring和spring 在初始化应用程序上下文时,Spring在遇到带有@Transactional标记的类时会创建代理. @Transactional可以应用于类级别或方法级别. 在类级别应用它 ...

  2. spring框架三层架构_Spring框架架构

    spring框架三层架构 这是Spring Framework Architecture的概述. 了解Spring Framework的各个组成部分如何组织以及如何相互联系. 如果您想了解什么是Spr ...

  3. spring框架mvc框架_5篇Spring框架书籍,通过MVC学习Spring

    spring框架mvc框架 Spring Framework is one of the most widely used Java EE Frameworks. It's an open sourc ...

  4. spring注释_Spring注释

    spring注释 Spring Annotations allows us to configure dependencies and implement dependency injection t ...

  5. spring事务 jdbc_Spring事务管理示例JDBC

    spring事务 jdbc Spring Transaction Management is one of the most widely used and important feature of ...

  6. 第五十五期:区块链将在2020年实现的重大改变

    科技界的每家公司都已经拥有区块链战略.如果他们现在没有,他们就有可能错过了这个时代的一个机会.在过去几年中,许多企业已经对整体采用区块链技术的好处和相关风险进行了估算,分析和讨论. 科技界的每家公司都 ...

  7. Java中的JDBC教程

    Java中的JDBC教程 欢迎使用JDBC教程.Java DataBase Connectivity(JDBC)是企业应用程序中使用最广泛的API之一.这是因为大多数应用程序使用某种数据库连接.我最近 ...

  8. 战胜阿里和腾讯,Ripple已经获得200家跨境支付客户!

    Euro Exim Bank是一家注册在案并接受监管的英国银行,其日前宣布将使用Ripple的xRapid软件配合XRP加密货币进行跨境支付.这亦是Ripple项目在2019年年内所披露的多项新的银行 ...

  9. 在Kubernetes上部署Hyperledger Fabric

    Hyperledger Fabric是一个开源区块链框架实现,是Linux基金会托管的Hyperledger项目之一. 它是用于分布式分类帐解决方案的平台. 本文旨在通过使用Kubernetes简化F ...

最新文章

  1. 剑指offer:字符流中第一个不重复的字符
  2. 搜索引擎蜘蛛为什么对网站不爬行呢?
  3. 24张IT工程师技能图谱,这些你都会吗?
  4. 用官方2012版本131兆,一共有四个自带软件
  5. 2.转动的地球shader
  6. caffe与tensorflow框架下卷积的维度计算与一致性证明
  7. qtcreator下拉列表怎么制作_如何用WPS制作月度记账表
  8. /proc/cpuinfo文件分析(查看CPU信息)
  9. c#通过RFC调用SAP接口程序之输入输出参数案例
  10. 数据可视化—如何利用R,制作DashBoard
  11. Gym - 100625G Getting Through 计算几何+并查集
  12. 报错java.lang.NoClassDefFoundError: org/jaxen/JaxenException
  13. 【Python】一元线性回归的分析
  14. gentoo linux u盘安装,Gentoo系统安装步骤详解
  15. C语言-make概述
  16. yii2项目实战-博客管理平台的搭建
  17. linux 删除保存wifi密码,怎样删除保存的无线上网WiFi密码
  18. FL Studio 20.9.2官方中文版全新发布更新功能介绍
  19. 使用spark处理天气数据并可视化
  20. springboot---web---静态资源映射

热门文章

  1. 在 eclipse 中 设置 jvm 的 运行时目录
  2. java泛型程序设计——Varargs 警告+不能实例化类型变量
  3. 控制台查出数据传到layui数据表格却没有数据的问题
  4. java使用迭代器删除元素_使用Java从地图中删除元素
  5. java 编写代码_如果您在2016年编写过Java代码-这是您不容错过的趋势
  6. Apache NetBeans?
  7. drill apache_如何使用Apache Drill分析高度动态的数据集
  8. swagger api文档_带有Swagger的Spring Rest API –公开文档
  9. Spring Boot微服务,Docker和Kubernetes研讨会–第3部分
  10. netty 压缩比_使Netty 4中的HTTP内容压缩工作