事务:事务是保证业务操作完整性的一种数据库机制。事务拥有四大特性:
**原子性(atomicity):**事务是一个不可分割的最小单元,要么全部提交,要么全部失败回滚。
一致性(consistency):指事务执行前后,数据从一个合法性状态
变换到另外一个合法性状态
。
隔离性(isolation):事务的隔离性是指一个事务的执行不能被其他事务干扰。
持久性(durability):一个事务一旦被提交,它对数据库中数据的改变就是永久性的。
如何控制事务:
JDBC
:
Connection.setAutoCommit(false);
Connection.commit();
Connection.rollback();
Mybatis
:
Mybatis自动开启事务
sqlSession.commit(),底层调用的还是Connection.commit;
SqlSession.rollback(),底层调用的还Connection.rollback()
总结:控制事务的底层,都是通过Connection
对象完成的。
Spring控制事务编码
XML形式
-
依赖
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>5.1.12.RELEASE</version> </dependency>
-
编码
public interface UserService { void register(User user); } @Service("userService") public class UserServiceImpl implements UserService { @Autowired private UserDao userDao; @Override public void register(User user) { userDao.save(user); } }
<!-- 连接池,获取Connection连接--> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/spring?useSSL=false"/> <property name="username" value="root"/> <property name="password" value="root"/> </bean> <!-- 额外功能: transactionManager就是事务的额外功能,负责事务的提交或回滚, 因为底层是Connection进行commit或rollback,所以注入连接池,便于快速获取Connection连接 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!--设置事务属性--> <tx:advice id="transactionInterceptor" transaction-manager="transactionManager"> <tx:attributes> <!-- 给register方法设置事务属性--> <tx:method name="register" isolation="DEFAULT" propagation="REQUIRED"/> <!-- 给除了register方法外的其他以modify为命名前缀的方法设置事务属性--> <tx:method name="modify*"/> </tx:attributes> </tx:advice> <!-- 切面:组长切入点和额外功能--> <aop:config> <!-- 切入点:给哪些方法加上事务--> <aop:pointcut id="pc" expression="execution(* edu.hzb.tx.xml.UserServiceImpl.*(..))"/> <aop:advisor advice-ref="transactionInterceptor" pointcut-ref="pc"/> </aop:config>
注解形式
@Configuration
@ComponentScan("edu.hzb.tx.annotation")
@EnableTransactionManagement
public class Appconfig {
@Bean
public DataSource dataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUsername("root");
dataSource.setPassword("root");
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/spring?useSSL=false");
return dataSource;
}
@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(dataSource);
return jdbcTemplate;
}
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
transactionManager.setDataSource(dataSource);
return transactionManager;
}
}
public interface UserService {
void register(User user);
}
@Service("userService")
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
@Override
@Transactional(isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
public void register(User user) {
userDao.save(user);
}
}
Spring事务属性
属性是描述物体特征的一系列值,比如人的身高、性别、体重。事务属性就是描述事务特征的一系列值。
事务属性包含:
- 隔离属性
- 传播属性
- 只读属性
- 超时属性
- 异常属性
隔离属性(isolation)
概念:描述了事务解决并发问题的特征。
-
什么是并发
多个事务在同一时间,访问操作了相同的数据。
-
并发会产生哪些问题
- 脏写(脏写问题太严重,所有的隔离级别都可以解决脏写)
- 脏读
- 不可重复读
- 幻读
-
并发问题如何解决
通过隔离属性解决,隔离属性中设置不同的值,解决并发处理过程中的问题。
数据库对隔离属性的支持
隔离属性 | MySQL | Oracle |
---|---|---|
READ_COMMITED | 支持 | 支持 |
REPEATABLE_READ | 支持 | 不支持 |
SERIALIAZBLE | 支持 | 支持 |
Oracle不支持REPEATABLE_READ,采用的是多版本对比(乐观锁)的方式,解决不可重复读的问题。
默认的隔离属性
ISOLATION_DEFAULT:会调用不同数据库所设置的默认隔离属性。
MySQL:REPEATABLE_READ
Oracle:READ_COMMITED
对于隔离属性,推荐使用Spring指定的ISOLATION_DEFAULT
,使用对应数据库的隔离级别。
传播属性(propagation)
**概念:**描述了事务解决嵌套问题的特征。
1. 什么叫事务的嵌套?
指的是一个打的事务中,包含了若干个小的事务。
2. 事务嵌套带来的问题?
大事务中嵌套了多个小的事务,彼此相互影响,最终导致外部大的事务丧失了事务的原子性。
传播属性的值及其用法
传播属性的值 | 外部不存在事务 | 外部存在事务 | 用法 | 备注 |
---|---|---|---|---|
REQUIRED | 开启新的事务 | 融合到外部事务中 | @Transational(propagation=Propagation.REQUIRED) | 增删改方法 |
SUPPORTS | 不开启事务 | 融合到外部事务中 | @Transational(propagation=Propagation.SUPPORTS) | 查询方法 |
REQUIRES_NEW | 开启新的事务 | 挂起外部事务,创建新的事务 | @Transational(propagation=Propagation.REQUIRES_NEW) | 日志记录方法中 |
NOT_SUPPORTED | 不开启事务 | 挂起外部事务 | @Transational(propagation=Propagation.NOT_SUPPORTED) | 极其不常用 |
NEVER | 不开启事务 | 抛出异常 | @Transational(propagation=Propagation.NEVER) | 极其不常用 |
MANDATORY | 抛出异常 | 融合到外部事务中 | @Transational(propagation=Propagation.MANDATORY) | 极其不常用 |
默认的传播属性:REQUIRED
推荐传播属性的使用方式:
增删改方法:直接使用默认值REQUIRED
查询方法:显式指定传播属性的值为SUPPORTS
只读属性(readOnly)
针对只进行查询操作的业务方法,可以加入只读属性,提高运行效率。
默认值:false
,可以改为true
来使用只读属性
Transactional(readOnly=true)
超时属性(timeout)
指定事务等待的最长时间。
1. 为什么事务进行等待?
当前事务访问数据时,有可能访问的数据被别的事务进行加锁的的处理,那么当前事务就必须进行等待。
2. 等待时间单位:秒
3 如何使用:Transactional(timeout=2)
4. 超时属性的默认是-1,-1表示超时属性由对应的数据库设置。
异常属性(exception)
Spring事务处理过程中:
- 默认对
RuntimeException
及其子类,采用的是回滚的策略。 - 默认对
Exception
及其子类(排除RuntimeException
及其子类),采用的是提交的策略。
@Transactional(rollbackFor = {java.lang.RuntimeException.class}, noRollbackFor = {java.lang.Exception.class})
学习哔哩哔哩《孙哥讲Spring5》视频所做的笔记