Spring(5、基於註解的事物)
Spring中的事物管理
注:本文用到的jar包請在同類文章Spring(1-1、基於xml裝配Bean)中查詢。
事務管理是企業級應用程式開發中必不可少的技術, 用來確保資料的完整性和一致性.
事務就是一系列的動作, 它們被當做一個單獨的工作單元. 這些動作要麼全部完成, 要麼全部不起作用
事務的四個關鍵屬性(ACID)
原子性(atomicity): 事務是一個原子操作, 由一系列動作組成. 事務的原子性確保動作要麼全部完成要麼完全不起作用.
一致性(consistency): 一旦所有事務動作完成, 事務就被提交. 資料和資源就處於一種滿足業務規則的一致性狀態中.
隔離性(isolation): 可能有許多事務會同時處理相同的資料, 因此每個事物都應該與其他事務隔離開來, 防止資料損壞.
永續性(durability): 一旦事務完成, 無論發生什麼系統錯誤, 它的結果都不應該受到影響. 通常情況下, 事務的結果被寫到持久化儲存器中事物的傳播屬性
REQUIRED_NEW傳播屬性
另一種常見的傳播行為是REQUIRES_NEW. 它表示該方法必須啟動一個新事務, 並在自己的事務內執行. 如果有事務在執行, 就應該先掛起它
方法上面的標註:@Transactional(propagation = Propagation.REQUIRES_NEW)
public void purchase(String username, String isbn) {
原理圖
使用到的表結構
CREATE TABLE `account` (
`username` varchar(255) COLLATE utf8_bin NOT NULL,
`balance` int(11) DEFAULT NULL,
PRIMARY KEY (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
CREATE TABLE `book` (
`isbn` int(255) NOT NULL AUTO_INCREMENT,
`book_name` varchar(255) COLLATE utf8_bin DEFAULT NULL,
`price` double(10,2) DEFAULT NULL,
PRIMARY KEY (`isbn`)
) ENGINE=InnoDB AUTO_INCREMENT=1003 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
CREATE TABLE `book_stock` (
`isbn` int(11) NOT NULL,
`stock` int(11) DEFAULT NULL,
PRIMARY KEY (`isbn`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
Spring的宣告式事物(註解)
dao
public interface BookShopDao {
/**根據書號獲取數的單價*/
public int findBookPriceByIsbn(String isbn);
/** 更新庫存,是書號對應的庫存*/
public void updateBookStock(String isbn);
/**更新使用者的賬戶餘額,使username的balance-price */
public void updateUserAccount(String username, int price);
}
@Repository("bookShopDao")
public class BookShopDaoImpl implements BookShopDao {
@Autowired
private JdbcTemplate jt;
public int findBookPriceByIsbn(String isbn) {
String sql = "SELECT price FROM book WHERE isbn=?";
return jt.queryForObject(sql, Integer.class, isbn);
}
public void updateBookStock(String isbn) {
// 檢查書的庫存是否足夠,若不夠,則丟擲異常
String sql2 = "SELECT stock FROM book_stock WHERE isbn=?";
Integer stock = jt.queryForObject(sql2, Integer.class, isbn);
if (stock == 0) {
throw new BookStockException("庫存不足!");
}
String sql = "UPDATE book_stock SET stock=stock-1 WHERE isbn=?";
int update = jt.update(sql, isbn);
System.out.println("更新了-->" + update + "條");
}
public void updateUserAccount(String username, int price) {
// 驗證使用者的餘額是否足夠
String banalce = "SELECT balance FROM account WHERE username=?";
int ba = jt.queryForObject(banalce, Integer.class, username);
if (ba > 0 && ba < price) {
throw new UserAccountException("賬戶餘額不足!");
}
String sql = "UPDATE account SET balance=balance-? WHERE username=?";
int update = jt.update(sql, price, username);
System.out.println("更新了-->" + update + "條");
}
}
service
public interface BookShopService {
public void purchase(String username, String isbn);
}
@Service("bookShopService")
public class BookShopServiceImpl implements BookShopService {
@Autowired
private BookShopDao bsd;
@Transactional
public void purchase(String username, String isbn) {
// 1獲取書的單價
int price = bsd.findBookPriceByIsbn(isbn);
// 2更新數的庫存
bsd.updateBookStock(isbn);
// 3更新使用者的餘額
bsd.updateUserAccount(username, price);
}
}
配置xml
<context:component-scan base-package="com.spring.beans"></context:component-scan>
<!-- 匯入配置檔案 -->
<context:property-placeholder location="classpath:db.properties" />
<!-- 配置資料來源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="${jdbc.user}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="driverClass" value="${jdbc.driverClass}"></property>
<property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
<property name="initialPoolSize" value="${jdbc.initPoolSize}"></property>
<property name="maxPoolSize" value="${jdbc.maxPoolSize}"></property>
</bean>
<!--配置Spring的JdbcTemplate工具類 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置事物管理器 -->
<bean id="tx"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 啟用事物註解-->
<tx:annotation-driven transaction-manager="tx" />
測試類:[測試的時候試著去掉service方法上面的@Transactional和不去掉就可以看出事物起到的作用]
public class BookShopDaoImplTest {
private ApplicationContext ctx = null;
private BookShopService bookShopService = null;
{
ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
bookShopService = (BookShopService) ctx.getBean("bookShopService");
}
@Test
public void testbookShopService() {
bookShopService.purchase("AA", "1001");
}
}
總結:
1、在xml檔案中新增兩個配置
<bean id="tx"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<tx:annotation-driven transaction-manager="tx" />
2、在對應的service方法上新增@Transactional就可以
事物的其他屬性(隔離級別,回滾,超時,只讀)
@Service("bookShopService")
public class BookShopServiceImpl implements BookShopService {
@Autowired
private BookShopDao bsd;
// 1.使用propagation指定事物的傳播行為
// 如何使用事物,預設取值為REQUIRED,即使用呼叫方法的事物
// 2.REQUIRES_NEW:事物自己的事物,呼叫的事物方法的事物掛起
// 使用isolation指定書屋的隔離級別,最常用的取值是read_commited
// 3.預設情況下Spring對宣告式事物對所有的執行時異常進行回滾,也可以通過對應的屬性進行設定。通常情況下取預設值即可
// 4.使用readOnly指定事物是否為只讀,表示這個事物只讀資料但不更新資料,這樣可以幫助資料庫引擎優化事物
// 若真的是一個只讀資料庫值的方法,應設定為readOnly=true
// 5.使用timeout指定強制回滾之前事物佔用的時間
// @Transactional(propagation = Propagation.REQUIRED, isolation =
// Isolation.READ_COMMITTED, noRollbackFor = { UserAccountException.class })
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED, readOnly = false, timeout = 3)
public void purchase(String username, String isbn) {
try {
Thread.sleep(5000);
} catch (Exception e) {
System.out.println(e.getMessage());
}
// 1獲取書的單價
int price = bsd.findBookPriceByIsbn(isbn);
// 2更新數的庫存
bsd.updateBookStock(isbn);
// 3更新使用者的餘額
bsd.updateUserAccount(username, price);
}
}
相關文章
- spring事物配置,宣告式事務管理和基於@Transactional註解的使用Spring
- 基於註解的 Spring MVC詳解SpringMVC
- Spring 使用註解方式進行事物管理Spring
- Spring基於註解的IoC配置Spring
- Spring基於註解的aop配置Spring
- Spring Aop基於註解的實現Spring
- Spring基於註解的AOP測試Spring
- Spring7:基於註解的Spring MVC(下篇)SpringMVC
- Spring6:基於註解的Spring MVC(上篇)SpringMVC
- Spring中基於註解方式的AOP操作Spring
- Spring7——開發基於註解形式的springSpring
- Spring5:@Autowired註解、@Resource註解和@Service註解Spring
- spring基於註解配置實現事務控制Spring
- Java Web之基於註解的Spring MVC環境配置JavaWebSpringMVC
- Spring / Spring boot 基於註解非同步程式設計@AsyncSpring Boot非同步程式設計
- 基於註解的方式使用spring-integration-redis分散式鎖SpringRedis分散式
- 基於註解的Spring多資料來源配置和使用Spring
- Spring5(七)——AOP註解Spring
- 基於註解的spring 在靜態方法中使用注入的類Spring
- spring和ehcache整合,實現基於註解的快取實現Spring快取
- Spring事物管理和hibernate事物管理的疑問Spring
- Spring事務的介紹,以及基於註解@Transactional的宣告式事務Spring
- Spring Boot 基於註解驅動原始碼分析--自動配置Spring Boot原始碼
- spring上 -基於註解配置bean,動態代理,AOP筆記SpringBean筆記
- Spring5原始碼 - Spring IOC 註解複習Spring原始碼
- Spring 5 中文解析資料儲存篇-理解Spring事物抽象Spring抽象
- Spring Security 實戰乾貨:基於註解的介面角色訪問控制Spring
- 基於註解的Spring多資料來源配置和使用(非事務)Spring
- 【基礎知識】基於事物的臨時表和基於會話的臨時表會話
- 快速搭建基於註解的 Dubbo 專案
- Spring Boot 基於註解驅動原始碼分析--自動掃描Spring Boot原始碼
- Spring基於註解的環繞通知實現請求方法日誌記錄Spring
- Spring註解Spring
- Spring的事物回滾問題Spring
- Mybatis相關:基於註解的Mybatis開發MyBatis
- 基於註解的 PHP 列舉類實現PHP
- 基於Aviator的註解驅動驗證框架框架
- Spring Boot 事物回滾Spring Boot