当前位置: 首页 > 知识库问答 >
问题:

旧的“@Transactional from in The same class”情况

汤飞
2023-03-14

原始问题的概要:使用带有AOP代理的标准Spring Transaction,不可能从同一类中的non-@Transactional-marked方法调用@Transactional标记的方法并在事务中(特别是由于前面提到的代理)。这应该在AeyJ模式下的Spring Transaction中是可能的,但是它是如何做到的呢?

编辑:使用加载时编织的AspectJ模式下Spring事务的完整运行:

将以下内容添加到META-INF/spring/applicationContext。xml:

<tx:annotation-driven mode="aspectj" />

<context:load-time-weaver />

(我假设您已经在应用程序上下文中设置了一个AnnotationSessionFactoryBean和一个HibernateTransactionManager。您可以添加事务管理器作为您的属性

添加META-INF/aop。xml。内容如下:

<aspectj>
  <aspects>
    <aspect name="org.springframework.transaction.aspectj.AnnotationTransactionAspect" />
  </aspects>
  <weaver>
    <include within="my.package..*" /><!--Whatever your package space is.-->
  </weaver>
</aspectj>

添加aspectjweaver-1.7.0。jar和spring-aspects-3.1.2。释放。jar到您的类路径。我使用Maven作为我的构建工具,下面是<代码>

<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjweaver</artifactId>
  <version>1.7.0</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-aspects</artifactId>
  <version>3.1.2.RELEASE</version>
</dependency>

spring-instrument-3.1.2。释放。jar不需要作为<代码>

-javaagent:full\path\of\spring-instrument-3.1.2.RELEASE.jar

我在Eclipse Juno中工作,所以要设置它,我转到了窗口-

现在是我的实际测试代码类。首先,我的主类,TestMain。java:

package my.package;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestMain {
  public static void main(String[] args) {
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("META-INF/spring/applicationContext.xml");
    TestClass testClass = applicationContext.getBean(TestClass.class);
    testClass.nonTransactionalMethod();
  }
}

然后我的事务类,TestClass.java

package my.package;

import my.package.TestDao;
import my.package.TestObject;
import org.springframework.transaction.annotation.Transactional;

public void TestClass {
  private TestDao testDao;

  public void setTestDao(TestDao testDao) {
    this.testDao = testDao;
  }

  public TestDao getTestDao() {
    return testDao;
  }

  public void nonTransactionalMethod() {
    transactionalMethod();
  }

  @Transactional
  private void transactionalMethod() {
    TestObject testObject = new TestObject();
    testObject.setId(1L);
    testDao.save(testObject);
  }
}

这里的诀窍是,如果TestClassTestMain中的一个字段,则它的类将在加载应用程序上下文之前由ClassLoader加载。由于编织是在类的加载时,并且这种编织是由Spring通过应用程序上下文完成的,因此它不会被编织,因为在加载应用程序上下文并意识到它之前,类已经加载了。

TestObjectTest道的进一步细节并不重要。假设它们与JPA和Hibernate注释连接并使用Hibernate进行持久性(因为它们是,而且确实如此),并且所有必需的

编辑:使用编译时编织的AspectJ模式下Spring事务的完整运行:

将以下内容添加到META-INF/spring/applicationContext。xml:

<tx:annotation-driven mode="aspectj" />

(我假设您已经在应用程序上下文中设置了一个AnnotationSessionFactoryBean和一个HibernateTransactionManager。您可以添加事务管理器作为您的属性

添加spring-aspects-3.1.2。释放。jar和aspectjrt-1.7.0。jar到您的类路径。我使用Maven作为我的构建工具,下面是<代码>

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-aspects</artifactId>
  <version>3.1.2.RELEASE</version>
</dependency>
<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjrt</artifactId>
  <version>1.7.0</version>
</dependency>

在Eclipse Juno中:帮助-

在重新启动Eclipse(它将使您)后,右键单击您的项目以打开上下文菜单。查看底部:配置-

添加以下

<plugin>
  <groupId>org.codehaus.mojo</groupId>
  <artifactId>aspectj-maven-plugin</artifactId>
  <version>1.4</version>
  <configuration>
    <aspectLibraries>
      <aspectLibrary>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aspects</artifactId>
      </aspectLibrary>
    </aspectLibraries>
  </configuration>
  <executions>
    <execution>
      <goals>
        <goal>compile</goal>
        <goal>test-compile</goal>
      </goals>
    </execution>
  </executions>
</plugin>

备选方案:右键单击项目以打开关联菜单。查看底部:AspectJ工具-

如果您采用Maven路线,则

安装插件并重新启动Eclipse后,POM. xml文件中的错误应该已经消失。如果没有,右键单击您的项目以调出上下文菜单:Maven-

现在来看我的实际测试代码类。这次只有一个,TestClass。java:

package my.package;

import my.package.TestDao;
import my.package.TestObject;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.transaction.annotation.Transactional;

public void TestClass {
  private TestDao testDao;

  public void setTestDao(TestDao testDao) {
    this.testDao = testDao;
  }

  public TestDao getTestDao() {
    return testDao;
  }

  public static void main(String[] args) {
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("META-INF/spring/applicationContext.xml");
    TestClass testClass = applicationContext.getBean(TestClass.class);
    testClass.nonTransactionalMethod();
  }

  public void nonTransactionalMethod() {
    transactionalMethod();
  }

  @Transactional
  private void transactionalMethod() {
    TestObject testObject = new TestObject();
    testObject.setId(1L);
    testDao.save(testObject);
  }
}

这个没有技巧;因为编织发生在编译时,也就是类加载和应用程序上下文加载之前,这两件事的顺序不再重要。这意味着一切都可以在同一个类中进行。在Eclipse中,每次你点击保存时,你的代码都会被不断地重新编译(当它说“构建工作区:(XX%)"?), 时,你想知道它在做什么,所以它是编织的,随时准备好。

就像在Load-Time示例中一样:TestObjectTest道的进一步细节并不重要。假设它们与JPA和Hibernate注释连接并使用Hibernate进行持久性(因为它们是,并且确实如此),并且所有必需的


共有1个答案

伊裕
2023-03-14

通过阅读您的问题,您并不清楚您被困在哪里,因此我将简要列出让AeyJ拦截您的@Transactional方法所需的内容。

  1. <代码>

最后一步可能不是必需的。这是一个非常简单的类,可以使用InstrumentationLoadTimeWeaver,但如果不可用,Spring将尝试使用另一个加载时间编织器。不过,我从未尝试过。

现在,如果您认为已经完成了所有步骤,但仍然存在问题,我建议您在weaver上启用一些选项(在aop.xml中定义):

<weaver options="-XnoInline -Xreweavable -verbose -debug -showWeaveInfo">

这使得编织者输出一系列正在编织的信息。如果您看到正在编织的类,您可以在那里查找您的测试类。然后,您至少有一个开始点来继续进行故障排除。

关于你的第二次编辑,“在类尝试执行之前,编织的速度几乎不够快。”,答案是肯定的,这是可能发生的。我以前经历过这样的情况。

我对细节有点生疏,但基本上是Spring无法在创建应用程序上下文之前编织加载的类。你是如何创建应用程序上下文的?如果你是以编程方式进行的,并且该类直接引用了TestClass,那么可能会出现这个问题,因为TestClass会太早加载。

不幸的是,我发现调试AspectJ简直就是地狱。

 类似资料:
  • 问题内容: 原始问题的提要: 使用具有AOP代理的标准Spring事务,不可能从同一类中的非@Transactional标记方法中调用@Transactional标记的方法,并且不能在事务内进行(特别是由于上述原因)代理)。据说在AspectJ模式下使用Spring Transactions可以做到这一点,但是如何完成呢? 编辑: 使用 Load-Time Weaving 在AspectJ模式下进

  • 我想将我的.java(几个)编译成一个,该至少兼容和更新版本,最好是和更新版本的Java。(我有)

  • 本文用于帮助理解旧脚本 本文所讲的内容对于帮助理解旧脚本很有用。 但这不是我们编写新代码的方式。 在本教程最开始那部分的 变量 这章中,我们提到了变量声明的三种方式: let const var var 声明与 let 相似。大部分情况下,我们可以用 let 代替 var 或者 var 代替 let,都能达到预期的效果: var message = "Hi"; alert(message); //

  • 在Autoconf的第2版,大部分宏被重新命名以使用更加统一和具有描述性的命名方案。下面是被重新命名了的宏的原来名字, 随后给出了这些宏现在的名字。虽然为了保持向后兼容,旧名字仍然能够被autoconf程序所接受,旧名字都 被看作过时的。关于新的命名方案,参见 宏名 。AC—ALLOCAAC—FUNC—ALLOCA AC—ARG—ARRAY 因为用途有限而被删除了。AC—CHAR—UNSIGNED

  • 任何色彩搭配淡紫色,最能诠释怀旧思古之情。能令人仿佛回到维多利亚时代,如梦似幻的时刻,优美的诗歌和浪漫的乐章。在紫色系中,淡紫色融合了红和蓝,比起粉色较精致,也较刚硬。淡紫色尽管无声无息,与其它色彩相配后,仍可见其清丽出众,往日如歌,犹在耳际。 补色色彩组合 二次色色彩组合 单色色彩组合 37 87 38 86 22 54 86 83 88 86 86 40 83 39 87 19 51 87 8

  • 新版接口 简介 本章为bricks引擎的详细接口说明,方便各位开发者查询。 1 BK.Script 工具 2 BK.Director 导演类 3 BK.Ticker 定时器 4 BK.Texture 纹理 5 BK.Node 节点 6 BK.Sprite 精灵 7 BK.Button 按钮 8 BK.Text 文字 9 BK.Editor 输入框 10 BK.TouchEvent 触摸事件 11