Spring之事务篇
提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
需要对于数据库的事务有所了解,mysql可能对于这个最好吧,毕竟mysql底层使用的数据库存储引擎为Innodb,
Innodb为事务性存储引擎
一、什么是事务
(1)事务是数据库操作最基本单元,逻辑上一组操作,要么都成功,如果有一个失败所有操 作都失败
(2)典型场景:
银行转账 * lucy 转账 100 元 给 mary * lucy 少 100,mary 多 100
二、事务四个特性(ACID)
(1)原子性 : 要么都成功,要么都失败,不能一个成功,一个失败
(2)一致性 :从一个状态到另一个状态, 银行转账:lucy少了100,mary多了100,不能lucy少了,marg没多
(3)隔离性:多事务在操作时候的先后顺序
(4)持久性: 一但操作执行了,就是永久性的修改
三、事务的操作
3.1 @Transactional注解
1.在需要配置事务的类或方法上添加
@Transactional() 开启事务
2.在 service 类上面添加注解@Transactional,在这个注解里面可以配置事务相关参数
3.2 事务的传播行为
多事务之间的管理
传播属性 | 描述 |
---|---|
.REQUIRED | 如果有事务在运行,加入该事务,没有则新建事务 |
.REQUIRED_NEW | 当前方法启动新事务运行,有事务在运行,则挂起 |
SUPPORTS | 如果有事务在运行,当前方法就运行在该事务,否则就不运行在事务中 |
NOT_SUPPORTS | 当前方法以非事务运行,如果有事务在运行则挂起,执行完恢复事务, |
MANDATORY | 当前方法必须运行在事务内部,如果没有正在运行的事务,则抛出异常 |
NEVER | 当前方法不应该运行在事务中,如果有运行的事务,则抛出异常 |
NESTED | 如果有事务在运行,就在这个事务内部嵌套事务运行,否则启动新事务,并在自己事务内运行 |
3.3 事务的隔离性
解决并发下多事务操作之间的影响
- 脏读: 对于两个事务 T1, T2, T1 读取了已经被 T2 更新但还没有被提交的字段。之后, 若 T2 回滚, T1读取的内容就是临时且无效的。
- 不可重复读: 对于两个事务T1, T2, T1 读取了一个字段, 然后 T2 更新了该字段。之后, T1再次读取同一个字段, 值就不同了。
- 幻读: 对于两个事务T1, T2, T1 从一个表中读取了一个字段, 然后 T2 在该表中插入了一些新的行。之后, 如果 T1 再次读取同一个表, 就会多出几行。
事务的隔离级别:MySQL默认是可重复读
3.4 timeout:超时时间
(1)事务需要在一定时间内进行提交,如果不提交进行回滚
(2)默认值是 -1 ,设置时间以秒单位进行计算
3.5 readOnly:是否只读
(1)读:查询操作,写:添加修改删除操作
(2)readOnly 默认值 false,表示可以查询,可以添加修改删除操作
(3)设置 readOnly 值是 true,设置成 true 之后,只能查询
3.6、rollbackFor:回滚
(1)设置出现哪些异常进行事务回滚
3.7 noRollbackFor:不回滚
(1)设置出现哪些异常不进行事务回滚
四、两种类型的事务
4.1 编程式事务
// 使用try cach
try {
// 第一步、开启事务
// 第二步、进行事务操作
// 第三步、没有异常 事务提交
// 第四步、有异常 事务回滚
// lucy少100
userDAO.reduceMoney();
System.out.println("lucy少100");
int i = 10 / 0;
// tom多一百
userDAO.addMoney();
System.out.println("tom多了100");
}catch (Exception e){
e.printStackTrace();
}
4.2 声明式事务xml配置
第一步 配置事务管理器
第二步 配置通知
第三步 配置切入点和切面
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<!-- 配置连接池 -->
<!-- DruidDataSource dataSource = new DruidDataSource(); -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<!-- dataSource.setDriverClassName("com.mysql.jdbc.Driver");
set方法注入
-->
<!-- 获取properties文件内容,根据key获取,使用spring表达式获取 -->
<property name="driverClassName" value="${prop.jdbcDriveClass}"></property>
<property name="url" value="${prop.url}"></property>
<property name="username" value="${prop.username}"></property>
<property name="password" value="${prop.password}"></property>
</bean>
<!--JDBCTemplate对象-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--开启组件扫描-->
<context:component-scan base-package="com.worker">
<!--配置扫描的规则-->
<!-- use-default-filters="false"-->
<!--<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Component"/>-->
</context:component-scan>
<bean id="userService" class="com.worker.spring5.service.UserService"></bean>
<!--1.创建事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入数据源-->
<property name="dataSource" ref="dataSource"/>
</bean>
<!--2.开启事务注解-->
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
<!--事务通知-->
<tx:advice id="txadvice">
<!--配置事务参数-->
<tx:attributes>
<!--指定哪种规则的方法上面添加事务-->
<tx:method name="accountMoney" isolation="READ_COMMITTED"/>
<!--account* account开头的方法-->
<!--<tx:method name="account*"></tx:method>-->
</tx:attributes>
</tx:advice>
<!--配置切入点和切面-->
<aop:config>
<!--配置切入点-->
<aop:pointcut id="p" expression="execution(* com.worker.spring5.service.UserService.*(..))"/>
<!--配置切面-->
<aop:advisor advice-ref="txadvice" pointcut-ref="p"></aop:advisor>
</aop:config>
4.3 声明式事务 config配置
@Configuration /* 注册为配置类 */
@ComponentScan(value = "com.worker") /* 开启组件扫描 */
@PropertySource({"classpath:jdbc.properties"}) /* 外部文件 */
@EnableTransactionManagement(proxyTargetClass = true) /* 开启事务 */
public class MyConfig {
@Value("${prop.jdbcDriveClass}")
private String driver;
@Value("${prop.url}")
private String url;
@Value("${prop.username}")
private String username;
@Value("${prop.password}")
private String password;
@Bean
public DruidDataSource getDruidDataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(driver);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
@Bean
public JdbcTemplate getJdbcTemplate(DataSource dataSource){
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(dataSource);
return jdbcTemplate;
}
// 配置事务管理器
@Bean
public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource){
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
transactionManager.setDataSource(dataSource);
return transactionManager;
}
}
总结
以上就是今天要讲的内容,本文仅仅简单介绍了