事务的传播行为
定义:事务的传播与事务的行为。
如果有多个事务进行嵌套运行,子事务是否要和大事务共用一个事务。
举例:
class AService{
void tx_a(){
//a方法的一些内容
void tx_b(){
}
void tx_c(){
}
}
}
//此时如果a方法的内容出现了异常,那么方法tx_b、tx_c要不要回滚?
//这个就是事务的传播性来决定的
传播属性 | 描述 |
---|---|
required | 如果有事务在运行,当前方法就跟这个它一起运行。没有就自己创建一个事务运行。 |
requires_new | 自己创建一个事务运行,如果有事务在运行,就把它挂起。 |
supports | 如果有事务在运行,当前方法就在这个事务内运行。如果没有事务运行,那么它就不运行事务。 |
not supports | 当前方法永远不运行在事务内,如果有事务就把事务挂起。 |
mandatory | 当前方法必须运行在事务内,如果没有运行的事务,就抛出异常。 |
never | 当前方法不应该运行在事务中,如果有运行的事务,就抛出异常。 |
nested | 事务内套事务。 |
代码演示
required
BookService类:有两个事务方法
package com.atguigu.bookService;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.support.DaoSupport;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.atguigu.dao.BookDao;
@Service
public class bookService {
@Autowired
BookDao bookDao;
@Transactional()
public void checkout(String username,String isbn) {
//减库存
bookDao.updateStock(isbn);
//查询书本价格
Integer price = bookDao.getPrice(isbn);
//减余额
bookDao.updateBalance(username, price);
}
@Transactional
public void updatePrice(String isbn,int price){
bookDao.updatePrice(isbn, price);
}
}
MulService:将这两个事务方法包在一个事务中
package com.atguigu.bookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class MulService {
@Autowired
private bookService bookService;
@Transactional
public void mulTx(){
bookService.checkout("Tom", "ISBN-001");
bookService.updatePrice("ISBN-002", 999);
}
}
传播行为用来设置这个事务方法是不是和之前的大事务共享一个事务(使用同一条连接)。
此时,将BookService中的两个方法的传播行为设置成required(见上表描述)
package com.atguigu.bookService;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.support.DaoSupport;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.atguigu.dao.BookDao;
@Service
public class bookService {
@Autowired
BookDao bookDao;
@Transactional(propagation=Propagation.REQUIRED)
public void checkout(String username,String isbn) {
//减库存
bookDao.updateStock(isbn);
//查询书本价格
Integer price = bookDao.getPrice(isbn);
//减余额
bookDao.updateBalance(username, price);
}
@Transactional(propagation=Propagation.REQUIRED)
public void updatePrice(String isbn,int price){
bookDao.updatePrice(isbn, price);
//手动设置异常
int a=10/0;
}
}
此时进行测试
@Test
public void testMulService(){
ApplicationContext context = new ClassPathXmlApplicationContext("tx.xml");
MulService mulService = context.getBean(MulService.class);
mulService.mulTx();
}
数据并没有被修改,因为其中的一个方法出现异常,所有事务进行回滚。
required new
把BookService中的updatePrice方法的传播方法改为requires_new
package com.atguigu.bookService;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.support.DaoSupport;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.atguigu.dao.BookDao;
@Service
public class bookService {
@Autowired
BookDao bookDao;
@Transactional(propagation=Propagation.REQUIRES_NEW)
public void checkout(String username,String isbn) {
//减库存
bookDao.updateStock(isbn);
//查询书本价格
Integer price = bookDao.getPrice(isbn);
//减余额
bookDao.updateBalance(username, price);
}
@Transactional(propagation=Propagation.REQUIRED)
public void updatePrice(String isbn,int price){
bookDao.updatePrice(isbn, price);
//手动设置异常
int a=10/0;
}
}
此时再进行测试
@Test
public void testMulService(){
ApplicationContext context = new ClassPathXmlApplicationContext("tx.xml");
MulService mulService = context.getBean(MulService.class);
mulService.mulTx();
}
此时checkout方法正常执行,数据被修改。而其他事务被回滚,因为checkout自己新建了一个事务,把别的事务挂起。所以updatePrice中的异常不会影响checkout的提交。
注意:如果是required,其他的所有属性都是继承于大事务的,自己设置的属性无效。而requires_new可以自己设置属性。
实现原理
required:将之前的事务用的connection传递给这个方法使用。
requires_new:这个方法直接使用新的connection。