我正在尝试使用Primeface JSF Spring Boot做一个示例User CRUD页面。在页面上,我有一个启用LazyLoding的表。我的User对象没有1对N或N对1字段,都是原始字段,在到达时不需要数据库访问或初始化。(所以FetchType.EAGER不会有帮助)
当试图在弹出窗口上显示用户列表中的用户时,出现以下异常:
ERROR j.e.r.webcontainer.jsf.context - javax.faces.component.UpdateModelException:
javax.el.ELException: /ui/admin/users.xhtml @176,64 value="#{userBean.selectedUser.username}":
org.hibernate.LazyInitializationException: could not initialize proxy [com.sampleapp.model.User#121] - no Session
at javax.faces.component.UIInput.updateModel(UIInput.java:868)
at javax.faces.component.UIInput.processUpdates(UIInput.java:751)
at javax.faces.component.UIComponentBase.processUpdates(UIComponentBase.java:1291)
at javax.faces.component.UIComponentBase.processUpdates(UIComponentBase.java:1291)
at org.primefaces.component.outputpanel.OutputPanel.processUpdates(OutputPanel.java:98)
at javax.faces.component.UIComponentBase.processUpdates(UIComponentBase.java:1291)
at org.primefaces.component.dialog.Dialog.processUpdates(Dialog.java:161)
at javax.faces.component.UIForm.processUpdates(UIForm.java:281)
at javax.faces.component.UIComponentBase.processUpdates(UIComponentBase.java:1291)
为什么 JSF 组件尝试从数据库中更新对象以获取 1 比 1 的 STRING 用户名字段?
我在谷歌上搜索了很多,看到一些修复提案可能会在以下期间举行公开会议:
但这些都是反模式,只是治疗症状,仍然会损害性能,并且无法按照设计使用框架。这是错误还是设计问题?
这个问题有合适的解决方案吗?
@Entity
@Table(name = "APP_USER")
public class User extends BaseModel {
private String username;
private String password;
private String firstName;
private String lastName;
private Role role;
private UserState state;
private String email;
}
users.xhtml
<h:form id="userform">
<p:panel id="mainpanel" >
<p:dataTable id="usertbl" var="user" value="#{userBean.userModel}"
paginator="true" rows="#{userBean.userModel.pageSize}"
selectionMode="single" selection="#{userBean.selectedUser}"
paginatorPosition="bottom" lazy="true"
emptyMessage="no data" >
<p:column sortBy="#{user.username}" filterBy="#{user.username}">
<f:facet name="header">
<h:outputText value="Username:" />
</f:facet>
<h:outputText value="#{user.username}" />
</p:column>
.
.
<p:column style="width:4%">
<p:commandButton update=":userform:editUserPopup"
oncomplete="PF('editUserPopupWgt').show()" icon="ui-icon-search" title="View">
</p:commandButton>
</p:column>
<p:column style="width:4%">
<p:commandButton update=":userform:deleteUserDialog"
oncomplete="PF('deleteUserDialogWgt').show()" icon="ui-icon-close" title="View">
</p:commandButton>
</p:column>
</p:dataTable>
.
.
UserBean.java
@Component(value = "userBean")
@Scope("session")
public class UserBean implements Serializable {
private UserLazyDataModel userModel;
private User selectedUser;
@Autowired
UserRepository userRepository;
@PostConstruct
public void initModel() {
userModel = new UserLazyDataModel(userRepository);
}
public void saveSelectedUser() {
userRepository.save(selectedUser);
userModel = new UserLazyDataModel(userRepository);
}
public void deleteUser() {
userRepository.delete(selectedUser);
userModel = new UserLazyDataModel(userRepository);
}
}
UserLazyLoadModel.java
@Log
@Data
public class UserLazyDataModel extends LazyDataModel<User> {
private UserRepository userRepository;
public UserLazyDataModel() {
super.setPageSize(Configurations.PAGE_SIZE);
}
public UserLazyDataModel(UserRepository userRepository) {
super.setPageSize(Configurations.PAGE_SIZE);
this.userRepository = userRepository;
}
@Override
public List<User> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, FilterMeta> filters) {
if (sortField == null) {
sortField = "createTime";
sortOrder = SortOrder.DESCENDING;
}
List<User> users = new ArrayList<User>();
try {
super.setRowCount(userRepository.countEntities(-1, -1, null, sortOrder.name(), filters, null, null).intValue());
users = userRepository.findEntities(first, pageSize, sortField, sortOrder.name(), filters, null, null);
} catch (Exception e) {
log.severe(e.getMessage());
}
return users;
}
@Override
public String getRowKey(User user) {
return user.getId() + "";
}
@Override
public User getRowData(String rowKey) {
try {
return userRepository.getOne(Long.parseLong(rowKey));
} catch (Exception e) {
return null;
}
}
@Override
public void setPageSize(int pageSize) {
super.setPageSize(pageSize);
}
}
懒散负荷时使用的方法(计数
@Data
public class BaseRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements BaseRepository<T, ID> {
private EntityManager entityManager;
public BaseRepositoryImpl(JpaEntityInformation<T, ?> entityInformation, EntityManager entityManager) {
super(entityInformation, entityManager);
this.entityManager = entityManager;
}
// ...
@Override
public Long countEntities(int first, int pageSize, String sortField, String sortOrder, Map<String, FilterMeta> filters, Map<String, String> aliases, Criterion extraCriterion)
throws SecurityException, NoSuchFieldException {
Long count = 0L;
Session session = entityManager.unwrap(Session.class);
try {
Criteria crit = session.createCriteria(getDomainClass());
crit = prepareCriteria(first, pageSize, sortField, sortOrder, filters, aliases, extraCriterion, crit);
crit.setProjection(Projections.rowCount());
if (crit.list() != null) {
count = (Long) crit.list().get(0);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if(session != null){
session.close();
}
}
return count;
}
@Override
public List<T> findEntities(int first, int pageSize, String sortField, String sortOrder, Map<String, FilterMeta> filters, Map<String, String> aliases, Criterion extraCriterion)
throws SecurityException, NoSuchFieldException {
List<T> list = null;
Session session = entityManager.unwrap(Session.class);
try {
Criteria crit = session.createCriteria(getDomainClass());
crit = prepareCriteria(first, pageSize, sortField, sortOrder, filters, aliases, extraCriterion, crit);
crit.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
list = crit.list();
} catch (Exception e) {
e.printStackTrace();
} finally {
if(session != null){
session.close();
}
}
return list;
}
private Criteria prepareCriteria(int first, int pageSize, String sortField, String sortOrder, Map<String, FilterMeta> filters, Map<String, String> aliases, Criterion extraCriterion, Criteria crit)
throws NoSuchFieldException {
if (aliases != null && !aliases.isEmpty()) {
Iterator<Entry<String, String>> iterator = aliases.entrySet().iterator();
while (iterator.hasNext()) {
Entry<String, String> entry = iterator.next();
crit.createAlias(entry.getKey(), entry.getValue(), Criteria.LEFT_JOIN);
}
}
if (extraCriterion != null) {
crit.add(extraCriterion);
}
if (sortField != null && !sortField.isEmpty()) {
if (!sortOrder.equalsIgnoreCase("UNSORTED")) {
if (sortOrder.equalsIgnoreCase("ASCENDING")) {
crit = crit.addOrder(Order.asc(sortField));
} else {
crit = crit.addOrder(Order.desc(sortField));
}
}
}
if (filters != null && !filters.isEmpty()) {
Iterator<Entry<String, FilterMeta>> iterator = filters.entrySet().iterator();
while (iterator.hasNext()) {
Entry<String, FilterMeta> entry = iterator.next();
Class<?> type = getDomainClass().getDeclaredField(entry.getKey()).getType();
if(entry.getValue().getFilterValue() == null) {
continue;
}
try {
if (BigDecimal.class.isAssignableFrom(type)) {
crit = crit.add(Restrictions.eq(entry.getKey(), new BigDecimal(entry.getValue().getFilterValue() + "")));
} else if (type.isEnum() || Number.class.isAssignableFrom(type) || Double.class.isAssignableFrom(type)) {
crit = crit.add(Restrictions.eq(entry.getKey(), type.getDeclaredMethod("valueOf", String.class).invoke(null, entry.getValue().getFilterValue())));
} else if (type.getCanonicalName().indexOf(Configurations.COMPANY_JAVA_PACKAGE) != -1) {
SimpleExpression idEq = Restrictions.eq(entry.getKey() + ".id", Long.parseLong(entry.getValue().getFilterValue() + ""));
crit = crit.add(idEq);
} else {
crit = crit.add(Restrictions.like(entry.getKey(), String.valueOf(entry.getValue().getFilterValue()), MatchMode.START));
}
} catch (Exception ex) {
}
}
}
if (first != -1) {
crit = crit.setFirstResult(first);
}
if (pageSize != -1) {
crit = crit.setMaxResults(pageSize);
}
return crit;
}
}
在这个问题上,LazyLoding似乎是在转移注意力。问题在于如何调用对话框。jsf片段包括dataTable上的行选择,但对话框是由按钮调用的。两者可能不同步。相反,在调用对话框时设置当前行选择,如下所示:
html prettyprint-override"><p:dataTable id="usertbl" var="user" value="#{userBean.userModel}" lazy="true"
paginator="true" rows="#{userBean.userModel.pageSize}"
paginatorPosition="bottom" emptyMessage="no data" >
.
.
<p:column style="width:4%">
<p:commandButton update=":userform:editUserPopup"
oncomplete="PF('editUserPopupWgt').show()"
icon="ui-icon-search" title="View">
<f:setPropertyActionListener value="#{user}"
target="#{userBean.selectedUser}"/>
</p:commandButton>
</p:column>
此问题导致Hibernate“无会话”错误的确切原因仍然是一个谜。
问题内容: 我有2台物理服务器,我的Web应用程序命中该服务器由负载均衡器管理。我总是得到- org.hibernate.LazyInitializationException:无法初始化代理-没有会话 当其中一台服务器受到攻击而另一台服务器运行平稳而没有任何问题时。我有一个由应用程序启用和管理的本地托管缓存存储。仅当尝试从一个表访问一个特定的列时,才会发生此异常。不管选择哪个服务器,其余的操作都
问题内容: 我试图从数据库中的对象进行简单加载,但出现错误“无法初始化代理-没有会话”,知道吗?谢谢 问题答案: 尝试添加到validate方法: 发生的事情是,因为没有注释,所以没有与该方法关联的会话,并且每个查询都将在其自己的会话中运行,该会话随后将立即关闭。 该方法始终返回一个代理,与之不同(请参阅此处,了解load与get之间的差异)。 因此,返回了代理,但是由于缺少代理,因此立即关闭了创
我试图从DB中的一个对象做一个简单的加载,但是我得到的错误是“Could not initialize proxy-no session”,有什么想法吗?谢谢
问题内容: 对数据库有以下查询: 在获取employee.address.street,employee.address.houseNumber或employee.address.city时,它将失败,但以下情况除外: 员工映射: 地址映射: 对于其他类(办公室,公司等),这是绝对正常的。如果注释,则在jsp应用程序中加载地址字段的行将正常工作。怎么了?顺便说一下,尽管有异常,它仍显示有关js
抱歉,如果我的帖子是重复的,但我不能从另一个主题解决我的问题,所以我创建了这个主题。希望有人帮助我。我用的是Hibernate,JSF和Glassfish。 这是我的完整代码 CusterBean(请求范围) 顾客道 xhtml 我得到这个错误: SEVERE:javax.el.ELException: /admin/customer_list.xhtml@68,106 value="#{cust
问题内容: 我得到以下异常: 当我尝试从以下几行拨打电话时: 我首先实现了这样的方法: 并得到了例外。然后一位朋友建议我始终测试该会话并获取当前会话,以避免出现此错误。所以我这样做: 但仍然会出现相同的错误。我已经阅读了很多有关此错误的内容,并找到了一些可能的解决方案。其中之一是将lazyLoad设置为false,但是不允许这样做,因此建议我控制会话 问题答案: 这是错误的,因为您在提交事务时将会