事务性 CDI bean 未将记录提交到数据库
Transactional CDI bean not committing record to database
我正在尝试使用 JAX-RS 构建一个简单的 REST 服务,它将在数据库 table 上执行标准的 CRUD 操作。我能够成功查询记录,但无法插入新记录。我没有收到任何错误,当我在调试模式下单步执行代码时,一切看起来都很好。我在 Glassfish 4.1 容器中使用事务性 CDI bean 运行。
感觉就是一直没有提交事务。我对 Java EE 很陌生,但我的理解是,由于 bean 是事务性的,容器应该为我处理提交。有人知道为什么不是吗?
@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>
当您使用 JTA 事务管理时,创建和管理数据库连接的责任由应用程序服务器提供,而不是您的应用程序。
基本上,您必须在 GlassFish 服务器实例中配置数据源,而不是直接在 persistence.xml 中通过属性配置:
- 在您的 GlassFish 服务器实例
中配置连接池和数据源 JNDI 名称
- Link 通过
<jta-data-source>
元素 persistence.xml 中的数据源配置
请查看此答案以获取更多详细信息:
您确定没有混用两个框架吗? RecipeResource 有一个来自 JavaEE 框架的 @Path 注解,而 @Transactional 注解来自 Spring 框架,我认为你应该将其替换为 @TransactionAttribute 这是等效的 JavaEE 注释。
查看 here 以了解 Spring JavaEE
中事务之间的详细信息
我在 weblogic 12.2.1 上试过你的应用程序,它成功地插入到数据库中,我对事务没有任何问题。
这是我的代码。
RecipeResource
class(我修改了 @Path
以通过网络浏览器调用它,还手动实例化了 Recipe
):
@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";
}
}
Recipe
class 与您的相同,只是我对架构进行了评论:
@Entity
@Table(name="RECIPES") //, schema="COOKBOOK")
public class Recipe {
}
我的persistence.xml
(我使用的是内存数据库):
<?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>
所以您的问题可能来自应用程序服务器。
您是否尝试在另一台服务器上部署您的网络应用程序?
我正在尝试使用 JAX-RS 构建一个简单的 REST 服务,它将在数据库 table 上执行标准的 CRUD 操作。我能够成功查询记录,但无法插入新记录。我没有收到任何错误,当我在调试模式下单步执行代码时,一切看起来都很好。我在 Glassfish 4.1 容器中使用事务性 CDI bean 运行。
感觉就是一直没有提交事务。我对 Java EE 很陌生,但我的理解是,由于 bean 是事务性的,容器应该为我处理提交。有人知道为什么不是吗?
@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>
当您使用 JTA 事务管理时,创建和管理数据库连接的责任由应用程序服务器提供,而不是您的应用程序。
基本上,您必须在 GlassFish 服务器实例中配置数据源,而不是直接在 persistence.xml 中通过属性配置:
- 在您的 GlassFish 服务器实例 中配置连接池和数据源 JNDI 名称
- Link 通过
<jta-data-source>
元素 persistence.xml 中的数据源配置
请查看此答案以获取更多详细信息:
您确定没有混用两个框架吗? RecipeResource 有一个来自 JavaEE 框架的 @Path 注解,而 @Transactional 注解来自 Spring 框架,我认为你应该将其替换为 @TransactionAttribute 这是等效的 JavaEE 注释。
查看 here 以了解 Spring JavaEE
中事务之间的详细信息我在 weblogic 12.2.1 上试过你的应用程序,它成功地插入到数据库中,我对事务没有任何问题。
这是我的代码。
RecipeResource
class(我修改了 @Path
以通过网络浏览器调用它,还手动实例化了 Recipe
):
@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";
}
}
Recipe
class 与您的相同,只是我对架构进行了评论:
@Entity
@Table(name="RECIPES") //, schema="COOKBOOK")
public class Recipe {
}
我的persistence.xml
(我使用的是内存数据库):
<?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>
所以您的问题可能来自应用程序服务器。
您是否尝试在另一台服务器上部署您的网络应用程序?