❤️‍Spring从入门到大神--事务管理(搞笑漫画讲解!简单易懂!!)


在这里插入图片描述

  • 事务指的是逻辑上的一组操作,组成这组操作的各个单元要么全都成功,要么全都失败.
  • 事务作用:保证一组操作要么全都成功,对数据库进行完整更新。要么在某一个动作失败的时候让数据恢复原状,不会引起不完整的修改。

1、案例:转账

1.1、需求描述:

完成转账功能, 根据两个账户的id和要转账的钱money,对其中一个id的钱-money,对另一个id的钱+money.

分析:
转账功能 需要由两个动作完成.
1)账户1减钱
2)账户2加钱

减钱:根据账户id对钱数 减
加钱:根据账户id 对钱数 加

总体思路:
1.SM整合环境搭建好.
2.在service中提供转账功能.
3.测试类中测试.转账功能

项目结构如下:在这里插入图片描述

1.2、环境搭建

  1. 步骤1:导入jar包坐标
  2. 步骤2:配置文件
  3. 步骤3:数据库和表

CREATE TABLE account(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(40),
money FLOAT
)
INSERT INTO account(NAME,money) VALUES(‘jack’,10);
INSERT INTO account(NAME,money) VALUES(‘rose’,10);

1.3、编写domain

@Entity(name = “accnout”)
public class Account {
@Id
private Integer id;
private String name;
//省略getter和setter方法
}

1.4、编写dao

public interface AccnoutMapper extends Mapper {
}

1.5、编写service

AccountService接口:

public interface AccnoutService {
public void change(Integer inId,Integer outId,Double money);
}

AccountServiceImpl实现类:

@Service
@Transactional()
public class AccnoutServiceImpl implements AccnoutService {
@Resource
private AccnoutMapper accnoutMapper;
@Override
public void change(Integer inId, Integer outId, Double money) {
//收款人+加钱
Account account = accnoutMapper.selectByPrimaryKey(inId);
account.setMoney(account.getMoney()+money);
accnoutMapper.updateByPrimaryKey(account);
//汇款人-减钱
Account account1 = accnoutMapper.selectByPrimaryKey(outId);
account1.setMoney(account1.getMoney()-money);
accnoutMapper.updateByPrimaryKey(account1);
}
}

1.6、配置类

MyBatisConfig 类

public class MyBatisConfig {
@Bean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
sqlSessionFactoryBean.setTypeAliasesPackage(“com.czxy.sm.domain”);
Configuration configuration = new Configuration();
configuration.setMapUnderscoreToCamelCase(true);
sqlSessionFactoryBean.setConfiguration(configuration);
//分页
PageHelper pageHelper = new PageHelper();
Properties properties = new Properties();
properties.setProperty(“dialect”,“mysql”);
properties.setProperty(“rowBoundsWithCount”,“true”);
pageHelper.setProperties(properties);
sqlSessionFactoryBean.setPlugins(new Interceptor[]{pageHelper});
return sqlSessionFactoryBean.getObject();
}
/**
* 扫描Dao的包,查找各种XxxMapper接口,创建好UserMapper等对象存入到IOC的容器中
* @return
*/
@Bean
public MapperScannerConfigurer mapperScannerConfigurer(){
MapperScannerConfigurer configurer = new MapperScannerConfigurer();
configurer.setBasePackage(“com.czxy.sm.dao”);
return configurer;
}
}

SpringConfiguiation 类

