MySQL中的查询事务问题

之前帮同学做个app的后台,使用了MySQL+MyBatis,遇到了一个查询提交的问题,卡了很久,现在有时间了来复盘下

环境情况

假设有学生表:

USE test;
CREATE TABLE `student` (
  Id int  NOT NULL PRIMARY KEY AUTO_INCREMENT,
  Name varchar(20) NOT NULL,
  Grade int NOT NULL
)

mybatis项目目录的大致结构为:

+---src
|   +---main
|   |   +---java
|   |   |   |   Test.java
|   |   |   |
|   |   |   +---pojo
|   |   |   |       Student.java
|   |   |   |
|   |   |   \---dao
|   |   |           IStudentDao.java
|   |   |
|   |   \---resources
|   |       |   log4j.properties
|   |       |   mybatis-config.xml
|   |       |
|   |       \---mappers
|   |               StudentMapper.xml

Test.java

import dao.IStudentDao;
import pojo.Student;

import java.io.InputStream;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class Test {
    public static void main(String args[]) throws Exception{
        String resource ="mybatis-config.xml";
        InputStream is = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        SqlSession sqlSession = sqlSessionFactory.openSession();
        IStudentDao studentDAO = sqlSession.getMapper(IStudentDao.class);
        Student currentStudent;

        currentStudent = studentDAO.getStudentById(1);
        System.out.println(currentStudent);

        Thread.sleep(1000 * 30);

        currentStudent = studentDAO.getStudentById(1);
        System.out.println(currentStudent);
    }
}

Student.java

package pojo;

public class Student {
    private int id;
    private String name;
    private int grade;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getGrade() {
        return this.grade;
    }

    public void setGrade(int grade) {
        this.grade = grade;
    }

    @Override
    public String toString(){
        return
                "id = " + id  + "\t" + "name = " + name  + "\t" + "grade = " + grade  + "\t";
    }
}

IStudentDao

package dao;

import org.apache.ibatis.annotations.Param;
import pojo.Student;

public interface IStudentDao {
    public Student getStudentById(@Param("studentId") int studentId);
}

mybatis-config.xml

<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <properties>
        <property name="driver" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/test?useUnicode=true&amp;characterEncoding=utf-8&amp;allowMultiQueries=true"/>
        <property name="username" value="root"/>
        <property name="password" value="nihaonihao123123"/>
    </properties>

    <environments default="test">
        <environment id="test">
            <transactionManager type="JDBC" />
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <mapper resource="mappers/StudentMapper.xml"></mapper>
    </mappers>
</configuration>

StudentMapper.xml

<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="dao.IStudentDao">
    <select id="getStudentById" resultType="pojo.Student">
        SELECT id AS id, name AS name, grade AS grade
        FROM student
        WHERE id = #{studentId} ;
    </select>
</mapper>

问题复盘

在第一次查询后,主线程暂停30秒,此时在MySQL WorkBench中修改了原来的数据,将“张三”变成“张三123”,主线程恢复后数据并没有任何变化。

开始以为是缓存问题,遂在mybatis-config.xml中禁用一级缓存:在configuration标签中,在 properties标签之后加入

<settings>
    <setting name="localCacheScope" value="STATEMENT"/>
</settings>

问题依旧(注意看时间的变化,确实进行了更新,查询的数据确实没有变化)

16:03:43    UPDATE test.student SET name = '张三123' WHERE id = 1 1 row(s) affected Rows matched: 1  Changed: 1  Warnings: 0  0.062 sec

开启mysql的查询日志比较差别

mysql> set GOLBAL general_log=on;
mysql> show variables like %general%;

注意:在我们的MyBatis中autocommit被设置为0,MySQL WorkBench中autocommit被设置为1

此时重新还原数据库数据,在Test.java手工加入提交

currentStudent = studentDAO.getStudentById(1);
sqlSession.commit();
System.out.println(currentStudent);

依然无效!!!

回顾一下,自动提交的问题确实存在,思路并没有问题。因此查询mybatis文档。

需要加入强制提交参数 true

currentStudent = studentDAO.getStudentById(1);
sqlSession.commit(true);
System.out.println(currentStudent);

加入后得到正确结果\::D

总结

在MySQL中,查询也是一次事务,如果没有提交,则每次查询的结果都是相同的。然而建议的还是关闭自动提交(autocommit=0,但MySQL还是会自动开启一个事务,只是不提交),这样在向多个表中写数据时可以保证一致性;对于增删改操作而言,(在单个客户端中)可以在确认执行后的数据正确,再提交,相当于提前模拟一遍。

