استفاده از DynamicInsert@ و DynamicUpdate@ در Spring

توی spring وقتی یک entity جدید میسازید یا entity موجود رو آپدیت می‌کنید، ممکنه فهمیده باشید که همیشه یه دستور SQL یکسان رو اجرا می‌کنید حتی اگه فقط یکی از ویژگی‌های اون entity رو به‌روزرسانی کرده باشید. این اتفاق یه جور بهینه سازی عملکردی هستش که توسط Hibernate ارائه شده . Hibernate سعی می کنه از بررسی اینکه کدوم attribute ها از entity تغییر کرده اجتناب کنه که مجبور نباشه یه دستور SQL خاص برای اونا ایجاد کنه در عوض یه دستور update و insert برای هر entity class ایجاد میکنه که برای هر insert و update از اون استفاده می کنه. استفاده مجدد از یه دستور یکسان، باعث optimize شدن Hibernate میشه اما یه ایرادی داره و اون اینه که اگه فقط یک attribute خاص رو از یه entity بزرگ بخوایم تغییر بدیم، این دستورها یه سربار(overhead) ایجاد می کنن و باعث تاثیر روی فیلدای زیادی روی جداول ما میشن که شاید اصلا نیازی به تغییر اونا نباشه، همچنین اگه نیاز باشه که همه ی تغییرات انجام شده توی دیتابیس رو بررسی کنید، مشکلاتی رو برای شما ایجاد میکنه. در اینجور مواقع اگه شما میخواید یه دستور insert یا update خاص فقط با توجه به تغییرات تون ایجاد کنید و از بقیه ی فیلدهای جداول تون (که قرار نیست تغییر کنن) صرف نظر کنید میتونید از انوتیشن های DynamicInsert@ و DynamicUpdate@ بالای entity class تون استفاده کنید؛ در ادامه نحوه ی کار این دو انوتیشن رو با هم میبینیم. خب قبل از اینکه نحوه انجام این کار رو ببینیم، اجازه بدید یه نگاه گذرا به حالت default توی spring بندازیم@Entity public class ChessPlayer { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String firstName; private String lastName; private Date birthDate; ..... }خب، برای مثال ما اینجا یه entity به اسم ChessPlayer رو ساختیم که شامل id, firstName, lastName, birhtDate میشه.public interface ChessPlayerRepository extends JpaRepository<ChessPlayer, Long>{}و بعد از اون یه Interface میسازیم که از JpaRepository ارث بری کنه.ChessPlayer p = new ChessPlayer(); p.setFirstName(&quotTorben&quot); p.setLastName(&quotJanssen&quot); chessPlayerRepository.save(p);حالا من یه object از کلاس Classplayer میسازم و مقادیر مربوط به attribute های این object رو میدم ولی مقداری رو برای birthDate در نظر نمیگیرم.org.hibernate.SQL : insert into chess_player (birth_date, first_name, last_name, id) values (?,?, ?, ?)همونطور که توی خروجی log میبینید، hibernate یه دستور sql insert اجرا میکنه که تمامی مقادیر جدول chess_player رو set کنه، حتی birth_date رو، با اینکه هیچ مقداری برای اون set نکردیم و null بود.انوتیشن DynamicInsert@@Entity @DynamicInsert public class ChessPlayer { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String firstName; private String lastName; private Date birthDate; ..... }همونطور که میبینید، توی مرحله بعدی من انوتیشن DynamicInsert@ رو بالای کلاس گذاشتم و حالا میریم ببینیم جواب ما بعد از اجرا چه تغییری میکنه.org.hibernate.SQL : insert into chess_player (first_name, last_name, id) values (?, ?, ?)مشخصه که این سری دستور sql insert ای که hibernate اجرا کرده شامل id, first_name, last_name میشه و birth_date رو که مقدارش null بود در نظر نگرفت.انوتیشن DynamicUpdate@این سری من یکی از attribute ها رو تغییر میدم (مثلا firstName) و میخوام ببینم hibernate در حالتی که از انوتیشن DynamicUpdate@ استفاده نکردم و همچنین موقعی که از این انوتیشن استفاده میکنم چه رفتاری داره.@Entity public class ChessPlayer { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String firstName; private String lastName; private Date birthDate; ..... }خب من این سری همون کلاس ChessPlayer رو بدون انوتیشن DynamicUpdate@ نوشتم و مقدار firstName رو تغییر میدم.org.hibernate.SQL : update chess_player set birth_date=?, first_name=?, last_name=? where id=?میبینید که hibernate دستور sql update رو برای تمامی مقادیر اعمال و اجرا میکنه با اینکه فقط first_name رو تغییر داده بودم.@Entity @DynamicUpdate public class ChessPlayer { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String firstName; private String lastName; private Date birthDate; ..... }حالا من انوتیشن DynamicUpdate@ رو بالای کلاس میذارم و برنامه رو دوباره اجرا میکنم تا این سری جواب hibernate رو ببینم.org.hibernate.SQL : update chess_player set first_name=? where id=?میبینید که این سری hibernate فقط اون فیلدی رو که تغییر دادم اعمال کرده و از بقیه ی فیلدهایی که تغییر نکرده بودن صرف نظر کرد.برای مطالعه دقیق تر و بهتر راجع به این دو انوتیشن میتونید این لینک و این یکی رو هم نگاه بندازید.