@Configuration
@PropertySource(“classpath:db.properties”)
@ComponentScan({“com.czxy.sm.dao”,“com.czxy.sm.service”})
public class SpringConfiguiation {
@Value(" j d b c . d r i v e r " ) p r i v a t e S t r i n g d r i v e r ; @ V a l u e ( " {jdbc.driver}") private String driver; @Value(" jdbc.driver")privateStringdriver;@Value("{jdbc.url}")
private String url;
@Value(" j d b c . u s e r n a m e " ) p r i v a t e S t r i n g u s e r n a m e ; @ V a l u e ( " {jdbc.username}") private String username; @Value(" jdbc.username")privateStringusername;@Value("{jdbc.password}")
private String password;
@Bean
public DataSource dataSource(){
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setDriverClassName(driver);
druidDataSource.setUrl(url);
druidDataSource.setUsername(username);
druidDataSource.setPassword(password);
return druidDataSource;
}

1.6、测试

@RunWith(SpringRunner.class)
@ContextConfiguration(classes = {SpringConfiguiation.class, MyBatisConfig.class})
public class TestSm {
@Resource
private AccnoutService accnoutService;
@Test
public void run1(){
accnoutService.change(1,2,3.0);
System.out.println(“完毕”);
}
}

2、事务概述

JavaEE体系进行分层开发,事务处理位于业务层,Spring提供了分层设计业务层的事务处理解决方案。
spring的事务控制是基于AOP的。也就是spring提供了实现类对我们的业务方法进行增强,完成事务具体的操作。

3、Spring事务相关的术语

3.1、事务平台管理器:PlatformTransactionManager

spring通过事务管理器来管理事务。
事务管理器PlatformTransactionManager提供了事务需要的基本操作
在这里插入图片描述
实现类:DataSourceTransactionManager:使用JdbcTemplate或MyBatis需要的事务管理器
在这里插入图片描述

4、事务入门

4.1、修改配置类

加粗为修改内容

@ComponentScan(basePackages={“com.czxy”})
@PropertySource(“classpath:jdbc.properties”) //加载配置文件
@EnableTransactionManagement
public class SpringConfigruation {
//解析 j d b c . d r i v e r 在 4.2.4 中 必 须 配 置 内 容 @ B e a n p u b l i c s t a t i c P r o p e r t y S o u r c e s P l a c e h o l d e r C o n f i g u r e r c o n f i g u r e r ( ) r e t u r n n e w P r o p e r t y S o u r c e s P l a c e h o l d e r C o n f i g u r e r ( ) ; / ∗ ∗ ∗ 获 得 数 据 ∗ / @ V a l u e ( " {jdbc.driver} 在 4.2.4中必须配置内容 @Bean public static PropertySourcesPlaceholderConfigurer configurer(){ return new PropertySourcesPlaceholderConfigurer(); } /** * 获得数据 */ @Value(" jdbc.driver4.2.4@BeanpublicstaticPropertySourcesPlaceholderConfigurerconfigurer()returnnewPropertySourcesPlaceholderConfigurer();//@Value("{jdbc.driver}")
private String driverClass;
@Value(" j d b c . u r l " ) p r i v a t e S t r i n g u r l ; @ V a l u e ( " {jdbc.url}") private String url; @Value(" jdbc.url")privateStringurl;@Value("{jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
/**
* 配置数据源
* @return
/
@Bean
public DataSource dataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(driverClass);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
/
* 事务管理器
* @param dataSource
* @return
/
@Bean
public DataSourceTransactionManager txManager(DataSource dataSource){
return new DataSourceTransactionManager(dataSource);
}

}

4.2、修改Service

加粗为修改内容

@Service
@Transactional
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountMapper accountMapper;
public void change(Integer inId, Integer outId, Double money) {
Account account = accountMapper.selectByPrimaryKey(inId);
account.setMoney(account.getMoney()+money);
accountMapper.updateByPrimaryKey(account);
// int i=1/0;
Account account1 = accountMapper.selectByPrimaryKey(outId);
account1.setMoney(account1.getMoney()-money);
accountMapper.updateByPrimaryKey(account1);
}
}

5、事务高级

5.1、事务特性:ACID

  • 原子性(Atomicity)原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
  • 一致性(Consistency)事务前后数据的完整性必须保持一致。
  • 隔离性(Isolation)事务的隔离性是指多个用户并发访问数据库时,一个用户的事务不能被其它用户的事务所干扰,多个并发事务之间数据要相互隔离。
  • 持久性(Durability)持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响。

5.2、并发访问问题

如果不考虑隔离性,事务存在并发访问问题。
1.脏读:一个事务读到了另一个事务未提交的数据.
在这里插入图片描述
2.不可重复读:一个事务读到了另一个事务已经提交(update)的数据。引发另一个事务,在事务中的多次查询结果不一致。
在这里插入图片描述
3.虚读 /幻读:一个事务读到了另一个事务已经提交(insert)的数据。导致另一个事务,在事务中多次查询的结果不一致。(数据量不同)
在这里插入图片描述
严重性: 脏读 > 不可重复读 >虚读(幻读)

5.3、隔离级别:解决问题

  • 数据库规范规定了4种隔离级别,分别用于描述两个事务并发的所有情况。
  1. read uncommitted 读未提交,一个事务读到另一个事务没有提交的数据。
    a)存放:3个问题(脏读、不可重复读、虚读)。
    b)解决:0个问题

效率最高,引发所有读问题
基本不设置

  1. read committed 读已提交,一个事务读到另一个事务已经提交的数据。
    a)存放:2个问题(不可重复读、虚读)。
    b)解决:1个问题(脏读)

如果要 效率,那么选择这个read committed

  1. repeatable read :可重复读,在一个事务中读到的数据信息始终保持一致,无论另一个事务是否提交。
    a)存放:1个问题(虚读)。
    b)解决:2个问题(脏读、不可重复读)

如果 要求安全,选择这个repeatable read

虚读的问题可以通过程序来规避:
1)事务刚开启时,可以count()
2)事务要关闭时,可以count(
)
3)比对,如果两次数据一致,说明没有虚读

  1. serializable 串行化,同时只能执行一个事务,相当于事务中的单线程。
    a)存放:0个问题。
    b)解决:1个问题(脏读、不可重复读、虚读)

没有效率,安全性最高,基本不设置

  • 安全和性能对比
  • 安全性:serializable > repeatable read > read committed > read uncommitted
  • 性能 : serializable < repeatable read < read committed < read uncommitted
  • 常见数据库的默认隔离级别:
  • MySql:repeatable read 安全,本身做的优化比较好
  • Oracle:read committed 效率

5.4、术语

事务:
在这里插入图片描述

TransactionDefinition:事务的定义信息对象,需要知道,方便知道事务有哪些设置项。
TransactionStatus:事务的状态对象,spring内部使用的对象,不需要关注。

5.5、定义对象:概述TransactionDefinition

在这里插入图片描述
通过分析事务定义信息对象,spring事务定义主要涉及以下4方面:隔离级别、传播行为、超时、只读

5.6、定义对象:只读

开发中,查询数据,不会伴随增删改,所以建议查询时设置为只读。

注解
@Transactional(readOnly=true):只读事务。DQL使用
@Transactional(readOnly=false):默认值,不是只读事务,可以进行增删改操作。DML使用

5.7、定义对象:超时

默认值是-1,没有超时限制。如果有,以秒为单位进行设置。(一般不设置)
注解
@Transactional(timeout=60):设置超时为60秒,如果还没有操作结束,将抛异常。

5.8、定义对象:隔离级别

事务隔离级别反映事务提交并发访问时的处理态度。
注解
@Transactional(isolation=Isolation.DEFAULT):默认级别
@Transactional(isolation=Isolation.READ_UNCOMMITTED):读未提交
@Transactional(isolation=Isolation.READ_COMMITTED):读已提交
@Transactional(isolation=Isolation.REPEATABLE_READ):可重复读
@Transactional(isolation=Isolation.SERIALIZABLE):串行化
在这里插入图片描述

5.9、定义对象:传播行为

传播行为:业务A使用了业务B,AB之间事务共享问题,就是事务的传播行为。
spring中事务的传播行为共7种。
注解
@Transactional(propagation=Propagation.REQUIRED):默认值,支持当前事务,如果当前没有事务,就新建一个事务
@Transactional(propagation=Propagation.SUPPORTS):支持当前事务,如果当前没有事务,就以非事务方式执行
@Transactional(propagation=Propagation.MANDATORY):支持当前事务,如果当前没有事务,就抛出异常
@Transactional(propagation=Propagation.REQUIRES_NEW):新建事务,如果当前存在事务,把当前事务挂起
@Transactional(propagation=Propagation.NOT_SUPPORTED):以非事务方式执行操作,如果当前存在事务,就把当前事务挂起
@Transactional(propagation=Propagation.NEVER):以非事务方式执行,如果当前存在事务,则抛出异常
@Transactional(propagation=Propagation.NESTED):如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行REQUIRED类似的操作

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值