spring和spring_Spring交易可见性

spring和spring

在初始化应用程序上下文时,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和spring

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/346763.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python上传文件到linux服务器_python上传大文件到服务器报错

项目需要&#xff0c;在mac上将打包好的文件(四五百兆)自动上传到web后台&#xff0c;用了两种方式上传&#xff0c;都报了类似的错误&#xff0c;在windows和linux上测试不会报错&#xff0c;但是到了mac打包机上就会报错&#xff1a;①第一种报错&#xff1a;Traceback (most…

mysql 更改root密码及 主机_设置更改root密码(远程,本地)、连接mysql、mysql常用命令...

设置更改root密码1、将mysql加入环境变量中[rootcentos7 ~]# grep mysql /etc/profileexport PATH/usr/local/mysql/bin/:$PATH2、直接登录&#xff0c;无密码[rootcentos7 ~]# mysql -uroot3、方式一&#xff1a;设置密码[rootcentos7 ~]# mysqladmin -uroot password 123456W…

从NetBeans运行和调试WildFly Swarm应用程序

使用NetBeans的Java EE开发人员习惯于直接在NetBeans所选择的应用程序服务器中运行和调试其瘦战应用程序。 在开发打包为ber或镂空jars的微服务时&#xff0c;您期望使用相同的轻松方式进行运行和调试。 好消息是您可以。 在本文中&#xff0c;我将逐步演示如何在NetBeans中运行…

mysql 事实表 维度表_数据库的事实表与维度表

维度表示你要对数据进行分析时所用的一个量&#xff0c;比如你要分析产品销售情况&#xff0c;你可以选择按类别来进行分析&#xff0c;或按区域来分析&#xff0c;这样的按照什么分析就构成一个维度。前面的实例就可以有两个维度&#xff1a;类型和区域。另外每个维度还可以有…

hazelcast入门教程_Hazelcast入门

hazelcast入门教程7月&#xff0c;我写了一个博客向Java开发人员介绍erlang&#xff0c;重点介绍了这两种语言之间的一些异同。 erlang虚拟机具有许多令人印象深刻的内置功能&#xff0c;其中之一是它们独立于位置且可以相互通信。 这意味着可以通过编写很少的代码行在VM之间同…

tcp java实例_实现了基于TCP的Java Socket编程实例代码

实现了基于TCP的Java Socket编程&#xff0c;功能很简单&#xff1a;客户端向服务器端输出一名话"connect"&#xff0c;服务器端接收输出到控制台并向客户端输出一名话"Hello",客户端接收并输出。1.服务器端package javase.net.socket;import java.io.Data…

java 批量上传图片插件_java多文件上传plupload控件实现多图片上传(一)

使用的是plupload-2.1.2 控件。网上资源挺多的&#xff0c;很好下载。plupload 官方地址 : http://www.plupload.com/plupload 示例: http://www.plupload.com/examples/plupload Github: https://github.com/moxiecode/plupload整体框架用的是easyui springMVC。1、前台jsp页…

java servlet_Java Servlet的前100个问题

java servlet1&#xff09;是“ servlets”目录还是“ servlet”目录&#xff1f; 回答&#xff1a; 对于Java Web Server&#xff1a; 在文件系统上&#xff0c;它是“ servlet” c&#xff1a;\ JavaWebServer1.1 \ servlets \ DateServlet.class 在URL路径中&#xff0c;…

精通java ee项目案例_精通JavaEE项目案例

第1章 Java EE开发入门 11.1 基本概念 11.1.1 Java EE API 11.1.2 MVC模型 21.1.3 JSP讨论 31.1.4 Servlet讨论 41.1.5 Model1和Model2 51.2 Eclipse 51.2.1 Eclipse的平台简介 61.2.2 Eclipse的体系结构 61.3 Struts 71.3.1 认识Struts 71.3.2 Strut…

java调用php session_php读取memcahed java session

情景&#xff1a;1&#xff1a;现在有两个系统&#xff0c;一个是Java做的系统&#xff0c;一个是PHP的系统&#xff0c;现在要把两个系统弄成一个单点登录。2&#xff1a;两个系统两个库&#xff0c;两个库的表结构完全不同&#xff0c;现在要解决的就是session共享问题和用户…

