Java EE JTA 从不事务

标签 java jpa transactions jta apache-tomee

我正在了解 JTA 事务并正在执行 Junit。我遵循了 TomEE 示例中的示例代码。为了更好地理解服务类,我做了一些改变。

我有 2 个测试用例。 1.有交易 2.无交易

第一个测试用例运行良好。但第二个不是。因为第二种方法以 Never 开始 Transaction Attribute。但是Service类的所有方法都需要TA(事务属性)。删除事务未提交,因为我的测试用例失败。

为什么删除事务没有提交? (即使删除方法有 REQUIRED TA )

那么添加事务是如何工作的? (从 GetMovies 方法获取电影)

实体 @实体 公开课电影{

    @Id
    private long movieId;

    private String title;

    private String director;
    private int year;

    public Movie() {
    }

    public Movie(String director, String title, int year, long id) {
        this.director = director;
        this.title = title;
        this.year = year;
        this.movieId = id;
    }

    public String getDirector() {
        return director;
    }

    public void setDirector(String director) {
        this.director = director;
    }

    public String getTitle() {
        return title;
    }

    public long getMovieId() {
        return movieId;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public int getYear() {
        return year;
    }

    public void setYear(int year) {
        this.year = year;
    }

}

服务等级

package com.demo.ex.service;

import com.demo.ex.entity.Movie;

import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceContextType;
import java.util.List;

@Stateless
public class MovieService {

    @PersistenceContext(unitName = "movie-unit", type = PersistenceContextType.TRANSACTION)
    private EntityManager em;

    @TransactionAttribute(value = TransactionAttributeType.REQUIRED)
    public void addMovie(Movie movie) {
        System.out.println(" Add Movie "+movie.getTitle() +" "+movie.getMovieId());
        em.persist(movie);
    }

    @TransactionAttribute(value = TransactionAttributeType.REQUIRED)
    public void deleteMovie(Movie movie) {
        em.remove(movie);
        System.out.println(" Delete Movie "+movie.getTitle()+" "+movie.getMovieId());

    }

    @TransactionAttribute(value = TransactionAttributeType.REQUIRED)
    public List<Movie> getMovies()throws Exception {
        System.out.println(" Get Movie ");
        return em.createQuery("select m from Movie as m").getResultList();
    }
}

测试类

package com.demo.ex;

import com.demo.ex.entity.Movie;
import com.demo.ex.service.MovieService;
import junit.framework.TestCase;

import javax.ejb.*;
import javax.ejb.embeddable.EJBContainer;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.Callable;

public class MovieTest extends TestCase {

    @EJB
    private MovieService movieService;

    @EJB(beanName = "TestTransaction")
    private Caller transactionCaller;


    @EJB(beanName = "TestNoTransaction")
    private Caller noTransactionCaller;


    protected void setUp() throws Exception {
        final Properties p = new Properties();
        p.put("movieDatabase", "new://Resource?type=DataSource");
        p.put("movieDatabase.JdbcDriver", "org.hsqldb.jdbcDriver");
        p.put("movieDatabase.JdbcUrl", "jdbc:hsqldb:mem:moviedb");
        EJBContainer.createEJBContainer(p).getContext().bind("inject", this);
    }

    @Override
    protected void tearDown() throws Exception {
        transactionCaller.call(new Callable<Object>() {
            @Override
            public Object call() throws Exception {
                System.out.println(" Tear Down Action.................");
                for (final Movie m : movieService.getMovies()) {
                    System.out.println(" Teardown delete :"+m);
                    movieService.deleteMovie(m);
                }
                System.out.println("After cleanup movie count="+movieService.getMovies().size());
                return null;
            }
        });
    }


    private void doWork() throws Exception {
        movieService.addMovie(new Movie("Quentin Tarantino", "Reservoir Dogs", 1992,1));
        movieService.addMovie(new Movie("Joel Coen", "Fargo", 1996,2));
        movieService.addMovie(new Movie("Joel Coen", "The Big Lebowski", 1998,3));

        List<Movie> list = movieService.getMovies();
        System.out.println(" Movie Serivce List :::"+list.size());

        assertEquals("List.size()", 3, list.size());

        for (Movie movie : list) {
            movieService.deleteMovie(movie);
        }
        System.out.println(" ???????????????????? SIZE:"+movieService.getMovies().size());
        assertEquals("Movies.getMovies()", 0, movieService.getMovies().size());
    }

    public void testWithTransaction() throws Exception {
        transactionCaller.call(() -> {
            doWork();
            return null;
        });
    }

    public void testWithoutTransaction() throws Exception {
        try {
            noTransactionCaller.call(() ->  {
                doWork();
                return null;
            });
        } catch (EJBException e) {
            e.printStackTrace();
        }
    }

    public static interface Caller {
        public <V> V call(Callable<V> callable) throws Exception;
    }



    @Stateless
    @TransactionAttribute(value = TransactionAttributeType.REQUIRES_NEW)
    public static class TestTransaction implements Caller {
        @Override
        public <V> V call(Callable<V> callable) throws Exception {
            return callable.call();
        }
    }

    @Stateless
    @TransactionAttribute(value = TransactionAttributeType.NEVER)
    public static class TestNoTransaction implements Caller {
        @Override
        public <V> V call(Callable<V> callable) throws Exception {
            return callable.call();
        }
    }


}

持久性.xml

<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">

    <persistence-unit name="movie-unit">
        <jta-data-source>movieDatabase</jta-data-source>
        <non-jta-data-source>movieDatabaseUnmanaged</non-jta-data-source>
        <class>com.demo.ex.entity.Movie</class>

        <properties>
            <property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)"/>
            <property name="openjpa.Log" value="SQL=TRACE" />
            <property name="openjpa.ConnectionFactoryProperties"
                      value="printParameters=true"/>
        </properties>
    </persistence-unit>
</persistence>

最佳答案

从非事务上下文调用:您正在对一个分离的实例进行删除。但是您在另一个事务中创建了实体电影。因此,首先您需要进行合并,使其成为托管实体。

managedMovie = em.merge(movie);

em.remove(managedMovie);

参见Javadoc:

IllegalArgumentException - 如果实例不是实体或者是独立实体

关于Java EE JTA 从不事务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53072693/

相关文章:

java - 解析整数字符串(大于 Integer.MAX_VALUE)

java - 带有 Swing 的 JRuby : "The OSX menu"

java - 将用户添加到 spring 3 security

spring - findById() 给出未找到属性 ID

delphi - 如何使用 FireDAC 设置 Firebird (InterBase) 的事务锁定超时?

java - 读取从 arraylist 创建的文件

使用 JPA 循环遍历大型表时出现 java.lang.OutOfMemoryError

java - 将自定义标识符分配给 @id 属性

c# - 如何创建与 TransactionScope 一起使用的类?

没有 MSDTC 的 WCF 事务