spring事物中的傳播及隔離

spring事物中的傳播及隔離

spring事物中的傳播及隔離

spring事物中的傳播及隔離


關注測試局| 會上癮
java

關於@Transactional註解:python

添加事務註解mysql

一、使用 propagation 指定事務的傳播行爲, 即當前的事務方法被另一個事務方法調用時。如何使用事務, 默認取值爲 REQUIRED, 即便用調用方法的事務REQUIRES_NEW: 事務本身的事務, 調用的事務方法的事務被掛起。spring

二、使用 isolation 指定事務的隔離級別, 最經常使用的取值爲 READ_COMMITTED。sql

三、默認狀況下 Spring 的聲明式事務對全部的運行時異常進行回滾. 也能夠經過對應的屬性進行設置. 一般狀況下去默認值便可。四、使用 readOnly 指定事務是否爲只讀. 表示這個事務只讀取數據但不更新數據,這樣能夠幫助數據庫引擎優化事務. 若真的是一個只讀取數據庫值的方法, 應設置 readOnly=true數據庫

五、使用 timeout 指定強制回滾以前事務能夠佔用的時間。微信

我的疑問有一些,結尾來講,用教程例子來講吧。ide

個人代碼以下:測試

BookShopDao接口package com.demo.spring.bean;

public interface
BookShopDao {

//根據書的編號返回書的單價

publicint findBookPriceByIsbn(String isbn);

//根據書的編號返回輸的庫存

publicvoidupdateBookStock(String isbn);

//更新用戶帳戶餘額

publicvoid updateUserAccount(String username, int price);
}

實現類優化

package com.demo.spring.bean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@Repository("bookShopDao")
public class BookShopDaoImpl implements BookShopDao {
@Autowired

private JdbcTemplate jdbcTemplate;
@Override

public int findBookPriceByIsbn(String isbn) {

// TODO Auto-generated method stub

String sql = "SELECT price FROM book WHERE isbn=?";

Integer price = jdbcTemplate.queryForObject(sql, Integer.class, isbn);

return price;

}

@Override

public void updateBookStock(String isbn) {
// TODO Auto-generated method stub

String sql = "SELECT stock FROM book_stock WHERE isbn= ? ";

Integer stock = jdbcTemplate.queryForObject(sql, Integer.class, isbn);

if (stock == 0) {

throw new BookStockException("庫存不足!!");

}

String sql1 = "UPDATE book_stock SET stock=stock-1 WHERE isbn=?";

jdbcTemplate.update(sql1, isbn);

}
@Override
public void updateUserAccount(String username, int price) {

// TODO Auto-generated method stub
String sql1 = "SELECT balance FROM account WHERE username= ? ";

Integer account = jdbcTemplate.queryForObject(sql1, Integer.class,

username);
if (account < price) {
throw new AccountException("餘額不足!!");

}
String sql = "UPDATE account SET balance=balance-? WHERE username=?";
.
jdbcTemplate.update(sql, price, username);

BookShopService接口

package com.demo.spring.bean;

publicinterfaceBookShopService {
//購書
publicvoid purchase(String username, String isbn);
}

實現類

package com.demo.spring.bean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service("bookShopService")
public class BookShopServiceImpl implements BookShopService {
@Autowired
private BookShopDao bookShopDao;
// @Transactional(propagation=Propagation.REQUIRES_NEW,isolation=Isolation.READ_COMMITTED,readOnly=true,timeout=5,noRollbackFor=AccountException.class)
@Transactional
@Override
public void purchase(String username, String isbn) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();

}

// TODO Auto-generated method stub

int price = bookShopDao.findBookPriceByIsbn(isbn);

bookShopDao.updateBookStock(isbn);

bookShopDao.updateUserAccount(username, price);

Cashier批量購書接口

package com.demo.spring.bean;
import java.util.List;

public interface Cashier {

//批量購書
public void checkout(String username, List<String> isbns);

實現類

package com.demo.spring.bean;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;
@Service("cashier")
public class CashierImpl implements Cashier {
@Autowired
private BookShopService bookShopService;
// @Transactional

@Override

public void checkout(String username, List<String> isbns) {
// TODO Auto-generated method stub
for (String isbn : isbns) {
bookShopService.purchase(username, isbn);}}

}

}

}

}
}

帳戶餘額不足異常(自定義異常)

庫存不足異常(自定義異常)
.

package com.demo.spring.bean;
public class AccountException extends RuntimeException {

/**

*

*/

private static final long serialVersionUID = 1L;

public AccountException() {

super();

// TODO Auto-generated constructor stub

}

public AccountException(String message, Throwable cause,
boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
// TODO Auto-generated constructor stub

}
public AccountException(String message, Throwable cause) {

super(message, cause);

// TODO Auto-generated constructor stub

}

public AccountException(String message) {

super(message);

// TODO Auto-generated constructor stub

}

public AccountException(Throwable cause) {

super(cause);

// TODO Auto-generated constructor stub

測試類

package com.demo.spring.bean;
import java.util.Arrays;
import org.junit.Test;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainTest {
private ApplicationContext ctx;
@Autowired

private Cashier cashier;
{

ctx=new ClassPathXmlApplicationContext("bean.xml");

cashier=(Cashier) ctx.getBean("cashier");

}

@Test

public void test(){

// System.out.println(bookShopDao.findBookPriceByIsbn("1001"));

cashier.checkout("rongrong", Arrays.asList("1001","1002"));

}

}

}
}