[MEGA DEAL]完整的Java编程训练营(94%折扣)

成为Java Master的10门课程&#xff08;83.5小时&#xff09;&#xff1a;使用JavaFX的设计UI&#xff0c;利用设计模式&#xff0c;Master Multithreading等 嘿&#xff0c;怪胎&#xff0c; 本周&#xff0c;在我们的JCG Deals商店中 &#xff0c;我们提供了另一个超值优惠…

怎么把java程序放进php_如何在php脚本中执行Java程序?

I have been struggling with this for awhile trying all sorts of options withno results – the file is never created(the file is created with an absolutepath so it’s not being created and Ijust can’t find the file). Does anyonehave any ideas?我认为问题是…

java重排序_Java内存模型FAQ(四)重排序意味着什么?

译者&#xff1a;Alex在很多情况下&#xff0c;访问一个程序变量(对象实例字段&#xff0c;类静态字段和数组元素)可能会使用不同的顺序执行&#xff0c;而不是程序语义所指定的顺序执行。编译器能够自由的以优化的名义去改变指令顺序。在特定的环境下&#xff0c;处理器可能会…

javafx响应式布局_JavaFX的响应式设计

javafx响应式布局使用CSS技术&#xff0c;为您的网站创建响应式设计相对容易。 根据屏幕的大小&#xff0c;您可以使用其他CSS文件和布局。 在JavaFX中&#xff0c;乍一看似乎有些困难&#xff0c;因为CSS仅负责样式&#xff0c;而不负责布局。 但是&#xff0c;为各个屏幕尺寸…

pojo java_什么是POJO,JavaBean?

什么是POJO&#xff0c;JavaBean&#xff1f;总结&#xff1a;POJO&#xff1a;一个简单的Java类&#xff0c;这个类没有实现/继承任何特殊的java接口或者类&#xff0c;不遵循任何主要java模型&#xff0c;约定或者框架的java对象。在理想情况下&#xff0c;POJO不应该有注解。…

JVM体系结构101:了解您的虚拟机

Java虚拟机&#xff08;JVM&#xff09;架构和Java字节码101的初学者速成班 Java应用程序无处不在&#xff0c;它们在我们的手机&#xff0c;平板电脑和计算机上。 在许多编程语言中&#xff0c;这意味着要多次编译代码才能使其在不同的OS上运行。 对于作为开发人员的我们来说…

flask对mysql数据库增删改查_Flask学习(三) - Flask-SQLAlchemy对数据库增删改查

Flask-SQLAlchemy对数据库增删改查安装pip install flask-sqlalchemy具体不多说了&#xff0c;主要是对数据库进行简单的增删改查&#xff0c;上代码&#xff0c;看注释app.route(/)def index():#增加article1 Article(titletest1, contentthe first test)db.session.add(arti…

逸出 java_【java】知识系谱-基础篇-线程-发布、逸出

java并发编程实战的解释&#xff0c;不够详细&#xff0c;尤其this引用逸出让人理解有些费解&#xff0c;java并发编程实战里面的内容就直接拷贝过来发布&#xff1a;使对象能够在当前作用域之外的代码中使用逸出&#xff1a;当某个不该被发布的对象被发布时&#xff0c;这种情…

lambda java_Java Lambdas简介

lambda javaJava 8的主题是lambdas。 我已经注意到&#xff0c;对于许多Java程序员来说&#xff0c;lambda都是非常难的材料。 因此&#xff0c;让我们尝试对它们有一个基本的了解。 首先&#xff0c;lambda到底是什么&#xff1f; Lambda是一个匿名函数&#xff0c;与常规函数…

java mousepress_Java线程原语弃用

为什么是线程停止不赞成&#xff1f;因为它本质上是不安全的。停止线程会使其解锁其锁定的所有监视器。(当ThreadDeath异常在堆栈上传播时&#xff0c;监视器将被解锁。)如果以前受这些监视器保护的任何对象处于不一致状态&#xff0c;其他线程现在可能会以不一致的状态查看这些…