title: Why does Spring close the DB-session in Runnable after first Repository method call?
body: <p>I'm working on a Spring MVC App with JPA (Hibernate as Provider) and a PostgreSQL database. I wanted to insert results (of a time consuming task) into the database in background and created a serviceclass which implements Runnable. In the run method, I receive an entity from the repository but when I try to access a lazy collection of the entity, the database session is already closed (I get a lazy initialization exception).</p>
  
  <p>The source code of my Background-Service:</p>
  
  <pre><code>@Service
  @Scope("prototype")
  public class ProjectServiceTestThread implements Runnable{
  
  static Logger log = Logger.getLogger(ProjectServiceTestThread.class);
  
  @Autowired
  ProjectRepository projectRepository;
  
  @Autowired
  ScenarioRepository scenarioRepository;
  
  @Override
  @Transactional
  public void run() {
  
      List&lt;Project&gt; projectList = projectRepository.findByName("thread test project");
      Project project;
      project = projectList.get(0);
  
      //A project can have multiple scenarios
      Scenario scenario;
      if (project.getScenarios().isEmpty()) { //this line fails -&gt; lazyInitializationException - no Session
          System.err.println("Creating new scenario");
          scenario = new Scenario();
          scenario.setName("thread test scenario");
          scenario.setDescription(this + ".runServiceFunction at " + System.currentTimeMillis());
          scenario.setProject(project);
          scenario = scenarioRepository.save(scenario);
      } else {
          System.err.println("Using existing scenario");
          scenario = project.getScenarios().iterator().next();
      }
  }    
  }
  </code></pre>
  
  <p>The Service and Spring TaskExecutor are Autowired in the Controller which is running on a Tomcat v8.0 Server. 
  Controller code:</p>
  
  <pre><code>@Autowired
  ProjectServiceTestThreadImpl testRunnable;
  
  @Autowired
  TaskExecutor taskExecutor;
  
  @RequestMapping(value="openproject", method=RequestMethod.GET)
  public String getStringProjects(Map&lt;String, Object&gt; model) throws InterruptedException
  {
      System.err.println(this + " before call to runnable ");
              testRunnable.run();
              taskExecutor.execute(testRunnable);
  
      return "openproject";
  }   
  </code></pre>
  
  <p>The log shows that the database session closes right after the findByName Query:</p>
  
  <pre><code>09:50:31,438 TRACE JdbcCoordinatorImpl:525 - Closing prepared statement [select distinct project0_.prjid as prjid1_24_, project0_.createdby as createdb2_24_, project0_.createdon as createdo3_24_, project0_.description as descript4_24_, project0_.designtarget as designta5_24_, project0_.location as location6_24_, project0_.name as name7_24_, project0_.modelid as modelid11_24_, project0_.timehorizon as timehori8_24_, project0_.updatedby as updatedb9_24_, project0_.updatedon as updated10_24_ from public.project project0_ where lower(project0_.name) like ('%'||lower('thread test project')||'%')]
  09:50:31,438 TRACE JdbcCoordinatorImpl:278 - Starting after statement execution processing [ON_CLOSE]
  09:50:31,438 TRACE StatefulPersistenceContext:880 - Initializing non-lazy collections
  09:50:31,439 TRACE SessionImpl:357 - Closing session
  09:50:31,439 TRACE JdbcCoordinatorImpl:199 - Closing JDBC container [org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl@3b95a16b]
  09:50:31,439 TRACE LogicalConnectionImpl:178 - Closing logical connection
  09:50:31,439 DEBUG LogicalConnectionImpl:246 - Releasing JDBC connection
  09:50:31,439 DEBUG LogicalConnectionImpl:264 - Released JDBC connection
  09:50:31,442 TRACE LogicalConnectionImpl:190 - Logical connection closed
  09:50:31,445 TRACE TransactionSynchronizationManager:243 - Removed value [org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$DefaultCrudMethodMetadata@7cc8f09] for key [public abstract java.util.List eu.cite.repository.ProjectRepository.findByName(java.lang.String)] from thread [myExecutor-1]
  09:50:31,451 TRACE LazyInitializationException:53 - failed to lazily initialize a collection of role: eu.cite.model.Project.scenarios, could not initialize proxy - no Session
  org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: eu.cite.model.Project.scenarios, could not initialize proxy - no Session
      at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:575)
      at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:214)
      at org.hibernate.collection.internal.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:155)
      at org.hibernate.collection.internal.PersistentSet.isEmpty(PersistentSet.java:166)
      at eu.cite.service.ProjectServiceTestThread.run(ProjectServiceTestThread.java:73)
      at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
      at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
      at java.lang.Thread.run(Unknown Source)
  </code></pre>
  
  <p>Configuration:
      </p>
  
  <pre><code>&lt;context:component-scan base-package="eu.cite.repository, eu.cite.service" scoped-proxy="targetClass" /&gt;
  &lt;jpa:repositories base-package="eu.cite.repository" /&gt;
  
  &lt;bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/&gt;
  
  &lt;bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"&gt;
      &lt;property name="persistenceUnitName" value="punit"/&gt;
      &lt;property name="dataSource" ref="dataSource"&gt;&lt;/property&gt;
      &lt;property name="jpaVendorAdapter"&gt;
          &lt;bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"&gt;
              &lt;property name="showSql" value="true"&gt;&lt;/property&gt;                   
          &lt;/bean&gt;
      &lt;/property&gt;
      &lt;property name="jpaPropertyMap"&gt;
          &lt;map&gt;
              &lt;entry key="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/&gt;
              &lt;entry key="hibernate.format_sql" value="true"/&gt;    
              &lt;entry key="hibernate.jdbc.batch_size" value="50"/&gt;                 
              &lt;entry key="hibernate.order_inserts" value="true"/&gt;
          &lt;/map&gt;
      &lt;/property&gt;
  &lt;/bean&gt;
  
  &lt;bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"&gt;
      &lt;property name="entityManagerFactory" ref="entityManagerFactory"/&gt;
  &lt;/bean&gt;
  
  &lt;tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/&gt;
  
  &lt;bean id="ModelMapper" class="org.modelmapper.ModelMapper"&gt;&lt;/bean&gt;
  
  &lt;bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"&gt;
      &lt;property name="driverClassName" value="org.postgresql.Driver"&gt;&lt;/property&gt;  
      &lt;property name="url" value="jdbc:postgresql://localhost:5432/Cite?autoReconnect=true"&gt;&lt;/property&gt;
      &lt;property name="username" value="cite"&gt;&lt;/property&gt;
      &lt;property name="password" value="***"&gt;&lt;/property&gt;   
  &lt;/bean&gt;
  
  &lt;task:executor id="myExecutor"/&gt;
  &lt;task:executor id="myExecutor"  pool-size="5"/&gt;
  </code></pre>
  
  <p>Can somebody tell me why it does not work this way? I figured out some ways to make it work, but I don't understand why it does not work with the code above. These three approaches correctly insert the Scenario, without closing the database Session in between:</p>
  
  <ol>
  <li>remove @Service from ProjectServiceTestThread and register the bean in the config manually</li>
  <li>Not implement Runnable and annotate the run() method of ProjectServiceTestThread with @Async</li>
  <li>Not using the Spring Task Executor</li>
  </ol>
  
  <p><strong>Edit - Project entity:</strong></p>
  
  <pre><code>@Entity
  @Table(name = "project", schema = "public", uniqueConstraints = @UniqueConstraint(columnNames = "name"))
  public class Project implements java.io.Serializable {
  
  private int prjid;
  private SimulationModel simulationmodel;
  private String name;
  private String description;
  private String designtarget;
  private Date timehorizon;
  private String location;
  private Date createdon;
  private Date updatedon;
  private Integer createdby;
  private Integer updatedby;
  private Set&lt;ObjectiveFunction&gt; objectivefunctions = new HashSet&lt;ObjectiveFunction&gt;(
          0);
  private Set&lt;Scenario&gt; scenarios = new HashSet&lt;Scenario&gt;(0);
  private Set&lt;ScenarioGenerator&gt; scenariogenerators = new HashSet&lt;ScenarioGenerator&gt;(
          0);
  private List&lt;Component&gt; components = new ArrayList&lt;Component&gt;();
  private Set&lt;OptConstraint&gt; optconstraints = new HashSet&lt;OptConstraint&gt;(0);
  private Set&lt;SearchConstraint&gt; searchconstraints = new HashSet&lt;SearchConstraint&gt;(
          0);
  private Set&lt;Metric&gt; metrics = new HashSet&lt;Metric&gt;(0);
  private Set&lt;UserGroupProject&gt; usergroupprojects = new HashSet&lt;UserGroupProject&gt;(
          0);
  private Set&lt;ExtParam&gt; extparams = new HashSet&lt;ExtParam&gt;(0);
  
  public Project() {
  }
  
  public Project(int prjid, String name) {
      this.prjid = prjid;
      this.name = name;
  }
  
  public Project(int prjid, SimulationModel simulationmodel, String name,
          String description, String designtarget, Date timehorizon, String location,
          Date createdon, Date updatedon, Integer createdby,
          Integer updatedby, Set&lt;ObjectiveFunction&gt; objectivefunctions,
          Set&lt;Scenario&gt; scenarios, Set&lt;ScenarioGenerator&gt; scenariogenerators,
          List&lt;Component&gt; components, Set&lt;OptConstraint&gt; optconstraints,
          Set&lt;SearchConstraint&gt; searchconstraints, Set&lt;Metric&gt; metrics,
          Set&lt;UserGroupProject&gt; usergroupprojects, Set&lt;ExtParam&gt; extparams) {
      this.prjid = prjid;
      this.simulationmodel = simulationmodel;
      this.name = name;
      this.description = description;
      this.designtarget = designtarget;
      this.timehorizon = timehorizon;
      this.location = location;
      this.createdon = createdon;
      this.updatedon = updatedon;
      this.createdby = createdby;
      this.updatedby = updatedby;
      this.objectivefunctions = objectivefunctions;
      this.scenarios = scenarios;
      this.scenariogenerators = scenariogenerators;
      this.components = components;
      this.optconstraints = optconstraints;
      this.searchconstraints = searchconstraints;
      this.metrics = metrics;
      this.usergroupprojects = usergroupprojects;
      this.extparams = extparams;
  }
  
  @SequenceGenerator(name="project_prjid_seq",sequenceName="project_prjid_seq") @GeneratedValue(strategy = GenerationType.SEQUENCE, generator="project_prjid_seq")
  @Id
  @Column(name = "prjid", unique = true, nullable = false)
  public int getPrjid() {
      return this.prjid;
  }
  
  public void setPrjid(int prjid) {
      this.prjid = prjid;
  }
  
  @ManyToOne(fetch = FetchType.LAZY,cascade=CascadeType.PERSIST)
  @JoinColumn(name = "modelid")
  public SimulationModel getSimulationmodel() {
      return this.simulationmodel;
  }
  
  public void setSimulationmodel(SimulationModel simulationmodel) {
      this.simulationmodel = simulationmodel;
  }
  
  @Column(name = "name", unique = true, nullable = false, length = 50)
  public String getName() {
      return this.name;
  }
  
  public void setName(String name) {
      this.name = name;
  }
  
  @Column(name = "description")
  public String getDescription() {
      return this.description;
  }
  
  public void setDescription(String description) {
      this.description = description;
  }
  
  @Column(name = "designtarget", length = 50)
  public String getDesigntarget() {
      return this.designtarget;
  }
  
  public void setDesigntarget(String designtarget) {
      this.designtarget = designtarget;
  }
  
  @Temporal(TemporalType.TIME)
  @Column(name = "timehorizon", length = 15)
  public Date getTimehorizon() {
      return this.timehorizon;
  }
  
  public void setTimehorizon(Date timehorizon) {
      this.timehorizon = timehorizon;
  }
  
  @Column(name = "location")
  public String getLocation() {
      return this.location;
  }
  
  public void setLocation(String location) {
      this.location = location;
  }
  
  @Temporal(TemporalType.TIMESTAMP)
  @Column(name = "createdon", length = 22)
  public Date getCreatedon() {
      return this.createdon;
  }
  
  public void setCreatedon(Date createdon) {
      this.createdon = createdon;
  }
  
  @Temporal(TemporalType.TIMESTAMP)
  @Column(name = "updatedon", length = 22)
  public Date getUpdatedon() {
      return this.updatedon;
  }
  
  public void setUpdatedon(Date updatedon) {
      this.updatedon = updatedon;
  }
  
  @Column(name = "createdby")
  public Integer getCreatedby() {
      return this.createdby;
  }
  
  public void setCreatedby(Integer createdby) {
      this.createdby = createdby;
  }
  
  @Column(name = "updatedby")
  public Integer getUpdatedby() {
      return this.updatedby;
  }
  
  public void setUpdatedby(Integer updatedby) {
      this.updatedby = updatedby;
  }
  
  @OneToMany(fetch = FetchType.LAZY, mappedBy = "project")
  public Set&lt;ObjectiveFunction&gt; getObjectivefunctions() {
      return this.objectivefunctions;
  }
  
  public void setObjectivefunctions(Set&lt;ObjectiveFunction&gt; objectivefunctions) {
      this.objectivefunctions = objectivefunctions;
  }
  
  @OneToMany(fetch = FetchType.LAZY, mappedBy = "project")
  public Set&lt;Scenario&gt; getScenarios() {
      return this.scenarios;
  }
  
  public void setScenarios(Set&lt;Scenario&gt; scenarios) {
      this.scenarios = scenarios;
  }
  
  @OneToMany(fetch = FetchType.LAZY, mappedBy = "project")
  public Set&lt;ScenarioGenerator&gt; getScenariogenerators() {
      return this.scenariogenerators;
  }
  
  public void setScenariogenerators(Set&lt;ScenarioGenerator&gt; scenariogenerators) {
      this.scenariogenerators = scenariogenerators;
  }
  
  @OneToMany(fetch = FetchType.LAZY, mappedBy = "project")
  @OrderBy("componentid")
  public List&lt;Component&gt; getComponents() {
      return this.components;
  }
  
  public void setComponents(List&lt;Component&gt; components) {
      this.components = components;
  }
  
  @OneToMany(fetch = FetchType.LAZY, mappedBy = "project")
  public Set&lt;OptConstraint&gt; getOptconstraints() {
      return this.optconstraints;
  }
  
  public void setOptconstraints(Set&lt;OptConstraint&gt; optconstraints) {
      this.optconstraints = optconstraints;
  }
  
  @OneToMany(fetch = FetchType.LAZY, mappedBy = "project")
  public Set&lt;SearchConstraint&gt; getSearchconstraints() {
      return this.searchconstraints;
  }
  
  public void setSearchconstraints(Set&lt;SearchConstraint&gt; searchconstraints) {
      this.searchconstraints = searchconstraints;
  }
  
  @OneToMany(fetch = FetchType.LAZY, mappedBy = "project")
  public Set&lt;Metric&gt; getMetrics() {
      return this.metrics;
  }
  
  public void setMetrics(Set&lt;Metric&gt; metrics) {
      this.metrics = metrics;
  }
  
  @OneToMany(fetch = FetchType.LAZY, mappedBy = "project")
  public Set&lt;UserGroupProject&gt; getUsergroupprojects() {
      return this.usergroupprojects;
  }
  
  public void setUsergroupprojects(Set&lt;UserGroupProject&gt; usergroupprojects) {
      this.usergroupprojects = usergroupprojects;
  }
  
  @OneToMany(fetch = FetchType.LAZY, mappedBy = "project")
  public Set&lt;ExtParam&gt; getExtparams() {
      return this.extparams;
  }
  
  public void setExtparams(Set&lt;ExtParam&gt; extparams) {
      this.extparams = extparams;
  }
  </code></pre>