Spring Data (Hibernate) JPA update of individual fields not visible within transaction
<p>I have an entity "Job" with a boolean flag "suspended":</p>

<pre><code>@Entity
@XmlRootElement(name = "Job")
@Where(clause = "deleted=0")
public class Job {
    ...
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;
    private boolean suspended;
    ...
}
</code></pre>

<p>And a Spring CrudRepository (JPA Hibernate) is used for persistence:</p>

<pre><code>@Repository
public interface JobRepository extends CrudRepository&lt;Job, Integer&gt;, JobStatusSupport {}
</code></pre>

<p>I need to update the "suspended" flag individually, without overwriting updates done to other fields in concurrent threads. So the natural thing to do seemed to be writing a method that only updates the "suspended" field:</p>

<pre><code>public class JobRepositoryImpl implements JobStatusSupport {
    private final static String SET_SUSPENDED = "UPDATE Job SET suspended = :suspended, modificationDate = :modificationDate WHERE id = :id";

    @Override
    public int setSuspended(int id, boolean suspended, Instant modificationDate) {
        int updateCount =  em.createQuery(SET_SUSPENDED)
                .setParameter("suspended", suspended)
                .setParameter("modificationDate", modificationDate)
                .setParameter("id", id)
                .executeUpdate();
        return updateCount;
    }
}
</code></pre>

<p>Now I have the following scenario in my code (shortened obviously, in reality this is spread out over several methods, but this example does reproduce the problem):</p>

<pre><code>@Transactional
public void resumeJob(int id) {
    Job jobA = jobRepository.findOne(Integer.valueOf(id));
      // jobA.suspended == true
      // let's set "suspended" to "false"
    int updateCount = jobRepository.setSuspended(id, false, Instant.now());
      // OK: updateCount is 1
    Job jobB = jobRepository.findOne(Integer.valueOf(id));
      // jobB.suspended == true ??? that was just set to "false, wasn't it?
}
</code></pre>

<p>Probably I am missing some basics about JPA/Hibernate. But still, this is extremely counterintuitive: <strong>Why is jobB.suspended still "true" although the update is successful and the data is read again "from the DB"? Why is the update of the individual field not visible within the transaction?</strong></p>

<p>(As one would expect, <em>after</em> the transaction is complete, Job.suspended is "false" in the database and for subsequent reads.)</p>

<p>How would one go about this properly? How should I write code that updates individual fields so that JPA becomes aware of what was done? Do I have to look into "merge" for something as simple as this?</p>

<p>Being able to write our own SQL statements is crucial for our project. I am trying Spring Data JPA mainly to avoid the tedious work of writing tons of CRUD operations. But if I am already encountering such problems with this simple scenario, I am wondering whether we would not be better of using JdbcTemplate.</p>

<p><strong>UPDATE: LEARNED SOMETHING ABOUT ORM</strong></p>

<p>Man, was I clueless! I worked in projects where JPA was used before. But I never had to deal with it in detail (and I wonder if anybody else did).</p>

<p><em>The entire effort of writing an "update method" is futile!</em> I have reduced this to the following:</p>

<pre><code>@Transactional
public void resumeJob(int id) {
    Job job = jobRepository.findOne(Integer.valueOf(id));
    job.setSuspended(false);
    job.setName("And Now for Something Completely Different.");
}
</code></pre>

<p>That's all! This updates the DB and the cache and God knows what. The @Transactional annotation alone is sufficient for persisting the changes. If the annotation is removed, the DB remains unchanged. So ORM is basically working against a cache (through "attached objects") that everybody sees. Then one hopes that people put @Transactional in the right places (not on private methods, for example...) and that the ORM machinery knows what it is doing (for example, not making cache updates visible outside of an open transaction).</p>

<p>Honestly, this seems a bit too magic for my taste. But now that I know what it is all about, I will give it a try. Writing gazillions of CRUD methods isn't very appealing, either.</p>

<p>Please comment if I got this wrong or if you have links with best practices. (I am starting to wonder if it wouldn't be best to immediately detach every object I get from the DB, defeating the entire purpose of ORM :-)</p>

<p><strong>UPDATE: EntityManager#clear() Is Enough for a Quick Fix</strong></p>

<p>This is definitely not the clever way to use ORM, but for the moment I can simply call clear() in the few update methods I have written. This invalidates the entire cache and the next read somewhere else in the transaction receives the updated data. Of course, the right way to do it, would be to simply modify the attached entity, i.e. "job.setSuspended(false);".</p>

<p>Calling flush() is not needed, probably it only becomes of interest when you want to minimize the risk of losing data in case of a system crash. I suppose that Hibernate does not immediately write completed transactions to disk?</p>