声明式事务和编程式事务
* 编程式事务使用TransactionTemplate ,是硬编码
*声明式事务是基于AOP。对指定方法前后进行拦截,在目标方法开始之前创建或加入一个事务,在执行完目标方法之后根据执行结果提交或者回滚事务。
1 基于TransactionProxyFactoryBean
xml配置文件
<!--导入外部文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--连接池配置-->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driverClass}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!--业务层类-->
<bean id="accountService" class="com.spring.transaction.demo2.AccountServiceImpl">
<property name="accountDao" ref="accountDao"/>
</bean>
<bean id="accountDao" class="com.spring.transaction.demo2.AccountDaoImpl">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--配置事务管理器-->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--配置业务层代理-->
<bean id="accountServiceProxy"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<!--配置目标对象-->
<property name="target" ref="accountService"/>
<!--注入事务管理器-->
<property name="transactionManager" ref="transactionManager"/>
<!--注入事务属性-->
<property name="transactionAttributes">
<props>
<!--prop格式
* PROPAGATION 传播行为
* ISOLATION 事务隔离级别
* readOnly 只读
* -Exception 发生那些异常回滚
* +Exception 发生那些异常不回滚
-->
<prop key="transfer">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
<!--声明式事务管理 基于TransactionProxyFactoryBean-->
注:在注入Service时需要注入代理类
//注入代理类
//@Resource(name = "accountService")
@Resource(name = "accountServiceProxy")
private AccountService accountService;
2基于AspectJ
<!--导入外部文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--连接池配置-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driverClass}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!--业务层类-->
<bean id="accountService" class="com.spring.transaction.demo4.AccountServiceImpl">
<property name="accountDao" ref="accountDao"/>
</bean>
<!--配置DAo-->
<bean id="accountDao" class="com.spring.transaction.demo4.AccountDaoImpl">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--配置事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--配置事务通知-->
<tx:advice id="txAdvice" transaction-manager ="transactionManager">
<!--<tx:attributes>-->
<!--<tx:method name="transfer"/>-->
<!--</tx:attributes>-->
<tx:attributes>
<tx:method name="*" />
</tx:attributes>
</tx:advice>
<!--配置切面-->
<aop:config>
<!--配置切入点 匹配demo3包下Service类-->
<aop:pointcut id="pointcut1" expression="execution(*
com.spring.transaction.demo3.*Service*.*(..))"/>
<!--配置切面-->
<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1"/>
</aop:config>
3基于@Transactional注解
配置好后只需要在指定的类或者方法上贴@Transactional注解(对public以外的方法是不会起作用的),在用Aop切入方法时,方法的类型要设置成public共有类型才会有效!
<!--导入外部文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--连接池配置-->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driverClass}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!--业务层类-->
<bean id="accountService" class="com.spring.transaction.demo4.AccountServiceImpl">
<property name="accountDao" ref="accountDao"/>
</bean>
<!--配置Dao-->
<bean id="accountDao" class="com.spring.transaction.demo4.AccountDaoImpl">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--配置事务管理器-->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--开启注解事务-->
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
事务隔离级别
为了解决并发时产生的 脏读,不可重复读,幻读 产生的。
脏读:事务A读到了事务B还没有提交的数据(事务B修改了数据,此时A读了该数据,B因发生异常回滚,A就读到了脏数据)
不可重复读:在一个事务里面读取了两次某个数据,读出来的数据不一致(A开启事务第一次读到数据后,事务B修改并提交了数据,此时切换回事务A又一次读取该数据,两次数据读取不一致,这就形成了不可重复读)
幻读:在一个事务中两次查询返回的记录数不一致(A事务第一次查询了N条记录,此时B事务又添加了新的记录或删除记录,当事务A再次读取时发现和之前读取的记录数不一致)
隔离级别由低到高(Spring 通过 ISOLATION 属性配置)
1 DEFAULT 数据库默认级别 mysql 默认 REPEATABLE_READ oracle默认 READ_COMMITED
2 READ_UNCOMMITTED 可以读取未提交的数据 会导致 脏读,不可重复读,幻读
3 READ_COMMITED 可以读取已提交的数据 可以解决脏读
4 REPEATABLE_READ 第一次读取时对该数据加锁在当前事务结束前防止其他事物修改,可解决脏读,不可重复读
5 SERLALIZABLE 不管多少事物,只能挨个完成(很少使用)
事务传播行为
通过PROPAGATION属性配置