Search code examples
jpajakarta-eecdi

Transactional CDI bean not committing record to database


I am trying to build a simple REST service, using JAX-RS, that will perform the standard CRUD operations on a database table. I am able to successfully query for records, but I cannot insert new ones. I do not get any errors and when I step through the code in debug mode everything looks good. I am using a transactional CDI bean running in a Glassfish 4.1 container.

It feels like it's just never committing the transaction. I'm pretty new to Java EE, but my understanding is that since the bean is transactional the container should handle the commit for me. Anyone know why it is not?

@Path("/recipes")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public class RecipeResource {
    @Inject
    RecipesService recipesService;

    @GET
    public List<Recipe> getRecipes() {
        return recipesService.getAllRecipes();
    }

    @POST
    public void addRecipse(Recipe recipe) {
        recipesService.addRecipe(recipe);
    }

}

public class RecipesService {
    @PersistenceContext(unitName="PANTRYDB", type=PersistenceContextType.TRANSACTION)
    EntityManager em;

    public RecipesService () {

    }

    public List<Recipe> getAllRecipes () {
        List<Recipe> recipes = null;

        try {
            TypedQuery<Recipe> typedQuery = em.createQuery("select r from Recipe r", Recipe.class);

            recipes = typedQuery.getResultList();
        } catch (Exception e) {
            System.out.println(e);
        }

        return recipes;
    }

    @Transactional
    //This is the method that seems to not commit it's transaction
    //The Recipe object is populated correctly, and the persist() doesn't 
    //throw any errors
    public void addRecipe(Recipe recipe) {
        try {
            em.persist(recipe);
        } catch (Exception e) {
            System.out.println(e);
        }
    }

}

@Entity
@Table(name="RECIPES", schema="COOKBOOK")
public class Recipe {
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private int id;

    @Column
    private String name;

    @Column(name="CREATED_DATE")
    private Calendar createdDate;

    @Column(name="LAST_MADE_DATE")
    private Calendar lastMadeDate;

    @Column
    private String description;

    @Column
    private String notes;

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Calendar getCreatedDate() {
        return createdDate;
    }

    public void setCreatedDate(Calendar createdDate) {
        this.createdDate = createdDate;
    }

    public Calendar getLastMadeDate() {
        return lastMadeDate;
    }

    public void setLastMadeDate(Calendar lastMadeDate) {
        this.lastMadeDate = lastMadeDate;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public String getNotes() {
        return notes;
    }

    public void setNotes(String notes) {
        this.notes = notes;
    }

    @Override
    public String toString() {
        return name;
    }
}

Persistence.xml:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
    <persistence-unit name="PANTRYDB" transaction-type="JTA">
    <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
        <class>com.domain.Recipe</class>
        <properties>
            <property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.EmbeddedDriver" />      
            <property name="javax.persistence.jdbc.url" value="jdbc:derby:/Users/development/eclipse/ws_playground/databases/pantry_db/PANTRYDB" />
            <property name="hibernate.dialect" value="org.hibernate.dialect.DerbyDialect"/>
            <property name="javax.persistence.jdbc.user" value=""/>
            <property name="javax.persistence.jdbc.password" value=""/>
        </properties>
    </persistence-unit>
</persistence>

Solution

  • I tried your application on a weblogic 12.2.1 and it successfully inserted in database and i do not have any problem with transaction.

    Here is my code.

    RecipeResource class (I modified the @Path to call it via web browser and also instanciated the Recipe manually):

    @Path("/recipes")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    
    public class RecipeResource {
    
        @Inject
        RecipesService recipesService;
    
        @GET
        @Path("get")
        public List<Recipe> getRecipes() {
            return recipesService.getAllRecipes();
        }
    
        @GET
        @Path("add")
        public String addRecipse() {
            Recipe recipe = new Recipe();
            recipe.setDescription("desc");
            recipesService.addRecipe(recipe);
            return "OK";
        }
    
    }
    

    The Recipe class is same as yours except that i commented the schema :

    @Entity
    @Table(name="RECIPES") //, schema="COOKBOOK")
    public class Recipe {
    }
    

    My persistence.xml (I'm using in-memory database):

    <?xml version="1.0" encoding="UTF-8"?>
    <persistence xmlns="http://java.sun.com/xml/ns/persistence"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xsi:schemaLocation="http://java.sun.com/xml/ns    /persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
                 version="2.0">
    
       <persistence-unit name="PANTRYDB" transaction-type="JTA">
                <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <jta-data-source>jdbc/__default</jta-data-source>
        <class>org.jvi.webservice.transactional.db.Recipe</class>
        <properties>
            <!--<property name="eclipselink.ddl-generation" value="create-tables"/>-->
            <property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>
            <property name="eclipselink.logging.level" value="FINE"/>
            <property name="eclipselink.logging.level.sql" value="FINE"/>
            <property name="eclipselink.logging.parameters" value="true"/>
            <property name="eclipselink.logging.logger" value="DefaultLogger"/>
            <property name="eclipselink.cache.shared.default" value="false"/>
        </properties>
    </persistence-unit>
    

    So your problem might come from the Application Server.

    Did you try to deploy your webapp on another server?