spring -事务和数据库事务

spring 事务底层分析:

一、数据库事务的基本特征:

   数据库事务是区分文件存储系统和nosql数据库的重要特征之一,即为了保证即使在并发情况下也能够正确执行crud操作。正确操作的
   特征就是数据库事务的基本特性,即ACID。
   1. 数据库事务的基本特性
       A(atomicity).  原子性:事务中各项操作,要么全成功,要么全失败,任何一个操作的失败都会导致整个事物的失败。
       C. ( consistency)一致性: 事务结束后系统状态是一致的。
       I (isolation)隔离性: 并发执行的事务彼此无法看到对方的中间状态。
       D (durability)持久性: 事务完成后所做的改动都会被持久化,即使发生灾难性的失败。
 
 在高并发的情况下,要完全保证其ACID特性是非常困难的,除非把所有的事物串行化执行,但带来的负面的影响将是性能大打折扣。
 很多时候我们有些业务对事物的要求是不一样的,所以数据库中设计了四种隔离级别,供用户基于业务进行选择。
  2. 数据库事务的隔离级别:
      隔离级别                            脏读(Dirty Read)                  不可重复读 (nonrepeatable read)                       幻读 (phantom read)
      
      未提交读
      (Read uncommited)            可能                                        可能                                                                   可能

   已提交读
   (Read commited)                  不可能                                     可能                                                                   可能

  可重复读                            
  (Repeatable read)                不可能                                    不可能                                                                 可能
   
   可串行化 
   (serializable)                 不可能                                      不可能                                                                 不可能
  • 脏读 :
    一个事物读取到另一事物未提交的更新数据
  • 不可重复读 :
    在同一事物中,多次读取同一数据返回的结果有所不同, 换句话说, 后续读取可以读到另一事物已提交的更新数据.
    相反, “可重复读”在同一事物中多次读取数据时, 能够保证所读数据一样, 也就是后续读取不能读到另一事物已提交
    的更新数据。
  • 幻读 :
    查询表中一条数据如果不存在就插入一条,并发的时候却发现,里面居然有两条相同的数据。这就幻读的问题。

数据库默认隔离级别:
Oracle中默认级别是 Read committed
mysql 中默认级别 Repeatable read。另外要注意的是mysql 执行一条查询语句默认是一个独立的事物,所以看上去效果跟 Read committed一样。

二、spring对事务的支持

  • spring事务相关API说明
  • 声明式事务的使用
  • 事务传播机制
  1. spring事务相关API说明:

spring 事物是在数据库事物的基础上进行封装扩展 其主要特性如下:
a. 支持原有的数据事物的隔离级别
b. 加入了事物传播的概念 提供多个事物的和并或隔离的功能
c. 提供声明式事物,让业务代码与事物分离,事物变得更易用。

spring提供了三个接口供使用事务
a TransactionDefinition :事务定义
b. PlatformTransactionManager :事务管理,提交和回滚
c. TransactionStatus : 事务运行时状态

  1. 声明式事务:
    使用api来实现对事务的控制特别繁琐,spring 为我们提供了声明式事务,使用起来非常简单,即使用
    @Transection 注解在方法上即可。
配置spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">

    <context:annotation-config/>
    <context:component-scan base-package="com.huonilaifu.service.**">
    </context:component-scan>

    <bean class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!-- similarly, don't forget the PlatformTransactionManager -->
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <!-- don't forget the DataSource -->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <constructor-arg name="url" value="jdbc:mysql://192.168.0.147/lirb"/>
        <constructor-arg name="username" value="root"/>
        <constructor-arg name="password" value="123456"/>
    </bean>
    <tx:annotation-driven transaction-manager="txManager"></tx:annotation-driven>
</beans>
编写服务类
@Transactional
public void addAccount(String name, int initMenoy) {
    String accountid = new SimpleDateFormat("yyyyMMddhhmmss").format(new Date());
    jdbcTemplate.update("insert INTO account (accountName,user,money) VALUES (?,?,?)", accountid, name, initMenoy);
    // 人为报错
    int i = 1 / 0;
}

  1. 事务传播机制。

    在这里插入图片描述
    常用事物传播机制:
     PROPAGATION_REQUIRED:
    这个也是默认的传播机制;
     PROPAGATION_NOT_SUPPORTED :
    可以用于发送提示消息,站内信、短信、邮件提示等。不属于并且不应当影响主体业务逻辑,即使发送失败也不应该对主体业务逻辑回滚。
     PROPAGATION_REQUIRES_NEW :
    总是新启一个事物,这个传播机制适用于不受父方法事物影响的操作,比如某些业务场景下需要记录业务日志,用于异步反查,那么不管主体业务逻辑是否完成,日志都需要记录下来,不能因为主体业务逻辑报错而丢失日志;

三、 aop 事务底层实现原理:

      aop 事务是通过动态代理的方式来实现。如果在一个类带有事务的方法中调用该类另一个带有事务的方法,使用this 则不会起到事务传播的特性,英文 必须拿到该类动态代理的对象才有事务。
      实现方式:
<!-- 配置暴露proxy -->
<aop:aspectj-autoproxy expose-proxy="true"/>

// 基于代理对象调用创建帐户,事物的配置又生效了
((UserSerivce) AopContext.currentProxy()).addAccount(name, 10000);

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值