Java EE JTA 从不事务
Java EE JTA Never Transaction
我正在了解 JTA 事务并正在使用 Junit。我遵循了 TomEE 示例中的示例代码。为了更好地理解服务 class,我做了一些改动。
我有 2 个测试用例。
1.有交易
2. 无交易
第一个测试用例运行良好。但是第二个不是。因为第二种方法以 Never 启动 Transaction Attribute。但是服务 class' 的所有方法都需要 TA(事务属性)。删除事务未提交,因为我的测试用例失败了。
为什么删除事务没有提交? (即使删除方法需要 TA)
那么添加事务是如何工作的? (从 GetMovies 方法获取电影)
实体
@实体
public class 电影 {
@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;
}
}
服务Class
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();
}
}
测试Class
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>
从非事务性上下文中调用:您正在对分离的实例执行 remove。但是您在另一笔交易中创建了实体 movie。因此,首先您需要执行 merge,使其成为托管实体。
managedMovie = em.merge(movie);
em.remove(managedMovie);
查看 Javadoc:
IllegalArgumentException - 如果实例不是实体或者是分离的实体
我正在了解 JTA 事务并正在使用 Junit。我遵循了 TomEE 示例中的示例代码。为了更好地理解服务 class,我做了一些改动。
我有 2 个测试用例。 1.有交易 2. 无交易
第一个测试用例运行良好。但是第二个不是。因为第二种方法以 Never 启动 Transaction Attribute。但是服务 class' 的所有方法都需要 TA(事务属性)。删除事务未提交,因为我的测试用例失败了。
为什么删除事务没有提交? (即使删除方法需要 TA)
那么添加事务是如何工作的? (从 GetMovies 方法获取电影)
实体 @实体 public class 电影 {
@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;
}
}
服务Class
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();
}
}
测试Class
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>
从非事务性上下文中调用:您正在对分离的实例执行 remove。但是您在另一笔交易中创建了实体 movie。因此,首先您需要执行 merge,使其成为托管实体。
managedMovie = em.merge(movie);
em.remove(managedMovie);
查看 Javadoc:
IllegalArgumentException - 如果实例不是实体或者是分离的实体