Spring对事务并发的处理
1、并发问题详解
1.1并发问题
问题1:脏读
A事务读到B事务没有提交的数据,如果恰好B做事务回滚。那么A读到的数据就是错误的,也就是脏读
问题2:不可重复读
指的是A事务读取了B事务已经提交了的更改数据。假设A取款的过程中向B账户汇款{B事务数据发生改变,且已经提交},A再做读取,那么A事务两次读取的事务不一致,这就是不可重复读,也就是A在它自己事务提交之前不能两次读取B事务里的数据
问题3:幻读
A事务读取B事务新增的数据,假设银行在一个事务中做统计,在统计过程中B新增了用户,A的事务中两次统计不同,这就是幻读{幻读和不可重复读很类似,唯一的区别是幻读两个事务都没有做提交而不可重复读是A事务没有提交B事务做了提交}
问题4:第一类丢失更新(回滚丢失,Lost update)
A事务撤销时,把已经提交的B事务的更新数据覆盖了。这种错误可能造成很严重的问题,
问题5:第二类丢失更新(覆盖丢失/两次更新问题,Second lost update)
A事务覆盖B事务已经提交的数据,造成B事务所做操作丢失:
第二类丢失更新,实际上和不可重复读是同一种问题。
2、并发问题的处理(Spring事物隔离级别)
隔离级别由低到高序列化读是隔离级别最高的可以防止所有事务并发造成的问题。
并不是隔离级别越高越好,隔离级别越高,并发性就越差,性能就越低
Orgle的默认隔离级别是可提交读
Mysql的默认隔离级别是可重复读
3、用配置文件形式管理事务
<?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:contex="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-3.2.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">
<!--配置数据源-->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<!--配置四个基本属性-->
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/spring_study?characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
<!--初始化连接数-->
<property name="initialSize" value="1"/>
<!--连接池的最大连接数-->
<property name="maxActive" value="8"/>
<!--连接池最大空闲连接数(最多闲着的(澡堂子洗澡师傅不能都闲着不然谁干活))-->
<property name="maxIdle" value="5"/>
<!--最小的空闲连接数(不能都忙不然顾客来了没人干活))-->
<property name="minIdle" value="3"/>
<!--最大等待时间-->
<property name="maxWait" value="-1"/>
</bean>
<!--用配置文件的方式对dataSource进行注入 dao依赖于datasorce-->
<bean id="orderDao" class="dao.daoImple.OrderDaoImple">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="detailDao" class="dao.daoImple.DetailDaoImple">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--用配置文件方式对userDao进行注入 service依赖dao-->
<bean id="orderService" class="service.serviceImple.SaveOrderAndDetailImple">
<property name="orderDao" ref="orderDao"/>
<property name="detailDao" ref="detailDao"/>
</bean>
<!--配置事务管理器-->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--开启事务通知的注解驱动 把事务管理器引过来(事务管理器的主键驱动)-->
<tx:annotation-driven transaction-manager="txManager"/>
<!--定义通知-->
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="save*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="NOT_SUPPORTED"/>
<tx:method name="query*" read-only="true"/>
</tx:attributes>
</tx:advice>
<!--定义切面-->
<aop:config>
<!--切点配置-->
<aop:pointcut id="myCut" expression="execution(* service..*.*(..))"/>
<!--引入通知和切点-->
<aop:advisor advice-ref="txAdvice" pointcut-ref="myCut"/>
</aop:config>
</beans>