一、什么是事物?
-
事物就是把一系列的动作当做一个独立的工作单元,这些动作要么全部完成,要么完成不了
-
特点:原子性,隔离性,持久性,一致性
-
分类:
编程式事务管理
- 将事务管理代码嵌到业务方法中来控制事务的提交和回滚
- 缺点:必须在每个事务操作业务逻辑中包含额外的事务管理代码
声明式事务管理
-
将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。
-
通过Spring AOP框架声明式事务管理
二、实现(一)
-
任务描述:模拟银行转账的程序,要求在转账时通过Spring对事务进行控制
-
数据库:
create DATABASE if not exists db_spring charset utf8 collate utf8_general_ci; use db_spring; #创建客户信息表 create table if not exists customer( id int(10) not null PRIMARY KEY AUTO_INCREMENT comment'id', username VARCHAR(50) not null comment'username', balance decimal not null comment'金额' )engine=innodb default CHARSET=utf8; #插入客户 insert into customer values (null,'韩庚',100), (null,'韩红',990), (null,'韩畅',550)
-
转账接口类
public interface AccountDao { /** * 转账方法 * @param outUser 转账人 * @param inUser 收款人 * @param money 金额 */ public void transfer(String outUser, String inUser, Double money); }
-
转账实现类
public class AccountDaoImpl implements AccountDao { //引用jdbcTemplate private JdbcTemplate jdbcTemplate; //setter方法 public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } @Override public void transfer(String outUser, String inUser, Double money) { // TODO Auto-generated method stub // 收款人 jdbcTemplate.update("update customer set balance=balance+ ? where username=?", money, inUser); // 转账人 jdbcTemplate.update("update customer set balance=balance-? where username=?", money, outUser); } }
JdbcTemplate是Spring对JDBC的封装,目的是使JDBC更加易于使用,我们只需要提供SQL语句和提取结果
-
配置文件
<!-- 配置数据库文件 --> <context:property-placeholder location="db.properties" /> <!--配置数据库连接池 --> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="${jdbc.driver}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </bean> <!-- 配置jdbcTemplate模板 --> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 注册实现类bean --> <bean id="accountDao" class="com.ruanyuan.dao.impl.AccountDaoImpl"> <!-- 将jdbcTmplate注入 --> <property name="jdbcTemplate" ref="jdbcTemplate"></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" isolation="DEFAULT" read-only="false" /> </tx:attributes> </tx:advice> <!-- 配置aop --> <aop:config> <aop:pointcut expression="execution(* com.ruanyuan.dao.*.*(..))" id="point" /> <aop:advisor advice-ref="txAdvice" pointcut-ref="point" /> </aop:config> </beans>
-
测试类
public class TxTest { @Test public void test3() { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); // 获取AccountDao实例 AccountDao accountDao = (AccountDao) context.getBean("accountDao"); accountDao.transfer("韩庚","韩红",100.0); System.out.println("success"); } }
三、实现(二):注解
-
接口类
public interface AccountService { /** * 转账方法 * @param inUser 收款 * @param outUser 转账 * @param money 金额 */ public void transfer(String inUser, String outUser, Double money); }
-
实现类
@Service("ax") public class AccountServiceImpl implements AccountService { @Resource(name = "jdbcTemplate") //匹配配置文件中jdbcTmpalte private JdbcTemplate jdbcTemplate; public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } //实现事物 @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, readOnly = false) public void transfer(String inUser, String outUser, Double money) { // TODO Auto-generated method stub // 收款人 jdbcTemplate.update("update customer set balance=balance+ ? where username=?", money, inUser); // 转账人 jdbcTemplate.update("update customer set balance=balance-? where username=?", money, outUser); } }
-
配置文件
<!-- 导入数据库信息 --> <context:property-placeholder location="db.properties" /> <!-- 配置连接池 --> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="${jdbc.driver}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </bean> <!-- 扫描包,使注解生效 --> <context:component-scan base-package="com.ruanyuan.service" /> <!-- 注册事物管理驱动 --> <tx:annotation-driven transaction-manager="transactionManager" /> <!-- 配置jdbcTemplate模板 --> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 配置事物管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean>
-
测试类
public class AnnotationTest { @Test public void test3() { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext-annotation.xml"); // 获取AccountDao实例 AccountService accountService = (AccountService) context.getBean("ax"); accountService.transfer("韩庚","韩红",100.0); System.out.println("success"); } }
四、事物的传播特性
多个事务方法相互调用时,事务如何在这些方法间传播。spring支持7种事务传播行为:
- propagation_requierd:如果当前没有事务,就新建一个事务,如果已存在一个事务中,加入到这个事务中,最常见。
- propagation_supports:支持当前事务,如果没有当前事务,就以非事务方法执行。
- propagation_mandatory:使用当前事务,如果没有当前事务,就抛出异常。
- propagation_required_new:新建事务,如果当前存在事务,把当前事务挂起。
- propagation_not_supported:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
- propagation_never:以非事务方式执行操作,如果当前事务存在则抛出异常。
- propagation_nested:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与propagation_required类似的操作