2

EJB アプリケーションを Spring に移植していますが、いくつかの問題に直面しています。アプリケーションは、eclipselink を使用してスタンドアロンで実行されます (そのため、Spring を選択します)。

このアプリケーションでは、注文を作成する必要があります。最初に Customer と OrderLines を作成し、次にこの注文の支払いを追加する必要があります。

問題は、単一のトランザクションですべての挿入を行いたいので、支払いが永続化されない場合は何も永続化する必要がないことです。これを達成しようとしましたが、複数の独立したトランザクションにまたがっているように見えます。失敗した場合、データが DB に永続化されるためです (例: 支払いが失敗し、とにかく顧客が作成されます)。

エントリ ポイントは次のとおりです。

public static void main(String[] args) {
    AbstractApplicationContext context = new ClassPathXmlApplicationContext(new String[] { "applicationContext.xml" });
    BeanFactory beanFactory = (BeanFactory) context;
    MyService service = beanFactory.getBean(MyService.class);
    service.getNewOrders(true);
}

これが私が解決しているBeanです(を使用beanFactory.getBean):

@Component
@Scope("prototype")
public class MyService {

    @Autowired
    private CustomerService customerService;

    @Autowired
    private OrderService orderService;

    @Autowired
    private PaymentService paymentService;

    @Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
    public void getNewOrders(boolean formattedOutput) {
        try {
            List<RawData> rawData = // Acquire data from a remote web service (http rest based)

            for (RawData data : rawData) {
                try {
                    this.handleOrder(data);
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    private Order handleOrder(RawData rawData) throws Exception {
        Customer customer = new Customer();
        // Fill customer with rawData
        this.customerService.create(customer);

        Order order = new Order();
        order.setCustomer(customer);
        // Fill order with rawData
        this.orderService.create(order);

        Payment payment = new Payment();
        payment.setOrder(order);
        // Fill payment with rawData
        this.paymentService.create(payment);

        return order;
    }
}

各サービスは次のようになります。

@Service
@Transactional
public class CustomerService {

    @Autowired
    private CustomerDao customerDao;

    public void create(Customer customer) {
        // some works on customer fields (checking values etc)
        this.customerDao.create(customer);
    }
}

これらはすべて Dao によってサポートされています:

@Repository
public class CustomerDao {

    @PersistenceContext
    protected EntityManager em;

    public void create(Customer customer) {
        this.em.persist(customer);
    }
}

maven pom.xml からのいくつかの依存関係を次に示します。

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>3.2.3.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>3.2.3.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>3.2.3.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>3.2.3.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-orm</artifactId>
        <version>3.2.3.RELEASE</version>
    </dependency>

    <dependency>
        <groupId>com.jolbox</groupId>
        <artifactId>bonecp</artifactId>
        <version>0.8.0-rc1</version>
    </dependency>

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.25</version>
    </dependency>
    <dependency>
        <groupId>org.eclipse.persistence</groupId>
        <artifactId>eclipselink</artifactId>
        <version>2.3.2</version>
    </dependency>
    <dependency>
        <groupId>org.eclipse.persistence</groupId>
        <artifactId>javax.persistence</artifactId>
        <version>2.0.3</version>
    </dependency>
    <dependency>
        <groupId>org.eclipse.persistence</groupId>
        <artifactId>org.eclipse.persistence.jpa.modelgen.processor</artifactId>
        <version>2.3.2</version>
    </dependency>

persistence.xml は次のとおりです。

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
    <persistence-unit name="default" transaction-type="RESOURCE_LOCAL">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <exclude-unlisted-classes>false</exclude-unlisted-classes>
        <shared-cache-mode>NONE</shared-cache-mode>
        <properties>
            <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
            <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/db" />
            <property name="javax.persistence.jdbc.user" value="root" />
            <property name="javax.persistence.jdbc.password" value="" />
        </properties>
    </persistence-unit>
</persistence>

春の構成は次のとおりです。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">

    <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

    <bean id="myDataSource" class="com.jolbox.bonecp.BoneCPDataSource" destroy-method="close">
        <property name="driverClass" value="com.mysql.jdbc.Driver" />
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/db" />
        <property name="username" value="root" />
        <property name="password" value="" />
    </bean>

    <bean id="myEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="myDataSource" />
        <property name="jpaPropertyMap">
            <map>
                <entry key="eclipselink.weaving" value="false" />
            </map>
        </property>
    </bean>

    <bean id="myTxManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="myEmf" />
    </bean>

    <tx:annotation-driven transaction-manager="myTxManager" />

    <context:component-scan base-package="com.application" />

</beans>

編集

main から ApplicationContext の作成を追加し、MyService.java からメソッドを省略しました

4

1 に答える 1

5

プライベートなので、どのようにサービスメソッドを呼び出すことができますか? 公開する必要があります。プライベート メソッドは、Spring トランザクション インターセプターによってインターセプトできず、CGLib 動的プロキシによってオーバーライドできません。

編集:OK、それは通常の問題です。メイン メソッドからメソッドを呼び出していますgetNewOrders()。これは public でトランザクションです。Spring インターセプターは、このメソッド呼び出しをインターセプトします。トランザクションがなく、メソッドが SUPPORTS としてマークされているため、Spring はトランザクションを開始しません。

次に、このメソッドはプライベートhandleOrder()メソッドを呼び出します。メソッドがプライベートであるため、Spring がメソッド呼び出しをインターセプトできないだけでなく、呼び出しがコンポーネント内のメソッドから同じコンポーネント内のメソッドへのものであることに注意してください。したがって、メソッドがパブリックであっても、Spring はこのメソッド呼び出しをインターセプトできませんでした。トランザクション処理はプロキシ ベースです。

method --> transactional proxy --> Spring bean 1 --> transactional proxy --> Spring bean2

この場合、別のコンポーネントのメソッドを呼び出していないため、プロキシ インターセプトは発生せず、トランザクションは開始されません。

method --> transactional proxy --> Spring bean 1 --> transactional proxy --> Spring bean2
                                      ^   |
                                      |___|

だから、あなたがしなければならないことは

  • たとえば、別のSpring Bean「OrderHandler」を作成します)
  • handleOrder() メソッドをこの Spring Bean に移動し、公開します
  • MyService に OrderHandler を挿入する

そして、それはうまくいきます。

これについては、 Spring のドキュメントで詳しく説明されています。

于 2013-07-17T11:26:41.373 に答える