事务
什么是事务?
事务是数据库操作最基本单元,逻辑上,一组操作要么都成功,如果有一个失败就都失败。
- 事务的四大特性(ACID):原子性、一致性、隔离性、持久性。
- 原子性:不可分割的,要么都成功,要么都失败。
- 一致性:总量不会减少(A给B转了100块钱,A-100,B+100)
- 隔离性:多事务时,各个事务之间不会产生影响。
- 持久性:事务提交后,数据永久的保存。
在银行转账业务中,首先是用户A扣除一定金额,然后再给用户B增加一定金额。这就是一个事务,他们不可分割,总量不会减少,其他的事务不会影响这个事务,一旦提交了,数据就永久保存。
- 事务操作说明
- 开启事务
- 进行业务
- 没有发生异常,事务提交
- 如果异常,事务回滚。
一般而言,事务添加在Service层。事务方式分为两种:编程式事务管理和声明式事务管理。一般使用声明式。声明式事务管理有基于注解方式和基于xml配置文件方式进行,一般使用基于注解方式。Spring提供了一个接口PlatformTransactionManager(事务管理器)
,根据不同的框架提供了不同的接口的实现(JDBC和MyBatis使用DataSourceTransactionManager
)
基于注解方式实现事务管理
-
在Spring中配置事务管理器,并完成数据源注入。
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean>
-
在Spring中开启注解扫描
-
先配置名称空间tx
-
开启事务注解并指定哪一个事务管理器
<tx:annotation-driven transaction-manager="TransactionManager"/>
-
-
在service类或方法上添加事务注解。
@Transactional
@Transactional
的参数配置。
-
propagation
:事务的传播行为:多事务方法直接进行调用,这个过程中事务是如何进行管理的。- Required:如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,这是最常见的选择,也是Spring默认的事务传播行为。
当内部方法和外部方法都有事务时,内部方法需要回滚时,外部方法不会回滚;如果外部方法没有事务,内部方法有事务,则只回滚内部方法;如果外部方法有事务,内部方法没有事务,则他们属于同一事务,回滚时都会回滚。
- 其他可以同理可得。
- Required:如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,这是最常见的选择,也是Spring默认的事务传播行为。
-
isolation
:事务的隔离级别- 读未提交
READ_UNCOMMITTED
——出现脏读、不可重复度、幻读。不能容忍的。 - 读已提交
READ_COMMITTED
——出现不可重复度、幻读。可以容忍的。 - 可重复读
REPEATABLE_READ
——出现幻读。可以容忍的。 - 串行化
SERIALIZABLE
——都可以解决,但是并发性差。可能会导致最后一张票被多个人购买。一般不使用。
- 读未提交
-
timeout
:超时时间 -
readOnly
:是否只读 -
rollBackFor
:回滚。 -
noRollBackFor
:不会滚。
基于XML方式实现事务管理
-
配置xml文件
-
配置事务管理器参数
<tx:advice id="tx"> <tx:attributes> <tx:method name="transfer"/> </tx:attributes> </tx:advice>
-
配置切入点、切面
<aop:config> <aop:pointcut id="pt" expression="execution(* com.boerk.txDemo.service.*(..))"/> <aop:advisor advice-ref="tx" pointcut-ref="pt"></aop:advisor> </aop:config>
基于完全注解开发实现事务操作
@Configuration
@ComponentScan(basePackages="com.boerk")
@EnableTransactionManagement
public class SpringConfig {
@Bean
public DruidDataSource getDruidDataSource(){
DruidDataSource druidDataSource = new DruidDataSource;
druidDataSource.setUrl("jdbc:mysql://localhost:3307/boerk");
druidDataSource.setUsername("root");
druidDataSource.setPassword("root123");
druidDataSource.setDriverClassName("com.mysql.jdbc.Driver");
return druidDataSource;
}
@Bean
public JdbcTemplate getJdbcTemplate(DruidDataSource druidDataSource){
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(druidDataSource);
return jdbcTemplate;
}
@Bean
public DataSourceTransactionManager getDataSourceTransactionManager(DruidDataSource druidDataSource){
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
dataSourceTransactionManager.setDataSource(druidDataSource);
return dataSourceTransactionManager;
}
}