Spring事务管理

一、关于数据库事务

一个数据库事务可以包含多个查询、修改、删除、插入等数据库动作,它们要么作为一个整体完全得到确认,要么完全失败

四大特性(ACID):

①、原子性(Atomic)

事务的操作作为整体执行,要么全部执行,要么全部失败

②、一致性(Consistency)

数据在事务执行之前和执行之后,处于一致状态

③、隔离性(Isolation)

多个事务之间是隔离的,互不影响

④、持久性(Durability)

一旦事务提交了,会持久化写到数据库,对数据库的修改是永久性的

二、案例

2.1编写用到事务管理的代码

在整合了Spring和MyBatis后继续对代码进行扩展

对接口的实现类进行方法的重写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package xyz.yolin.mapper;

import org.apache.ibatis.session.SqlSession;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import xyz.yolin.pojo.User;

import java.util.List;

public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper {
@Override
public List<User> selectUser() {
SqlSession sqlSession = getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
return mapper.selectUser();
}
@Override
public int addUser(User user) {
return getSqlSession().getMapper(UserMapper.class).addUser(user);
}
@Override
public int deleteUser(int id) {
return getSqlSession().getMapper(UserMapper.class).deleteUser(id);
}
}

2.2测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserMapper userMapper2 = context.getBean("userMapper2", UserMapper.class);
List<User> users = userMapper2.selectUser();
for(User user:users){
System.out.println(user);
}
int count = userMapper2.addUser(new User(9, "王虎", "65655"));
if(count==1){
System.out.println("数据插入成功");
}else{
System.out.println("数据插入失败");
}
int i = userMapper2.deleteUser(9);
if(i==0){
System.out.println("数据插入成功");
}else{
System.out.println("数据插入失败");
}

}
}

2.3执行结果

可以发现事务并没有作为一个整体得到确认,数据插入到数据库了,但删除操作出现异常。

此时需要配置事务管理

官方文档

三、配置声明式事务

spring-dao.xml文件中进行如下配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!--    配置声明式事务-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--使用注释事务 -->
<!-- <tx:annotation-driven transaction-manager="transactionManager"/>-->
<!--结合AOP实现事务的织入-->
<!--配置事务通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--给哪些方法配置事务,可指定方法,也可所有-->
<tx:attributes>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>

<!--配置事务切入-->
<aop:config>
<aop:pointcut id="txPointCut" expression="execution(* xyz.yolin.mapper.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
</aop:config>

至此,查询,增加,删除用户已经作为一个整体,要么都成功执行,要么都失败。

四、事务的扩展

4.1 Spring支持的事务管理类型

Spring支持两种类型的事务管理

  • 编程式事务管理:这意味你通过编程的方式管理事务,有极大的灵活性,但难以维护
  • 声明式事务管理:你可以将业务代码和事务管理分离,你只需用注解和XML配置来管理事务

4.2 Spring事务实现方式

Spring事务的本质其实就是数据库对事务的支持,真正的数据库层的事务提交和回滚是通过binlog或redo log实现的。

4.3 Spring的事务隔离

spring 有五大隔离级别,默认值为 ISOLATION_DEFAULT(使用数据库的设置),其他四个隔离级别和数据库的隔离级别一致:

  1. ISOLATION_DEFAULT:用底层数据库的设置隔离级别,数据库设置的是什么我就用什么;

  2. ISOLATION_READ_UNCOMMITTED:未提交读,最低隔离级别、事务未提交前,就可被其他事务读取(会出现幻读、脏读、不可重复读);

  3. ISOLATION_READ_COMMITTED:提交读,一个事务提交后才能被其他事务读取到(会造成幻读、不可重复读),SQL server 的默认级别;

  4. ISOLATION_REPEATABLE_READ:可重复读,保证多次读取同一个数据时,其值都和事务开始时候的内容是一致,禁止读取到别的事务未提交的数据(会造成幻读),MySQL 的默认级别;

  5. ISOLATION_SERIALIZABLE:序列化,代价最高最可靠的隔离级别,该隔离级别能防止脏读、不可重复读、幻读。

  • 脏读 :表示一个事务能够读取另一个事务中还未提交的数据。比如,某个事务尝试插入记录 A,此时该事务还未提交,然后另一个事务尝试读取到了记录 A。

  • 不可重复读 :是指在一个事务内,多次读同一数据。

  • 幻读 :指同一个事务内多次查询返回的结果集不一样。比如同一个事务 A 第一次查询时候有 n 条记录,但是第二次同等条件下查询却有 n+1 条记录,这就好像产生了幻觉。发生幻读的原因也是另外一个事务新增或者删除或者修改了第一个事务结果集里面的数据,同一个记录的数据内容被修改了,所有数据行的记录就变多或者变少了。

请我喝杯咖啡吧~

支付宝
微信