title: What is the difference between 'getDelegate()' and 'unwrap()' for getting the Hibernate session of an entity manager
body: <p>To speed up iteration of all rows in a SQL table using Hibernate (since JPA doesn't support streaming), I followed the approach of <a href="https://stackoverflow.com/a/5182888/883073">this answer</a>. While this works well, <a href="https://stackoverflow.com/a/4151834/883073">this answer</a> tells us that we should retrieve the <code>Session</code> object using</p>
  
  <pre><code>Session session = entityManager.unwrap(Session.class);
  </code></pre>
  
  <p>instead of the way it was done in the answer:</p>
  
  <pre><code>Session session = (Session) manager.getDelegate();
  </code></pre>
  
  <p>Hower, with this change I suddenly get the following exception:</p>
  
  <pre><code>java.lang.IllegalStateException: No transactional EntityManager available
  </code></pre>
  
  <p>The entity manager is autowired into a field in a Spring component like this:</p>
  
  <pre><code>@Component
  public class Updater {
      @Autowired
      private EntityManager entityManager;
  
      @Transactional
      public void update() {
          // ...
          Result loadedResult = loadAll()
          // ...
      }
  
      private Result loadAll() {
          Session session = (Session) manager.getDelegate();
          //Session session = entityManager.unwrap(Session.class);
  
          SessionFactory sessionFactory = session.getSessionFactory();
          StatelessSession statelessSession = sessionFactory.openStatelessSession();
  
          // ... @linked answer ...
      }
  }
  </code></pre>
  
  <p>As the name suggests, <code>loadAll</code> only reads data and transforms it into some <code>Result</code>. <code>update</code> does write to the database.</p>
  
  <p>Note that <code>loadAll</code> is only called through <code>update</code>. Also, annotating <code>loadAll</code> with <code>@Transactional</code> doesn't fix the problem.</p>
  
  <p>I know there are several other questions regarding this error, stating <code>@Transactional</code> to be the answer. My question is what the difference between <code>getDelegate</code> and <code>unwrap</code> really is: Why does the one fail and the other not? (And why doesn't <code>@Transactional</code> fix the problem?)</p>
  
  <p>I'm using H2 1.4.190 and Hibernate 4.3.11.Final (through Spring Boot 1.3.2.RELEASE).</p>
  
  <p><strong>EDIT</strong> Full minimal example (with package declarations and imports omitted). All classes are in package <code>com.example</code>:</p>
  
  <p><em>Entity.java</em></p>
  
  <pre><code>@javax.persistence.Entity
  public class Entity {
  
      @Id
      @GeneratedValue
      public int id;
  
      public int value;
  }
  </code></pre>
  
  <p><em>EntityRepository.java</em></p>
  
  <pre><code>public interface EntityRepository extends JpaRepository&lt;Entity, Integer&gt; {
  }
  </code></pre>
  
  <p><em>Config.java</em>:</p>
  
  <pre><code>@Configuration
  @ComponentScan
  @EnableJpaRepositories
  @EntityScan
  @EnableTransactionManagement
  public class Config {
  }
  </code></pre>
  
  <p><em>Runner.java</em>:</p>
  
  <pre><code>@SpringBootApplication
  public class Runner implements CommandLineRunner {
  
      public static void main(String[] args) {
          SpringApplication application = new SpringApplication(Runner.class);
          application.setWebEnvironment(false);
          application.run(args);
      }
  
      @Autowired
      private Updater updater;
  
      @Override
      public void run(String... args) throws Exception {
          updater.insert(1, 4, 2);
          updater.update();
  
          updater.printAll();
      }
  }
  </code></pre>
  
  <p><em>Updater.java</em>:</p>
  
  <pre><code>@Component
  public class Updater {
  
      @Autowired
      private EntityRepository repository;
  
      @PersistenceContext //@Autowired
      private EntityManager entityManager;
  
      public void insert(int... values) {
          for (int value : values) {
              Entity entity = new Entity();
              entity.value = value;
              repository.save(entity);
          }
          repository.flush();
      }
  
      public void update() {
          // Call "transactioned" method through an intermediary method.
          // The code works if 'Runner' calls 'transactionedUpdate' directly.
          transactionedUpdate();
      }
  
      @Transactional
      public void transactionedUpdate() {
          int sum = loadAll();
  
          // Set all 'value's to 'sum'.
          List&lt;Entity&gt; entities = repository.findAll();
          for (Entity entity : entities) {
              entity.value = sum;
              repository.save(entity);
          }
          repository.flush();
      }
  
      public int loadAll() {
  //        Session session = (Session) entityManager.getDelegate();
          Session session = entityManager.unwrap(Session.class);
  
          SessionFactory sessionFactory = session.getSessionFactory();
          StatelessSession statelessSession = sessionFactory.openStatelessSession();
  
          Query query = statelessSession.createQuery("FROM com.example.Entity e");
          query.setFetchSize(1000);
          query.setReadOnly(true);
          query.setLockMode("e", LockMode.NONE);
          ScrollableResults results = query.scroll(ScrollMode.FORWARD_ONLY);
  
          int sum = 0;
          while (results.next()) {
              Entity entity = (Entity) results.get(0);
              sum += entity.value;
          }
  
          results.close();
          statelessSession.close();
  
          return sum;
      }
  
      public void printAll() {
          List&lt;Entity&gt; entities = repository.findAll();
          for (Entity entity : entities) {
              System.out.println(entity.id + ": " + entity.value);
          }
      }
  }
  </code></pre>
  
  <p><em>application.yml</em>:</p>
  
  <pre><code>spring:
      jpa:
          open-in-view: false
          hibernate:
              ddl-auto: update
              naming-strategy: org.springframework.boot.orm.jpa.hibernate.SpringNamingStrategy
          database: H2
          show_sql: false
          properties:
              hibernate.cache.use_second_level_cache: true
              hibernate.cache.use_query_cache: false
      datasource:
          driver-class-name: org.h2.Driver
          url: jdbc:h2:file:~/data-test/db;DB_CLOSE_DELAY=-1
          name:
          username: test
          password:
  </code></pre>
  
  <p><em>Stack trace</em>:</p>
  
  <pre><code>java.lang.IllegalStateException: Failed to execute CommandLineRunner
      at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:809) ~[spring-boot-1.3.2.RELEASE.jar:1.3.2.RELEASE]
      at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:790) ~[spring-boot-1.3.2.RELEASE.jar:1.3.2.RELEASE]
      at org.springframework.boot.SpringApplication.afterRefresh(SpringApplication.java:777) ~[spring-boot-1.3.2.RELEASE.jar:1.3.2.RELEASE]
      at org.springframework.boot.SpringApplication.run(SpringApplication.java:308) ~[spring-boot-1.3.2.RELEASE.jar:1.3.2.RELEASE]
      at com.example.Runner.main(Runner.java:16) [classes/:na]
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_60]
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_60]
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_60]
      at java.lang.reflect.Method.invoke(Method.java:497) ~[na:1.8.0_60]
      at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144) [idea_rt.jar:na]
  Caused by: java.lang.IllegalStateException: No transactional EntityManager available
      at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:268) ~[spring-orm-4.2.4.RELEASE.jar:4.2.4.RELEASE]
      at com.sun.proxy.$Proxy49.unwrap(Unknown Source) ~[na:na]
      at com.example.Updater.loadAll(Updater.java:49) ~[classes/:na]
      at com.example.Updater.doUpdate(Updater.java:36) ~[classes/:na]
      at com.example.Updater.update(Updater.java:31) ~[classes/:na]
      at com.example.Updater$$FastClassBySpringCGLIB$$503dcdb8.invoke(&lt;generated&gt;) ~[classes/:na]
      at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) ~[spring-core-4.2.4.RELEASE.jar:4.2.4.RELEASE]
      at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:651) ~[spring-aop-4.2.4.RELEASE.jar:4.2.4.RELEASE]
      at com.example.Updater$$EnhancerBySpringCGLIB$$f362c2c8.update(&lt;generated&gt;) ~[classes/:na]
      at com.example.Runner.run(Runner.java:25) [classes/:na]
      at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:806) ~[spring-boot-1.3.2.RELEASE.jar:1.3.2.RELEASE]
      ... 9 common frames omitted
  </code></pre>