【Spring】Spring 有关事务的操作 事务篇详解

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;
    }
}


总结

以上就是今天要讲的内容,本文仅仅简单介绍了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值