目录
事务:逻辑上的一组操作,组成这组操作的各个单元,要么全都成功,要么全都失败。
PlatformTransactionManager:平台事务管理器
事务:逻辑上的一组操作,组成这组操作的各个单元,要么全都成功,要么全都失败。
特性:
- 原子性:事务是不可分割的
- 一致性:事务执行前后,数据的完整性保持一致
- 隔离性:一个事务不应该受到其他事务的干扰
- 持久性:事务结束,数据就持久化保存在数据库里
如果不考虑隔离性引发安全性问题
- 读问题
- 脏读 :一个事务读到另一个事务未提交的数据
- 不可重复读 :一个事务读到另一个事务已经提交的update的数据,导致一个事务中多次查询结果不一致
- 虚读、幻读 :一个事务读到另一个事务已经提交的insert的数据,导致一个事务中多次查询结果不一致。
- 写问题
- 丢失更新
解决读问题
- 设置事务的隔离级别(isolation)
- Read uncommitted :未提交读,任何读问题解决不了。(效率最高)
- Read committed :已提交读,解决脏读,但是不可重复读和虚读有可能发生。
- Repeatable read :重复读,解决脏读和不可重复读,但是虚读有可能发生。
- Serializable :解决所有读问题。(效率最低)
Spring的事务管理的API
PlatformTransactionManager:平台事务管理器
- 平台事务管理器:接口,是Spring用于管理事务的真正的对象。
- DataSourceTransactionManager :底层使用JDBC管理事务
- HibernateTransactionManager :底层使用Hibernate管理事务
TransactionDefinition :事务定义信息
- 事务定义:用于定义事务的相关的信息,隔离级别、超时信息、传播行为、是否只读
TransactionStatus:事务的状态
- 事务状态:用于记录在事务管理过程中,事务的状态的对象。
事务管理的API的关系:
Spring进行事务管理的时候,首先平台事务管理器根据事务定义信息进行事务的管理,在事务管理过程中,产生各种状态,将这些状态的信息记录到事务状态的对象中。
Spring的事务的传播行为
Spring中提供了七种事务的传播行为:
- 保证多个操作在同一个事务中
PROPAGATION_REQUIRED
:默认值,如果A中有事务,使用A中的事务,如果A没有,创建一个新的事务,将操作包含进来
PROPAGATION_SUPPORTS
:支持事务,如果A中有事务,使用A中的事务。如果A没有事务,不使用事务。
PROPAGATION_MANDATORY
:如果A中有事务,使用A中的事务。如果A没有事务,抛出异常。
- 保证多个操作不在同一个事务中
PROPAGATION_NEVER
:如果A中有事务,报异常。
PROPAGATION_NOT_SUPPORTED
:如果A中有事务,将A的事务挂起。不使用事务管理。
PROPAGATION_REQUIRES_NEW
:如果A中有事务,将A的事务挂起(暂停),创建新事务,只包含自身操作。如果A中没有事务,创建一个新事务,包含自身操作。
- 嵌套式事务
PROPAGATION_NESTED
:嵌套事务,如果A中有事务,按照A的事务执行,执行完成后,设置一个保存点,执行B中的操作,如果没有异常,执行通过,如果有异常,可以选择回滚到最初始位置,也可以回滚到保存点。
搭建Spring的事务管理的环境
- 创建Service的接口和实现类
/**
* from 转出账户
* to 转入账户
* money 多少钱
*/
public class AccountServiceimpl implements AccountService {
想用dao的方法,把属性注入进来
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
@Override
public void zhuan(String from,String to, Double money) {
/**
* 调用dao的方法
*/
accountDao.outmoney(from,money);
accountDao.inmoney(to,money);
}
}
2 . 创建DAO的接口和实现类
public class AccountDaoimpl implements AccountDao {
@Override
public void outmoney(String from, double money) {
}
@Override
public void inmoney(String to, double money) {
}
3. 配置Service和DAO:交给Spring管理
配置业务层的类
<bean id="acountservice" class="com.tx.demo.AccountServiceimpl">
配置DAO层的对象,要使用dao层的对象,这里是使用set方法注入属性
<property name="accountDao" ref="accountdao"/>
</bean>
配置DAO层的类
<bean id="accountdao" class="com.tx.demo.AccountDaoimpl">
</bean>
4.在DAO中编写扣钱和加钱的方法
Dao的实现类继承了JdbcDaoSupport
- 不用把jdbc模板属性注入进来
- 或者不用配置jdbc模板,直接把连接池交给DAO的实现类,让JdbcDaoSupport底层创建,直接调用
<!--配置DAO层的类--> <bean id="accountdao" class="com.tx.demo.AccountDaoimpl"> <!--配置了jdbc模板,使用jdbc模板--> <!--<property name="jdbcTemplate" ref="jdbcTemplate"/>--> <!--不用配置jdbc模板,把连接池交给JdbcDaoSupport类,让他来创建--> <property name="dataSource" ref="datasource"/> </bean>
public class AccountDaoimpl extends JdbcDaoSupport implements AccountDao {
/* private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}*/
/**
* 继承了JdbcDaoSupport
* @ 1 . 这里就可以直接使用jdbcTemplate对象,
* 不用在把属性注入进来
* @ 2 . 也可以直接把连接池配给他,他有一种方法是直接创建一个模板
*/
@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);
}
}
配置连接池和JDBC的模板
引入属性文件
<context:property-placeholder location="classpath:jdbc.properties"/>
配置连接池
<bean id="datasource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driverclass}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
配置jdbc模板
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="datasource"/>
</bean>
使用JDBC模板
配置业务层的类
<bean id="acountservice" class="com.tx.demo.AccountServiceimpl">
配置DAO层的对象,要使用dao层的对象,这里是使用set方法注入属性
<property name="accountDao" ref="accountdao"/>
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
配置DAO层的类
<bean id="accountdao" class="com.tx.demo.AccountDaoimpl">
</bean>
声明式事务的两种方式
XML方式的声明式事务
配置事务管理器
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
连上连接池
<property name="dataSource" ref="datasource"/>
</bean>
配置事物的增强
<tx:advice id="txadvice" transaction-manager="transactionManager">
<tx:attributes>
事务管理,应该作用于哪个方法 isolation隔离级别 propagation传播行为
<tx:method name="*" isolation="DEFAULT" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
aop设置,将事务切面到哪个目标类
<aop:config>
<!--目标类-->
<aop:pointcut id="pointcut1" expression="execution(* com.tx.demo.AccountServiceimpl.zhuan(..))"/>
<!--切面类-->
<aop:advisor advice-ref="txadvice" pointcut-ref="pointcut1"/>
</aop:config>
注解方式的声明式事务
1.注解声明式事务管理
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="datasource"/>
</bean>
2.开启注解事务
<tx:annotation-driven transaction-manager="transactionManager"/>
3.在业务层添加注解
//添加事务注解 @Transactional public class AccountServiceimpl implements AccountService {}