JAVA事务隔离级别有问题,读到了脏数据

一个方法被掉了2次,我看日志,第一次调用在走到新增费用方法的时候,第二次调用进来了,并且拿到了第一次方法扣费导致账户余额改变的数据
image.png
mysql的事务隔离级别是READ-COMMITTED。java用注解式事务也是用的默认的隔离级别,应该不会脏读的,还有什么要注意的吗
image.png

image.png
<description>finance配置</description>

<bean id="dataSource-finance" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="${finance-saas-jdbc.driver}" />
    <property name="url" value="${finance-saas-jdbc.url}" />
    <property name="username" value="${finance-saas-jdbc.username}" />
    <property name="password" value="${finance-saas-jdbc.password}" />
    <property name="initialSize" value="${finance-saas-jdbc.initialSize}"></property>
    <property name="maxActive" value="${finance-saas-jdbc.maxActive}"></property>
    <property name="minIdle" value="${finance-saas-jdbc.minIdle}"></property>
    <property name="maxIdle" value="${finance-saas-jdbc.maxIdle}"></property>
    <property name="maxWait" value="${finance-saas-jdbc.maxWait}"></property>
    <property name="logAbandoned" value="true" ></property>
    <property name="removeAbandoned" value="true" ></property>
    <property name="removeAbandonedTimeout" value="180" ></property>
    <property name="validationQuery" value="select now() from dual"/>
    <property name="defaultAutoCommit" value="true"></property>
</bean>
<!-- MyBatis配置 -->
<bean id="mybatisSqlSessionFactory-finance" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource-finance" />
    <property name="configLocation" value="classpath:/config/sqlMapConfig.xml" />
    <!--     自动扫描entity目录, 省掉Configuration.xml里的手工配置 -->
    <property name="typeAliasesPackage" value="com.baiduxx.finance.dao.entity" />
    <!--     显式指定Mapper文件位置 -->
    <!--<property name="mapperLocations" value="classpath:/config/mappers/*Mapper.xml" />-->
    <property name="plugins">
        <array>
            <bean class="com.baiduxx.util.zipkin.interceptor.MybatisZipkinSqlInfoInterceptor"/>
            <bean class="com.github.pagehelper.PageInterceptor">
                <property name="properties">
                    <value>
                        helperDialect=mysql
                    </value>
                </property>
            </bean>
        </array>
    </property>
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="com.baiduxx.finance.daoext.mappers;com.baiduxx.finance.dao.mappers" />
    <property name="sqlSessionFactoryBeanName" value="mybatisSqlSessionFactory-finance" />
</bean>
<bean id="txManager-finance" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource-finance" />
</bean>

<tx:annotation-driven transaction-manager="txManager-finance" />
阅读 3k
3 个回答

猜测你扣费的SQL语句UPDATE user SET balance=balance-10 WHERE id=10

如果余额balance大于等于20,2次扣费没问题,否则就会透支,出现负数的情况

建议增加更新条件

UPDATE user SET balance=balance-10 WHERE id=10 AND balance>=10

UPDATE user SET balance=balance-10 WHERE id=10 AND balance=A

第一条支持并发更友好一些,但日志中记录的初始余额可能是错的

第二条语句更严谨一些,A是你第一次查询到的余额

已参与了 SegmentFault 思否「问答」打卡,欢迎正在阅读的你也加入。

这是mysql 默认的隔离级别,具体还得看使用。可能你没有开启事务,可能你使用的其他隔离级别。

1.mysql默认隔离级别读已提交是读不到别的事务未提交的数据的,尝试手动在Navicat开启事务写sql执行流程,看能不能复现。
2.不能复现则debug检查代码中事务是否生效,事务不生效原因有很多,百度一下一一对照排查

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题