在项目 JSF + EJB + CDI + JAX-RS + GlassFish 4.1 的 ManagedBean 中回滚
Rollback in ManagedBean on a project JSF + EJB + CDI + JAX-RS + GlassFish 4.1
我正在开始一个结合 "JSF + EJB + CDI + JAX-RS + GlassFish 4.1"
的项目
看了一些书,做了一些研究,终于把这些技术完美的结合起来了。除了事务控制,一切正常。
为了帮助理解问题,我创建了一个测试项目https://github.com/douglasjunior/TestRollbackJsfEjbCdiRest
问题是:在ManagedBean中,没有运行抛出异常时回滚事务
但 JAX-RS 资源中的相同问题完美运行。
在我的示例中,我试图在数据库中插入重复记录。我应该在哪里收到异常 DuplicatedKey。因此,交易应该被逆转,数据库中不应该插入任何东西。
但是当这在ManagedBean中完成时,异常不会回滚事务。第一条记录已提交。
GenericDao.java
@Stateless
public class GenericDao implements Serializable {
@PersistenceContext(unitName = "PU")
private EntityManager em;
public void persist(Object entity) {
getEntityManager().persist(entity);
getEntityManager().flush();
}
}
User.java
@Entity
@Table(name = "table_user")
@XmlRootElement
public class User extends AbstractEntity<Long> {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(length = 100, unique = true)
private String someText;
}
TestManagedBean.java(回滚无效)
@Named(value = "testManagedBean")
@ViewScoped
@TransactionManagement(TransactionManagementType.CONTAINER) // I tested also as BEAN
public class TestManagedBean extends AbstractManagedBean {
@Inject
private GenericDao dao;
private User user;
public TestManagedBean() {
user = new User();
}
@TransactionAttribute(TransactionAttributeType.REQUIRED) // I tested also as REQUIRES_NEW
public String test() {
if (user.getSomeText() == null || user.getSomeText().isEmpty()) {
sendErrorMessage("Text is riquired!");
return null;
}
dao.persist(user);
User user2 = new User();
user2.setSomeText(user.getSomeText()); // "someText" is unique on database
dao.persist(user2); // org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "table_user_sometext_key"
return null;
}
public User getUser() {
return user;
}
}
TestResource.java(回滚正常)
@Path("test")
@Stateless
public class TestResource {
@Inject
private GenericDao dao;
@Context
private UriInfo context;
public TestResource() {
}
@GET
@Produces(MediaType.APPLICATION_JSON)
public User getTeste(@QueryParam("someText") String someText) {
if (someText == null || someText.isEmpty()) {
throw new WebApplicationException("Text is riquired!", Response.Status.BAD_REQUEST);
}
System.out.println("someText: " + someText);
User user = new User();
user.setSomeText(someText);
dao.persist(user);
User user2 = new User();
user2.setSomeText(user.getSomeText()); // "someText" is unique on database
dao.persist(user2); // org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "table_user_sometext_key"
return user;
}
}
如下更改您的class:
@Transactional
public class TestManagedBean extends AbstractManagedBean {
你的方法如下:
@Transactional
public String test() {
我正在开始一个结合 "JSF + EJB + CDI + JAX-RS + GlassFish 4.1"
的项目看了一些书,做了一些研究,终于把这些技术完美的结合起来了。除了事务控制,一切正常。
为了帮助理解问题,我创建了一个测试项目https://github.com/douglasjunior/TestRollbackJsfEjbCdiRest
问题是:在ManagedBean中,没有运行抛出异常时回滚事务
但 JAX-RS 资源中的相同问题完美运行。
在我的示例中,我试图在数据库中插入重复记录。我应该在哪里收到异常 DuplicatedKey。因此,交易应该被逆转,数据库中不应该插入任何东西。
但是当这在ManagedBean中完成时,异常不会回滚事务。第一条记录已提交。
GenericDao.java
@Stateless
public class GenericDao implements Serializable {
@PersistenceContext(unitName = "PU")
private EntityManager em;
public void persist(Object entity) {
getEntityManager().persist(entity);
getEntityManager().flush();
}
}
User.java
@Entity
@Table(name = "table_user")
@XmlRootElement
public class User extends AbstractEntity<Long> {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(length = 100, unique = true)
private String someText;
}
TestManagedBean.java(回滚无效)
@Named(value = "testManagedBean")
@ViewScoped
@TransactionManagement(TransactionManagementType.CONTAINER) // I tested also as BEAN
public class TestManagedBean extends AbstractManagedBean {
@Inject
private GenericDao dao;
private User user;
public TestManagedBean() {
user = new User();
}
@TransactionAttribute(TransactionAttributeType.REQUIRED) // I tested also as REQUIRES_NEW
public String test() {
if (user.getSomeText() == null || user.getSomeText().isEmpty()) {
sendErrorMessage("Text is riquired!");
return null;
}
dao.persist(user);
User user2 = new User();
user2.setSomeText(user.getSomeText()); // "someText" is unique on database
dao.persist(user2); // org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "table_user_sometext_key"
return null;
}
public User getUser() {
return user;
}
}
TestResource.java(回滚正常)
@Path("test")
@Stateless
public class TestResource {
@Inject
private GenericDao dao;
@Context
private UriInfo context;
public TestResource() {
}
@GET
@Produces(MediaType.APPLICATION_JSON)
public User getTeste(@QueryParam("someText") String someText) {
if (someText == null || someText.isEmpty()) {
throw new WebApplicationException("Text is riquired!", Response.Status.BAD_REQUEST);
}
System.out.println("someText: " + someText);
User user = new User();
user.setSomeText(someText);
dao.persist(user);
User user2 = new User();
user2.setSomeText(user.getSomeText()); // "someText" is unique on database
dao.persist(user2); // org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "table_user_sometext_key"
return user;
}
}
如下更改您的class:
@Transactional
public class TestManagedBean extends AbstractManagedBean {
你的方法如下:
@Transactional
public String test() {