4.事务支持
4-1 什么是事务
所谓的事务,表示一次不可再分的操作序列
这些操作序列中的所有操作
要么都执行,要么都不执行
它是一个不可分割的完整的工作单元
4-2 传统数据库的事务特性
ACID
A
Atomicity原子性 C
Consistency一致性 I
Isolation隔离性 D
Durability持久性
4-3 Spring事务特性
传播行为
在Spring中,传播的规则有很多,一般需要熟练掌握其中两种REQUIRED
表示当前的方法必须运行在一个存在事务管理的环境中在运行时会判断当前的环境中是否存在事务管理
如果存在,则会自动加入到当前的事务管理中如果不存在,则会开启一个新的事务环境用于执行当前的业务 一般用于增删改操作 SUPPORTS
表示当前的方法不是必须运行在事务管理的环境中有事务可以运行,没有事务也可以运行在运行时会判断当前的环境中是否存在事务管理
如果存在,则会自动加入到当前的事务管理中如果不存在,则拉倒 一般用于查询操作一般不会单独使用,会与其他属性联合使用 回滚条件
默认情况下,当遇到RuntimeException以及其子类的时候,会自动回滚可以进行手动设置
rollbackFor="异常的class类型"
表示遇到指定的异常会进行回滚 noRollbackFor="异常的class类型"
表示遇到指定的异常不进行回滚 只读优化
当你确定你的业务中有且仅有查询操作时才能使用readOnly=true一般与传播规则的SUPPORTS联合使用 超时
Timeout 隔离级别
从小到大TRANSACTION_NONE
指示事务不受支持的常量即没有事务 TRANSACTION_READ_UNCOMMITTED
指示可以发生脏读 (dirty read)、不可重复读和虚读 (phantom read) 的常量。即读未提交数据 TRANSACTION_READ_COMMITTED
指示不可以发生脏读的常量;不可重复读和虚读可以发生。即读已提交数据 TRANSACTION_REPEATABLE_READ
指示不可以发生脏读和不可重复读的常量;虚读可以发生。大部分的数据库均未对该级别做实现MySql与Oracle均未实现 TRANSACTION_SERIALIZABLE
指示不可以发生脏读、不可重复读和虚读的常量。解决了并发但是产生了悲观锁的问题
4-4 POM配置
<dependency>
<groupId>org.springframework
</groupId>
<artifactId>spring-tx
</artifactId>
<version>${spring.version}
</version>
</dependency>
4-5 Spring配置
以注解事务为例
Spring整合JDBC与MyBatis使用的是相同的事务管理器
DataSourceTransactionManager
<context:component-scan base-package="service"/>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
4-6 注解使用
@Transactional
表示配置事务的相关操作该注解可以标注在类上,也可以标注在方法上该注解标注在类上表示当前类均使用此时进行的事务配置该注解标注在方法上表示当前方法使用此时进行的实物配置如果类上与方法上均有该注解,优先使用方法上的事务配置 propagation属性
配置传播规则的事务属性其值是一个枚举类型,使用Propagation中提供的值其值一般使用REQUIRED或者SUPPOTRS rollbackFor属性
配置回滚条件当遇到指定的异常时进行回滚 noRollbackFor属性
配置回滚条件当遇到指定的异常时不进行回滚 readOnly=true
配置是否只读当操作中有且仅有查询操作时使用
@Service
@Transactional(propagation
= Propagation
.REQUIRED
,rollbackFor
= Exception
.class,noRollbackFor
= ArithmeticException
.class)
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper
;
@Override
public void regist(User user
) throws UserExistException
{
UserExample example
= new UserExample();
example
.or()
.andUsernameEqualTo(user
.getUsername());
List
<User> users
= userMapper
.selectByExample(example
);
if(!users
.isEmpty()){
throw new UserExistException("该用户已经被注册");
}
userMapper
.insertSelective(user
);
int i
= 1/0;
}
@Transactional(propagation
= Propagation
.SUPPORTS
,readOnly
= true)
@Override
public User
login(String username
, String password
) throws UserNotExistException
{
UserExample example
= new UserExample();
example
.or()
.andUsernameEqualTo(username
)
.andPasswordEqualTo(password
);
List
<User> users
= userMapper
.selectByExample(example
);
if(users
.isEmpty()){
throw new UserNotExistException("用户名或密码错误");
}
return users
.get(0);
}
}