<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Satyaki Saha</title>
    <description>The latest articles on DEV Community by Satyaki Saha (@satyaki_saha_367d015583da).</description>
    <link>https://dev.to/satyaki_saha_367d015583da</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4138121%2Fde9431ac-5069-4d03-9fe0-7a865198cb2d.png</url>
      <title>DEV Community: Satyaki Saha</title>
      <link>https://dev.to/satyaki_saha_367d015583da</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/satyaki_saha_367d015583da"/>
    <language>en</language>
    <item>
      <title>Silent Saves: How JPA Persists Your Changes Without You Asking</title>
      <dc:creator>Satyaki Saha</dc:creator>
      <pubDate>Tue, 22 Sep 2026 18:28:19 +0000</pubDate>
      <link>https://dev.to/satyaki_saha_367d015583da/silent-saves-how-jpa-persists-your-changes-without-you-asking-4iii</link>
      <guid>https://dev.to/satyaki_saha_367d015583da/silent-saves-how-jpa-persists-your-changes-without-you-asking-4iii</guid>
      <description>&lt;p&gt;One of our junior devs wrote an API that was supposed to be &lt;em&gt;&lt;strong&gt;“read-only”&lt;/strong&gt;&lt;/em&gt; and act as an internal data funnel — pull some records, transform them, pass them on. nothing that should ever come close to the database. But it corrupted the production data badly.&lt;/p&gt;

&lt;p&gt;Then I started to dig into the code, and saw that he had @Transactional on the function. He was retrieving entities internally via EntityManager.find() (or a JPQL query, same thing) and &lt;em&gt;mutating some fields on them in the middle of processing&lt;/em&gt;, just as a way to store intermediate state while composing the response. No save, no merge, no repository.update() anywhere in sight, which is exactly what made him feel it was safe.&lt;/p&gt;

&lt;p&gt;But because the entities were managed and the method ran inside an active transaction, every one of those "intermediate state" field mutations got picked up by &lt;em&gt;Hibernate's dirty checking at commit time. What he thought was a harmless, read-only data funnel was silently issuing UPDATE statements against production data&lt;/em&gt; — overwriting real records with transient values that were only ever meant to exist in memory for the duration of the request.&lt;/p&gt;

&lt;p&gt;The fix was intuitive at that point: mark the transaction readOnly = true (@Transactional(readOnly = true)), which tells Hibernate to skip dirty checking and flushing entirely for that context. But 2 things I learnt were Hibernate engineering is a masterclass in abstraction, and learning hibernate is go deep or go home case.&lt;/p&gt;

</description>
      <category>jpa</category>
      <category>hibernate</category>
      <category>programming</category>
      <category>springboot</category>
    </item>
  </channel>
</rss>