bean文件

<context:property-placeholder location="classpath:db.properties"/>
<!-- 配置mysql數據源 -->
<bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${db.driverClassName}"></property>
<property name="url" value="${db.url}"></property>
<property name="username" value="${db.username}"></property>
<property name="password" value="${db.password}"></property>

</bean>

<!-- 配置jdbc模板 -->

<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="datasource"></property>
</bean>
<!-- 配置事務管理器 -->
<bean id="transactionManagertest" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="datasource"></property>

</bean> 

<!-- 啓用事務註解 -->

<tx:annotation-driven transaction-manager="transactionManagertest"/>
</beans>

數據源

db.driverClassName=com.mysql.jdbc.
Driver
db.url=jdbc:mysql:
//localhost:3306/spring
db.username=root
db.password=root

spring事物中的傳播及隔離

疑問以下:

一、前提條件:用戶按照1001,1002這種順序去購書,調用checkout接口批量購書 @Transactional註解確實知足原子性操做,要麼都作,要麼不作 可是,我試驗了下,若是在public void checkout(String username, Listisbns) 上方不加Transactional註解與在public void purchase(String username, String isbn)上方加@Transactional(propagation=Propagation.REQUIRES_NEW效果同樣

二、當帳戶餘額爲120,能夠知足帳戶減去1001的單價,1001的庫存減1 可是,將帳戶餘額改成80,從單價上看能夠買1002那本書,按照上面的順序去買書,按照上面加上註解@Transactional(propagation=Propagation.REQUIRES_NEW效果同樣,根本很差使,我我的以爲由於在更新帳戶餘額,那有個判斷先查詢1001的書的單價確實大於當前帳戶餘額80,先判斷了,因此拋異常後面代碼就不走了

三、另外當前帳戶餘額能夠買1002這本書,想在不改變購書的順序狀況下,用@Transactional註解實現,能夠買1002這本書?,減去當前帳戶餘額80,更新1002書的庫存,哪位大神看到,幫我看下,怎麼用這個註解實現?

以上爲個人我的疑惑的點,有興趣的同窗能夠研究下,而後在公號留言給我便可,小編不勝感謝!
附上:sql

/*
Navicat MySQL Data Transfer
Source Server         : myTestdata
Source Server Version : 50627
Source Host           : localhost:3306
Source Database       : spring

Target Server Type    : MYSQL
Target Server Version : 50627
File Encoding         : 65001

Date: 2017-01-18 11:28:50
*/

SET FOREIGN_KEY_CHECKS=
0
;

-- ----------------------------
-- 
Table
 structure 
for
 account
-- ----------------------------
DROP TABLE IF EXISTS 
`account`
;
CREATE TABLE 
`account`
 (

`username`
 varchar(
50
) NOT NULL,
`balance`int(11) DEFAULT NULL,  PRIMARY KEY (
`username`)) ENGINE=InnoDB DEFAULT CHARSET=gbk;

-- ----------------------------
-- 
Records of account
-- ----------------------------
INSERT INTO `account` VALUES ('rongrong', '300');
INSERT INTO `account` VALUES ('zhangsan', '200');

-- ----------------------------
-- 
Table structure for book
-- ----------------------------
DROP TABLE IF EXISTS `book`;CREATE TABLE `book` (

`isbn`varchar(50) NOT NULL,

`book_name varchar(100) DEFAULT NULL,

`price`int(11) DEFAULT NULL,  PRIMARY KEY (`isbn`)
) ENGINE=
InnoDB DEFAULT CHARSET=gbk;

-- ----------------------------
-- 
Records of book
-- ----------------------------
INSERT INTO `book` VALUES ('1001', 'java', '100');
INSERT INTO `book` VALUES ('1002', 'python', '60');

-- ----------------------------
-- 
Tablestructure for book_stock
-- ----------------------------
DROP TABLE IF EXISTS `book_stock`;CREATE TABLE 
`book_stock` (  `isbn` varchar(50) NOT NULL,

`bookname varchar(100) DEFAULT NULL,
`stock int(11
) DEFAULT NULL,
  PRIMARY KEY (`isbn`)) ENGINE=InnoDB
DEFAULT CHARSET=gbk;

-- ----------------------------
-- 
Recordsof book_stock
-- ----------------------------
INSERT INTO `book_stock` VALUES ('1001', 'java','10');
INSERT INTO `book_stock` VALUES ('1002', 'python', '10');

還有一件重要的事情要和你們說,我不是常常看公衆號後臺,因此有時候你們在後臺發留言,時間一旦超過2天,我就沒有回覆權限了。因此,我要公佈本身的微信號了,歡迎你們來埋伏我
spring事物中的傳播及隔離

關於測試技術你或許還想看:

軟件測試工程師在上海的求職經歷
個人測試用例是這樣寫的

TestNg中的斷言你真的瞭解嗎

若是給你一個登錄頁面你怎麼測試?

最後,漲工資從轉發開始!!

相關文章
相關標籤/搜索