title: Hibernate inconsistently generating duplicate primary keys
body: <p>I'm using Spring and Hibernate (hibernate-core 3.3.1.GA), and as a result of a web call, the code does a transaction with several inserts. Sometimes, one of the inserts fails with Hibernate saying <code>'Duplicate entry ... for key 'PRIMARY'</code>. I have not been able to identify any pattern on when this happens -- it may work for 4 - 5 requests, and then it fails, then works on retrying, and then may fail on the next request.</p>
  
  <p>Below are the relevant parts of the code:</p>
  
  <p><strong>Controller</strong></p>
  
  <pre><code>@RequestMapping(value = "/users", method = RequestMethod.POST)
  public @ResponseBody Map&lt;Object, Object&gt; save(&lt;params&gt;) throws IllegalArgumentException {
      ...
      try {
              map = userHelper.save(&lt;parameters&gt;);
      ...
      } catch (Exception e) {
          e.printStackTrace();
      }
  }
  </code></pre>
  
  <p>The exception is thrown in the above part.</p>
  
  <p><strong>UserHelper.save() method</strong></p>
  
  <pre><code>@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
  public HashMap&lt;String, Object&gt; save(&lt;parameters&gt;) throws NumberParseException, IllegalArgumentException, HibernateException {
      ....
      userService.save(&lt;parameters&gt;);
      return save;
  }
  </code></pre>
  
  <p><strong>UserService</strong></p>
  
  <pre><code>HBDao dao;
  
  @Autowired
  public UserService(org.hibernate.SessionFactory sessionFactory) {
      dao = new HBDao(sessionFactory);
  }
  ...
  @Transactional(propagation = Propagation.SUPPORTS, rollbackFor = Exception.class)
  public HashMap&lt;String, Object&gt; save(&lt;parameters&gt;) throws NumberParseException {
      ...
      User user;
      // several lines to create User object
      dao.save(user);
      ...
      lookupService.saveUserConfigurations(user, userType, loginById);
      ...
      return response;
  }
  </code></pre>
  
  <p><strong>HBDao</strong></p>
  
  <p>This class wraps hibernate sessions.</p>
  
  <pre><code>public HBDao(SessionFactory sf) {
      this.sessionFactory = sf;
  }
  
  private Session getSession() {
      sessionFactory.getCurrentSession();
  }
  
  public void save(Object instance) {
      try {
          getSession().saveOrUpdate(instance);
      } catch (RuntimeException re) {
          throw re;
      }
  }
  </code></pre>
  
  <p><code>lookupService.saveUserConfigurations(user, userType, loginById)</code> call results in the below methods in <code>LookupRepository</code> class to be executed:</p>
  
  <p><strong>LookupRepository</strong></p>
  
  <pre><code>@Transactional(propagation = Propagation.SUPPORTS, rollbackFor = Exception.class)
  public LookupMapping save(LookupMapping configuration) {
      dao.save(configuration);
      return configuration;
  }
  
  public Collection&lt;LookupMapping&gt; saveAll(Collection&lt;LookupMapping&gt; configurations) {
      configurations.forEach(this::save);
      return configurations;
  }
  </code></pre>
  
  <p><strong>LookupMapping</strong></p>
  
  <pre><code>@Entity
  public class LookupMapping {
      @Id
      @GeneratedValue(strategy = GenerationType.IDENTITY)
      private Long configId;
      ...
  }
  </code></pre>
  
  <p><strong>Hibernate Mapping for LookupMapping class</strong></p>
  
  <pre><code>&lt;hibernate-mapping package="com...configuration.domain"&gt;
      &lt;class name="LookupMapping" table="lookup_mapping" mutable="false"&gt;
          &lt;id column="id" name="configId" type="long"&gt;
              &lt;generator class="increment"/&gt;
          &lt;/id&gt;
          ...
      &lt;/class&gt;
  &lt;/hibernate-mapping&gt;
  </code></pre>
  
  <p><strong>Hibernate config</strong></p>
  
  <pre><code>&lt;hibernate-configuration&gt;
      &lt;session-factory name="sosFactory"&gt;
          &lt;!-- Database connection settings --&gt;
          ...
  
          &lt;property name="connection.pool_size"&gt;2&lt;/property&gt;
  
          &lt;!-- SQL dialect --&gt;
          &lt;property name="dialect"&gt;com. ... .CustomDialect&lt;/property&gt;
  
          &lt;!-- Enable Hibernate's current session context --&gt;
          &lt;property name="current_session_context_class"&gt;org.hibernate.context.ManagedSessionContext&lt;/property&gt;
  
          &lt;!-- Disable the second-level cache --&gt;
          &lt;property name="cache.provider_class"&gt;org.hibernate.cache.NoCacheProvider&lt;/property&gt;
  
          &lt;!-- Echo all executed SQL to stdout --&gt;
          &lt;property name="show_sql"&gt;true&lt;/property&gt;
          &lt;property name="format_sql"&gt;true&lt;/property&gt;
  
          ...
  &lt;/session-factory&gt;
  &lt;/hibernate-configuration&gt;
  </code></pre>
  
  <p>Below are the lines from the log:</p>
  
  <pre><code>2018-05-04 10:24:51.321 7|13|60f566fa-4f85-11e8-ba9b-93dd5bbf4a00 ERROR [http-nio-8080-exec-1] org.hibernate.util.JDBCExceptionReporter - Duplicate entry '340932' for key 'PRIMARY'
  2018-05-04 10:24:51.321 7|13|60f566fa-4f85-11e8-ba9b-93dd5bbf4a00 WARN [http-nio-8080-exec-1] org.hibernate.util.JDBCExceptionReporter - SQL Error: 1062, SQLState: 23000
  2018-05-04 10:24:51.322 7|13|60f566fa-4f85-11e8-ba9b-93dd5bbf4a00 ERROR [http-nio-8080-exec-1] org.hibernate.event.def.AbstractFlushingEventListener - Could not synchronize database state with session
  org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
      at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:94) ~[hibernate-core-3.3.1.GA.jar:3.3.1.GA]
      at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66) ~[hibernate-core-3.3.1.GA.jar:3.3.1.GA]
      at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:275) ~[hibernate-core-3.3.1.GA.jar:3.3.1.GA]
      at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:266) ~[hibernate-core-3.3.1.GA.jar:3.3.1.GA]
      at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:167) ~[hibernate-core-3.3.1.GA.jar:3.3.1.GA]
      at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321) [hibernate-core-3.3.1.GA.jar:3.3.1.GA]
      at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:50) [hibernate-core-3.3.1.GA.jar:3.3.1.GA]
      at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1027) [hibernate-core-3.3.1.GA.jar:3.3.1.GA]
      at com.arl.mg.helpers.UserHelper.save(UserHelper.java:329) [classes/:?]
  ...
  </code></pre>
  
  <p>I'm working on a legacy codebase (so cannot upgrade Hibernate easily), and the code that I wrote are in <code>LookupRepository</code> class (and <code>LookupService</code> which is called in <code>UserService</code>).</p>
  
  <p>The <code>Duplicate entry</code> error happens while persisting the <code>LookupMapping</code> objects. There are always two of this object being persisted, and when the error occurs, the duplicate ID is created same as the last entry. That is, if for the first request, IDs <code>999</code> and <code>1000</code> were inserted, and if the error occurs for the next request, the duplicate ID will be <code>1000</code> (and not 999).</p>
  
  <p>Another, possibly important thing to note is that Hibernate shows this line:</p>
  
  <pre><code>org.hibernate.jdbc.ConnectionManager [] - transaction completed on session with on_close connection release mode; be sure to close the session to release JDBC resources!
  </code></pre>
  
  <p>This is all the info that I have so far, and I hope I've covered the relevant code as well. Any help will be much appreciated. Do let me know if I have to give more info.</p>
  
  <p>Thanks!</p>