spring事务
作者:互联网
事务
什么是事务
事务:事务是逻辑上的一组操作,组成这组操作的各个单元,要么全部成功,要么全都失败。
事务的特性
- 原子性:事务不可分割
- 一致性:事务执行前后数据完整性保持一致
- 隔离性:一个事务的执行不应该受到其他事务的干扰
- 持久性:一旦事务结束,数据就持久化到数据库
如果不考虑隔离性引发的安全性问题
- 读问题
- 赃读:一个事务读到另一个事务未提交的数据
- 不可重复读:一个事务读到另一个事务已经提交的
update
的数据,导致一个事务中多次查询结果不一致。 - 虚读、幻读:一个事务读到另一个事务已经提交的
insert
的数据,导致一个事务中多次查询的结果不一致。
- 写问题
- 丢失更新
解决读问题
可以通过设置事务的隔离级别来解决读的问题
- 事务的隔离级别
read uncommitted:
未提交读,任何读问题都解决不了read committed
:已提交读,解决赃读,但是不可重复读和虚读有可能发生repeatable read
:重复读,解决赃读和不可重复读,但是虚读有可能发生serializable
:解决所有读问题
spring事务管理的主要api
PlatformTransactionManager:平台事务管理器
平台事务管理器,这是一个接口,是spring用于管理事务的真正的对象
DataSourceTransactionManager
:底层使用jdbc
管理事务HibernateTransactionManager
:底层使用Hibernate管理事务
TransactionDefinition:事务定义信息
事务定义,用于定义事务的相关的信息,隔离级别、超时信息、传播行为、是否只读
TransactionStatus:事务的状态
事务状态,用于记录在事务管理过程中,事务的状态的对象
事务管理的api的关系
spring在进行事务管理的时候,首先平台事务管理器根据事务定义信息进行事务的管理,
在事务管理过程中,产生各种状态,将这些状态的信息记录到事务状态的对象中。
spring的事务的传播行为
什么是事务的传播行为
我们知道事务是建立在service
层的,一个service
里面可能调用多个dao
层的方法,但是也有可能一个service
去调用另外一个service里面的方法,当一个service
去调用另外一个service
的时候就是事务之间的关系就叫做事务的传播行为,因为每一个service
里面可能都有自己的事务。
spring中提供了七种事务的传播行为
这七种事务的传播行为主要是有三类,下面讲解的时候假设有两个service
,这两个service
中各有一个方法,分别是A
和B
。并且在B
方法中调用了A
方法。
保证多个操作在同一个事务中
PROPAGATION_REQUIRED
: 这是默认值,表示的是如果A中有事务,使用A
中的事务,如果A
没有事务,创建一个新的事务,将操作包含进来,也就是说无论怎么样A
中的方法和B
中的方法总是在同一个事务当中。PROPAGATION_SUPPORT
: 支持事务,如果A中有事务,使用A中的事务,如果A
中没有事务,不使用事务。PROPAGATION_MANDATORY
: 如果A中有事务,使用A
中的事务,如果A
中没有事务,抛出异常。
保证多个操作不在同一个事务中
PROPAGATION_REQUIRED_NEW
:如果A中有事务,将A的事务挂起,创建新的事务,只包含自身操作(也就是只包含B
里面的方法的一些操作),如果A中没有事务,创建一个新事务,只包含自身操作。PROPAGATION_NOT_SUPPORT
: 如果A
中有事务,将A
的事务挂起,不适用事务管理。PROPAGATION_NEVER
:如果A
中有事务,报异常。
嵌套式事务
PROPAGATION_NESTED
:嵌套事务,如果A
中有事务,按照A
的事务执行,执行完成后,设置一个保存点,执行B
中的操作,如果没有异常,执行通过。如果有异常,可以选择回滚到最初始的位置,也可以回滚到保存点。
spring的事务管理
下面的案例是转账案例
service
的实现类
public class AccountServiceImpl implements AccountService{
//注入DAO
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao){
this.accountDao = accountDao;
}
/**
* from 转出账号
* to 转入账号
* money 转账金额
*/
public void transfer(String from, String to, Double money){
accountDao.outMonty(from, money);
accountDao.inMoney(to, money);
}
}
dao的实现类
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao{
public void outMoney(String from, Double money){
this.getJdbcTemplate().update("update account set money = money - ? where name = ?", money, from);
}
public void inMoney(String to, Double money){
this.getJdbcTemplate().update("update account set money = money + ? where name = ?", money, to);
}
}
配置service和dao交给spring管理
<bean id="accountService" class="xxxxxxxxx.AccountServiceImpl"></bean>
<bean id="accountDao" class="xxxxxx.AccountDaoImpl"></bean>
配置连接池和JDBC的模板
<!--配置连接池和JDBC的模板-->
<!--第二种方式通过context标签引入的-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--配置C3Pe连接池-->
<bean id="dataSource"class="com.mchange.v2.c3pe.ComboPooledDatasource">
<property name="driverClass"value="${jdbc.driverclass}"/>
<property name="jdbcUrl"value="s{jdbc.url}"/>
<property name="user"value="${jdbc.username}"/>
<property name="password"value="${jdbc.password}"/>
</bean>
在上面的dao
实现类中看到了继承了JdbcDaoSupport
这个类,这样我们就可以不用在dao
从创建jdbc
模板了,因为这个类中已经有了,只有dao
继承了这个类然后在配置文件中直接注入这个属性即可。
<!--配置DAO-->
<bean id="accountDao"class="com.itheima.tx.demo1.AccountDaoImpl">
<property name="dataSource" ref="dataSource"/>
</bean>
第一种spring的事务管理方式,编程式
所谓的编程式事务也就是需要自己去手动编写代码
-
第一步是配置平台事务管理器,不论使用哪种方式来实现spring的事务这一步都是需要的。
<!--配盟平台事务管理器--> <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
-
在业务层注入事务管理的模板
<!--配置Service --> <bean id="accountService"class="xxxxxx.AccountServiceImpl"> <property name="accountDao" ref="accountDao"/> <!--注入事务管理的模板--> <property name="trsactionTemplate"ref="transactionTemplate"/>| </bean>
-
编写事务管理的代码
public void transfer(final String from, final String to, final Double money){ trsactionTemplate.execute(new TransactioncallbackwithoutResult(){ @Override protected void doInTransactionwithoutResult(TransactionStatus transactionstatus){ accountDao.outMoney(from, money); intd=1/e; accountDao.inMoney(to, money); }); }
第二种spring事务管理,声明式事务(通过配置实现)
首先需要引入aop
的开发环境的包,因为这种方式本质上时通过aop
来实现的。
-
配置事务管理器
<!--配置事务管理器--> <bean id="transactionManager"class="org.springframework.jdbc.datasource.DataSource TransactionManager"> <property name="dataSource"ref="dataSource"/> </bean>
-
配置增强规则
<!--配置事务的增强--> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <!--事务管理的规则--> <!--<tx:method name="save*"propagation="REQUIRED"isolation="DEFAULT"/> <tx:method name="update*"propagation="REQUIRED"/> <tx:method name="delete*"propagation="REQUIRED"/> <tx:method name="find*"read-only="true"/> --> <tx:method name="*" propagation="REQUIRED"/> </tx:attributes> </tx:advice>
-
配置aop
<!--aop的配置--> <aop:config> <aop:pointcut expression="execution(*com.itheima.tx.demo2.AccountServiceImpl.*(.…))"id="pointcut1"/> <aop:advisor advice-ref="txAdvice"pointcut-ref="pointcut1"/> </aop:config>
第二种spring事务管理,声明式事务(通过注解实现)
同样的需要使用aop开发环境的jar包
-
配置事务管理器
<!--配置事务管理器--> <bean id="transactionManager"class="org.springframework.jdbc.datasource.DataSource TransactionManager"> <property name="dataSource"ref="dataSource"/> </bean>
-
开启注解事务
<!--开启注解事务--> <tx:annotation-driven transaction-manager="transactionManager"/>
-
在业务层添加注解
@Transactional
即可@Transactional public class AccountServiceImpl implements AccountService{ xxxxxx }
标签:事务管理,事务,accountDao,service,spring,money 来源: https://blog.csdn.net/weixin_44600908/article/details/96366006