https://www.bilibili.com/video/av47952931
p75-78
几个点:
- JavaEE体系进行分层开发,事务处理位于业务层
- Spring提供事务控制的接口,在spring-tx-5.0.2.RELEASE.jar中
- Spring的事务控制基于AOP。它既可以用配置方式实现,也可以用编程方式实现(重点是配置实现)
Spring中事务控制的API
该接口提供事务操作的方法:
- 获取状态 getTransaction()
- 提交 commit()
- 回滚 rollback()
常用实现类:
- org.springframework.jdbc.datasource.DataSourceTransactionManager
- org.springframework.orm.hibernate5.HibernateTransactionManager
TransactionDefinition
该接口是事务的定义信息对象,可以获取事务对象名称、隔离级别、传播行为、超时时间、是否只读
Spring默认使用数据库的隔离级别
传播行为指什么情况下必须有事务、什么情况可有可无
TransactionStatus
该接口提供事务的运行状态,可以刷新事务、获取是否存在存储点(可以理解为按步提交,回滚可以回滚到当前点,不用全部回滚)、是否完成、是否为新的事务、是否回滚、设置回滚
Spring的事务控制
代码准备
pom.xml中需要导入aspectj的依赖,因为事务控制基于AOP
准备数据库表和实体类(还是账户)
实现三个方法:根据Id查询账户、根据名称查询账户、转账
编写Dao层和业务层接口和实现类
基于XML的声明式事务控制
配置步骤
1、配置事务管理器
2、配置事务的通知
此时需要导入事务的约束(文档首页点Data Access,搜xmlns:tx,同时也会导入AOP的约束)
使用tx:advice标签配置事务通知
属性:id:事务通知的唯一标识 transaction-manager:给事务通知提供一个事务管理器引用
3、配置AOP中的通用切入点表达式
4、建立事务通知和切入点表达式的对应关系
5、配置事务的属性(在事务的通知tx:advice标签的内部)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| <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:config> <aop:pointcut id="pt1" expression="execution(* com.itheima.service.impl.*.*(..))"></aop:pointcut> <aop:advisor advice-ref="txAdvice" pointcut-ref="pt1"></aop:advisor> </aop:config>
|
这样service.impl下的实现类就都配置好事务控制了
基于注解的声明式事务控制
导名称空间时要多一个context,以及对应的约束
业务层
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| @Service("accountService") @Transactional(propagation= Propagation.SUPPORTS,readOnly=true) public class AccountServiceImpl implements IAccountService{
@Autowired private IAccountDao accountDao;
public Account findAccountById(Integer accountId) { return accountDao.findAccountById(accountId);
}
@Transactional(propagation= Propagation.REQUIRED,readOnly=false) public void transfer(String sourceName, String targetName, Float money) { Account source = accountDao.findAccountByName(sourceName); Account target = accountDao.findAccountByName(targetName); source.setMoney(source.getMoney()-money); target.setMoney(target.getMoney()+money); accountDao.updateAccount(source);
int i=1/0;
accountDao.updateAccount(target); } }
|
Dao层
1 2 3 4 5 6 7 8 9
| @Repository("accountDao") public class AccountDaoImpl implements IAccountDao {
@Autowired private JdbcTemplate jdbcTemplate;
}
|
此时不能再继承JdbcDaoSupport了(因为没法给jdbcTemplate加注解),必须自己定义一个jdbcTemplate,并在xml中配置(并注入dataSource,还要配置Spring在创建容器时需要扫描的包)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| <context:component-scan base-package="com.itheima"></context:component-scan>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <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/eesy"></property> <property name="username" value="root"></property> <property name="password" value="1234"></property> </bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean>
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
|
属性在@Transactional中配置
一个问题是,如果有十个事务,一半只读一半读写,就都得单独配置属性
而用xml配置时一次就解决了