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

MyBatis 查詢結果-錯誤

開啟mysql的查詢日志比較差別

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

mybatis提交事務-未提交

Mysql WorkBench 自動提交事務

注意:在我們的MyBatis中autocommit被設置為0,MySQL WorkBench中autocommit被設置為1

此時重新還原數據庫數據,在Test.java手工加入提交

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

依然無效!!!

回顧一下,自動提交的問題確實存在,思路並沒有問題。因此查詢mybatis文檔。

MyBatis 提交事務api

需要加入強制提交參數 true

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

加入后得到正確結果\:😄

MyBatis 查詢 正確結果

總結

在MySQL中,查詢也是一次事務,如果沒有提交,則每次查詢的結果都是相同的。然而建議的還是關閉自動提交(autocommit=0,但MySQL還是會自動開啟一個事務,只是不提交),這樣在向多個表中寫數據時可以保證一致性;對於增刪改操作而言,(在單個客戶端中)可以在確認執行后的數據正確,再提交,相當於提前模擬一遍。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM