spring - 通过弹簧数据和 f:viewAction 加载实体然后访问其属性之一时出现延迟加载异常
问题描述
我正在为我的项目使用 JSF、spring boot 和 spring 数据。我正在尝试编辑现有对象。为此,我将对象 id 作为参数传递给视图,然后指定在数据库中查找并加载对象的 f:viewAction。我得到的是“无法初始化代理..没有会话” Lazyloadexception 稍后,在不同的方法中,当在该 SAME 对象上调用简单的 getter 时(我通过 id 获得的相同对象,而不是内部的对象收藏或任何东西)。
我试过了:
- 将 @Transactional 放在 JSF bean 类和 DAO 类上
- 将 @Transactional 放在从 f:viewAction 调用的 onload 方法和对象的 getter 方法上。
- 将 spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true 放在我的 application.properties 中(是的,我知道,反模式,但是使用反模式的工作应用程序比根本不工作的应用程序要好。无论如何,它什么也没做)
- 将 @EnableTransactionManagement 放在扩展 SpringBootServletInitializer 的设置类上
- 将 @EnableTransactionManagement 放在 PersistenceConfig 类上
基本上,经过数小时谷歌搜索此错误后,我能找到的每一个“解决方案”。我不确定此时该怎么做。我感觉这与加载顺序和 f:viewAction 方法中的 DAO 调用有关。也许这使用了一个不同的会话,任何通过方法访问对象的东西?
抱歉包含了很多部分,我只是不知道根本原因在哪里。我怀疑这是某个地方的弹簧数据、JPA 和 JSF 的相互作用。
当我尝试使用 @PostConstruct 注释进行数据库调用以初始化方法中的对象时,我遇到了同样的错误。我“解决”(阅读:已修补)的方式是在 getter 内部进行数据库调用,这是愚蠢的( if(myobject == null) 进行 db 调用。else return myobject)
错误:
org.hibernate.LazyInitializationException: could not initialize proxy [mypackage.recipe.RecipeItem#8] - no Session
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:169)
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:309)
at org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor.intercept(ByteBuddyInterceptor.java:45)
at org.hibernate.proxy.ProxyConfiguration$InterceptorDispatcher.intercept(ProxyConfiguration.java:95)
at mypackage.recipe.RecipeItem$HibernateProxy$G4ytmgbe.getDisplayName(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
@EnableJpaRepositories(basePackages = "mypackage")
@EnableTransactionManagement
public class PersistenceConfig
{
// nothing here
}
@SpringBootApplication(scanBasePackages={"mypackage"})
@EnableJpaRepositories(basePackages = "mypackage")
@EnableTransactionManagement
public class SpringBootTomcatApplication extends SpringBootServletInitializer {
@Bean
public JpaVendorAdapter jpaVendorAdapter() {
HibernateJpaVendorAdapter bean = new HibernateJpaVendorAdapter();
bean.setDatabase(Database.MYSQL);
bean.setGenerateDdl(true);
bean.setShowSql(true);
return bean;
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource,
JpaVendorAdapter jpaVendorAdapter) {
LocalContainerEntityManagerFactoryBean bean = new LocalContainerEntityManagerFactoryBean();
bean.setDataSource(dataSource);
bean.setJpaVendorAdapter(jpaVendorAdapter);
bean.setPackagesToScan("mypackage");
return bean;
}
@Bean
public JpaTransactionManager transactionManager(EntityManagerFactory emf) {
return new JpaTransactionManager(emf);
}
}
@Component
@Transactional
@Scope("session")
public class EditRecipeItemControllerBean extends RecipeItemControllerBean
{
private Logger log = LoggerFactory.getLogger(this.getClass());
@Transactional
public void onload() {
Map<String,String> params = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();
String recipeId = params.get("recipeId");
log.info("from context recipe id: " + recipeId);
//TODO error handling
setRecipe(recipeDao.getOne(Long.valueOf(recipeId)));
}
public void submit() {
super.save();
}
}
public class RecipeItemControllerBean implements Serializable
{
private Logger log = LoggerFactory.getLogger(this.getClass());
@Autowired
AuthenticationFacade authenticationFacade;
@Autowired
RecipeItemDao recipeDao;
private RecipeItem recipe;
/**
* @return the recipe
*/
public RecipeItem getRecipe()
{
return recipe;
}
/**
* @param recipe the recipe to set
*/
public void setRecipe(RecipeItem recipe)
{
this.recipe = recipe;
}
public void save() {
log.debug("Saving recipe: " + recipe);
recipeDao.save(recipe);
}
}
@Entity
@Table(name = "recipe_item")
@NamedQueries(
{
// a bunch of named queries here
})
public class RecipeItem extends ClientSpecific
{
@Column(length = 256)
private String description;
@Lob
@Column(name = "full_info", length = 65535)
private String fullInfo;
@Column(name = "thumbnail_uri", length = 1024)
private String thumbnailUri;
@Lob
@Column(name = "preparation_instructions", length = 65535)
private String preparationInstructions;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "recipeItem", fetch = FetchType.EAGER)
private Collection<RecipeItemIngredients> recipeItemIngredients;
public RecipeItem()
{
}
//getters and setters
}
@MappedSuperclass
public abstract class ClientSpecific extends NamedBaseEntity
{
@JoinColumn(name = "client_id", referencedColumnName = "id")
@ManyToOne
private Client client;
public ClientSpecific()
{
}
public ClientSpecific(Long id)
{
super(id);
}
public ClientSpecific(Long id, Client client)
{
super(id);
this.client = client;
}
// getters and setters clipped for brevity
}
@MappedSuperclass
public abstract class NamedBaseEntity extends BaseEntity
{
@Size(max = 64)
@Column(name = "display_name")
private String displayName;
public NamedBaseEntity()
{
}
public NamedBaseEntity(Long id)
{
super(id);
}
// gettes setters and tostring
}
@MappedSuperclass
@JsonIgnoreProperties(value = {"updated", "created"})
public abstract class BaseEntity implements Serializable
{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@Column(name = "created")
@Temporal(TemporalType.TIMESTAMP)
private Date created;
@Column(name = "updated")
@Temporal(TemporalType.TIMESTAMP)
private Date updated;
@Column(name = "active")
private Short active = (short) 1;
public BaseEntity()
{
}
public BaseEntity(Long id)
{
this.id = id;
}
// getters, settes, toString, hascode and equals
}
@Repository
@Transactional
@Component
public interface RecipeItemDao extends JpaRepository<RecipeItem, Long>
{
// methods and implementation auto-generated by Spring Data
}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>mypackage.web</groupId>
<artifactId>CoffeeShopWebApp</artifactId>
<version>0</version>
<packaging>war</packaging>
<name>CoffeeShopWebApp</name>
<properties>
<endorsed.dir>${project.build.directory}/endorsed</endorsed.dir>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.1.2.RELEASE</version>
<exclusions>
<exclusion>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<version>2.1.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>2.1.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>2.1.2.RELEASE</version>
</dependency>
<dependency>
<groupId>mypackage.base</groupId>
<artifactId>myapplication-module-base</artifactId>
<version>0</version>
</dependency>
<dependency>
<groupId>org.joinfaces</groupId>
<artifactId>joinfaces-dependencies</artifactId>
<version>4.0.2</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.primefaces</groupId>
<artifactId>primefaces</artifactId>
<version>6.2</version>
</dependency>
<dependency>
<groupId>org.primefaces.extensions</groupId>
<artifactId>primefaces-extensions</artifactId>
<version>6.2.10</version>
</dependency>
<dependency>
<groupId>org.primefaces.extensions</groupId>
<artifactId>resources-ckeditor</artifactId>
<version>6.2.10</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>myapplication-recipe</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.1.4.RELEASE</version>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<compilerArguments>
<endorseddirs>${endorsed.dir}</endorseddirs>
</compilerArguments>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.6</version>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<outputDirectory>${endorsed.dir}</outputDirectory>
<silent>true</silent>
<artifactItems>
<artifactItem>
<groupId>javax</groupId>
<artifactId>javaee-endorsed-api</artifactId>
<version>7.0</version>
<type>jar</type>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
spring.datasource.url=jdbc:mysql://myDatabaseStuff?zeroDateTimeBehavior=convertToNull
spring.datasource.username=censored
spring.datasource.password=censored
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.jmx.default-domain: censored
spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true
spring.jpa.hibernate.ddl-auto=none
server.error.whitelabel.enabled=false
解决方案
我想到了。这不是我的任何交易内容,就像我想的那样。这是我使用 getOne() 而不是 findById() 的事实。
这是帮助我的问题/答案:
spring data jpa getOne 抛出 LazyInitializationException 和 findBy 不
推荐阅读
- javascript - 如何使用 React Hooks 传递函数?
- c# - 如何更改 ViewModel 属性并将其保存到我的所有页面?
- php - 未定义的属性:stdClass::$column_name
- sql - ORA-01427: 单行子查询返回多于一行 - 在简单查询中
- java - 如何从 Spring Boot maven Web 项目调用 dll 调用?
- python - 如何根据散景中的用户选择单选按钮更改图表类型
- unity3d - Unity在手机上切换武器
- junit - 如何修复“java.lang.AssertionError:预期:
但是是: “? - forms - 在运行 Powershell 脚本之前提示域管理员凭据
- javascript - 如何在完成时阻止javascript计时器重置