Spring基础学习8——Spring事务处理
事物特性
原子性:事务不可分割
一致性:事务执行前后数据完整性保持一致
隔离性:一个事务的执行不受其他事务的干扰
持久性:一旦事务结束,数据就持久化到数据库
事务的安全性问题
-
读问题:
-
脏读:一个事务读到另一个事务未提交的数据
-
不可重复读:一个事务读到另外一个事务已经提交的update数据,导致一个事务中多次查询结果不一致
-
虚读、幻读:一个事务读到另外一个事务已经提交的insert数据,导致一个事务中多次查询结果不一致
-
-
些问题
-
丢失更新
-
解决读写问题
-
事务的隔离级别
-
Read uncommitted:未提交读、任何读问题解决不了。
-
Read committed:已提交读,解决脏读,但是不可重复读和虚读有可能发生
-
Repeatable read:重复读,解决脏读和不可重复读,但是虚读有可能发生
-
serializable:解决所有问题
-
Spring事务管理API
平台事务管理器:PlatformTransactionManager
底层使用jdbc事务管理用:DataSourceTransactionManager
底层用Hibernate事务管理用:HibernateTransactionManager
事务定义信息:TransactionDefinition
事务状态:TransactionStatus
事务管理的API关系
Spring进行事务管理时:首先平台事务管理器根据事务定义信息进行事务的管理,在事务管理过程中,产生各种状态,将这些状态的信息记录到事务状态的对象中
Spring事务传播行为:
对象B调用对象A:
-
保证多个操作在同一个事务中:
-
PROPAGATION_REQUIRED:(默认值)如果A中有事务,则使用A中的事务,如果A中没有,则会创建一个新事务,将操作进行包裹。
-
PROPAGATION_SUPPORTS:如果A中有事务,则使用A中的事务,如果A中没有,不使用事务
-
PROPAGATION_MANDATORY:如果A中有事务,则使用A中的事务,如果A中没有,爆出异常
-
-
保证多个操作不在统一事务中:
-
PROPAGATION_REQUIRES_NEW:如果A中有事务,将A的事务挂起,创新新的事务,只包含自身的操作,如果A中没有,创新新的事务,只包含自身的操作
-
PROPAGATION_NOT_SUPPORTED:如果A中有事务,将A的事务挂起,不使用事务
-
PROPAGATION_NEVER:如果A中有事务,则报异常
-
-
嵌套式事务:
-
PROPAGATION_NESTED: 如果A中有事务,按照A的事务执行,执行完成后,设置一个保存点,执行B中的操作,如果没有异常执行通过,有异常则可以选择回滚到初始位置也可回滚到保存点
-
Spring事务案例:
基础业务流程:转款
// 数据库操作接口及其实现类
public interface AccountDao {
public void outMoney(String from ,Double money);
public void inMoney(String to,Double money);
}
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {
@Override
public void outMoney(String from, Double money) {
this.getJdbcTemplate().update("update account set money = money - ? where name =?",money,from);
}
@Override
public void inMoney(String to, Double money) {
this.getJdbcTemplate().update("update account set money = money + ? where name =?",money,to );
}
}
// 服务接口及其实现类
public interface AccountService {
public void tranfer(String formid, String to,Double money);
}
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao){
this.accountDao = accountDao;
}
@Override
public void tranfer(String from, String to, Double money) {
accountDao.outMoney(from,money);
accountDao.inMoney(to,money);
}
}
// 用于用户调用的服务
<bean id="accountService" class="com.hhh.spring.demo.inter.AccountServiceImpl">
<property name="accountDao" ref="accountDao"/>
</bean>
// 操作数据库对象
<bean id="accountDao" class="com.hhh.spring.demo.inter.AccountDaoImpl">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 通过context标签引入配置文件-->
<context:property-placeholder location="classpath:jdbcConfigurer.properties"/>
<!-- 设置才c3p0数据库配置-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driverClass}"></property>
<property name="jdbcUrl" value="jdbc:mysql://127.0.0.1:3306/homework"/>
<property name="user" value="root"/>
<property name="password" value="123456"/>
</bean>
加入事务管理的转款
// 数据库操作接口及其实现类不变
// 服务接口及其实现类,
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao){
this.accountDao = accountDao;
}
// 在服务中加入平台事务管理模板
private TransactionTemplate transactionTemplate;
public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
this.transactionTemplate = transactionTemplate;
}
@Override
public void tranfer(String from, String to, Double money) {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
accountDao.outMoney(from,money);
accountDao.inMoney(to,money);
}
});
}
}
// 用于用户调用的服务
<bean id="accountService" class="com.hhh.spring.demo.inter.AccountServiceImpl">
<property name="accountDao" ref="accountDao"/>
<!--注入事务管理的模板-->
<property name="transactionTemplate" ref="transactionTemplate"/>
</bean>
<bean id="accountDao" class="com.hhh.spring.demo.inter.AccountDaoImpl">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--配置平台事务管理器-->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--配置事务管理的模板-->
<bean id="transactionTemplate"
class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="transactionManager"/>
</bean>
<!-- 通过context标签引入-->
<context:property-placeholder location="classpath:jdbcConfigurer.properties"/>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driverClass}"></property>
<property name="jdbcUrl" value="jdbc:mysql://127.0.0.1:3306/homework"/>
<property name="user" value="root"/>
<property name="password" value="123456"/>
</bean>
xml方式声明事务管理,配置事务管理aop增强
// 服务实现类,
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
@Override
public void tranfer(String from, String to, Double money) {
accountDao.outMoney(from, money);
int a = 1/0;
accountDao.inMoney(to, money);
}
}
<!--配置平台事务管理器-->
<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="*" propagation="REQUIRED" isolation="DEFAULT" timeout="-1"/>
<tx:method name="find" read-only="true"/>
</tx:attributes>
</tx:advice>
<!--aop的增强-->
<aop:config>
<aop:pointcut id="pointcut" expression="execution(* com.hhh.spring.demo.inter.AccountServiceImpl.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"/>
</aop:config>
这里的"配置事务的增强" 配置的是方法的事务规则name:适用的方法(*
为任意方法) isolation配置的是隔离规则,read-only:只读选项,timeout:读取超时(-1
一直有效)。
"aop增强"配置的的具体的切点和切面
通过注解的方式加入事务管理
// 使用注解,为服务中的每个方法都设置事务规则
@Transactional(isolation = Isolation.DEFAULT,propagation = Propagation.REQUIRED)
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
@Override
public void tranfer(String from, String to, Double money) {
accountDao.outMoney(from, money);
int a = 1/0;
accountDao.inMoney(to, money);
}
}
<!--配置平台事务管理器-->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--开启注解事务-->
<tx:annotation-driven transaction-manager="transactionManager"/>
上面三个方法的共性是都必须有:
<!--配置平台事务管理器-->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>