文章目录
一、PlateformTransactionManager
1.源码分析
首先让我们来看一下PlateformTransactionManager接口源码
public interface PlatformTransactionManager {
TransactionStatus getTransaction(@Nullable TransactionDefinition var1) throws TransactionException;
void commit(TransactionStatus var1) throws TransactionException;
void rollback(TransactionStatus var1) throws TransactionException;
}
该接口里一共有三个方法,分别是获取事务状态信息、提交和回滚。在Spring中,数据库事务是通过PlateformTransactionManager进行管理的。当事务产生异常,在默认的实现中所有异常都会产生回滚(可以通过修改配置项达到某些异常不回滚或不回滚事务);当无异常时,事务正常提交。
2.DataSourceTransactionManager实现类
public class DataSourceTransactionManager extends AbstractPlatformTransactionManager
implements ResourceTransactionManager, InitializingBean {
@Nullable
private DataSource dataSource;
private boolean enforceReadOnly = false;
public abstract class AbstractPlatformTransactionManager implements PlatformTransactionManager, Serializable
作为实际参与管理对象的事务管理器,DataSourceTransactionManager继承了抽象事务管理器AbstractPlatformTransactionManager,而AbstractPlatformTransactionManager又实现了PlateformTransactionManager。因此在Spring中就可以使用PlateformTransactionManager接口的方法。
二、配置事务管理器和声明式事务
1.声明式事务
声明式事务是一种约定型事务,为保证数据库数据一致性,Spring给了一个约定,当业务不发生异常时(或发生异常,但该异常被配置信息允许提交事务),Spring会让事务管理器自动提交事务,发生异常时则让事务管理器回滚事务(或该异常不被配置信息允许提交)
2.编程式事务
非主流,不建议使用。
3.使用xml配置事务管理器
<?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: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.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--配置accountService-->
<bean id="accountService" class="com.lry.service.AccountServiceImpl">
<property name="accountDao" ref="accountDao"></property>
</bean>
<!--配置accountDao-->
<bean id="accountDao" class="com.lry.dao.AccountDaoImpl">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--配置数据源-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/spring?characterEncoding=utf-8"></property>
<property name="username" value="root"></property>
<property name="password" value="123456"></property>
</bean>
<!--配置事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入数据源-->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--配置事务通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--配置事务属性-->
<tx:attributes>
<tx:method name="*" propagation="REQUIRED" read-only="false"/><!--全通配,优先级低-->
<tx:method name="find*" propagation="SUPPORTS" read-only="true"></tx:method><!--部分选定,此处为所有查询方法,优先级高-->
</tx:attributes>
</tx:advice>
<!--配置AOP-->
<aop:config>
<!--配置切入点表达式-->
<aop:pointcut id="pt1" expression="execution(* com.lry.service.AccountServiceImpl.*(..))"/>
<!--建立切入点表达式和事务通知的对应关系,告知Spring哪些类需要用事务拦截器进行拦截-->
<aop:advisor advice-ref="transactiguaonInterceptor" pointcut-ref="pt1"></aop:advisor>
</aop:config>
</beans>
事务属性详解
isolation:隔离级别,默认值取数据库数据库默认隔离级别
propagation:传播行为,默认值为REQUIRED,表示一定会有事务
timeout:超时时间,默认值为-1,永不超时
readOnly:开启只读,默认false
rollback-for:用于指定一个异常,当执行产生该异常时,事务回滚。产生其他异常,事务不回滚。 没有默认值,任何异常都回滚。
no-rollback-for:用于指定一个异常,当产生该异常时,事务不回滚,产生其他异常时,事务回 滚。没有默认值,任何异常都回滚。
4.使用纯注解配置事务管理器
创建配置类
添加事务驱动管理器注解
@Configuration
@ComponentScan("com.lry")
@Import({JdbcConfig.class, TransactionConfig.class})
@PropertySource("JdbcConfig.properties")
//使用事务驱动管理器
@EnableTransactionManagement
public class SpringConfiguration {
}
实现接口方法,使得返回数据库事务管理器
此处使用DataSourceTransactionManager去定义数据库事务管理器的实例,并把数据源设置给它
public class TransactionConfig {
@Bean("transactionManager")
public PlatformTransactionManager createTransactionManager(DataSource dataSource){
return new DataSourceTransactionManager(dataSource);
}
}
使用@Transactional注解配置类和类方法
@Service("accountService")
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)//将类下所有方法设为查询只读
public class AccountServiceImpl implements IAccountService{
@Autowired
private IAccountDao accountDao;
public Account findById(int id) {
return accountDao.findById(id);
}
public void updateAccount(Account account) {
accountDao.updateAccount(account);
}
@Transactional(propagation = Propagation.REQUIRED, readOnly = false)//将该方法设置为读写
public void transfer(int sourceAid, int targetAid, float money) {
System.out.println("执行转账操作");
//根据ID查询转出用户名
Account source=accountDao.findById(sourceAid);
//根据ID查询转入用户名
Account target=accountDao.findById(targetAid);
//转出账户减钱
source.setMoney(source.getMoney()-money);
//转入账户加钱
target.setMoney(target.getMoney()+money);
//更新转出账户
accountDao.updateAccount(source);
// int i=3/0;//插入报错语句
//更新转入账户
accountDao.updateAccount(target);
}
}
注意:使用注解@EnableTransactionManagement后,在Spring上下文中使用事务注解@Transactional,Spring就知道采用这个数据库事务管理器管理事务了
5声明式事务约定流程
无论是@Transactional注解还是XML配置,在Spring Ioc容器初始化时,Spring会读入这个注解或者XML配置的事务信息,并保存到一个事务定义类里面以备将来使用(TransactionDefinition接口的子类)。运行时,Spring会拦截注解标注的某一个方法或者类的所有方法。