<?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: Phat Tang</title>
    <description>The latest articles on DEV Community by Phat Tang (@tlphat).</description>
    <link>https://dev.to/tlphat</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F654587%2Fb2e4ca50-ffbd-432d-a34f-910b61b930e1.png</url>
      <title>DEV Community: Phat Tang</title>
      <link>https://dev.to/tlphat</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tlphat"/>
    <language>en</language>
    <item>
      <title>Winnie - Celebrate Your Wins: Tips For Productivity And Motivation</title>
      <dc:creator>Phat Tang</dc:creator>
      <pubDate>Sat, 30 Mar 2024 09:50:28 +0000</pubDate>
      <link>https://dev.to/tlphat/winnie-celebrate-your-wins-tips-for-productivity-and-motivation-597b</link>
      <guid>https://dev.to/tlphat/winnie-celebrate-your-wins-tips-for-productivity-and-motivation-597b</guid>
      <description>&lt;p&gt;Recently, I've been developing &lt;a href="https://winnietracker.netlify.app/"&gt;Winnie&lt;/a&gt;, a simple tool designed to help people celebrate their wins and milestones while working on big projects. I believe journaling is essential, especially for engineers, to stay motivated and focused on our goals.&lt;/p&gt;

&lt;p&gt;As a software engineer early in my career, I'm passionate about coding, problem-solving, and building new things. However, like many of you, I've realized that solely focusing on coding in isolation can lead to being overlooked.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdql5ai0v5xsr5l1gh00t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdql5ai0v5xsr5l1gh00t.png" alt="Isolation" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In my early months, I struggled to effectively communicate my accomplishments during standups, sprint reviews, or performance evaluations. This resulted in my performance being seen as just average after the first cycle, despite "having delivered a tremendous amount of code", and "having completed a tremendous amount of tasks".&lt;/p&gt;

&lt;p&gt;To address this, I started documenting my daily achievements in a Google Doc, and I noticed significant changes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuiimpy4d7rkiams5yfpk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuiimpy4d7rkiams5yfpk.png" alt="Example of my document" width="800" height="441"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Firstly, I became more productive. By taking time to refine my achievements daily, my updates during standups became more engaging. People started to acknowledge my work and offer constructive feedback that improved my efficiency.&lt;/p&gt;

&lt;p&gt;For instance, I transformed a basic update like "Yesterday I fixed an issue in ticket 12. No blockers" into something like: "I was fixing the permission issue when publishing messages to the broker. After working with SRE team, we detected the incorrect service principal got injected into the container runtime. Today..." It became a meaningful story where everyone got interested and actually understood what was going on.&lt;/p&gt;

&lt;p&gt;Secondly, having a documented record of my accomplishments proved invaluable during performance reviews. With managers overseeing multiple engineers, it's easy for them to lose track of individual contributions. Having concrete evidence at hand saved time and effort, and also improved my review result.&lt;/p&gt;

&lt;p&gt;Lastly, documenting my wins allowed me to reflect on my progress, make necessary adjustments, and feel a sense of pride in my achievements. If I couldn't come up with some meaningful achievement for a few days in a row, I knew that something needed to be changed, so I reached out to peers and managers to get more meaningful tasks. In general, the habit of documenting and celebrating wins fosters a proactive and positive mindset.&lt;/p&gt;

&lt;p&gt;Motivated by this experience, I created &lt;a href="https://winnietracker.netlify.app/"&gt;Winnie&lt;/a&gt; to enhance the journaling experience for others. With Winnie, you can easily record, view, and update achievements with just a click. Data is stored completely in your browser, and most importantly, no sign-in is required.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fich0vzj6k81po29iv8pb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fich0vzj6k81po29iv8pb.png" alt="Winnie Landing Page" width="800" height="392"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I invite you to try &lt;a href="https://winnietracker.netlify.app/"&gt;Winnie&lt;/a&gt; and experience its impact on your productivity and mindset. Your feedback will shape Winnie's evolution, ensuring it meets the needs of users.&lt;/p&gt;

&lt;p&gt;Right now, I'm planning for a set of features for the next release:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tagging (for categorization)&lt;/li&gt;
&lt;li&gt;Searching for wins&lt;/li&gt;
&lt;li&gt;Exporting to PDF&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>motivation</category>
      <category>productivity</category>
      <category>sideprojects</category>
      <category>career</category>
    </item>
    <item>
      <title>Locking Mechanism, Serializable, and Deadlock</title>
      <dc:creator>Phat Tang</dc:creator>
      <pubDate>Sun, 13 Mar 2022 12:57:06 +0000</pubDate>
      <link>https://dev.to/tlphat/locking-mechanism-serializable-and-deadlock-17l2</link>
      <guid>https://dev.to/tlphat/locking-mechanism-serializable-and-deadlock-17l2</guid>
      <description>&lt;p&gt;In the post about &lt;a href="https://dev.to/tlphat/repeatable-read-consistent-read-and-serialization-anomaly-4eln"&gt;repeatable read isolation level&lt;/a&gt;, I've mentioned the serialization anomaly problem. Despite having consistent read results, the writing operations can introduce unexpected behaviors or even inconsistent data states after our transaction got committed.&lt;/p&gt;

&lt;p&gt;The last transaction isolation level is called SERIALIZABLE, and it can be used to protect our transactions from being interfered with by others when running concurrently. But before going through this isolation level, I'd like to describe the approach that MySQL uses to eliminate the interference of UPDATE statements into our read results.&lt;/p&gt;

&lt;h2&gt;
  
  
  Locking mechanism
&lt;/h2&gt;

&lt;p&gt;First, we might need to go through the basics of &lt;a href="https://dev.mysql.com/doc/refman/8.0/en/innodb-locking.html#innodb-shared-exclusive-locks"&gt;shared lock and exclusive lock&lt;/a&gt;. Those two locks are respectively similar to read lock and write lock in the famous readers-writers problem. &lt;/p&gt;

&lt;p&gt;Simply put, if a transaction is holding a shared lock on a row, other transactions can only acquire the shared lock on that row, but &lt;strong&gt;not the exclusive lock&lt;/strong&gt;. Meanwhile, if a transaction is holding an exclusive lock on a row, then no other transactions can acquire &lt;strong&gt;any kind of lock&lt;/strong&gt; on that row.&lt;/p&gt;

