Spring事务管理学习笔记
Spring事务管理高层抽象主要包括3个接口
1.platformTransactionManage 事务管理器
2.TransactionDefinition 事务定义信息(隔离、传播、超时、只读)
3.TransactionStatus 事务具体运行状态
1.platformTransactionManage 事务管理器
Spring为不同的持久化框架提供了不同platformTransactionManage接口实现
JDBC及iBATIS、MyBatis框架事务管理器:org.springframework.jdbc.datasource.DataSourceTransactionManager
Jdo事务管理器:org.springframework.orm.jdo.JdoTransactionManager
Jpa事务管理器:org.springframework.orm.jpa.JpaTransactionManager
Hibernate事务管理器:org.springframework.orm.hibernate3.HibernateTransactionManager
2.TransactionDefinition 事务定义信息(隔离、传播、超时、只读)
原子性:事务不可分割
一致性:事务执行的前后,数据完整性保持一致
隔离性:一个事务执行的时候,不应该收到其他事务的干扰
持久性:一旦结束,数据就永久的保存到数据库
脏读:一个事务读取了另一个事务改写但还未提交的数据,如果这些数据被回滚,则读到的数据是无效的。
不可重复读:你读取过的数据,再次读取出来发现值不一样了。
例子:
在事务1中,JoonWhee读取了自己的工资为1000,但是此时事务1的操作还并没有完成 ,后面还有1次相同的读取 操作。
con1 = getConnection();
select salary from employee where employeeName ="JoonWhee";
在事务2中,这时财务人员修改了JoonWhee的工资为2000,并提交了事务。
con2 = getConnection();
update employee set salary = 2000 where employeeName = "JoonWhee";
con2.commit();
在事务1中,JoonWhee再次读取自己的工资时,工资变为了2000 。
select salary from employee where employeeName ="JoonWhee";
幻读:同样的条件,第1次和第2次读出来的记录数不一样。
例子:
目前工资为1000的员工有10人。
事务1,读取所有工资为1000的员工,共读取10条记录 。
con1 = getConnection();
Select * from employee where salary =1000;
这时另一个事务向employee表插入了一条员工记录,工资也为1000
con2 = getConnection();
Insert into employee(employeeName,salary) values("Lili",1000);
con2.commit();
事务1再次读取所有工资为1000的员工,共读取到了11条记录,这就产生了幻读。
select * from employee where salary =1000;
DEFAULT:默认的隔离级别,使用数据库默认的事务隔离级别
READ_COMMITTED:保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。这种事务隔离级别可以避免脏读出现,但是可能会出现不可重复读和幻像读。
READ_UNCOMMITTED:这是事务最低的隔离级别,它充许别外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻像读。
REPEATABLE_READ:这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了避免不可重复读。(mysql默认的事务隔离级别)
SERIALIZABLE:这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。除了防止脏读,不可重复读外,还避免了幻像读。
spring事务的传播行为说的是当一个方法调用另一个方法时,事务该如何操作。
PROPAGATION_MANDATORY:该方法必须运行在一个事务中。如果当前事务不存在则抛出异常。
例子:A,B如果A有事务,B使用A的使用,如果A没有事务,抛出异常
PROPAGATION_NESTED:如果当前存在一个事务,则该方法运行在一个嵌套的事务中。被嵌套的事务可以从当前事务中单独的提交和回滚。如果当前不存在事务,则开始一个新的事务。
PROPAGATION_NEVER:当前方法不应该运行在一个事务中。如果当前存在一个事务,则抛出异常。
PROPAGATION_NOT_SUPPORTED:当前方法不应该运行在一个事务中。如果一个事务正在运行,它将在该方法的运行期间挂起。
例子:A,B非事务运行,A有事务,就挂起当前的事务
PROPAGATION_REQUIRED:该方法必须运行在一个事务中。如果一个事务正在运行,该方法将运行在这个事务中。否则,就开始一个新的事务。
例子:A,B如果A有事务,B使用A的事务,如果A没有事务,B就开启一个新的事务
PROPAGATION_REQUIRES_NEW:该方法必须运行在自己的事务中。它将启动一个新的事务。如果一个现有的事务正在运行,将在这个方法的运行期间挂起。
例子:A,B如果A有事务,B将A的事务挂起,重新创建一个事务
PROPAGATION_SUPPORTS:支持当前事务,如果不存在,就不使用事务
例子:A,B如果A有事务,B使用A的事务,如果A没有事务,B就不适用事务
3.TransactionStatus 事务具体运行状态
TransactionStatus接口中定义了事务的运行状态
public interface TransactionStatus{
boolean isNewTransaction(); // 是否是新的事物
boolean hasSavepoint(); // 是否有恢复点
void setRollbackOnly(); // 设置为只回滚
boolean isRollbackOnly(); // 是否为只回滚
boolean isCompleted; // 是否已完成
}
Spring事务配置文件
<?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:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:util="http://www.springframework.org/schema/util"
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-3.2.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd" >
<!--开启自动扫描-->
<context:component-scan base-package="demo1"/>
<!--配置数据源-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/123"/>
<property name="username" value="root"/>
<property name="password" value="123"/>
</bean>
<!--配置JdbcTemplate-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</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="find*" isolation="DEFAULT" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!--aop配置-->
<aop:config>
<aop:pointcut id="s" expression="execution(* demo1.personService.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="s"/>
</aop:config>
</beans>