黑龙江省城乡建设厅网站,焦作建网站,磁力,无锡响应式网站设计今日目标 能够掌握Spring事务配置 Spring事务管理
1 Spring事务简介【重点】
1.1 Spring事务作用 事务作用#xff1a;在数据层保障一系列的数据库操作同成功同失败 Spring事务作用#xff1a;在数据层或业务层保障一系列的数据库操作同成功同失败
1.2 案例分析Spring…今日目标 能够掌握Spring事务配置 Spring事务管理
1 Spring事务简介【重点】
1.1 Spring事务作用 事务作用在数据层保障一系列的数据库操作同成功同失败 Spring事务作用在数据层或业务层保障一系列的数据库操作同成功同失败
1.2 案例分析Spring事务 需求实现任意两个账户间转账操作 需求微缩A账户减钱B账户加钱 分析 ①数据层提供基础操作指定账户减钱outMoney指定账户加钱inMoney ②业务层提供转账操作transfer调用减钱与加钱的操作 ③提供2个账号和操作金额执行转账操作 ④基于Spring整合MyBatis环境搭建上述操作 结果分析 ①程序正常执行时账户金额A减B加没有问题 ②程序出现异常后转账失败但是异常之前操作成功异常之后操作失败整体业务失败 结构 1.3 代码实现
【前置工作】环境准备 创建数据库和表 CREATE DATABASE IF NOT EXISTS spring_db2 DEFAULT CHARACTER SET utf8
USE spring_db2;DROP TABLE IF EXISTS tbl_account;
CREATE TABLE tbl_account (id INT(11) NOT NULL AUTO_INCREMENT,name VARCHAR(20) DEFAULT NULL,money DOUBLE DEFAULT NULL,PRIMARY KEY (id)
) ENGINEINNODB AUTO_INCREMENT3 DEFAULT CHARSETutf8;INSERT INTO tbl_account(id,name,money) VALUES
(1,Jack,1000),
(2,Rose,1000);DROP TABLE IF EXISTS tbl_log;
CREATE TABLE tbl_log (id INT(11) NOT NULL AUTO_INCREMENT,info VARCHAR(255) DEFAULT NULL,create_date DATETIME DEFAULT NULL,PRIMARY KEY (id)
) ENGINEINNODB AUTO_INCREMENT3 DEFAULT CHARSETutf8;INSERT INTO tbl_log(id,info,create_date) VALUES
(2,Jack向Rose转账520.0元,2021-11-04 17:19:18);pom.xml添加依赖 dependencies!--导入spring的坐标spring-context对应版本是5.2.10.RELEASE--dependencygroupIdorg.springframework/groupIdartifactIdspring-context/artifactIdversion5.3.15/version/dependencydependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdversion1.18.28/version/dependencydependencygroupIdorg.springframework/groupIdartifactIdspring-jdbc/artifactIdversion5.3.15/version/dependency
!--mysql--dependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactIdversion8.0.27/version/dependency!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --dependencygroupIdorg.mybatis/groupIdartifactIdmybatis/artifactIdversion3.5.13/version/dependencydependencygroupIdorg.mybatis/groupIdartifactIdmybatis-spring/artifactIdversion1.3.0/version/dependency!-- https://mvnrepository.com/artifact/com.alibaba/druid --dependencygroupIdcom.alibaba/groupIdartifactIddruid/artifactIdversion1.2.18/version/dependency!--junit,spring对junit4的要求必须是4.12版本以上--dependencygroupIdjunit/groupIdartifactIdjunit/artifactIdversion4.13/versionscopetest/scope/dependency!--spring-test--dependencygroupIdorg.springframework/groupIdartifactIdspring-test/artifactIdversion5.3.22/versionscopetest/scope/dependency/dependenciesSpring整合Mybatis相关代码(依赖、JdbcConfig、MybatisConfig、SpringConfig) JdbcConfig package com.zbbmeta.config;import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;import javax.sql.DataSource;public class JdbcConfig {Value(${jdbc.driverClassName})private String driverClassName;Value(${jdbc.url})private String url;Value(${jdbc.username})private String userName;Value(${jdbc.password})private String password;Beanpublic DataSource dataSource(){DruidDataSource ds new DruidDataSource();ds.setDriverClassName(driverClassName);ds.setUrl(url);ds.setUsername(userName);ds.setPassword(password);return ds;}//spring提供的事务切面类里面增强了事务管理功能里面有事务提交和事务回滚功能Beanpublic PlatformTransactionManager transactionManager(DataSource dataSource){DataSourceTransactionManager ptm new DataSourceTransactionManager();ptm.setDataSource(dataSource);return ptm;}
}MybatisConfig package com.zbbmeta.config;import org.apache.ibatis.logging.stdout.StdOutImpl;
import org.apache.ibatis.session.Configuration;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.context.annotation.Bean;import javax.sql.DataSource;public class MybatisConfig {Bean //不仅可以将返回值加入IOC容器而且可以实现方法参数进行依赖注入参数默认会根据类型从IOC容器中获取对象自动注入public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource){SqlSessionFactoryBean ssfb new SqlSessionFactoryBean();ssfb.setTypeAliasesPackage(com.zbbmeta.entity); //告诉mybatis设置实体类包别名ssfb.setDataSource(dataSource); //将IOC容器中连接池给到Mybatis//注意必须导入org.apache.ibatis.session.Configuration;Configuration configuration new Configuration();//设置整合mybatis驼峰命名映射configuration.setMapUnderscoreToCamelCase(true);//设置打印日志configuration.setLogImpl(StdOutImpl.class);ssfb.setConfiguration(configuration);return ssfb;}
}SpringConfig Configuration
ComponentScan(com.zbbmeta)
PropertySource(classpath:jdbc.properties)
Import({JdbcConfig.class,MybatisConfig.class})
public class SpringConfig {
}Account ToString
Data
public class Account {private Integer id;private String name;private Double money;}AccountDao public interface AccountDao {Update(update tbl_account set money money #{money} where name #{name})void inMoney(Param(name) String name, Param(money) Double money);Update(update tbl_account set money money - #{money} where name #{name})void outMoney(Param(name) String name, Param(money) Double money);
}public interface AccountService {/*** 转账操作* param out 传出方* param in 转入方* param money 金额*/void transfer(String out,String in,Double money) ;
}AccountServiceImpl Service
public class AccountServiceImpl implements AccountService {Autowiredprivate AccountDao accountDao;public void transfer(String out, String in, Double money) {//转出accountDao.outMoney(out, money);//模拟出现异常//System.out.println(1 / 0);//转入accountDao.inMoney(in, money);System.out.println(转账成功);}
}
【第一步】在业务层接口上添加Spring事务管理 在转账的方法上添加Transactional注解 /*** 业务接口*/
public interface AccountService {/*** 转账操作* param out 传出方* param in 转入方* param money 金额*/Transactionalvoid transfer(String out,String in ,Double money) ;
}注意事项 Spring注解式事务通常添加在业务层接口中而不会添加到业务层实现类中降低耦合 注解式事务可以添加到业务方法上表示当前方法开启事务也可以添加到接口上表示当前接口所有方法开启事务
【第二步】设置事务管理器(将事务管理器添加到IOC容器中) 说明可以在JdbcConfig中配置事务管理器 //配置事务管理器mybatis使用的是jdbc事务
Bean
public PlatformTransactionManager transactionManager(DataSource dataSource){DataSourceTransactionManager transactionManager new DataSourceTransactionManager();transactionManager.setDataSource(dataSource);return transactionManager;
}注意事项 事务管理器要根据实现技术进行选择 MyBatis框架使用的是JDBC事务
【第三步】开启注解式事务驱动
EnableTransactionManagement
Configuration
ComponentScan(com.itheima)
PropertySource(classpath:jdbc.properties)
Import({JdbcConfig.class,MybatisConfig.class})
EnableTransactionManagement //开启事务注解扫描
public class SpringConfig {
}【第四步】运行测试类查看结果 去掉EnableTransactionManagement注解即没有进行事务管理当转账出现问题时结果 加上EnableTransactionManagement注解账户钱都恢复成1000 结果 转账成功的时候 结果 RunWith(SpringJUnit4ClassRunner.class) //指定第三方的运行器
ContextConfiguration(classes SpringConfig.class) //读取类配置文件
public class AccountDaoTest {Autowired //自动注入业务对象private AccountService accountService;Testpublic void testFindById() throws IOException {//直接使用业务方法accountService.transfer(Jack,Rose, 100d);}
}2 Spring事务角色【理解】
问题导入
什么是事务管理员什么是事务协调员
2.1 Spring事务角色 事务管理员发起事务方在Spring中通常指代业务层开启事务的方法 事务协调员加入事务方在Spring中通常指数据层方法也可以是业务层方法 3 Spring事务相关配置
问题导入
什么样的异常Spring事务默认是不进行回滚的
3.1 Transactional注解中与事务相关配置
属性作用示例readOnly设置是否为只读事务readOnlytrue 只读事务timeout设置事务超时时间timeout -1永不超时rollbackFor设置事务回滚异常classrollbackFor {FileNotFoundException.class}rollbackForClassName设置事务回滚异常String同上格式为字符串noRollbackFor设置事务不回滚异常classnoRollbackFor {FileNotFoundException.class}noRollbackForClassName设置事务不回滚异常String同上格式为字符串propagation设置事务传播行为……
属性作用示例readOnly设置是否为只读事务readOnlytrue 只读事务timeout设置事务超时时间timeout -1永不超时rollbackFor设置事务回滚异常classrollbackFor {FileNotFoundException.class}rollbackForClassName设置事务回滚异常String同上格式为字符串noRollbackFor设置事务不回滚异常classnoRollbackFor {FileNotFoundException.class}noRollbackForClassName设置事务不回滚异常String同上格式为字符串propagation设置事务传播行为…… 说明对于RuntimeException类型异常或者Error错误Spring事务能够进行回滚操作。但是对于非运行时异常Spring事务是不进行回滚的所以需要使用rollbackFor来设置要回滚的异常。 3.2 案例转账业务追加日志
需求和分析 需求实现任意两个账户间转账操作并对每次转账操作在数据库进行记录 需求微缩A账户减钱B账户加钱数据库记录日志 分析 ①基于转账操作案例添加日志模块实现数据库中记录日志 ②业务层转账操作transfer调用减钱、加钱与记录日志功能 实现效果预期 无论转账操作是否成功均进行转账操作的日志留痕 存在的问题 日志的记录与转账操作隶属同一个事务同成功同失败 实现效果预期改进 无论转账操作是否成功日志必须保留 事务传播行为事务协调员对事务管理员所携带事务的处理态度 【准备工作】环境整备
创建新的LogDao接口
public interface LogDao {Insert(insert into tbl_log (info,create_date) values(#{info},now()))void log(String info);
}创建业务接口使用事务
public interface LogService {/*** 记录日志* param out 转出账户* param in 转入账户* param money 金额* 设置事务属性传播行为设置为需要新事务*/Transactionalvoid log(String out, String in, Double money);
}实现类
Service
public class LogServiceImpl implements LogService {Autowiredprivate LogDao logDao;public void log(String out, String in, Double money) {logDao.log(转账操作由 out 到 in ,金额 money);}
}【第一步】在AccountServiceImpl中调用logService中添加日志的方法
因为无论成功与否都需要记录日志所以日志放在finally语句块中但异常不需要捕获要抛出用来激活事务的处理
/*** 业务接口*/
public interface AccountService {/*** 转账操作* param out 传出方* param in 转入方* param money 金额*/Transactionalvoid transfer(String out,String in ,Double money) ;
}Service
public class AccountServiceImpl implements AccountService {Autowiredprivate AccountDao accountDao;Autowiredprivate LogService logService;public void transfer(String out,String in ,Double money) {try{accountDao.outMoney(out,money);//int i 1/0;accountDao.inMoney(in,money);} finally {logService.log(out,in,money);}}
}【第二步】在LogService的log()方法上设置事务的传播行为
需求无论有没有异常日志都要记录下来不能被回滚 先只设置Transactional查看运行结果 设置成当前操作需要新事务再查看运行结果
public interface LogService {//propagation设置事务属性传播行为设置为当前操作需要新事务Transactional(propagation Propagation.REQUIRES_NEW)void log(String out, String in, Double money);
}【第三步】运行测试类查看结果
RunWith(SpringJUnit4ClassRunner.class) //指定第三方的运行器
ContextConfiguration(classes SpringConfig.class) //读取类配置文件
public class AccountServiceTest {Autowired //自动注入业务对象private AccountService accountService;/*** 转账的测试*/Testpublic void testTransfer() {accountService.transfer(Jack, Rose, 10d);}
}思考:为什么 在LogService的方法上设置propagation Propagation.REQUIRES_NEW接可以创建新的事务? 这就是事务传播行为(经常会面试提问) 3.3 事务传播行为
传播属性Method1Method2REQUIRED开启TI事务加入T1事务无新建T2事务REQUIRES_NEW开启TI事务新建T2事务无新建T2事务SUPPORTS开启TI事务加入T1事务无无NOT_SUPPORTED开启TI事务无无无MANDATORY开启TI事务加入T1事务无ERRORNEVER开启TI事务ERROR无无NESTED
思考:事务会一直生效有没有事务失效的情况为什么会失效大家可以思考一下这也是一个长问面试题