Spring事务

事务管理

事务回顾:

原子性:要么全成功,要么全失败
一致性:事务前后,数据总数不变
隔离性:事务隔离,避免脏读,重复读等等
持久性:只要事务完成,数据就会持久化到数据库中

事务问题

脏读(必须杜绝):在一个事务中,读取到了另一个事务还没有提交的数据
重复读(可以允许):一个事务,两次读取到的数据内容不同(update)
虚读(可以允许):一个事务,两次读取的数据不同(insert)

回顾:硬编码方式

setAutoConmmit(false):取消自动提交
commit():提交事务
rollback():回滚事务    

Spring事务

Spring已经给我们封装好了事务管理,以往我们使用的是硬编码方式,
然而实际开发中很少这么使用,但是为了理解xml和注解方式,还是需要了解

硬编码(api)

1.接口:PlatformTransactionManager:平台事务管理器(封装事务的方法)
—-实现类:DataSourceTransactionManager
dbutils,jdbcTempalte 使用DataSourceTransactionManager
—-实现类:HibernateTransactionManager
hibernate 使用HibernateTransactionManager

2.TransactionDefinition:事务的定义信息对象
      设定/获取:事务的隔离级别(默认获取的就是数据库的隔离级别)

                 事务的超时时间(默认 time = -1  永不超时)

                 事务的是否只读(默认 rederOnly = false 可以做任何的CRUD操作)

                 事务的传播行为(解决:事务嵌套事务的问题)
                    应用场景:A方法中有事务,B方法也有事务
                        问:用谁的事务???
                            REQUIRED(默认值):让所有方法在一个事务中                            
                                a方法调用b方法,b先看看a有没有事务,
                                如果a没有事务,就为a创建一个事务,然后加入a中,
                                如果a有事务,就放弃自己的事务,然后加入a中。
                            SUPPORT:查看当前是否有事务,如果有事务就使用当前的事务,如果没事务就使用非事务。
                                a方法调用b方法,b先看看a有没有事务,
                                如果a有事务,加入到a。
                                如果a没事务,全部放弃事务,使用非事务。

3.TransactionStatus 运行状态对象
    查看事务的运行状态
    查看事务当前是否完成
    查看是否为新的事务
    查看是否回滚.....

Spring声明式事务

配置文件的方式–xml方式
接下来就要使用xml配置的方式来使用事务了

导包

spring-tx.jar
以及AOP联盟
spring-aop.jar
aspectj.jar
spring-aspects.jar

applicationContext.xml的配置如下

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans.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
         http://www.springframework.org/schema/tx
          http://www.springframework.org/schema/tx/spring-tx.xsd">

    <context:property-placeholder location="classpath:jdbc.properties"/>

    <!--c3p0:-->
    <bean id="c3p0" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${jdbc.driver}"></property>
        <property name="jdbcUrl" value="${jdbc.url}"></property>
        <property name="user" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>


    <!--Spring配置jdbcTemplate -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="c3p0"></property>
    </bean>

    <!--配置bean-->
    <bean id="dao" class="test.daoTest">
        <property name="jdbcTemplate" ref="jdbcTemplate"></property>
    </bean>

    <bean id="service" class="test.serviceTest">
        <property name="dao" ref="dao"></property>
    </bean>

    <!--配置事务管理器-->
    <bean id="transaction" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="c3p0"></property>
    </bean>

    <tx:advice transaction-manager="transaction" id="txadvice">
        <tx:attributes>
            <tx:method name="*"/>
        </tx:attributes>
    </tx:advice>

    <!--织入-->
    <aop:config>
        <aop:pointcut id="point" expression="execution(public void test.serviceTest.*(..))"/>
        <aop:advisor advice-ref="txadvice" pointcut-ref="point"/>
    </aop:config>

</beans>

Spring 注解式事务

需要添加

<context:component-scan base-package = “包名”></context:component-scan>

<tx:annotation-driven transaction-manager = “transactionManager”/>
然后在需要代理的方法或类上添加
@Transactional

写在最后的心得体会

以上是我的测试内容及结果,实际上遇到了很多问题
特意记录在此:
首先,java动态代理需要一个被代理类所实现的接口类,
Proxy始终无法摆脱仅支持 interface 代理的桎梏,
因为它的设计注定了这个遗憾。
java 的继承机制注定了这些动态代理类们无法实现对 class 的动态代理,
原因是多继承在 Java 中本质上就行不通。


总结
Spring的事务实际上就是spring 在启动的时候会去解析生成相关的bean,
就是为了在Spring容器中创建一个切面类的对象,
这时候会查看拥有相关注解的类和方法,并且为这些类和方法生成代理,
并根据相关参数进行相关配置注入,这样就在代理中为我们把相关的事务处理掉了(开启正常提交事务,异常回滚事务)
所以我之所以之前产生了很多问题的原因就是因为我对于AOP思想还是似懂非懂,经此一役,希望自己能够融会贯通。