原文地址:https://www.cnblogs.com/battor/p/mybatis_autocommit_problem.html

时间: 2024-08-29 17:11:54

MySQL中的查询事务问题的相关文章

mysql中条件查询加排序和索引的关系

跟一个朋友,不错公司的主管交流时,对于mysql中条件查询和排序时 与索引的关系 mysql> explain select * from article where title='希望光伏企业挺过2个月' o rder by id desc\\\\\\\\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: article type: index pos

mysql中模糊查询的四种用法介绍

下面介绍mysql中模糊查询的四种用法: 1,%:表示任意0个或多个字符.可匹配任意类型和长度的字符,有些情况下若是中文,请使用两个百分号(%%)表示. 比如 SELECT * FROM [user] WHERE u_name LIKE '%三%' 将会把u_name为“张三”,“张猫三”.“三脚猫”,“唐三藏”等等有“三”的记录全找出来. 另外,如果需要找出u_name中既有“三”又有“猫”的记录,请使用and条件 SELECT * FROM [user] WHERE u_name LIKE

mysql中给查询结果添加序号列

生成一个字段(非表中字段)用以记录排序   [类比为oracle数据库中的rownum] MySQL中一个表(表名:stuscore) 字段有:id(主键).stuid(学号).sname(学生姓名).subject(课程名称).score(分数) 列出数学成绩排名 (要求显示字段:排名,姓名 , 课程名称, 分数 , 学号) 用于排名的字段,查询时此处将其用 pm表示  select (@i:[email protected]+1)pm,s.* from stuscore s,(select

MySql 中游标,事务,终止存储过程方法总结

最近在项目开发中,有段逻辑处理,需要在网站,app,后台分别运行,这样给后期的维护带来了很大的不方便,容易遗漏app端或者后台,所以讲java代码转换成存储过程,把逻辑处理写在了mysql端,其中遇到游标,事务的处理.问题并不困难,只是容易忘记,做了一下总结: DECLARE err INT DEFAULT 0;#声明一个整形变量err,默认值是0 DECLARE orderDone INT DEFAULT FALSE;-- 遍历游标结束标识 DECLARE cur_order CURSOR F

一条SQL在MySql中如何查询

1.1 MySQL 基本架构概览 连接器: 身份认证和权限相关(登录 MySQL 的时候). 查询缓存: 执行查询语句的时候,会先查询缓存(MySQL 8.0 版本后移除,因为这个功能不太实用). 分析器: 没有命中缓存的话,SQL 语句就会经过分析器,分析器说白了就是要先看你的 SQL 语句要干嘛,再检查你的 SQL 语句语法是否正确. 优化器: 按照 MySQL 认为最优的方案去执行. 执行器: 执行语句,然后从存储引擎返回数据. 简单来说 MySQL 主要分为 Server 层和存储引擎层

mysql中的查询连接

查询连接分为4类:内连接.外连接.交叉连接.自然连接 一.交叉连接 cross join select * from 表A cross join 表B; -- 结果是笛卡尔积, 等价于select * from 表A, 表B; 避免使用 二.内连接 inner join select * from 表A [inner] join 表B [on 表A.字段 = 表B.字段]; -- on后的条件若省略, 等同于交叉连接. 同时on可用where代替,但效率会降低. select A.*, B.na

mysql中general_log(查询日志)关闭

今天,遇到一个问题,zabbix提示数据盘/opt不足20%,需要清理.经查看,/opt/mysql的一个日志文件达到16G,而数据盘总共20G,该日志文件为 master.log,查询后得知,它为mysql的通用查询日志,记录增删改查操作的. 经上网查资料,得知,通用查询日志--可以关闭 首先,进入mysql,输入 mysql> show global variables like '%general%'; +------------------+-----------------------

下面介绍mysql中模糊查询的四种用法:

1,%:表示任意0个或多个字符.可匹配任意类型和长度的字符,有些情况下若是中文,请使用两个百分号(%%)表示. 比如 SELECT * FROM [user] WHERE u_name LIKE '%三%' 将会把u_name为"张三","张猫三"."三脚猫","唐三藏"等等有"三"的记录全找出来. 另外,如果需要找出u_name中既有"三"又有"猫"的记录,请使用a

mysql中general_log查询日志

作为mysql的通用查询日志,记录增删改查操作的,都有日志文件记录的. 经上网查资料,得知,通用查询日志--可以关闭 show global variables like '%general%'; 同样可以关闭日志: set global general_log = off; // 关闭查询日志 原文地址:https://www.cnblogs.com/phpper/p/8359023.html