Java EE JTA永不事务

时间:2018-10-30 20:49:01

标签: java jpa transactions jta tomee

我正在了解JTA交易并进行Junit。我遵循了TomEE示例中的示例代码。我做了一些更改,以便更好地理解服务类。

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

第一个测试用例运行良好。但是第二个不是。因为第二种方法使用Never来启动Transaction Attribute。但是服务类的所有方法都需要TA(Transaction Attribute)。由于我的测试用例失败,因此未提交删除事务。

为什么不提交删除事务? (即使删除方法具有必需的TA)

然后Add事务如何工作? (从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();
        }
    }


}

Persistence.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>

1 个答案:

答案 0 :(得分:1)

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

  

managedMovie = em.merge(movie);

     

em.remove(managedMovie);

请参阅Javadoc:

IllegalArgumentException-如果实例不是实体或分离的实体