【不可重复读】Spring事务的并发问题(脏读,不可重复读、幻读)

不可重复读

这是由于查询时系统中其他事务修改的提交而引起的。比如事务T1读取某一数据,事务T2读取并修改了该数据,T1为了对读取值进行检验而再次读取该数据,便得到了不同的结果。

一种更易理解的说法是:在一个事务内,多次读同一个数据。在这个事务还没有结束时,另一个事务也访问该同一数据并修改数据。那么,在第一个事务的两次读数据之间。由于另一个事务的修改,那么第一个事务两次读到的数据可能不一样,这样就发生了在一个事务内两次读到的数据是不一样的,因此称为不可重复读,即原始读取不可重复。

不可重复读

示例:

1、UserDao接口

public interface UserDao {
    //不可重复读
    public List find2();

    public void update2();
}

2、UserDaoImpl实现类

public class UserDaoImpl extends JdbcDaoSupport implements UserDao {
    //测试不可重复读
    //@Transactional(isolation =Isolation.READ_COMMITTED)
    //解决不可重复读
    @Transactional(isolation =Isolation.REPEATABLE_READ)
    public List find2() {
        System.out.println("查询进入");
        List before=getJdbcTemplate().queryForList("select * from user where id=1");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        List after=getJdbcTemplate().queryForList("select * from user where id=1");

        List list2=new ArrayList();
        list2.add(before);
        list2.add(after);
        return list2;
    }

    public void update2() {
        String sql="update user set money=222 where id=1";
        getJdbcTemplate().update(sql);
    }

}

3、applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
                           http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/tx
                           http://www.springframework.org/schema/tx/spring-tx.xsd">

    <!--1、指定数据源-->
    <bean id="datasource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/weifan"></property>
        <property name="user" value="root"></property>
        <property name="password" value="root"></property>
    </bean>

    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <constructor-arg index="0" ref="datasource"></constructor-arg>
    </bean>

    <bean id="userDao" class="dao.impl.UserDaoImpl">
        <property name="jdbcTemplate" ref="jdbcTemplate"></property>
    </bean>

    <!--1、创建事务管理器对象-->
    <bean id="tx"  class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="datasource"/>
    </bean>

    <!--① 对标注@Transactional注解的Bean进行加工处理,以织入事物管理切面 -->
    <tx:annotation-driven transaction-manager="tx" />
</beans>

4、测试类

public class Test2 {
    ApplicationContext app=new ClassPathXmlApplicationContext("applicationContext.xml");
    class  A extends  Thread{
        public void run(){
            System.out.println("查询线程开始");
            UserDao dao=(UserDao) app.getBean("userDao");
            List list=dao.find2();
            System.out.println("before:"+list.get(0));
            System.out.println("after:"+list.get(1));
        }
    }
    class  B extends  Thread{
        public void run(){
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("更新线程开始");
            UserDao dao=(UserDao) app.getBean("userDao");
            dao.update2();
        }
    }

    public static void main(String[] args) {
        Test2 test1=new Test2();
        Test2.A a=test1.new A();
        Test2.B b=test1.new B();
        a.start();
        b.start();
    }
}

测试结果

测试结果

解决不可重复读

 @Transactional(isolation =Isolation.REPEATABLE_READ)
解决不可重复读
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容