Artikel ini menjelaskan manajemen transaksi di Spring dengan contoh. Bagikan dengan semua orang untuk referensi Anda. Analisis spesifiknya adalah sebagai berikut:
Pengenalan bisnis:
Manajemen transaksi adalah teknologi penting dalam pengembangan aplikasi perusahaan untuk memastikan integritas dan konsistensi data
Transaksi adalah serangkaian tindakan yang diperlakukan sebagai satu unit kerja. Entah semua tindakan ini berhasil, atau tidak satupun yang berhasil
Empat atribut utama transaksi (ACID)
① Atomisitas: Operasi atom di ruang transaksi terdiri dari serangkaian tindakan. Atomisitas transaksi memastikan bahwa tindakan telah selesai sepenuhnya atau tidak berpengaruh sama sekali. ② Konsistensi: Setelah semua tindakan transaksi selesai, transaksi telah dilakukan. Data dan sumber daya berada dalam keadaan konsisten yang memenuhi aturan bisnis ③ Isolasi: Mungkin ada banyak transaksi yang memproses data yang sama pada waktu yang sama, sehingga setiap hal harus diisolasi dari transaksi lain untuk mencegah kerusakan data ④ Daya Tahan: Setelah transaksi selesai , hasilnya tidak akan terpengaruh apa pun kesalahan sistem yang terjadi. Biasanya, hasil transaksi ditulis ke penyimpanan persisten
Manajemen transaksi di Musim Semi
Sebagai kerangka aplikasi perusahaan, Spring mendefinisikan lapisan abstraksi di atas API manajemen transaksi yang berbeda. Pengembang aplikasi tidak perlu memahami API manajemen transaksi yang mendasarinya untuk menggunakan mekanisme manajemen transaksi Spring.
Spring mendukung manajemen transaksi terprogram dan manajemen transaksi deklaratif.
Manajemen transaksi terprogram: Sematkan kode manajemen transaksi ke dalam metode bisnis untuk mengontrol pengiriman dan pengembalian transaksi. Dalam transaksi terprogram, kode manajemen transaksi tambahan harus disertakan dalam setiap operasi bisnis.
Manajemen transaksi deklaratif: Lebih baik digunakan daripada manajemen transaksi terprogram dalam banyak kasus. Ini memisahkan kode manajemen transaksi dari metode bisnis dan menerapkan manajemen transaksi secara deklaratif. Manajemen transaksi, sebagai masalah lintas sektoral, dapat dimodulasi melalui metode AOP. Spring mendukung manajemen transaksi deklaratif melalui kerangka Spring AOP.
Properti propagasi transaksi Spring:
Ketika suatu metode transaksi dipanggil oleh metode transaksi lain, Anda harus menentukan bagaimana transaksi tersebut harus disebarkan. Misalnya: metode mungkin terus berjalan pada transaksi yang sudah ada, atau mungkin memulai transaksi baru dan berjalan pada transaksinya sendiri.
Perilaku propagasi suatu transaksi dapat ditentukan oleh atribut propagasi. Spring mendefinisikan 7 perilaku komunikasi:
perilaku komunikasi | arti |
PROPAGASI_WAJIB | Menunjukkan bahwa metode harus dijalankan dalam suatu transaksi. Jika transaksi saat ini tidak ada, pengecualian akan dilempar. |
PROPAGASI_NESTED | Menunjukkan bahwa jika transaksi sedang ada, metode ini akan dijalankan dalam transaksi bersarang. Transaksi bertumpuk dapat dilakukan atau dibatalkan secara independen dari transaksi saat ini. Jika transaksi saat ini tidak ada, perilakunya sama dengan PROPAGATION_REQUIRED. Perhatikan bahwa dukungan setiap produsen terhadap perilaku propagasi ini berbeda-beda. Anda dapat melihat dokumentasi pengelola sumber daya Anda untuk mengonfirmasi apakah mereka mendukung transaksi bertingkat. |
PROPAGASI_TIDAK PERNAH | Menunjukkan bahwa metode saat ini tidak boleh dijalankan dalam konteks transaksi. Jika saat ini ada transaksi yang berjalan, pengecualian akan dilempar |
PROPAGATION_NOT_SUPPORTED | Menunjukkan bahwa metode ini tidak boleh dijalankan dalam suatu transaksi. Jika ada transaksi saat ini, transaksi tersebut akan ditangguhkan saat metode ini berjalan. Jika Anda menggunakan JTATransactionManager, Anda perlu mengakses TransactionManager |
PROPAGATION_REQUIRED | Menunjukkan bahwa metode saat ini harus dijalankan dalam suatu transaksi. Jika transaksi saat ini ada, metode akan dijalankan dalam transaksi tersebut. Jika tidak, transaksi baru akan dimulai |
PROPAGATION_REQUIRED_NEW | Menunjukkan bahwa metode saat ini harus dijalankan dalam transaksinya sendiri. Transaksi baru akan dimulai. Jika ada transaksi saat ini, transaksi tersebut akan ditangguhkan selama pelaksanaan metode ini. Jika Anda menggunakan JTATransactionManager, Anda perlu mengakses TransactionManager |
PROPAGASI_DUKUNGAN | Menunjukkan bahwa metode saat ini tidak memerlukan konteks transaksi, tetapi jika ada transaksi saat ini, metode akan berjalan dalam transaksi ini |
Diantaranya PROPAGATION_REQUIRED adalah atribut propagasi default
Masalah yang disebabkan oleh transaksi bersamaan
Banyak masalah tak terduga yang dapat muncul ketika beberapa transaksi dalam aplikasi yang sama atau aplikasi berbeda dijalankan secara bersamaan pada kumpulan data yang sama.
Masalah yang disebabkan oleh transaksi bersamaan dapat dibagi menjadi tiga kategori berikut:
① Bacaan kotor: Bacaan kotor terjadi ketika satu transaksi membaca data yang telah ditulis ulang oleh transaksi lain tetapi belum dilakukan. Jika penulisan ulang kemudian dibatalkan, data yang diperoleh pada transaksi pertama menjadi tidak valid.
② Pembacaan yang tidak dapat diulang: Pembacaan yang tidak dapat diulang terjadi ketika suatu transaksi mengeksekusi kueri yang sama dua kali atau lebih, tetapi mendapatkan data yang berbeda setiap kali. Hal ini biasanya karena transaksi bersamaan lainnya memperbarui data antar kueri
③ Pembacaan hantu: Pembacaan hantu mirip dengan pembacaan yang tidak dapat diulang. Ini terjadi ketika satu transaksi (T1) membaca beberapa baris data, dan kemudian transaksi bersamaan lainnya (T2) memasukkan beberapa data. Dalam kueri berikutnya, transaksi pertama (T1) akan menemukan bahwa ada beberapa catatan lagi yang awalnya tidak ada.
contoh kode
Pertama adalah tabel database:
Termasuk buku(isbn, nama_buku, harga), akun(nama pengguna, saldo), stok_buku(isbn, stok)
Kemudian kelas yang digunakan:
Toko BukuDao
Copy kode kodenya sebagai berikut:
paket com.yl.spring.tx;
antarmuka publik BookShopDao {
//Dapatkan harga satuan buku berdasarkan nomor buku
public int findBookPriceByIsbn(String isbn);
//Perbarui inventaris buku sehingga inventaris yang sesuai dengan nomor buku adalah -1
pembaruan kekosongan publikBookStock(String isbn);
//Perbarui saldo akun pengguna: buat harga saldo nama pengguna
public void updateUserAccount(String nama pengguna, harga int);
}
Toko BukuDaoImpl
Copy kode kodenya sebagai berikut:
paket com.yl.spring.tx;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@Repositori("tokobukuDao")
kelas publik BookShopDaoImpl mengimplementasikan BookShopDao {
@ Kabel Otomatis
JdbcTemplate pribadi JdbcTemplate;
@Mengesampingkan
public int findBookPriceByIsbn(String isbn) {
String sql = "PILIH harga DARI buku WHERE isbn = ?";
kembalikan JdbcTemplate.queryForObject(sql, Integer.class, isbn);
}
@Mengesampingkan
public void updateBookStock(String isbn) {
//Periksa apakah inventaris buku mencukupi, jika tidak, berikan pengecualian
String sql2 = "PILIH stok DARI book_stock WHERE isbn = ?";
int stok = JdbcTemplate.queryForObject(sql2, Integer.class, isbn);
jika (stok == 0) {
throw new BookStockException("Stok tidak mencukupi!");
}
String sql = "UPDATE book_stock SET stok = stok - 1 WHERE isbn = ?";
JdbcTemplate.update(sql, isbn);
}
@Mengesampingkan
public void updateUserAccount(String nama pengguna, harga int) {
//Periksa apakah saldo tidak mencukupi, jika tidak, berikan pengecualian
String sql2 = "PILIH saldo DARI akun DIMANA nama pengguna = ?";
int balance = JdbcTemplate.queryForObject(sql2, Integer.class, nama pengguna);
if (saldo < harga) {
throw new UserAccountException("Saldo tidak mencukupi!");
}
String sql = "UPDATE akun SET saldo = saldo - ? WHERE nama pengguna = ?";
JdbcTemplate.update(sql, harga, nama pengguna);
}
}
Layanan Toko Buku
Copy kode sebagai berikut: package com.yl.spring.tx;
antarmuka publik Layanan Toko Buku {
pembatalan pembelian publik (String nama pengguna, String isbn);
}
Layanan Toko BukuImpl
Copy kode kodenya sebagai berikut:
paket com.yl.spring.tx;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@Layanan("LayananToko Buku")
kelas publik BookShopServiceImpl mengimplementasikan BookShopService {
@ Kabel Otomatis
buku pribadi BookShopDaoShopDao;
/**
* 1. Tambahkan anotasi transaksi
* Gunakan propagasi untuk menentukan perilaku propagasi transaksi, yaitu cara menggunakan transaksi ketika metode transaksi saat ini dipanggil oleh metode transaksi lain.
* Nilai defaultnya adalah REQUIRED, yang berarti menggunakan metode pemanggilan transaksi
* REQUIRES_NEW: Gunakan transaksi Anda sendiri, dan transaksi metode transaksi yang dipanggil ditangguhkan.
*
* 2. Gunakan isolasi untuk menentukan tingkat isolasi transaksi. Nilai yang paling umum digunakan adalah READ_COMMITTED.
* 3. Secara default, transaksi deklaratif Spring mengembalikan semua pengecualian runtime, yang juga dapat diatur melalui properti terkait. Biasanya, nilai default sudah cukup.
* 4. Gunakan readOnly untuk menentukan apakah transaksi bersifat read-only. Menunjukkan bahwa transaksi ini hanya membaca data tetapi tidak memperbarui data, yang dapat membantu mesin database mengoptimalkan transaksi. Jika ini benar-benar metode yang hanya membaca database, readOnly=true harus disetel.
* 5. Gunakan timeOut untuk menentukan waktu yang diperlukan suatu transaksi sebelum memaksa rollback.
*/
@Transaksional(propagasi=Propagasi.REQUIRES_NEW,
isolasi=Isolasi.READ_COMMITTED,
noRollbackFor={UserAccountException.kelas},
readOnly=benar, batas waktu=3)
@Mengesampingkan
pembelian batal publik(String nama pengguna, String isbn) {
//1. Dapatkan harga satuan buku tersebut
int harga = bookShopDao.findBookPriceByIsbn(isbn);
//2. Perbarui inventaris buku
bookShopDao.updateBookStock(isbn);
//3. Perbarui saldo pengguna
bookShopDao.updateUserAccount(nama pengguna, harga);;
}
}
BookStockException
Copy kode kodenya sebagai berikut:
paket com.yl.spring.tx;
kelas publik BookStockException memperluas RuntimeException {
/**
*
*/
serialVersionUID panjang akhir statis pribadi = 1L;
BookStockException publik() {
super();
// TODO Stub konstruktor yang dibuat secara otomatis
}
BookStockException publik(String arg0, Arg1 yang dapat dilempar, boolean arg2,
boolean arg3) {
super(arg0, arg1, arg2, arg3);
// TODO Stub konstruktor yang dibuat secara otomatis
}
public BookStockException(String arg0, Throwable arg1) {
super(arg0, arg1);
// TODO Stub konstruktor yang dibuat secara otomatis
}
BookStockException publik(String arg0) {
super(arg0);
// TODO Stub konstruktor yang dibuat secara otomatis
}
publik BookStockException(Arg0 yang dapat dilempar) {
super(arg0);
// TODO Stub konstruktor yang dibuat secara otomatis
}
}
Pengecualian Akun Pengguna
Copy kode kodenya sebagai berikut:
paket com.yl.spring.tx;
kelas publik UserAccountException memperluas RuntimeException {
/**
*
*/
serialVersionUID panjang akhir statis pribadi = 1L;
UserAccountException publik() {
super();
// TODO Stub konstruktor yang dibuat secara otomatis
}
UserAccountException publik(String arg0, Arg1 yang dapat dilempar, boolean arg2,
boolean arg3) {
super(arg0, arg1, arg2, arg3);
// TODO Stub konstruktor yang dibuat secara otomatis
}
public UserAccountException(String arg0, Throwable arg1) {
super(arg0, arg1);
// TODO Stub konstruktor yang dibuat secara otomatis
}
UserAccountException publik(String arg0) {
super(arg0);
// TODO Stub konstruktor yang dibuat secara otomatis
}
public UserAccountException(Arg0 yang dapat dilempar) {
super(arg0);
// TODO Stub konstruktor yang dibuat secara otomatis
}
}
Kasir
Copy kode kodenya sebagai berikut:
paket com.yl.spring.tx;
impor java.util.List;
antarmuka publik Kasir {
public void checkout(String nama pengguna, Daftar<String>isbns);
}
Impl Kasir. CashierImpl.checkout dan bookShopService.purchase bersama-sama menguji perilaku penyebaran transaksi
Copy kode kodenya sebagai berikut:
paket com.yl.spring.tx;
impor java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Layanan("kasir")
kelas publik CashierImpl mengimplementasikan Cashier {
@ Kabel Otomatis
Layanan Toko Buku Layanan Toko Buku pribadi;
@Transaksional
@Mengesampingkan
public void checkout(String nama pengguna, Daftar<String> isbns) {
for(String isbn : isbns) {
bookShopService.purchase(nama pengguna, isbn);
}
}
}
Kelas tes:
Copy kode kodenya sebagai berikut:
paket com.yl.spring.tx;
import java.util.Array;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
kelas publik SpringTransitionTest {
pribadi ApplicationContext ctx = null;
BookShopDao pribadi bookShopDao = null;
Layanan Toko Buku pribadi Layanan Toko Buku = null;
kasir pribadi kasir = null;
{
ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
bookShopDao = ctx.getBean(BookShopDao.class);
bookShopService = ctx.getBean(BookShopService.class);
kasir = ctx.getBean(Kasir.kelas);
}
@Tes
public void testBookShopDaoFindPriceByIsbn() {
System.out.println(bookShopDao.findBookPriceByIsbn("1001"));
}
@Tes
kekosongan publik testBookShopDaoUpdateBookStock(){
bookShopDao.updateBookStock("1001");
}
@Tes
kekosongan publik testBookShopDaoUpdateUserAccount(){
bookShopDao.updateUserAccount("AA", 100);
}
@Tes
kekosongan publik testBookShopService(){
bookShopService.pembelian("AA", "1001");
}
@Tes
kekosongan publik testTransactionPropagation(){
kasir.checkout("AA", Arrays.asList("1001", "1002"));
}
}
Saya harap artikel ini bermanfaat untuk desain pemrograman Spring semua orang.