1、通过注解的方式配置事务的步骤:
①配置事务管理器
②开启注解方式声明事务
③在需要配置的方法上添加@Transaction注解
2、事务传播性:
(1)概念:当事务方法被另一个事务方法调用时,制定事务该如何传播
(例子:有事务方法A和B,A多次调用B,事务传播性就是用于指定A应该在什么时候提交数据,是B的所有调用都完成后就提交,还是完成一次调用就提交一次,还是其他情况)
(2)传播属性:(默认REQUIRED,常用的有REQUIRED和REQUIRED_NEW)
①REQUIRED:事务内所有子事务都成功结束后才提交数据(事务都不抛出异常时提交)
②REQUIRED_NEW:事务内所有子事务都是一个独立事务,执行一个挂起一个,结束一个提交一个的数据(事务完成一个提交一个,抛出异常的不提交并停止整个事务)
③SUPPORTS:如果有事务在运行,则在该事务内运行,否则可不运行在事务中
④NOT_SUPPORTED:当前事务不运行在事务中,如果有运行的事务,则将该事务挂起
⑤MANDATORY:当前方法必须运行在事务中,如果没有正在运行的事务,则抛出异常
⑥NEVER:当前方法不运行在事务中,如果有运行的事务,则抛出异常
⑦nested:如果有事务在运行,当前事务方法嵌套到运行事务中运行,否则开启一个新事务运行
3、逻辑
(1)写一个被调用的事务方法A,再写一个新的事务方B法调用该事务方法A
(2)在事务方法B上配置传播@Transaction,在事务方法A中配置@Transaction的传播属性(即:传播属性是配置在真正有操作逻辑的事务方法上,如操作数据库的事务方法)
(3)调用事务方法B
4、使用步骤
①创建对应的bean
②写数据库连接数据的properties
③编写spring配置文件,导入资源文件
④编写spring配置文件,配置C3P0数据源
⑤编写spring配置文件,配置JdbcTemplate
⑥编写spring配置文件,基于注解 配置事务管理器
⑦编写spring配置文件,开启注解方式声明事务
⑧对事务类用annotation配置注入关系,对事务添加@Transactional注解
⑨编写代码,获取相关配置文件,连接数据库
⑩编写代码,调用事务逻辑代码
5、事务无效的原因排查及解决:
①检查数据库的表的存储引擎,如:mysql的时候,表的存储引擎为MyISAM时,是非事务性表,不支持事务,需要改为InnoDB,可以用SHOW TABLE STATUS LIKE ‘表名’ 来查看存储引擎是什么,使用ALTER TABLE 表名
ENGINE = InnoDB 来修改储存引擎为InnoDB
②事务抛出的异常为Exception而不是RuntimeException时,不会回滚(抛出异常需要这样写:throw new RuntimeException(“xxxxxxxxxxxx”);)
③@Transactional注解放在private方法上,不会回滚,但是不会报错
6、文件
①TestMain.java:测试类
②MyException.java:自定义错误抛出类
③TxDao.java:更新账户信息的方法接口
④TxDaoImpl.java:更新账户信息的实现类
⑤ProductDao.java:更新商品信息的方法接口
⑥ProductDaoImpl.java:更新商品信息的实现类
⑦SummaryPruchase.java:交易接口(根据交易信息,调用账户信息和商品信息的更新方法实现类)
⑧SummaryPruchaseImpl.java:交易接口实现类
⑨db.properties:数据库配置信息
⑩jdbcTemplateContext.xml:配置文件
9、TestMain.java
package com.demo.sshtest;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
/*
通过注解的方式配置事务的步骤:
1、配置事务管理器
2、开启注解方式声明事务
3、在需要配置的方法上添加@Transaction注解
事务传播性:
1、概念:当事务方法被另一个事务方法调用时,制定事务该如何传播
(例子:有事务方法A和B,A多次调用B,事务传播性就是用于指定A应该在什么时候提交数据,是B的所有调用都完成后就提交,还是完成一次调用就提交一次,还是其他情况)
2、传播属性:(默认REQUIRED,常用的有REQUIRED和REQUIRED_NEW)
(1)REQUIRED :事务内所有子事务都成功结束后才提交数据(事务都不抛出异常时提交)
(2)REQUIRED_NEW :事务内所有子事务都是一个独立事务,执行一个挂起一个,结束一个提交一个的数据(事务完成一个提交一个,抛出异常的不提交并停止整个事务)
(3)SUPPORTS :如果有事务在运行,则在该事务内运行,否则可不运行在事务中
(4)NOT_SUPPORTED:当前事务不运行在事务中,如果有运行的事务,则将该事务挂起
(5)MANDATORY :当前方法必须运行在事务中,如果没有正在运行的事务,则抛出异常
(6)NEVER :当前方法不运行在事务中,如果有运行的事务,则抛出异常
(7)nested :如果有事务在运行,当前事务方法嵌套到运行事务中运行,否则开启一个新事务运行
3、步骤:
(1)写一个被调用的事务方法A,再写一个新的事务方B法调用该事务方法A
(2)在事务方法B上配置传播@Transaction,在事务方法A中配置@Transaction的传播属性(即:传播属性是配置在真正有操作逻辑的事务方法上,如操作数据库的事务方法)
(3)调用事务方法B
*/
public class TestMain {
private static ApplicationContext applicationContext = null;
private static JdbcTemplate jdbcTemplate;
private static ProductDao productDao = null;
private static TxDao txDao=null;
private static SummaryPurchase summaryPurchase=null;
public static void main(String[] args) {
try{
testConnection();
//testTX();
testTransactionPropagation();
}catch(Exception e){
System.out.println(e.getMessage());
}
}
//获取相关配置文件,连接数据库
public static void testConnection() throws SQLException{
applicationContext = new ClassPathXmlApplicationContext("jdbcTemplateContext.xml");
DataSource dataSource = applicationContext.getBean(DataSource.class);
System.out.println(dataSource.getConnection());
jdbcTemplate = (JdbcTemp