Spring框架框架事务:
为什么?
package club.shaoyu.coupon.service;
import java.util.UUID;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import club.shaoyu.book.dao.BookDao;
import club.shaoyu.coupon.dao.CouponDao;
import club.shaoyu.exception.UpdateException;
import club.shaoyu.money.dao.MoneyDao;
import club.shaoyu.vo.Coupon;
@Service
public class CouponService implements ICouponService {
@Autowired
private BookDao bookDao;
@Autowired
private MoneyDao moneyDao;
@Autowired
private CouponDao couponDao;
@Override
@Transactional
public boolean insert(String bookId, String userId, int count) {
if(bookDao.enough(bookId, count)) {
try {
bookDao.update(bookId, count);
} catch (UpdateException e) {
e.printStackTrace();
}
}
float price =bookDao.getPrice(bookId);
float totle=price*count;
if(moneyDao.enough(userId, totle)) {
Coupon coupon=new Coupon();
coupon.setId(UUID.randomUUID().toString());
coupon.setBookId(bookId);
coupon.setUserId(userId);
coupon.setTotle(totle);
couponDao.insert(coupon);
moneyDao.update(userId, totle);
}
return true;
}
}
如图所示:我们在使用上述insert代码对数据库进行修改时,不难发现-->如果数据查询满足要求,但是钱包不够,此时仅仅可以将书籍修改,从而异常抛出-->为了解决上述问题-->我们使用Spring中的事务框架进行修改,达到的结果-->除非无异常抛出,其他的情况下均会使事务回滚,从而达到办公的要求
@Transactional配置
一、是什么
@Transactional注解修饰的方法中会自动形成代理类并且形成上述Spring事务机制
二、怎么配置?
在Spring中如下配置,与连接数据库配置多了transactionManager类和annotation-driven标签进行驱动
相应的jar包:
将此形成代理类的包引入:spring-aspects-4.3.10.RELEASE.jar
同时Spring相关和数据连接池相关的以及log4j引入即可
三、怎么做?
@Transactional(属性=数值)
timeout属性和readOnly
在timeout中的方法为描述,若是对应的方法在三秒钟不执行结束,那么指定不执行
如果想测试,大可将Thread.sleep(20000)添加代码中
输出的结果为:Transaction timed out: deadline was Thu Mar 19 18:26:35 CST 2020
readOnly
只读操作是不可以对数据进项修改,否则报错
输出异常:Connection is read-only
rollbackFor和rollbackForClassName
前提:定对哪些异常回滚事务。默认情况下,如果在事务中抛出了运行时异常(继承自RuntimeException异常类),则回滚事务;如果没有抛出任何异常,或者抛出了检查时异常,则依然提交事务,这告诉我们要想回滚相应异常或者是不会滚异常,我们需要相应的属性进行控制
rollbackFor=检查时异常类便可:、
事物的传播级别:
propagation:正常情况下-->假设一个事务中的中有方法去调用另外一个事务,那么另外这个事务如何创建?这便涉及到事物的传播机制问题
REQUIRED:默认值,如果有事务在运行,当前的方法就在这个事务内运行,否则,就启动一个新的事务,并在自己的事务内运行
REQUIRES_NEW:当前方法必须启动新事务,并在它自己的事务内运行,如果有事务在运行,则把当前事务挂起,直到新的事务提交或者回滚才恢复执行
此时若是在一个事务中调用一个事物多次,默认情况下其中一个子事务失败,则全部失败,若是第二种的话便会发生一个事物下的事务单独执行
isolation:指定事务隔离级别,Spring定义了如下5种事务隔离级别:
DEFAULT:默认值,表示使用底层数据库的默认隔离级别。对大部分数据库而言,通常为READ_COMMITTED。
READ_UNCOMMITTED:表示一个事务可以读取另一个事务修改但还没有提交的数据。该级别可能出现脏读、不可重复读或幻读,因此很少使用该隔离级别。
READ_COMMITTED:表示一个事务只能读取另一个事务已经提交的数据。该级别可以防止脏读,但可能出现不可重复读或幻读,这也是大多数情况下的推荐值。
REPEATABLE_READ:表示一个事务在整个过程中可以多次重复执行某个查询,且每次返回的记录都相同,除非数据被当前事务自生修改。即使在多次查询之间有新增的数据满足该查询,这些新增的记录也会被忽略。该级别可以防止脏读和不可重复读,但可能出现幻读。
SERIALIZABLE:表示所有的事务依次逐个执行,事务之间互不干扰,该级别可以防止脏读、不可重复读和幻读,但是这将严重影响程序的性能,因此通常情况下也不会用到该级别。
当多个事务同时发生,此时会发生多重不必要的行为,为了避免这些行为,我们采用上述方法将数据进行隔离,这些内容在前面的SQL中的事务隔离级别中也讲过