为什么Wildfly应用重启后Hibernate查询不到之前持久化的数据?
问题现象
我正在学习JPA、EJB、Servlet相关技术,大部分功能运行正常,但无论怎么操作,我都无法在Wildfly服务器重启应用后,让Hibernate查询到我之前持久化的任何数据。
这个问题全程没有任何错误提示,日志中也没有相关输出,而且我调用实体管理器的.contains方法检查对象,返回结果为true,说明对象确实存在于实体管理器中。
已尝试的排查手段
- 手动添加
flush()调用 - 将实体类显式添加到
persistence.xml中(按规则框架应该可以自动扫描到) - 修改
javax.persistence.schema-generation.database.action配置为create、drop-and-create、drop、none,均没有效果
相关配置与代码
persistence.xml
<?xml version="1.0" encoding="UTF-8"?> <persistence version="2.2" 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_2.xsd"> <persistence-unit name="EJBColis"> <class>jpa.Colis</class> <exclude-unlisted-classes>false</exclude-unlisted-classes> <properties> <property name="javax.persistence.schema-generation.database.action" value="create"/> </properties> </persistence-unit> </persistence>
EJBColis.java
package ejb; import java.util.LinkedList; import java.util.List; import javax.ejb.LocalBean; import javax.ejb.Stateless; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.TypedQuery; import jpa.Colis; import jpa.Mesure; import jpa.Position; @Stateless @LocalBean public class EJBColis { @PersistenceContext private EntityManager em; /** * 无参构造函数(必填) */ public EJBColis() { } public Colis addColis(double poid,double valeur,String origin,String destination,Position p ) { Colis m = new Colis(poid, valeur, origin, destination, p); em.persist(m); em.flush(); em.refresh(m); return m; } public Colis findColis(long id) { Colis m = em.find(Colis.class, id); return m; } public Position changePosition(long ColisId,double longitude,double lat,String origin,String destination) { Position m = new Position(longitude,lat, origin, destination); Colis c = findColis(ColisId); c.setPosition(m); em.persist(c); em.flush(); return m; } public Position findPosition(long id) { Position m = em.find(Position.class, id); return m; } }
addColisServlet.java
package servlet; import java.io.IOException; import javax.ejb.EJB; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import ejb.EJBColis; import jpa.Colis; import jpa.Mesure; import jpa.Position; /** * AddColisServlet实现类 */ @WebServlet("/AddColisServlet") public class AddColisServlet extends HttpServlet { private static final long serialVersionUID = 1L; // EJB引用注入 @EJB private EJBColis ejb; /** * @see HttpServlet#HttpServlet() */ public AddColisServlet() { super(); } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { double Poid = Double.parseDouble(request.getParameter("poid")); double valeur = Double.parseDouble(request.getParameter("valeur")) ; String origine = request.getParameter("origine"); String destination = request.getParameter("destination"); Position position = null; Colis m = ejb.addColis(Poid, valeur, origine, destination, position); // 将包裹信息存入请求 request.setAttribute("Colis",m); // 转发到展示JSP页面 request.getRequestDispatcher("/showColis.jsp").forward(request, response); } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
调用addColisServlet的前端页面
<!DOCTYPE html> <html> <head> <meta charset="ISO-8859-1"> <title>包裹管理</title> <link rel="stylesheet" type="text/css" href="css/base.css" > </head> <body> <h1>包裹管理</h1> <h2>查询包裹物流:</h2> <form action="ShowColisServlet" method="post"> ID : <input type="number" name="ID"> <input type="submit" value="提交"> </form> <h2>创建新包裹</h2> <form action="AddColisServlet" method="post"> 重量 : <input type="number" name="poid"> 价值 : <input type="number" name="valeur"> 始发地 : <input type="text" name="origine"> 目的地 : <input type="text" name="destination"> <input type="submit" value="提交"> </form> <h2>修改包裹位置:</h2> <form action="ModifColisServlet" method="post"> ID : <input type="text" name="ID"> 纬度 : <input type="number" name="lat"> 经度 : <input type="number" name="long"> 当前位置 : <input type="text" name="emplacement"> 状态 : <input type="text" name="etat"> <input type="submit" value="提交"> </form> </body> </html>
解决方案
根因1:默认使用了Wildfly内存数据库
Wildfly默认集成的嵌入式H2数据库默认是内存存储模式,服务重启后所有内存数据会自动清空,你没有显式配置持久化数据源,所以写入的数据重启后自然丢失。
根因2:表生成策略配置错误
你当前persistence.xml中javax.persistence.schema-generation.database.action配置值为create,这个配置的含义是每次应用启动都会删除原有表、重新创建表结构,就算你用了持久化存储的数据库,启动后原有数据也会被清空。
修复步骤
- 修改表生成策略:开发阶段可以改成
update(仅同步表结构变更,不会清空数据),生产环境必须改成none,示例配置:
<property name="javax.persistence.schema-generation.database.action" value="update"/>
- 配置持久化数据源:可以将H2改成文件存储模式,或者配置MySQL、PostgreSQL等独立数据库作为数据源,在
persistence-unit节点中指定配置好的数据源JNDI名称即可,示例:
<persistence-unit name="EJBColis" transaction-type="JTA"> <jta-data-source>java:/MySqlDS</jta-data-source> <!-- 其余原有配置保持不变 --> </persistence-unit>
- 代码优化:更新包裹位置的
changePosition方法中,查询出来的Colis已经是持久态对象,不需要重复调用persist,直接修改属性后flush即可。
内容的提问来源于stack exchange,提问作者water thief
相关产品推荐
相关产品推荐