&lt;p&gt;Let's continue with the familiar example of Tom's balance in the &lt;strong&gt;account&lt;/strong&gt; table.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt; @@transaction_isolation&lt;span class="p"&gt;;&lt;/span&gt;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| REPEATABLE-READ         |
+-------------------------+
1 row &lt;span class="k"&gt;in &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;0.00 sec&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; describe account&lt;span class="p"&gt;;&lt;/span&gt;
+---------+-------------+------+-----+---------+-------+
| Field   | Type        | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+-------+
| owner   | varchar&lt;span class="o"&gt;(&lt;/span&gt;50&lt;span class="o"&gt;)&lt;/span&gt; | NO   | PRI | NULL    |       |
| balance | int         | YES  |     | NULL    |       |
+---------+-------------+------+-----+---------+-------+
2 rows &lt;span class="k"&gt;in &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;0.03 sec&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; from account&lt;span class="p"&gt;;&lt;/span&gt;
+-------+---------+
| owner | balance |
+-------+---------+
| Mary  |     160 |
| Tom   |     300 |
+-------+---------+
2 rows &lt;span class="k"&gt;in &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;0.00 sec&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are in the REPEATABLE READ isolation level. For now, let's just stick to one terminal, and start the transaction that adds $50 to Mary's balance. However, do not commit this transaction at the moment, because we are going to see what happened after we update that row.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; begin&lt;span class="p"&gt;;&lt;/span&gt;
Query OK, 0 rows affected &lt;span class="o"&gt;(&lt;/span&gt;0.01 sec&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; update account &lt;span class="nb"&gt;set &lt;/span&gt;balance &lt;span class="o"&gt;=&lt;/span&gt; balance + 50 where owner &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Mary'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
Query OK, 1 row affected &lt;span class="o"&gt;(&lt;/span&gt;0.04 sec&lt;span class="o"&gt;)&lt;/span&gt;
Rows matched: 1  Changed: 1  Warnings: 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let's make a SELECT statement to query what rows have been locked by our engine.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; from performance_schema.data_locks&lt;span class="se"&gt;\G&lt;/span&gt;
&lt;span class="k"&gt;***************************&lt;/span&gt; 1. row &lt;span class="k"&gt;***************************&lt;/span&gt;
               ...
          OBJECT_NAME: account
               ...
            LOCK_TYPE: TABLE
            LOCK_MODE: IX
          LOCK_STATUS: GRANTED
            LOCK_DATA: NULL
&lt;span class="k"&gt;***************************&lt;/span&gt; 2. row &lt;span class="k"&gt;***************************&lt;/span&gt;
               ...
          OBJECT_NAME: account
               ...
            LOCK_TYPE: RECORD
            LOCK_MODE: X,REC_NOT_GAP
          LOCK_STATUS: GRANTED
            LOCK_DATA: &lt;span class="s1"&gt;'Mary'&lt;/span&gt;
2 rows &lt;span class="k"&gt;in &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;0.00 sec&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I've added the suffix "\G" to the query to make the result is rendered in vertical format. Ignoring some irrelevant fields, I want you to notice that there are currently two locks that are active in our database.&lt;/p&gt;

&lt;p&gt;The first lock is the TABLE lock, and it is of mode IX (which stands for &lt;strong&gt;intention exclusive&lt;/strong&gt;). It is used to indicate that our &lt;strong&gt;account&lt;/strong&gt; table will require a record exclusive lock. And that exclusive lock is also the second entry in the retrieved results. It is of mode X (which stands for &lt;strong&gt;exclusive&lt;/strong&gt;), and the level of granularity is RECORD.&lt;/p&gt;

&lt;p&gt;Let's commit the transaction and check the &lt;strong&gt;performance_schema&lt;/strong&gt; table again.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; commit&lt;span class="p"&gt;;&lt;/span&gt;
Query OK, 0 rows affected &lt;span class="o"&gt;(&lt;/span&gt;0.01 sec&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; SELECT &lt;span class="k"&gt;*&lt;/span&gt; from performance_schema.data_locks&lt;span class="se"&gt;\G&lt;/span&gt;
Empty &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;0.00 sec&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The locks are now released. From this, we can have a sense that whenever we make an update (or a write) on the data, our transaction will acquire an exclusive lock on the rows that we updated. And the locks are only released when we commit (or rollback) our transaction.&lt;/p&gt;

&lt;p&gt;What happened if another transaction also wants to acquire the exclusive lock on that row (say, by trying to subtract $60 from Mary's balance)? The answer is: that transaction will be &lt;strong&gt;pending&lt;/strong&gt;, either until &lt;strong&gt;timeout&lt;/strong&gt; or the &lt;strong&gt;exclusive lock is released by our transaction&lt;/strong&gt;. Feel free to verify my statement.&lt;/p&gt;

&lt;p&gt;"But wait," you might say. "We've tried to read the row that got updated in the examples of dirty read, non-repeatable read, and phantom read. However, you said that shared lock is similar to the concept of read lock. Why we can still acquire the shared lock to read the exclusive locked records?"&lt;/p&gt;

&lt;p&gt;Well, in fact, our transaction cannot acquire the shared lock on the records that have been locked before by the exclusive lock. What happened is the SELECT statement &lt;strong&gt;does not&lt;/strong&gt; apply the shared lock (by default) to the records in the result. Our transaction only acquires the shared lock when our SELECT statement ends with two words: FOR SHARE.&lt;/p&gt;

&lt;p&gt;Let's open two transactions on two separate connections to test what I've just said.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;:: TERMINAL A
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; begin&lt;span class="p"&gt;;&lt;/span&gt;
Query OK, 0 rows affected &lt;span class="o"&gt;(&lt;/span&gt;0.00 sec&lt;span class="o"&gt;)&lt;/span&gt;

mysql&amp;gt; &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; from account where owner &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Tom'&lt;/span&gt; &lt;span class="k"&gt;for &lt;/span&gt;share&lt;span class="p"&gt;;&lt;/span&gt;
+-------+---------+
| owner | balance |
+-------+---------+
| Tom   |     300 |
+-------+---------+
1 row &lt;span class="k"&gt;in &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;0.00 sec&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; from performance_schema.data_locks&lt;span class="se"&gt;\G&lt;/span&gt;
&lt;span class="k"&gt;***************************&lt;/span&gt; 1. row &lt;span class="k"&gt;***************************&lt;/span&gt;
               ...
          OBJECT_NAME: account
               ...
            LOCK_TYPE: TABLE
            LOCK_MODE: IS
          LOCK_STATUS: GRANTED
            LOCK_DATA: NULL
&lt;span class="k"&gt;***************************&lt;/span&gt; 2. row &lt;span class="k"&gt;***************************&lt;/span&gt;
               ...
          OBJECT_NAME: account
               ...
            LOCK_TYPE: RECORD
            LOCK_MODE: S,REC_NOT_GAP
          LOCK_STATUS: GRANTED
            LOCK_DATA: &lt;span class="s1"&gt;'Tom'&lt;/span&gt;
2 rows &lt;span class="k"&gt;in &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;0.01 sec&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;IS and S stand for intention shared and shared, respectively.&lt;/p&gt;

&lt;p&gt;Now, we can try updating Tom's balance in another transaction and see if we can still get the result immediately.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;:: TERMINAL B
mysql&amp;gt; begin&lt;span class="p"&gt;;&lt;/span&gt;
Query OK, 0 rows affected &lt;span class="o"&gt;(&lt;/span&gt;0.00 sec&lt;span class="o"&gt;)&lt;/span&gt;

mysql&amp;gt; update account &lt;span class="nb"&gt;set &lt;/span&gt;balance &lt;span class="o"&gt;=&lt;/span&gt; balance + 50 where owner &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Tom'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's pending. You can rollback (or commit) transaction A and check to see if the update got executed immediately.&lt;/p&gt;

&lt;p&gt;There are other modes of lock (say, REC_NOT_GAP). But having a grasp of the X lock and S lock is enough to talk about the last isolation level.&lt;/p&gt;

&lt;h2&gt;
  
  
  Serializable
&lt;/h2&gt;

&lt;p&gt;For your convenience, I will repeat the anomaly scenario we encountered in the previous post:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;I want to subtract $50 from Tom's account if he has enough money&lt;/li&gt;
&lt;li&gt;I open a transaction, run a SELECT statement, and realize that he has $100&lt;/li&gt;
&lt;li&gt;At this very moment, someone opens a transaction, check and see that Tom has $100, then he subtracts $60 from Tom's balance and commits immediately&lt;/li&gt;
&lt;li&gt;Since I've checked that Tom got $100, I proceed to subtract $50 from this account&lt;/li&gt;
&lt;li&gt;Now, his on-disk balance value is -$50, which is an inconsistent state&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The main cause of this issue is that someone can still update Tom's account after I've read it. Imagine if my SELECT statement is replaced by the SELECT FOR SHARE statement, what would happen?&lt;/p&gt;

&lt;p&gt;After step 2, Tom's row got locked (by a shared lock hold by my transaction). Then, as long as my transaction is still in progress, I can be sure that no one can update Tom's row anymore. And we can get rid of the write interferences.&lt;/p&gt;

&lt;p&gt;That's exactly what the SERIALIZABLE isolation level does. It implicitly replaces all SELECT statements by SELECT FOR SHARE, and we are free from serialization anomalies.&lt;/p&gt;

&lt;p&gt;Once again, we can try to see if the transaction is SERIALIZABLE level actually acquires shared lock on normal SELECT statements (remember to rollback or commit all previous transactions to make sure that Tom's row got free).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;set &lt;/span&gt;session transaction isolation level serializable&lt;span class="p"&gt;;&lt;/span&gt;
Query OK, 0 rows affected &lt;span class="o"&gt;(&lt;/span&gt;0.01 sec&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt; @@transaction_isolation&lt;span class="p"&gt;;&lt;/span&gt;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| SERIALIZABLE            |
+-------------------------+
1 row &lt;span class="k"&gt;in &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;0.00 sec&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; begin&lt;span class="p"&gt;;&lt;/span&gt;
Query OK, 0 rows affected &lt;span class="o"&gt;(&lt;/span&gt;0.00 sec&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; from account where owner &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Tom'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
+-------+---------+
| owner | balance |
+-------+---------+
| Tom   |     150 |
+-------+---------+
1 row &lt;span class="k"&gt;in &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;0.00 sec&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; from performance_schema.data_locks&lt;span class="se"&gt;\G&lt;/span&gt;
&lt;span class="k"&gt;***************************&lt;/span&gt; 1. row &lt;span class="k"&gt;***************************&lt;/span&gt;
               ...
          OBJECT_NAME: account
               ...
            LOCK_TYPE: TABLE
            LOCK_MODE: IS
          LOCK_STATUS: GRANTED
            LOCK_DATA: NULL
&lt;span class="k"&gt;***************************&lt;/span&gt; 2. row &lt;span class="k"&gt;***************************&lt;/span&gt;
               ...
          OBJECT_NAME: account
               ...
            LOCK_TYPE: RECORD
            LOCK_MODE: S,REC_NOT_GAP
          LOCK_STATUS: GRANTED
            LOCK_DATA: &lt;span class="s1"&gt;'Tom'&lt;/span&gt;
2 rows &lt;span class="k"&gt;in &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;0.00 sec&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we can see, our transaction did acquire the shared lock on the SELECT statement. We now get rid of dirty read, non-repeatable read, phantom read, and even serialization anomaly. However, it doesn't mean that SERIALIZABLE is the best choice for all situations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deadlock
&lt;/h2&gt;

&lt;p&gt;If you have some experience with locking before in the OS courses, or when trying to make a multithread application, you probably have heard of this issue. Whenever there is a lock, there is a chance that we might encounter deadlocks.&lt;/p&gt;

&lt;p&gt;Imagine this scenario:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Transaction A reads Tom's account (acquire the shared lock on Tom's row)&lt;/li&gt;
&lt;li&gt;Transaction B reads Tom's account (acquire the shared lock on Tom's row, remember shared lock is shareable)&lt;/li&gt;
&lt;li&gt;Transaction A updated Tom's account and got pending, waiting for transaction B (since it has been locked by the shared lock of transaction B)&lt;/li&gt;
&lt;li&gt;Transaction B updated Tom's account and got pending, waiting for transaction A (for the same reason)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Two transactions wait for each other. Neither transaction can commit or rollback, we are in a deadlock situation. Luckily, our DBMS is smart enough to detect it in advance and resolve the deadlock. Typically, some transaction needs to roll back to get rid of the locks.&lt;/p&gt;

&lt;p&gt;You might ask: "If the SERIALIZABLE transaction is free from dirty read, non-repeatable read, phantom read, and serialization anomaly, then why it's not the default isolation level? Why do people still even use other isolation levels?"&lt;/p&gt;

&lt;p&gt;One of the reasons I can think of is the deadlock. Once our transaction got rollback due to deadlock, it should be executed again. Having to re-execute transactions decreases our application performance significantly. Therefore, for some scenarios, where read phenomena are not likely to happen or not cause some serious issues, people can tolerate it and choose a lower isolation level to increase application performance.&lt;/p&gt;

&lt;p&gt;It's also the end of the isolation levels series. We went through the basics of the ACID properties, four isolation levels, and how they resolve the read phenomena. I also include some examples in MySQL.&lt;/p&gt;

&lt;p&gt;Hope you guys find this helpful and continue to explore other interesting topics of DBMS. You can also lookup the documentation of other DB systems to see how they implement the isolation levels (like &lt;a href="https://www.postgresql.org/docs/9.5/transaction-iso.html"&gt;PostgreSQL&lt;/a&gt; and &lt;a href="https://docs.oracle.com/cd/B13789_01/server.101/b10743/consist.htm"&gt;Oracle&lt;/a&gt;). There is a slight variation but the fundamental ideas are the same.&lt;/p&gt;

</description>
      <category>database</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Repeatable Read, Consistent Read, and Serialization Anomaly</title>
      <dc:creator>Phat Tang</dc:creator>
      <pubDate>Sat, 05 Mar 2022 14:24:12 +0000</pubDate>
      <link>https://dev.to/tlphat/repeatable-read-consistent-read-and-serialization-anomaly-4eln</link>
      <guid>https://dev.to/tlphat/repeatable-read-consistent-read-and-serialization-anomaly-4eln</guid>
      <description>&lt;p&gt;As I mentioned earlier in &lt;a href="https://dev.to/tlphat/read-uncommitted-and-read-committed-1clm"&gt;the previous part&lt;/a&gt;, the READ COMMITTED isolation level does not guarantee that our read results are repeatable. &lt;strong&gt;Non-repeatable read&lt;/strong&gt; and &lt;strong&gt;phantom read&lt;/strong&gt; are the two phenomena that we would resolve in the next isolation level. It is called REPEATABLE READ.&lt;/p&gt;

&lt;h2&gt;
  
  
  Repeatable Read
&lt;/h2&gt;

&lt;p&gt;Let me remind you a bit about the example that we used last time for the demonstration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; describe account&lt;span class="p"&gt;;&lt;/span&gt;
+---------+-------------+------+-----+---------+-------+
| Field   | Type        | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+-------+
| owner   | varchar&lt;span class="o"&gt;(&lt;/span&gt;50&lt;span class="o"&gt;)&lt;/span&gt; | NO   | PRI | NULL    |       |
| balance | int         | YES  |     | NULL    |       |
+---------+-------------+------+-----+---------+-------+
2 rows &lt;span class="k"&gt;in &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;0.03 sec&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; from account&lt;span class="p"&gt;;&lt;/span&gt;
+-------+---------+
| owner | balance |
+-------+---------+
| Mary  |     210 |
| Tom   |     200 |
+-------+---------+
2 rows &lt;span class="k"&gt;in &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;0.00 sec&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First, we open two connections to our local MySQL server. REPEATABLE READ is the default isolation level of the InnoDB engine. To verify this, we can run a command to check for the value of the &lt;strong&gt;@@transaction_isolation&lt;/strong&gt; variable. In case it has been changed before, we can run the following command to make sure that the isolation level on both sessions is REPEATABLE READ.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;:: BOTH TERMINALS
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;set &lt;/span&gt;session transaction isolation level repeatable &lt;span class="nb"&gt;read&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
Query OK, 0 rows affected &lt;span class="o"&gt;(&lt;/span&gt;0.00 sec&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt; @@transaction_isolation&lt;span class="p"&gt;;&lt;/span&gt;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| REPEATABLE-READ         |
+-------------------------+
1 row &lt;span class="k"&gt;in &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;0.00 sec&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In terminal B, let's re-run the two queries (which cause us some troubles in the READ COMMITTED level).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;:: TERMINAL B
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; begin&lt;span class="p"&gt;;&lt;/span&gt;
Query OK, 0 rows affected &lt;span class="o"&gt;(&lt;/span&gt;0.00 sec&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; from account where owner &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Tom'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
+-------+---------+
| owner | balance |
+-------+---------+
| Tom   |     200 |
+-------+---------+
1 row &lt;span class="k"&gt;in &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;0.00 sec&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; from account where balance &amp;lt; 220&lt;span class="p"&gt;;&lt;/span&gt;
+-------+---------+
| owner | balance |
+-------+---------+
| Mary  |     210 |
| Tom   |     200 |
+-------+---------+
2 rows &lt;span class="k"&gt;in &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;0.00 sec&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's update Tom's account in terminal A. You might be tempted to also check for the dirty read phenomena.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;:: TERMINAL A
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; begin&lt;span class="p"&gt;;&lt;/span&gt;
Query OK, 0 rows affected &lt;span class="o"&gt;(&lt;/span&gt;0.00 sec&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; update account &lt;span class="nb"&gt;set &lt;/span&gt;balance &lt;span class="o"&gt;=&lt;/span&gt; balance + 50 where owner &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Tom'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
Query OK, 1 row affected &lt;span class="o"&gt;(&lt;/span&gt;0.01 sec&lt;span class="o"&gt;)&lt;/span&gt;
Rows matched: 1  Changed: 1  Warnings: 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;:: TERMINAL B
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; begin&lt;span class="p"&gt;;&lt;/span&gt;
Query OK, 0 rows affected &lt;span class="o"&gt;(&lt;/span&gt;0.00 sec&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; from account where owner &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Tom'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
+-------+---------+
| owner | balance |
+-------+---------+
| Tom   |     200 |
+-------+---------+
1 row &lt;span class="k"&gt;in &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;0.00 sec&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; from account where balance &amp;lt; 220&lt;span class="p"&gt;;&lt;/span&gt;
+-------+---------+
| owner | balance |
+-------+---------+
| Mary  |     210 |
| Tom   |     200 |
+-------+---------+
2 rows &lt;span class="k"&gt;in &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;0.00 sec&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So far so good, no dirty read. Let's commit transaction A and check for the result of those two queries again (in transaction B).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;:: TERMINAL A
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; commit&lt;span class="p"&gt;;&lt;/span&gt;
Query OK, 0 rows affected &lt;span class="o"&gt;(&lt;/span&gt;0.01 sec&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;:: TERMINAL B
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; begin&lt;span class="p"&gt;;&lt;/span&gt;
Query OK, 0 rows affected &lt;span class="o"&gt;(&lt;/span&gt;0.00 sec&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; from account where owner &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Tom'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
+-------+---------+
| owner | balance |
+-------+---------+
| Tom   |     200 |
+-------+---------+
1 row &lt;span class="k"&gt;in &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;0.00 sec&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; from account where balance &amp;lt; 220&lt;span class="p"&gt;;&lt;/span&gt;
+-------+---------+
| owner | balance |
+-------+---------+
| Mary  |     210 |
| Tom   |     200 |
+-------+---------+
2 rows &lt;span class="k"&gt;in &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;0.00 sec&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The results are the same as the first time we executed those two queries. We now get rid of non-repeatable read and phantom read. &lt;/p&gt;

&lt;p&gt;Notice that if we read the standard definition of the isolation levels, we might see that REPEATABLE READ only guarantees to eliminate non-repeatable phenomena, while allowing phantom read to occur. However, some RDBMS (like MySQL and PostgreSQL) choose to also eliminate phantom read in REPEATABLE READ isolation level.&lt;/p&gt;

&lt;p&gt;In short, with MySQL, REPEATABLE READ guarantee that our reads are consistent. However, there are a couple of things that we need to notice here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Consistent Read
&lt;/h2&gt;

&lt;p&gt;First, I want to emphasize that "our reads are consistent". It means that when we read the row for the first time in our transaction, the DBMS will take a snapshot of that row. Then, &lt;strong&gt;as long as we didn't make any change in that transaction&lt;/strong&gt;, later read results of that row will stay the same as that snapshot.&lt;/p&gt;

&lt;p&gt;However, what if we &lt;strong&gt;make some changes in that transaction&lt;/strong&gt;? Let's say we subtract $50 from Mary's balance in transaction B.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;:: TERMINAL B
mysql&amp;gt; update account &lt;span class="nb"&gt;set &lt;/span&gt;balance &lt;span class="o"&gt;=&lt;/span&gt; balance - 50 where owner &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Mary'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
Query OK, 1 row affected &lt;span class="o"&gt;(&lt;/span&gt;0.01 sec&lt;span class="o"&gt;)&lt;/span&gt;
Rows matched: 1  Changed: 1  Warnings: 0

mysql&amp;gt; &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; from account where balance &amp;lt; 220&lt;span class="p"&gt;;&lt;/span&gt;
+-------+---------+
| owner | balance |
+-------+---------+
| Mary  |     160 |
| Tom   |     200 |
+-------+---------+
2 rows &lt;span class="k"&gt;in &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;0.00 sec&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we can see, Mary's balance changed to $160, while Tom's balance remains at $200. We can see one interesting property of this isolation level: the SELECT statement might return a set of rows that &lt;strong&gt;never exists&lt;/strong&gt; in the database. &lt;/p&gt;

&lt;p&gt;Before transaction A, those two balance values (on-disk) should be ($210, $200). After transaction A, it should be ($210, $250). And after the update in transaction B, it should be ($160, $250). The result ($160, $200) that we see is just a combination of the real Mary's balance and the snapshot of Tom's balance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Serialization Anomaly
&lt;/h2&gt;

&lt;p&gt;So we can get the feeling of what is called "consistent read" in REPEATABLE READ. Let me ask you one more question. If we increase Tom's balance by $50 in transaction B, what would be Tom's balance after we run the SELECT statement again?&lt;/p&gt;

&lt;p&gt;Would it be $250? Or would it be $300?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;:: TERMINAL B
mysql&amp;gt; update account &lt;span class="nb"&gt;set &lt;/span&gt;balance &lt;span class="o"&gt;=&lt;/span&gt; balance + 50 where owner &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Tom'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
Query OK, 1 row affected &lt;span class="o"&gt;(&lt;/span&gt;0.01 sec&lt;span class="o"&gt;)&lt;/span&gt;
Rows matched: 1  Changed: 1  Warnings: 0

mysql&amp;gt; &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; from account where owner &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Tom'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
+-------+---------+
| owner | balance |
+-------+---------+
| Tom   |     300 |
+-------+---------+
3 rows &lt;span class="k"&gt;in &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;0.00 sec&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It was $300. So the balance value that got increased is the actual balance value that resides on the disk. Let me summarize what's happening here: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In transaction B, we read Tom's balance and know that he has $200.&lt;/li&gt;
&lt;li&gt;Then we increase his balance by $50, and when we read his balance again, he suddenly has $300!!!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Our transaction somehow still gets interfered with by other transactions.&lt;/p&gt;

&lt;p&gt;And if you don't see that it's big trouble. Let's think about this scenario (I changed the number to emphasize how bad it can be):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I want to subtract $50 from Tom's account if he has enough money&lt;/li&gt;
&lt;li&gt;I open a transaction, run a SELECT statement and realize that he has $100&lt;/li&gt;
&lt;li&gt;At this very moment, someone opens a transaction, check and see that Tom has $100, then he subtracts $60 from Tom's balance and commits immediately&lt;/li&gt;
&lt;li&gt;Since I've checked that Tom got $100, I proceed to subtract $50 from this account&lt;/li&gt;
&lt;li&gt;Now, his on-disk balance value is &lt;del&gt;-$50&lt;/del&gt; (update: -$10), which is an inconsistent state&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is a serialization anomaly. It means that transactions A &amp;amp; B interfere and result in an anomaly state (a state that cannot be achieved if we run A before B or B before A).&lt;/p&gt;

&lt;p&gt;This is also the last phenomenon that we need to solve. As long as we can guarantee that there is no serialization anomaly, we can confidently say that our transactions are isolated.&lt;/p&gt;

&lt;p&gt;The solution turns out to be very familiar: we need to apply a certain kind of locking mechanism to our read/write operations. Anyway, we will discuss the solution more in the next post, along with the last isolation level.&lt;/p&gt;

</description>
      <category>database</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Read Uncommitted and Read Committed</title>
      <dc:creator>Phat Tang</dc:creator>
      <pubDate>Wed, 02 Mar 2022 13:12:41 +0000</pubDate>
      <link>https://dev.to/tlphat/read-uncommitted-and-read-committed-1clm</link>
      <guid>https://dev.to/tlphat/read-uncommitted-and-read-committed-1clm</guid>
      <description>&lt;p&gt;First, we initialize the &lt;strong&gt;account&lt;/strong&gt; table with some records as follows. I use MySQL to demonstrate all four isolation levels. The main concepts still apply for other RDBMS.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; describe account&lt;span class="p"&gt;;&lt;/span&gt;
+---------+-------------+------+-----+---------+-------+
| Field   | Type        | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+-------+
| owner   | varchar&lt;span class="o"&gt;(&lt;/span&gt;50&lt;span class="o"&gt;)&lt;/span&gt; | NO   | PRI | NULL    |       |
| balance | int         | YES  |     | NULL    |       |
+---------+-------------+------+-----+---------+-------+
2 rows &lt;span class="k"&gt;in &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;0.03 sec&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; from account&lt;span class="p"&gt;;&lt;/span&gt;
+-------+---------+
| owner | balance |
+-------+---------+
| Mary  |     210 |
| Tom   |     200 |
+-------+---------+
2 rows &lt;span class="k"&gt;in &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;0.00 sec&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In fact, &lt;strong&gt;owner&lt;/strong&gt; should not be chosen as a primary key. However, for demonstration, let's simplify our schema that way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Read Uncommitted
&lt;/h2&gt;

&lt;p&gt;This isolation level permits the transaction to read even the uncommitted data. Let's see what does it mean. We open two connections on terminals A and B, respectively. Then, apply the following command to set the isolation level to READ UNCOMMITTED.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;:: BOTH TERMINALS
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;set &lt;/span&gt;session transaction isolation level &lt;span class="nb"&gt;read &lt;/span&gt;uncommitted&lt;span class="p"&gt;;&lt;/span&gt;
Query OK, 0 rows affected &lt;span class="o"&gt;(&lt;/span&gt;0.00 sec&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt; @@transaction_isolation&lt;span class="p"&gt;;&lt;/span&gt;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| READ-UNCOMMITTED        |
+-------------------------+
1 row &lt;span class="k"&gt;in &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;0.00 sec&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now start the new transaction in both terminals. From now on, let's call the transaction in terminal A transaction A, and similarly for transaction B on terminal B.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;:: BOTH TERMINALS
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; begin&lt;span class="p"&gt;;&lt;/span&gt;
Query OK, 0 rows affected &lt;span class="o"&gt;(&lt;/span&gt;0.00 sec&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, in terminal A, add $50 to Tom's balance, and don't commit this transaction yet.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;:: TERMINAL A
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; update account &lt;span class="nb"&gt;set &lt;/span&gt;balance &lt;span class="o"&gt;=&lt;/span&gt; balance + 50 where owner &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Tom'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
Query OK, 1 row affected &lt;span class="o"&gt;(&lt;/span&gt;0.01 sec&lt;span class="o"&gt;)&lt;/span&gt;
Rows matched: 1  Changed: 1  Warnings: 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now if we take a look at Tom's balance on transaction B, we see that his balance has also increased to $250.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;:: TERMINAL B
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; from account where owner &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Tom'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
+-------+---------+
| owner | balance |
+-------+---------+
| Tom   |     250 |
+-------+---------+
1 row &lt;span class="k"&gt;in &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;0.00 sec&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This phenomenon is called &lt;strong&gt;dirty read&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Why dirty? You might ask. Well, we know that a transaction carries our data from one consistent state to another consistent state (the C in ACID). However, transaction A has not been committed yet. It means that our transaction has not finished, and probably another UPDATE statement is waiting ahead (say, subtract 50$ from Tom's balance again).&lt;/p&gt;

&lt;p&gt;That's the reason why Tom's current balance ($250) is not an "official" value yet. And by allowing other transactions to read such data, we might end up with a wrong condition check during transaction B or even worse, inconsistent data after the transactions have been committed.&lt;/p&gt;

&lt;p&gt;Let's roll back both transactions and move on to the second isolation level.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;:: BOTH TERMINALS
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; rollback&lt;span class="p"&gt;;&lt;/span&gt;
Query OK, 0 rows affected &lt;span class="o"&gt;(&lt;/span&gt;0.00 sec&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; from account where owner &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Tom'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
+-------+---------+
| owner | balance |
+-------+---------+
| Tom   |     200 |
+-------+---------+
1 row &lt;span class="k"&gt;in &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;0.00 sec&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Read Committed
&lt;/h2&gt;

&lt;p&gt;With this isolation level, the data being read in our transaction is always guaranteed to be committed. Let's change the isolation level in both terminals to read committed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;:: BOTH TERMINALS
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;set &lt;/span&gt;session transaction isolation level &lt;span class="nb"&gt;read &lt;/span&gt;committed&lt;span class="p"&gt;;&lt;/span&gt;
Query OK, 0 rows affected &lt;span class="o"&gt;(&lt;/span&gt;0.00 sec&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt; @@transaction_isolation&lt;span class="p"&gt;;&lt;/span&gt;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| READ-COMMITTED          |
+-------------------------+
1 row &lt;span class="k"&gt;in &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;0.00 sec&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; begin&lt;span class="p"&gt;;&lt;/span&gt;
Query OK, 0 rows affected &lt;span class="o"&gt;(&lt;/span&gt;0.00 sec&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we perform the same dirty read experiment, we will no longer encounter that phenomenon.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;:: TERMINAL A
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; update account &lt;span class="nb"&gt;set &lt;/span&gt;balance &lt;span class="o"&gt;=&lt;/span&gt; balance + 50 where owner &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Tom'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
Query OK, 1 row affected &lt;span class="o"&gt;(&lt;/span&gt;0.01 sec&lt;span class="o"&gt;)&lt;/span&gt;
Rows matched: 1  Changed: 1  Warnings: 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;:: TERMINAL B
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; from account where owner &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Tom'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
+-------+---------+
| owner | balance |
+-------+---------+
| Tom   |     200 |
+-------+---------+
1 row &lt;span class="k"&gt;in &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;0.00 sec&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; from account where balance &amp;lt; 220&lt;span class="p"&gt;;&lt;/span&gt;
+-------+---------+
| owner | balance |
+-------+---------+
| Mary  |     210 |
| Tom   |     200 |
+-------+---------+
2 rows &lt;span class="k"&gt;in &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;0.00 sec&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, Tom's balance is still $200. Let's commit transaction A and check the result again.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;:: TERMINAL A
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; commit&lt;span class="p"&gt;;&lt;/span&gt;
Query OK, 0 rows affected &lt;span class="o"&gt;(&lt;/span&gt;0.01 sec&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;:: TERMINAL B
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; from account where owner &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Tom'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
+-------+---------+
| owner | balance |
+-------+---------+
| Tom   |     250 |
+-------+---------+
1 row &lt;span class="k"&gt;in &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;0.00 sec&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; from account where balance &amp;lt; 220&lt;span class="p"&gt;;&lt;/span&gt;
+-------+---------+
| owner | balance |
+-------+---------+
| Mary  |     210 |
+-------+---------+
1 rows &lt;span class="k"&gt;in &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;0.00 sec&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we can have a sigh of relief that the data we read is always clean. But READ COMMITTED is not the highest level of isolation yet. Why? Because changes in one transaction can still interfere with other transactions. &lt;/p&gt;

&lt;p&gt;Suppose that you run transaction B on a completely separate machine, without any knowledge about transaction A. You first execute those 2 queries and get some results. A few seconds later, you re-execute those 2 queries and get completely different results. It is not very reasonable behavior.&lt;/p&gt;

&lt;p&gt;In other words, those read statements are non-repeatable. The issue with the first SELECT statement is called &lt;strong&gt;non-repeatable read&lt;/strong&gt;, and the issue with the second SELECT statement is called &lt;strong&gt;phantom read&lt;/strong&gt;. Non-repeatable read means that you get two different rows, and phantom read means that you get two different sets of rows.&lt;/p&gt;

&lt;p&gt;Therefore, we need a higher isolation level to resolve those two issues. And we will mention it in the next post.&lt;/p&gt;

&lt;p&gt;Anyway, we still have one interesting scenario left to consider. When transaction A runs in READ UNCOMMITTED and transaction B runs in READ COMMITTED level, can you guess what will happen?&lt;/p&gt;

&lt;p&gt;It turns out that nothing really special happened. Each transaction still follows its principles. Changes by transaction A before commit still cannot be read by transaction B, and A can read the result of any UPDATE statements in B immediately. I shall left the task of verifying to you.&lt;/p&gt;

</description>
      <category>database</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Things I learned from the Internet course</title>
      <dc:creator>Phat Tang</dc:creator>
      <pubDate>Tue, 01 Mar 2022 14:36:54 +0000</pubDate>
      <link>https://dev.to/tlphat/things-i-learned-from-the-internet-course-2o9c</link>
      <guid>https://dev.to/tlphat/things-i-learned-from-the-internet-course-2o9c</guid>
      <description>&lt;h2&gt;
  
  
  What is the Internet?
&lt;/h2&gt;

&lt;p&gt;Internet is a large hierarchical network of devices talking to each other. The devices that reside at the edge of the Internet are called hosts. The devices at the center are a bunch of interconnected packet switches, including switches and routers. Those devices rely on protocols to talk to each other.&lt;/p&gt;

&lt;p&gt;Together, those devices form groups of networks. And those networks are interconnected to create a larger network. The links between them can be either wired or wireless. They form a very complex infrastructure for daily applications to operate. They facilitate the development of modern and convenient services such as instant messaging, video streaming, social media, etc.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nwt_G3qQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8frxdv77btq821e2aty4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nwt_G3qQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8frxdv77btq821e2aty4.png" alt="Internet overview" width="880" height="546"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How do devices communicate on Internet?
&lt;/h2&gt;

&lt;p&gt;When two processes on the same host communicate, they rely on inter-process communication mechanisms provided by the OS. However, the communication between two processes on two different hosts is different. They need to use messages to talk to each other. And those messages need to be passed around the Internet.&lt;/p&gt;

&lt;p&gt;A typical way to model the networking system is to use the five layers TCP/IP model. From the top to the bottom, we have the application layer, transport layer, network layer, link layer, and physical layers. Each layer has a separate consideration, with a different set of protocols, and is often stacked together to make protocol stacks. &lt;/p&gt;

&lt;p&gt;Those stacks are the things that empower the Internet. If an application on one machine needs to send the message to another application that resides on a different machine, that message should travel from the application layer, transport layer, network layer, link layer, and physical layer. From that layer, it will be bit by bit transmitted to the other host's physical layer and then travels back to the application layer in the reverse manner.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--y2cmPp37--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m9clnaof49hr41tt64rq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--y2cmPp37--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m9clnaof49hr41tt64rq.png" alt="TCP/IP model" width="434" height="262"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  What happened behind the scene when we browse for somesite.com?
&lt;/h2&gt;

&lt;p&gt;Notes: &lt;strong&gt;somesite.com&lt;/strong&gt; is just an arbitrary domain name. I assume that there is a web server running behind that domain name.&lt;/p&gt;

&lt;p&gt;When you enter &lt;strong&gt;somesite.com&lt;/strong&gt; in your browser, you'll get a homepage of that website. The server of that website has done an amazing job to serves our request in just a second. But there are lots of things that happened behind the scene.&lt;/p&gt;

&lt;p&gt;The very first thing is DNS lookup. We can imagine that &lt;strong&gt;somesite.com&lt;/strong&gt; is like a person's name. If we know a name of a person, we cannot send them letters. We need to know their address. Similarly, on the Internet, we also have what is called an IP address. The IP address of &lt;strong&gt;somesite.com&lt;/strong&gt; is kept in some DNS servers, and we need to send the query to those servers to get the address.&lt;/p&gt;

&lt;p&gt;There are a lot of DNS servers around the world. And they form a hierarchical structure. On the top, we have root DNS servers. Then at the lower level is top-level domain servers, authoritative servers, and local DNS servers.&lt;/p&gt;

&lt;p&gt;Our local machine might keep a cache of the recent DNS queries. But in case there is a cache miss, we might send the query to the local DNS server to get the IP address. Wait! How do we know the IP address of the local DNS server? Don't worry, it is often configured on our machines when we first set up the Internet.&lt;/p&gt;

&lt;p&gt;At that time, the local DNS might or might not have that address. If it doesn't, it will act on our behalf to send the query to some root server. Then, that root server might return the address of &lt;strong&gt;somesite.com&lt;/strong&gt;, or it will return the address of another server who might know that address (usually the &lt;strong&gt;.com&lt;/strong&gt; top-level domain servers). And the local DNS server needs to send queries back and forth until it reaches the server that contains the IP address of &lt;strong&gt;somesite.com&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vukRyQI5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yjf5ke9mfdgse7zezq76.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vukRyQI5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yjf5ke9mfdgse7zezq76.png" alt="DNS lookup" width="622" height="580"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;And we've done so many things just to know the destination that we are going to send. At this time, our browser will open a TCP connection to the destination IP address on port 443 (&lt;a href="https://paulbutler.org/2022/what-does-it-mean-to-listen-on-a-port/"&gt;this article&lt;/a&gt; gives a interesting discussion on what does it mean to listen on a port). Notice that we assume &lt;strong&gt;somesite.com&lt;/strong&gt; supports HTTPS. The details of this connection are far more complicated since a couple of packets will be sent back and forth to make sure both parties acknowledge each other.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cvlmnE7T--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5rnn0fkq145inmhm2kqi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cvlmnE7T--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5rnn0fkq145inmhm2kqi.png" alt="TCP handshake" width="492" height="221"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;After the TCP handshake (sending packets to open the connection), we still have the TLS handshake to make. TLS is a protocol used to secure the data being transmitted. At the end of this handshake, your browser and web server have the same session key that is used to encrypt and decrypt the message.&lt;/p&gt;

&lt;p&gt;After TLS, the browser can officially send the GET HTTP request, which is then encrypted by TLS before passing to the TCP socket. HTTP is an application layer protocol, and TCP is a transport layer protocol. Once the message goes to the hand of the TCP socket, it will be the job of TCP to make sure that data will reach the TCP socket on the &lt;strong&gt;somesite.com&lt;/strong&gt; server-side. Then, the &lt;strong&gt;somesite.com&lt;/strong&gt; server will return the HTTP response, which contains the HTML page to be rendered.&lt;/p&gt;

&lt;p&gt;Then the communication keeps going on. The browser may also request CSS files, JS files, or a couple of other requests, and the server replies to them with different responses. After they think that they have talked enough, there is also a ritual they need to follow to terminate the TCP connection.&lt;/p&gt;

&lt;h2&gt;
  
  
  Anything else?
&lt;/h2&gt;

&lt;p&gt;We have just finished probably the simplest journey over the network. There are lots of things that I haven't covered yet. What happened if the transmission message is lost? What happened when the traffic is too busy? How messages from one computer can find their way to another computer that is thousands of miles away? How data can be transmitted in a wireless environment?&lt;/p&gt;

&lt;p&gt;There are a lot of interesting problems along the way when people try to make computers talk together. They rely on some fundamentals (say, TCP/IP layer model), and offer enough flexibility for further improvement (the way they replace TCP by UDP in HTTP/3 stack). It's the reason why learning about the Internet is so much fun. But there is one thing for sure, people always try to make things better, and I believe the Internet is getting far better than it used to be.&lt;/p&gt;

</description>
      <category>network</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Overview of database transaction and ACID properties</title>
      <dc:creator>Phat Tang</dc:creator>
      <pubDate>Sun, 27 Feb 2022 02:11:05 +0000</pubDate>
      <link>https://dev.to/tlphat/overview-of-database-transaction-and-acid-properties-d0p</link>
      <guid>https://dev.to/tlphat/overview-of-database-transaction-and-acid-properties-d0p</guid>
      <description>&lt;p&gt;Back when I was studying Relational Database, I found that database transaction is a very interesting topic. But things soon get complicated when we need to deal with concurrent transactions. Recently I have had a chance to reread my notes about this subject. Therefore, I decided to write a couple of posts to review the knowledge. It will be a series focusing on isolation levels.&lt;/p&gt;

&lt;p&gt;So let's start by defining what is a database transaction.&lt;/p&gt;

&lt;h2&gt;
  
  
  Transaction
&lt;/h2&gt;

&lt;p&gt;Briefly speaking, transaction is an independent &lt;strong&gt;unit of work&lt;/strong&gt;. It usually consists of a list of statements that attempt to read and write data. Let's take an example, with MySQL, it will be a list of SELECTs, UPDATEs, INSERTs, DELETEs, and so on.&lt;/p&gt;

&lt;p&gt;A classic example of a database transaction is to simulate a bank transaction. Suppose Tom wants to transfer $50 from his account to Mary's. We can demonstrate such a transaction in SQL as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;START&lt;/span&gt; &lt;span class="n"&gt;TRANSACTION&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;account&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="k"&gt;owner&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Tom'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;account&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="k"&gt;owner&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Mary'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;COMMIT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a very simplified transaction. In fact, there can also be a SELECT statement to read Tom's balance before making the transfer to guarantee that he has enough money to do so. The statements inside a transaction can also access and modify the data at different scales.&lt;/p&gt;

&lt;p&gt;Anyway, the database management system (DBMS) should (and they tried to) guarantee that such transactions are ACID compliant. And by ACID compliance, I mean that it should satisfy 4 properties: &lt;strong&gt;A&lt;/strong&gt;tomicity, &lt;strong&gt;C&lt;/strong&gt;onsistency, &lt;strong&gt;I&lt;/strong&gt;solation, and &lt;strong&gt;D&lt;/strong&gt;urability.&lt;/p&gt;

&lt;p&gt;In the scope of this overview blog post, I shall try to briefly explain those four concepts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Atomicity
&lt;/h2&gt;

&lt;p&gt;A transaction is called atomic when it never occurs partially. When Tom transfers $50 to Mary, either both the UPDATE statements above are executed, or none of them is executed at all. There cannot be the case when Tom's account got subtracted $50, but Mary's account does not change.&lt;/p&gt;

&lt;p&gt;Remember that a transaction is not guaranteed to be successfully executed. If it fails due to some reason, it must undo all the previous changes (rollback) before exiting. Anything between the BEGIN and COMMIT statements should be atomic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Consistency
&lt;/h2&gt;

&lt;p&gt;It's easier to define the consistency of the data. When all the necessary constraints (e.g. uniqueness, range of values, etc.) of our data are satisfied. Specifically, in the beginning, when our database is empty, it can be considered as a consistent state. &lt;/p&gt;

&lt;p&gt;Imagine we have a special camera that can capture the data at that time of the database (and let's call it a snapshot instead of a photo). Then, someone begins a transaction, making some operations on our data, and commits it. After that, we take another snapshot. The consistency property simply means that if the initial snapshot is consistent, then the snapshot after the transaction is executed is also consistent.&lt;/p&gt;

&lt;p&gt;Up to this point, we can view transactions as ways to carry our data from a consistent state to another consistent state.&lt;/p&gt;

&lt;h2&gt;
  
  
  Isolation
&lt;/h2&gt;

&lt;p&gt;The level of isolation measures how much concurrent transactions can interfere with each other. Ideally, two isolated transactions that are running concurrently should not affect each other. However, as we see, this is often not the case.&lt;/p&gt;

&lt;p&gt;We know that whenever we have concurrency, we need to deal with race conditions. To a certain extent, DBMS also suffers from race conditions between transactions. Those issues are called read phenomena, and different isolation levels will try to resolve a couple of these phenomena.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--J1Av6mgc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d6firazwg1o8vc4o9edx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--J1Av6mgc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d6firazwg1o8vc4o9edx.png" alt="Meme about concurrency" width="735" height="500"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;This is also the focus of this series. In the next posts, we will cover 4 isolation levels, namely, READ UNCOMMITTED, READ COMMITTED, REPEATABLE READ, and SERIALIZABLE.&lt;/p&gt;

&lt;h2&gt;
  
  
  Durability
&lt;/h2&gt;

&lt;p&gt;What does it mean durable? It means "last for a long time". Data stored in RAM is not durable, and data stored in the hard disk is more durable. Most DBMSs try to guarantee that successful transactions will survive permanently, and by survive I mean its effects on the data will never be lost, despite system crashes. This is often implemented by certain log and recovery mechanisms.&lt;/p&gt;

&lt;p&gt;ACID, in some way, is not separated from each other. They are related and support each other. For example, one of the situations we might encounter with the SERIALIZABLE isolation level is deadlock. And when a deadlock occurs, we expect that the transaction is rolled back properly.&lt;/p&gt;

&lt;p&gt;That's it. We will cover dirty read and two first isolation levels next time.&lt;/p&gt;

</description>
      <category>database</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
