book_stock图书库存表:
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/tx
jdbc.username=root
jdbc.password=126433
<context:property-placeholder location=“classpath:jdbc.properties”/>
<context:component-scan base-package=“com.BookCheck”/>
BookDao类:
@Repository
public class BookDao {
@Autowired
private JdbcTemplate jdbcTemplate;
/减去某个用户的剩余金额/
public void updateBalance(String username,int price)
{
String sql=“update account set money=money-? where name=?”;
jdbcTemplate.update(sql,price,username);
}
/获取某本图书的价格/
public int getBookPrice(String isbn)
{
String sql=“select price from book where ISBN=?”;
return jdbcTemplate.queryForObject(sql, Integer.class,isbn);
}
/减去某本书库存/
public void updateStock(String isbn)
{
String sql=“update book_stock set stock=stock-1 where isbn=?”;
jdbcTemplate.update(sql,isbn);
}
}
Service类:
@Service
public class BookService {
@Autowired
BookDao bookDao;
/结账/
public void checkOut(String username,String isbn)
{
//1.减去库存
bookDao.updateStock(isbn);
//2.获取图书的价格
int bookPrice = bookDao.getBookPrice(isbn);
//3.减去余额
bookDao.updateBalance(username,bookPrice);
}
}
主类:
public class test {
static ApplicationContext ioc= new ClassPathXmlApplicationContext(“appOfDao.xml”);
public static void main(String[] args) {
BookService bs = ioc.getBean(BookService.class);
bs.checkOut(“大忽悠”,“ISBN_001”);
System.out.println(“结账成功”);
}
}
====================================================================
Spring只是个容器,因此它并不做任何事务的具体实现。他只是提供了事务管理的接口PlatformTransactionManager,具体内容由就由各个事务管理器来实现。
事务管理器可以在目标方法运行前后进行事务控制
目前使用DataSourceTransactionManager
第一步:配置事务管理器,让其进行事务控制
第二步: 开启基于注解的事务控制模式,依赖tx命名空间
<tx:annotation-driven transaction-manager=“transactionManager”/>
第三步:给事务方法加上注解即可
加上注解之后,如果事务方法里面出现异常,那么整个事务方法会进行回滚,数据恢复原样
timeout---->参数值为int(秒为单位),超时,事务超出指定执行时长后自动终止并回滚
@Transactional(timeout = 3)
public void checkOut(String username,String isbn)
{
//1.减去库存
bookDao.updateStock(isbn);
//2.获取图书的价格
int bookPrice = bookDao.getBookPrice(isbn);
//3.减去余额
bookDao.updateBalance(username,bookPrice);
}
readOnly---->参数值为bool,设置事务为只读,可以进行事务优化,默认readOnly=false,改为readOnly=true后,可以加快查询速度,因此不用管事务的相关操作了(设置自动提交…)
如果事务方法中有增删改相关操作,还设置为true时,运行时会报错
/结账/
@Transactional(readOnly = false)
public void checkOut(String username,String isbn)
{
//1.减去库存
bookDao.updateStock(isbn);
//2.获取图书的价格
int bookPrice = bookDao.getBookPrice(isbn);
//3.减去余额
bookDao.updateBalance(username,bookPrice);
}
异常分类
noRollbackFor---->参数值为Class[] (字节码文件类型,是个数组) ,那些异常事务可以不回滚
noRollbackForClassName---->参数值为String[] (全类名) ,那些异常事务可以不回滚
可以让原来默认回滚的异常给它不回滚
@Transactional(noRollbackFor ={ArithmeticException.class,NullPointerException.class} )
//数学异常不回滚,空指针异常不回滚
public void checkOut(String username,String isbn)
{
//1.减去库存
bookDao.updateStock(isbn);
//2.获取图书的价格
int bookPrice = bookDao.getBookPrice(isbn);
//3.减去余额
bookDao.updateBalance(username,bookPrice);
}
rollbackFor---->参数值为Class[] (字节码文件类型) ,哪些异常事务需要回滚
rollbackForClassName---->参数值为String[] (全类名),哪些异常事务需要回滚
原本不回滚的异常指定让其回滚,原本编译时异常不会回滚
@Transactional(rollbackFor = {FileNotFoundException.class})
//文件异常回滚
public void checkOut(String username,String isbn)
{
//1.减去库存
bookDao.updateStock(isbn);
//2.获取图书的价格
int bookPrice = bookDao.getBookPrice(isbn);
//3.减去余额
bookDao.updateBalance(username,bookPrice);
}
ioslation调整隔离级别
前置知识:数据库事务并发问题
同时对一个数据进行修改(并发修改同一个数据下的排队,挨个按照顺序进行修改操作)
前置知识:隔离级别
前置知识:查询mysql的隔离级别
前置知识:事务操作
前置知识:修改mysql的隔离级别
例如:
set [session|global] transaction isolation level read uncommitted
有事务的业务逻辑,容器中保存的是这个业务逻辑的代理对象(了解即可)
如果有多个事务同时进行嵌套运行,子事务是否要和大事务共同用一个事务
简单理解: 一个事务相等于一辆车,如果子事务和大事务共同用一个事务,那么可以理解为子事务和大事务位于同一辆车上。如果子事务开启一个新事务,相当于子事务开了一辆新车,大事务和子事务位于不同的车上面
注意: 出现的异常回一层一层往上面进行传递,坐一辆车的全崩,开新车并且在异常之前执行的不崩;开新车,但是位于异常之后,崩。
注意:如果子事务出现了异常,并且子事务位于大事务的方法体内部,那么大事务会感受到异常,那么即便大事务和子事务开不同的车,大事务也会崩掉,因为方法体内部出现了异常
子事务只和上一级的事务坐一辆车,不会和上一级的上一级的事务坐一辆车,除非他的上一级的事务和他的上一级的上一级的事务坐一辆车
总结图
设置事务传播行为演示
@Repository
public class BookDao {
@Autowired
private JdbcTemplate jdbcTemplate;
/减去某个用户的剩余金额/
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void updateBalance(String username,int price)
{
String sql=“update account set money=money-? where name=?”;
jdbcTemplate.update(sql,price,username);
}
/获取某本图书的价格/
public int getBookPrice(String isbn)
{
String sql=“select price from book where ISBN=?”;
return jdbcTemplate.queryForObject(sql, Integer.class,isbn);
}
/减去某本书库存/
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void updateStock(String isbn)
{
String sql=“update book_stock set stock=stock-1 where isbn=?”;
jdbcTemplate.update(sql,isbn);
}
}
@Transactional(propagation = Propagation.REQUIRED)
//文件异常回滚
public void checkOut(String username,String isbn)
{
//1.减去库存
bookDao.updateStock(isbn);
//2.获取图书的价格
int bookPrice = bookDao.getBookPrice(isbn);
//3.减去余额
bookDao.updateBalance(username,bookPrice);
}
重点:REQUIRED事务属性来源于大事务(子事务和大事务坐一辆车时),即子事务的所有属性,例如超时设置,回滚设置,都继承于大事务,即使子事务里面设置了,也没有用
propagation = Propagation.REQUIRES_NEW可以调整,默认是REQUIRED
REQUIRED将之前事务使用的connection传递给这个事务使用
REQUIRED_NEW这个方法直接使用新的connection
本类事务方法之间的调用就只是一个事务
@Transactional
@Service
public class BookService {
@Autowired
BookDao bookDao;
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void checkOut(String username,String isbn)
{
//1.减去库存
bookDao.updateStock(isbn);
//2.获取图书的价格
int bookPrice = bookDao.getBookPrice(isbn);
//3.减去余额
bookDao.updateBalance(username,bookPrice);
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void updateStock(String isbn)
{
bookDao.updateStock(isbn);
}
@Transactional
void testmain()
{
checkOut(“大忽悠”,“ISBN_001”);
updateStock(“ISBN_002”);
System.out.println(“结账成功”);
int i=10/0;
}
}
主类:
public static void main(String[] args) {
ApplicationContext ioc= new ClassPathXmlApplicationContext(“appOfDao.xml”);
BookService bs = ioc.getBean(BookService.class);
//虽然testmain里面的两个方法都开了新车,
//但是testmain方法最后出现了异常,效果并不如预期般改变(即回滚了事务)
bs.testmain();
}
原因:代理对象调用方法的时候,才能实现事务的控制
无法进行事务控制,也就相当于无法通过动态代理,对方法进行增强的操作,无法进行增强的操作,当然也就无法进行事务控制了
在本类中给本类对象进行注入,会造成死循环
死循环原因: IOC容器创建时,先去实例化BookService对象,实例化BookService时,发现需要给其成员变量bookService装配对象,为了给成员变量装配对象,会去容器中找对应类型的对象,结果找到了还没创建的对象BookService对象(还没创建是因为正在为其成员变量赋值),于是又去给他创建对象…
要导入spring-tx坐标,spring处理事务相关的坐标
1.引入依赖
org.aspectj
aspectjweaver
1.8.4
org.springframework
spring-context
5.0.5.RELEASE
org.springframework
spring-test
5.0.5.RELEASE
junit
junit
4.13.1
mysql
mysql-connector-java
5.1.32
c3p0
c3p0
0.9.1.2
com.alibaba
druid
1.1.10
org.springframework
spring-jdbc
5.0.5.RELEASE
org.springframework
spring-tx
5.0.5.RELEASE
2.开启注解扫描—引入context命名空间
<context:component-scan base-package=“com.BookCheck”/>
3.引入properties配置文件
<context:property-placeholder location=“classpath:jdbc.properties”/>
4.创建数据源dataSource
5.创建JdbcTemplate对象
6.创建事务管理器对象: 增强(通知)
7.事务增强:对方法的过滤
<tx:advice id=“myAdvice” transaction-manager=“transactionManager”>
tx:attributes
<tx:method name=“*”/>
<tx:method name=“checkOut” propagation=“REQUIRED” timeout=“-1”></tx:method>
分享
1、算法大厂——字节跳动面试题
2、2000页互联网Java面试题大全
3、高阶必备,算法学习
)5.创建JdbcTemplate对象
6.创建事务管理器对象: 增强(通知)
7.事务增强:对方法的过滤
<tx:advice id=“myAdvice” transaction-manager=“transactionManager”>
tx:attributes
<tx:method name=“*”/>
<tx:method name=“checkOut” propagation=“REQUIRED” timeout=“-1”></tx:method>
分享
1、算法大厂——字节跳动面试题
[外链图片转存中…(img-1Izin1FR-1714472133708)]
2、2000页互联网Java面试题大全
[外链图片转存中…(img-Mu4yWNwU-1714472133709)]
3、高阶必备,算法学习
[外链图片转存中…(img-kWXV34vF-1714472133709)]