I'm starting a project that combines "JSF + EJB + CDI + JAX-RS + GlassFish 4.1"
After reading some books and make some research, I managed to make the perfect integration of these technologies. Everything works fine except the transaction control.
To help the understanding of the problem, I created a test project https://github.com/douglasjunior/TestRollbackJsfEjbCdiRest
The problem is: In ManagedBean, is not running Rollback the transaction when an exception is thrown.
But the same question in a JAX-RS resource, works perfectly.
In my example, I am trying to insert a duplicate record in the database. Where should I receive the exception DuplicatedKey. Therefore, the transaction should be reversed and nothing should be inserted in the database.
But when this is done in ManagedBean, the exception does not rollback the transaction. The first record is committed.
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 (rollback not work)
@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 (rollback works fine)
@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;
}
}
Change your class as below:
@Transactional
public class TestManagedBean extends AbstractManagedBean {
And your method as below:
@Transactional
public String test() {