现在我正在使用REST API为智能平板制作项目。我正在使用Spring,Spring,Hibernate,MySql。 现在我已经为用户创建了实体,当我尝试通过我的API检索用户时,我遇到了这样的异常:
无法编写JSON:无法初始化代理 - 无会话;
我找到了解决方案如何通过下一个链接阻止此异常
JsonMappingException: could not initialize proxy - no Session
@Proxy(lazy = false) - 解决了我的问题,但我真的不明白为什么当我试图让用户在Spring控制器中关闭会话时?
当我坚持用户时 - 没有这样的例外!然而,相同的服务用于持久化和获取对象。怎么会这样?
我的应用程序的逻辑是从web.xml开始的。我正在使用
org.springframework.web.servlet.DispatcherServlet
此servlet映射请求并传输到我的控制器。我正在使用spring json消息转换器
org.springframework.http.converter.json.MappingJackson2HttpMessageConverter
spring的dispatcherServlet的配置是
<mvc:annotation-driven/>
<context:component-scan base-package="com.smartcore.controllers.mysql"/>
<!-- Configure to plugin JSON as request and response in method handler -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="jsonMessageConverter"/>
</list>
</property>
</bean>
<!-- Configure bean to convert JSON to POJO and vice versa -->
<bean id="jsonMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
</bean>
我的实体很简单,与其他实体没有任何关系
@Entity
@Table(name = "User")
//@Proxy(lazy = false)
public class UserMySql {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "user_id")
private Long id;
@Column(name = "name")
private String name;
@Column(name = "surname")
private String surname;
@Column(name = "email")
private String eMail;
@Column(name = "login")
private String login;
@Column(name = "password")
private String password;
public UserMySql() {}
public UserMySql(String name, String surname, String login, String password, String eMail) {
this.name = name;
this.surname = surname;
this.login = login;
this.password = password;
this.eMail = eMail;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSurname() {
return surname;
}
public void setSurname(String surname) {
this.surname = surname;
}
public String getLogin() {
return login;
}
public void setLogin(String login) {
this.login = login;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String geteMail() {
return eMail;
}
public void seteMail(String eMail) {
this.eMail = eMail;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("UserMySql [id=");
sb.append(id);
sb.append(", name=");
sb.append(name);
sb.append(", surname=");
sb.append(surname);
sb.append(", eMail=");
sb.append(eMail);
sb.append(", login=");
sb.append(login);
sb.append(", password=");
sb.append(password);
sb.append("]");
return sb.toString();
}
控制器代码
@RestController
public class MySqlUserAccountController {
private UserMySqlService userMySqlService;
@Autowired
public MySqlUserAccountController( UserMySqlService userMySqlService) {
this.userMySqlService = userMySqlService;
};
@GetMapping("/user/{userId}")
public @ResponseBody UserMySql findUserById(@PathVariable("userId") Long userId) {
return userMySqlService.getUserById(userId);
}
@PostMapping("/user/add")
public void addUser(@RequestBody UserMySql user){
userMySqlService.save(user);
}
}
我正在使用Spring数据,它使用了JpaRepository getOne(id)的原生methot来检索用户。
return this.userRepo.getOne(id);
我也找到了使用
的解决方案org.springframework.orm.hibernate5.support.OpenSessionInViewFilter
但是配置过滤器和添加bean会话没有帮助。
添加了web.xml
<servlet-mapping>
<servlet-name>dispServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<filter>
<filter-name>OpenSessionInViewFilter</filter-name>
<filter-class>org.springframework.orm.hibernate5.support.OpenSessionInViewFilter</filter-class>
<!-- Replace with hibernate3, hibernate4 or hibernate5 depending on the
hibernate version one uses -->
</filter>
添加了application-context.xml
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="packagesToScan" value="com.smartcore.entities.mysqldb"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
实施的最佳方式是什么?如果使用@Proxy(lazy = false) - 导致从任何对象的实时链接包含它,它是否会导致内存消耗增加?
在之前的回答中,我没有找到控制器中会话无效的原因。你能否详细描述一下原因是什么?
更新
我仍然没有解决延迟加载的问题。我找到了这里描述的解决方案
http://blog.pastelstudios.com/2012/03/12/spring-3-1-hibernate-4-jackson-module-hibernate/
但在我的情况下,它不起作用,我不明白为什么?
web.xml config
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<!-- Processes application requests -->
<servlet>
<servlet-name>dispServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/dispatcher-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- needed for ContextLoaderListener -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/spring/root-context.xml</param-value>
</context-param>
<!-- Bootstraps the root web application context before servlet initialization -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
dispatcher-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<context:component-scan base-package="com.smartcore.controllers.mysql" />
<mvc:annotation-driven>
<mvc:message-converters>
<bean
class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="com.smartcore.mappers.json.HibernateAwareObjectMapper" />
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
</beans>
HibernateAwareObject
public class HibernateAwareObjectMapper extends ObjectMapper {
private static final long serialVersionUID = 5371945173448137189L;
public HibernateAwareObjectMapper() {
this.registerModule(new Hibernate5Module());
}
}
在日志中,我看不到我的自定义对象会被调用。它看起来像配置的东西。
2017-11-17 13:58:50 DEBUG DispatcherServlet:891 - DispatcherServlet 名字&#39; dispServlet&#39;处理GET请求 [/ Smart_Core_Control / user / 3] 2017-11-17 13:58:50 DEBUG RequestMappingHandlerMapping:313 - 查找路径的处理程序方法 / user / 3 2017-11-17 13:58:50 DEBUG RequestMappingHandlerMapping:320 - 返回处理程序方法[public com.smartcore.entities.mysqldb.UserMySql com.smartcore.controllers.mysql.MySqlUserAccountController.findUserById(java.lang.Long中)] 2017-11-17 13:58:50 DEBUG DefaultListableBeanFactory:255 - 返回 单例bean的缓存实例&#39; mySqlUserAccountController&#39; 2017-11-17 13:58:50 DEBUG DispatcherServlet:979 - Last-Modified值 for [/ Smart_Core_Control / user / 3]是:-1 2017-11-17 13:58:50 DEBUG TransactionalRepositoryProxyPostProcessor $ CustomAnnotationTransactionAttributeSource:354 - 添加交易方法&#39; getOne&#39; with属性:PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly; &#39;&#39; 2017年11月17日 13:58:50 DEBUG DefaultListableBeanFactory:255 - 返回缓存 单例bean的实例&#39; transactionManager&#39; 2017-11-17 13:58:50 DEBUG JpaTransactionManager:368 - 使用名称创建新事务 [org.springframework.data.jpa.repository.support.SimpleJpaRepository.getOne]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,只读; &#39;&#39; 2017年11月17日 13:58:50 DEBUG JpaTransactionManager:391 - 打开新的EntityManager [SessionImpl(PersistenceContext [entityKeys = [],collectionKeys = []]; ActionQueue [插入= ExecutableList {大小= 0} updates = ExecutableList {size = 0} deletions = ExecutableList {size = 0} orphanRemovals = ExecutableList {大小= 0} collectionCreations = ExecutableList {大小= 0} collectionRemovals = ExecutableList {大小= 0} collectionUpdates = ExecutableList {大小= 0} collectionQueuedOps = ExecutableList {大小= 0} 对于JPA事务2017-11-17,unresolvedInsertDependencies = null])] 13:58:50 DEBUG DriverManagerDataSource:143 - 创建新的JDBC DriverManager连接到[jdbc:mysql:// localhost:3306 / core_data] Fri Nov 17 13:58:50 EET 2017 WARN:在没有的情况下建立SSL连接 不建议使用服务器的身份验证。根据MySQL 5.5.45 +,5.6.26 +和5.7.6+要求如果未设置显式选项,则必须默认建立SSL连接。为了合规 使用SSL的现有应用程序验证verifyServerCertificate 属性设置为“错误”。您需要显式禁用SSL 通过设置useSSL = false,或设置useSSL = true并为其提供truststore 服务器证书验证。 2017-11-17 13:58:50 DEBUG DataSourceUtils:176 - 设置JDBC连接 只读2017-11-17只读[com.mysql.cj.jdbc.ConnectionImpl@29154676] 13:58:50 DEBUG TransactionImpl:55 - 2017-11-17 13:58:50开始调试 JpaTransactionManager:423 - 将JPA事务公开为JDBC 交易 [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@34dcedf7] 2017-11-17 13:58:50 DEBUG JpaTransactionManager:739 - 启动 交易提交2017-11-17 13:58:50 DEBUG JpaTransactionManager:531 - 在EntityManager上提交JPA事务[SessionImpl(PersistenceContext [entityKeys = [],collectionKeys = []]; ActionQueue [insertions = ExecutableList {size = 0} updates = ExecutableList {size = 0} deletions = ExecutableList {size = 0} orphanRemovals = ExecutableList {大小= 0} collectionCreations = ExecutableList {大小= 0} collectionRemovals = ExecutableList {大小= 0} collectionUpdates = ExecutableList {大小= 0} collectionQueuedOps = ExecutableList {大小= 0} unresolvedInsertDependencies = null])] 2017-11-17 13:58:50 DEBUG TransactionImpl:66 - 承诺2017-11-17 13:58:50 DEBUG DataSourceUtils:233 - 重置JDBC连接的只读标志 [com.mysql.cj.jdbc.ConnectionImpl@29154676] 2017-11-17 13:58:50调试 JpaTransactionManager:622 - 关闭JPA EntityManager [SessionImpl(PersistenceContext [entityKeys = [],collectionKeys = []]; ActionQueue [插入= ExecutableList {大小= 0} updates = ExecutableList {size = 0} deletions = ExecutableList {size = 0} orphanRemovals = ExecutableList {大小= 0} collectionCreations = ExecutableList {大小= 0} collectionRemovals = ExecutableList {大小= 0} collectionUpdates = ExecutableList {大小= 0} collectionQueuedOps = ExecutableList {大小= 0} 交易2017-11-17之后的unresolvedInsertDependencies = null])] 13:58:50 DEBUG EntityManagerFactoryUtils:419 - 关闭JPA EntityManager 2017-11-17 13:58:50调试 ExceptionHandlerExceptionResolver:137 - 解决异常 handler [public com.smartcore.entities.mysqldb.UserMySql com.smartcore.controllers.mysql.MySqlUserAccountController.findUserById(java.lang.Long中)〕: org.springframework.http.converter.HttpMessageNotWritableException: 无法编写JSON:无法初始化代理 - 没有会话;嵌套 异常是com.fasterxml.jackson.databind.JsonMappingException: 无法初始化代理 - 没有会话2017-11-17 13:58:50调试 ResponseStatusExceptionResolver:137 - 解决处理程序中的异常 [public com.smartcore.entities.mysqldb.UserMySql com.smartcore.controllers.mysql.MySqlUserAccountController.findUserById(java.lang.Long中)〕: org.springframework.http.converter.HttpMessageNotWritableException: 无法编写JSON:无法初始化代理 - 没有会话;嵌套 异常是com.fasterxml.jackson.databind.JsonMappingException: 无法初始化代理 - 没有会话2017-11-17 13:58:50调试 DefaultHandlerExceptionResolver:137 - 解决处理程序中的异常 [public com.smartcore.entities.mysqldb.UserMySql com.smartcore.controllers.mysql.MySqlUserAccountController.findUserById(java.lang.Long中)〕: org.springframework.http.converter.HttpMessageNotWritableException: 无法编写JSON:无法初始化代理 - 没有会话;嵌套 异常是com.fasterxml.jackson.databind.JsonMappingException: 无法初始化代理 - 没有会话2017-11-17 13:58:50警告 DefaultHandlerExceptionResolver:380 - 无法写入HTTP消息: org.springframework.http.converter.HttpMessageNotWritableException: 无法编写JSON:无法初始化代理 - 没有会话;嵌套 异常是com.fasterxml.jackson.databind.JsonMappingException: 无法初始化代理 - 没有会话2017-11-17 13:58:50调试 DispatcherServlet:1076 - Null ModelAndView返回 DispatcherServlet,名称为&#39; dispServlet&#39;:假设为HandlerAdapter 完成请求处理2017-11-17 13:58:50 DEBUG DispatcherServlet:1004 - 成功完成请求
有什么不对?
答案 0 :(得分:1)
您正在通过@Responsebody
返回一个对象,您返回的userObject是代理对象,因为您使用的是“LAZY”提取。在控制器层中,不再有活动事务来获取实体对象的属性。
您可以EAGER
获取对象,也可以将子属性声明为Transient
。