今天来学习下spring事务的隔离等级。在讲到spring的五种事务隔离性时,我们先来说说我们在一个事务中,我们在读取数据可能会遇到的几种情况:
1、脏读(dirty reads),什么是脏读,观其字,我们大概就能猜到它的大致意思,就是读取了不该读取的数据。在事务中,是指A事务在读取数据时,读取了在B事务中没有提交的数据,如果B事务对数据回滚,就会造成A事务的脏读。
2、不可重复读(no repeatabled reads),A事务在两次读取的数据不一致,原因是B事务的修改导致的,这就造成了A事务数据的混乱。
3、幻读(phontom reads),事务A在两次读取数据时,两次读取的记录数不一致,原因是B事务插入了新的数据,导致了A事务两次读取的记录数不一致。
以上三种情况就是我们读取数据经常遇到的,而spring事务的隔离性就是为了避免以上1种或几种情况的出现。
spring中有五种隔离等级:
1、SERIALIZABLE:最严格的级别,事务串行执行,资源消耗最大;
2、REPEATABLE_READ:保证了一个事务不会修改已经由另一个事务读取但未提交(回滚)的数据。避免了“脏读取”和“不可重复读取”的情况,但是带来了更多的性能损失。
3、READ_COMMITTED:大多数主流数据库的默认事务等级,保证了一个事务不会读到另一个并行事务已修改但未提交的数据,避免了“脏读取”。该级别适用于大多数系统。
4、READ_UNCOMMITTED:保证了读取过程中不会读取到非法数据。隔离级别在于处理多事务的并发问题
5、DEFAULT,默认级别,应该改等同于Read committed
先来看看READ COMMITTED等级
测试类:
package com.aop;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.thread.service.IBaseFacadeService;
//@RunWith(SpringJUnit4ClassRunner.class)
//@ContextConfiguration(locations = { "classpath:/spring-ibatis.xml", "classpath:/spring-jdbctemplate.xml" })
public class TestStudentDao {
public static void main(String[] args) {
try {
BeanFactory factory = new ClassPathXmlApplicationContext("spring-jdbctemplate.xml");
IBaseService service = (IBaseService) factory.getBean("businessSerivce");
service.doA();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
事务类:
package com.aop;
import java.util.List;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.entity.Student;
@Service("businessSerivce")
public class BusinessServiceImpl implements IBaseService,ApplicationContextAware {
@Autowired
IStudentDao studentDao;
@Autowired
ApplicationContext context;
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, rollbackFor = Exception.class)
public String doA() throws Exception {
Student st = new Student();
st.setId(1);
st.setSex("girlinsert");
st.setUsername("zxinsert");
studentDao.insertStudent(st);
//studentDao.updateStudent(st);
IBaseService service = (IBaseService)context.getBean("businessSerivce");
// 使用代理调用方法doB()
service.doB();
return "success";
}
@Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.READ_COMMITTED, rollbackFor = Exception.class)
public String doB() throws Exception {
List<Student> list = studentDao.getAllStudent();
System.out.println("新事物读取数据:"+list);
return "success";
}
@Override
public void setApplicationContext(ApplicationContext arg0) throws BeansException {
context = arg0;
}
}
执行结果:
新事物读取数据:[]
从结果我们可以发现,事务B并没有读取到A事务未提交的数据。
我们将事务的隔离等级修改为READ_UNCOMMITTED
执行结果:
新事物读取数据:[Student [id=1, username=zxinsert, sex=girlinsert]]
从结果我们可以发现我们读取到了脏数据(A事务未提交的数据)
我么将事务的隔离等级修改为REPEATABLE_READ
执行结果:
新事物读取数据:[]
从结果我们可以发现我们没有读取到A事务插入的数据,这就避免了幻读的出现。