①事務的屬性ACID
a、原子性atomicity:事務是一個不可分割的工作機關。
b、一緻性consistency:事務必須是資料庫從一個一緻性狀态換到另一個一緻性狀态。
c、隔離性isolation:一個事務的執行不受其他事物的幹擾。
d、持久性durability:事務對資料庫的改變是永久的。
②事務的隔離級别

③mysql隔離級别的實作:通過鎖的方式
讀未送出:性能最好,不加鎖。
串行化:讀的時候加共享鎖,即其他事務可以并發讀,但是不能寫。寫的時候加排它鎖,其他事務不能并發讀寫。
讀已送出和可重複讀:MySQL 采用了 MVCC (多版本并發控制) 的方式,在資料庫表中看到的一行記錄可能實際上有多個版本,每個版本的記錄除了有資料本身外,還要有一個表示版本的字段,記為 row trx_id,而這個字段就是使其發生改變的事務的 id,事務 ID 記為 transaction id,它在事務開始的時候向事務系統申請,按時間先後順序遞增。可重複讀是在事務開始的時候生成一個目前事務全局性的快照,而讀已送出則是每次執行語句的時候都重新生成一次快照。
對于一個快照來說,它能夠讀到哪些版本資料,要遵循以下規則:
- 目前事務内的更新,可以讀到;
- 版本未送出,不能讀到;
- 版本已送出,但是卻在快照建立後送出的,不能讀到;
- 版本已送出,且是在快照建立前送出的,可以讀到;
事務的傳播機制是針對于嵌套事務而言。@Transactional(propagation = Propagation.REQUIRED)
①REQUIRED:spring
預設的事務傳播行為。支援事務。如果方法執行時已經在一個事務中,則加入目前事務,否則重新開啟一個事務,必須在事務中執行。
外層事務送出了,内層才會送出。内/外隻要有報錯,他倆會一起復原,因為内外層方法在同一個事務中,内層隻要抛出了異常,這個事務就會被設定成rollback-only,即使外層try-catch内層的異常,該事務也會復原。
②REQUIRES_NEW:支援事務。每次都是建立一個新事務,如果目前已經在事務中了,會挂起目前事務,必須在新的事務中執行。内層事務結束,内層就送出了,不用等着外層一起送出。外層報錯復原,不影響内層。内層報錯復原,外層try-catch内層的異常,外層不會復原。内層報錯復原,然後又會抛出異常,外層如果沒有捕獲處理内層抛出的異常,外層復原。
③NESTED:支援事務。如果目前已經在一個事務中了,則嵌套在已有的事務中作為一個子事務。如果目前沒在事務中則開啟一個事務。内層事務結束,要等着外層一起送出。外層復原,内層也復原。如果隻是内層復原,不影響外層。這個内層復原不影響外層的特性是有前提的,否則内外都復原。
④SUPPORTS:支援事務。目前有事務就支援。目前沒有事務就算了,不會開啟一個事物。
⑤MANDATORY:支援事務,如果業務方法執行時已經在一個事務中,則加入目前事務,否則抛出異常。
⑥NOT_SUPPORTED:不支援事務,如果業務方法執行時已經在一個事務中,則挂起目前事務,等方法執行完畢後,事務恢複進行。
⑦NEVER:不支援事務。如果目前已經在一個事務中了,抛出異常。
3、對象在記憶體中的結構布局?HotSpot虛拟機中,對象在記憶體中存儲的布局可以分為三塊區域:
對象頭(Header)、
執行個體資料(Instance Data)和
對齊填充(Padding)。①Mark Word(标記字段):對象的Mark Word部分占4個位元組,其内容是一系列的标記位,比如輕量級鎖的标記位,偏向鎖标記位等等。②Klass Pointer(Class對象指針):Class對象指針的大小也是4個位元組,其指向的位置是對象對應的Class對象(其對應的中繼資料對象)的記憶體位址③對象實際資料:這裡面包括了對象的所有成員變量,其大小由各個成員變量的大小決定,比如:byte和boolean是1個位元組,short和char是2個位元組,int和float是4個位元組,long和double是8個位元組,reference是4個位元組④對齊:最後一部分是對齊填充的位元組,按8個位元組填充。
①當堆記憶體(Heap Space)沒有足夠空間存放新建立的對象時,會抛出
java.lang.OutOfMemoryError:Javaheap space錯誤(根據實際生産經驗,可以對程式日志中的 OutOfMemoryError 配置關鍵字告警,一經發現,立即處理)。
a、請求建立一個
超大對象,通常是一個大數組,檢視對象的合理性。
b、超出預期的通路量/資料量,通常是上遊系統請求流量飙升,常見于各類促銷/秒殺活動,可以結合
業務流量名額排查是否有尖狀峰值,添加機器資源或者降流限級。
c、過度使用終結器(Finalizer),該對象沒有立即被 GC。
d、
記憶體洩漏(Memory Leak),大量對象引用沒有釋放,JVM 無法對其自動回收,常見于使用了 File 等資源沒有回收。
②當 Java 程序花費 98% 以上的時間執行 GC,但隻恢複了不到 2% 的記憶體,且該動作連續重複了 5 次,就會抛出
java.lang.OutOfMemoryError:GC overhead limit exceeded錯誤。問題的産生原因跟①中的相似。
③
java.lang.OutOfMemoryError:Permgen space該錯誤表示永久代(Permanent Generation)已用滿,通常是因為加載的 class 數目太多或體積太大。
a、
程式啟動報錯,修改 -XX:MaxPermSize 啟動參數,調大永久代空間。
b、應用重新部署時報錯,很可能是
應用重新開機導緻加載了多份 class 資訊,隻需重新開機 JVM 即可解決。
c、運作時報錯,應用程式可能會
動态建立大量 class,而這些 class 的生命周期很短暫,但是 JVM 預設不會解除安裝 class,可以設定 -XX:+CMSClassUnloadingEnabled 和 -XX:+UseConcMarkSweepGC這兩個參數允許 JVM 解除安裝 class。
d、如果上述方法無法解決,可以通過 jmap 指令 dump 記憶體對象 jmap-dump:format=b,file=dump.hprof<process-id> ,然後利用 Eclipse MAT https://www.eclipse.org/mat 功能逐一分析開銷最大的 classloader 和重複 class。
④JDK 1.8 使用
Metaspace替換了永久代(Permanent Generation),該錯誤表示 Metaspace 已被用滿,通常是因為加載的 class 數目太多或體積太大。此類問題的原因與解決方法跟 Permgenspace 非常類似,需要特别注意的是調整 Metaspace 空間大小的啟動參數為 -XX:MaxMetaspaceSize。
⑤
java.lang.OutOfMemoryError:Unableto createnewnativethread :每個 Java 線程都需要占用一定的記憶體空間,當 JVM 向底層作業系統請求建立一個新的 native 線程時,如果沒有足夠的資源配置設定就會報此類錯誤。
a、線程數
超過作業系統最大線程數ulimit 限制;
b、線程數超過 kernel.pid_max(隻能重新開機);
c、
native 記憶體不足;
⑥
Out of swap space:該錯誤表示所有可用的虛拟記憶體已被耗盡。虛拟記憶體(Virtual Memory)由實體記憶體(Physical Memory)和交換空間(Swap Space)兩部分組成,當運作時程式請求的虛拟記憶體溢出時就會報 Outof swap space錯誤。
a、
位址空間不足;
b、
實體記憶體已耗光;
c、應用程式的
本地記憶體洩漏(native leak),例如不斷申請本地記憶體,卻不釋放。
⑦
Kill process or sacrifice child:有一種核心作業(Kernel Job)名為 Out of Memory Killer,它會在可用記憶體極低的情況下“殺死”(kill)某些程序。OOM Killer 會對所有程序進行打分,然後将評分較低的程序“殺死”,具體的評分規則可以參考 Surviving the Linux OOM Killer。不同于其他的 OOM 錯誤, Killprocessorsacrifice child 錯誤不是由 JVM 層面觸發的,而是由作業系統層面觸發的。
⑧
Requested array size exceeds VM limit:
JVM 限制了數組的最大長度,該錯誤表示程式請求建立的數組超過最大長度限制。JVM 在為數組配置設定記憶體前,會檢查要配置設定的資料結構在系統中是否可尋址,通常為
Integer.MAX_VALUE-2。
此類問題比較罕見,通常需要檢查代碼,确認業務是否需要建立如此大的數組,是否可以拆分為多個塊,分批執行。
⑨
Direct buffer memory:Java 允許應用程式通過 Direct ByteBuffer 直接通路堆外記憶體,許多高性能程式通過 Direct ByteBuffer 結合記憶體映射檔案(Memory Mapped File)實作高速 IO。Direct ByteBuffer 的預設大小為 64 MB,一旦使用超出限制,就會抛出 Directbuffer memory 錯誤。
5、Finalizer的運作過程是什麼?為什麼過度使用Finalizer會出現OOM錯誤?①JVM建立實作了finalize()方法的類的對象
②JVM會建立java.lang.ref.Finalizer執行個體,指向①中建立的對象
③垃圾回收器首先會把①中對象添加到java.lang.ref.Finalizer.ReferenceQuene隊列中,Finalizer線程會處理這個隊列,将裡面的對象逐個彈出,并調用他們的finalize()方法。
④finalize()方法調用完後,Finalizer線程會将引用從Finalizer執行個體中去掉,在下一輪GC中,①中的對象可以被回收。
⑤Finalizer線程會與main線程進行競争,由于他的優先級較低,獲得的cpu資源較少,是以永遠趕不上主線程,是以會導緻程式消耗所有的可用資源,導緻OOM錯誤。