6 Replies Latest reply on Jul 3, 2008 5:18 PM by Damian Harvey

    Sanity check on FlushMode.MANUAL and persist()

    Damian Harvey Apprentice

      I'm having one of those days. Can someone confirm my sanity on this one.


      What is the expected behaviour when I have my FlushMode set to MANUAL and I call a persist()? I'm seeing the entity added to the database even though I haven't called a flush() nor reached a method boundary. Is this normal?


      I see the expected behaviour updating the entity - ie. the second setName doesn't appear in the database until a flush is called.


      Code:


      @Transactional
      public void test() {
              
              log.info("FLUSH MODE : #0", PersistenceContexts.instance().getFlushMode().toString());
              
              Person p = new Person();
              p.setName("Damian");
              
              entityManager.persist(p);  //appears in db after this
              
              p.setName("Is going crazy");  //this won't appear until the flush
              
              log.info("At method boundary");
      }
      
      public void flush() {
              entityManager.flush();
      }
      



      Cheers,


      Damian.

        • 1. Re: Sanity check on FlushMode.MANUAL and persist()
          Christian Bauer Master

          Difference between pre- and post-INSERT id generators. There are books about it.

          • 2. Re: Sanity check on FlushMode.MANUAL and persist()
            Damian Harvey Apprentice

            Thanks Christian. I have your book and chapter 11.2.3 was very helpful. I see your point about pre and post-INSERT ID generators.


            I am using GenerationType.IDENTITY which is forcing the insert so that Hibernate can get the ID.


            As I see it I now have 3 options that are discussed in that chapter:



            1. Change my GenerationType to something like SEQUENCE or TABLE. However MySQL doesn't support SEQUENCE.

            2. Follow the JPA approach and perform the insert outside of a transaction (which just seems odd)

            3. Use Compensation actions to undo what has been inserted to this point.



            For my use case option 3 will be the easiest to implement.


            Cheers,


            Damian.





            • 3. Re: Sanity check on FlushMode.MANUAL and persist()
              Darryl Sibeon Newbie

              Hello there,


              The solution we found here was to use the evict(obj) option that comes with the Hibernate Session.


              Try it out


              Darryl A. Sibeon

              • 4. Re: Sanity check on FlushMode.MANUAL and persist()
                Christian Bauer Master

                Look at how the wiki software uses a fake-sequence generator on MySQL, which is a relatively new Hibernate feature. You definitely want pre-INSERT identifier generators wherever you are.

                • 6. Re: Sanity check on FlushMode.MANUAL and persist()
                  Damian Harvey Apprentice

                  Thanks, that works a treat.


                  Is the best practice here to use the SequenceStyleGenerator with one common record for all Entities (as per the Seam Wiki) or to maybe use the TableGenerator with a row for each entity? Are there advantages/disadvantages of each approach? With over 100 entities I'm leaning toward the TableGenerator.


                  For anyone finding this thread later I have changed the ID of my test entity from:


                  @Id
                  @GeneratedValue(strategy = IDENTITY)
                  @Column(name = "ID", unique = true, nullable = false)
                  public Long getId() {
                          return this.id;
                  }
                  


                  to


                  @Id
                  @GenericGenerator(
                                  name = "personSequenceGenerator",
                                  strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator",
                                  parameters = {
                                          @Parameter(name = "sequence_name", value = "PERSON_SEQUENCE"),
                                          @Parameter(name = "initial_value", value = "1000"),
                                          @Parameter(name = "increment_size", value = "1")
                                  }
                          )
                  @GeneratedValue(generator = "personSequenceGenerator")
                  @Column(name = "ID", unique = true, nullable = false)
                  public Long getId() {
                          return this.id;
                  }
                  


                  And created a table called PERSON_SEQUENCE with one field called next_val.


                  Cheers,


                  Damian