开发者社区> 问答> 正文

mysql 事务回滚原理及疑问

最近在研究mysql的事务,参考了网上的一些例子写了一些,但是感觉有一点疑问,google后发现还是没找到答案,翻了下源码,还没找到核心关键点,想请大神们,帮忙指个路

1.如果在commit之前发生异常,进入catch里显式rollback,会造成什么隐形后果,如果在catch里去掉rollback,因为也没有commit所以数据还是不会提交,什么情况下会rollback才会真正发挥作用,并且这个作用如何和innodb挂钩的,看了下ConnectionImpl里的rollback源码,还没找到核心重点部分。

2.我写的这段简单的jdbc事务,有没有问题,我也是按照网上的模仿了下,如果有问题,一般的写法是怎么样的

3.commit和rollback实际的作用,原理是什么让事务提交和回滚,我所知道的spring-mybatis是用的aop,但是jdbc都是依赖的数据库的手动提交方式,那回滚呢?

4.Spring里所谓的小事务控制是什么样的,Manager层

5.insertTest1方法是自己try catch 还是抛出去 让外层得到异常 然后rollback

6.感觉insertTest1(con);insertTest2(con);这里有问题,如果insertTest1有异常 直接insertTest2不会执行,也就相当于事务的感觉(要么同时执行,要么都不执行)但是这里是通过异常造成的流程控制,不是真正的事务控制。
7.执行下面代码 insertTest1(),insertTest2()都正常执行(插入符合规范的值,不抛异常),finally里的rollback不起作用,test1,test2里还是有数据,怎么样去最终为什么没起作用,查看了数据库是innodb的

public static void main(String[] args) {
        Connection con = null;
        try {
            con = getConnection();
            con.setAutoCommit(false);
            insertTest1(con);
            insertTest2(con);
            con.commit();
            System.out.println("=======JDBC Transaction commit===========");
        } catch (SQLException e) {
            try {
                con.rollback();
                System.out.println("=======JDBC Transaction rolled back successfully=======");
            } catch (SQLException e1) {
                System.out.println("=======SQL Exception in rollback" + e1.getMessage()); //回滚必要条件:1.同一个transaction 2.connection未关,所以这里要加异常处理
            }
            e.printStackTrace();
        }finally{
            try {
                con.rollback();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
            if (con != null) {
                try {
                    con.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }

Sql:
screenshot
javaCode:

public class JdbcTransaction {
        
        public final static String DB_DRIVER_CLASS = "com.mysql.jdbc.Driver";
        public final static String DB_URL = "jdbc:mysql://xxx.mysql.rds.aliyuncs.com/weitoo";
        public final static String DB_USERNAME = "xxx";
        public final static String DB_PASSWORD = "xxx";
        public static final String INSERT_TEST1 = "INSERT INTO test1(id,name) VALUES(?,?)";
        public static final String INSERT_TEST2 = "INSERT INTO test2(id,name) VALUES(?,?)";
    
        
    
        public static void main(String[] args) {
            Connection con = null;
            try {
                con = getConnection();
                con.setAutoCommit(false);
                insertTest1(con);
                insertTest2(con);
                con.commit();
                System.out.println("=======JDBC Transaction commit===========");
            } catch (SQLException e) {
                try {
                    con.rollback();
                    System.out.println("=======JDBC Transaction rolled back successfully=======");
                } catch (SQLException e1) {
                    System.out.println("=======SQL Exception in rollback" + e1.getMessage()); //回滚必要条件:1.同一个transaction 2.connection未关,所以这里要加异常处理
                }
                e.printStackTrace();
            }finally{
                if (con != null) {
                    try {
                        con.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
            }
        
            
        }
        
        public static Connection getConnection() {
            Connection conn = null;
                try {
                    Class.forName(DB_DRIVER_CLASS);
                    conn = DriverManager.getConnection(
                            DB_URL,
                            DB_USERNAME, DB_PASSWORD);
                    System.out.println("======DB connection successfully========");
                } catch (ClassNotFoundException | SQLException e) {
                    System.out.println("======DB connection failed=========");
                    e.printStackTrace();
                } 
            return conn;
        }
        
        public static void insertTest1(Connection conn) throws SQLException {
            PreparedStatement stmt;
                stmt = conn.prepareStatement("INSERT INTO test1(id,name) VALUES(?,?)");
                stmt.setInt(1, 1);
                stmt.setString(2, "1"); 
                stmt.executeUpdate();
                System.out.println("======insert into test1 successfully======");
                stmt.close();
        
        }
        
        public static void insertTest2(Connection conn) throws SQLException {
            PreparedStatement stmt;
                stmt = conn.prepareStatement("INSERT INTO test2(id,name) VALUES(?,?)");
                stmt.setInt(1, 1);
                stmt.setString(2, "11"); //故意长度超出
                stmt.executeUpdate();
                System.out.println("======insert into test2 successfully========");
                stmt.close();
            
        }
    }

展开
收起
蛮大人123 2016-03-09 17:16:02 7679 0
2 条回答
写回答
取消 提交回答
  • MySQL内核开发者, 《高性能MySQL 第三版》译者之一,活跃于MySQL社区,BugList,etc...

    没get到问题点, 你问的是客户端如何发起回滚么 ??

    2019-07-17 18:56:26
    赞同 展开评论 打赏
  • 我说我不帅他们就打我,还说我虚伪

    进行事务处理的时候,MySQL 在开始事务时会切换到一个延缓操作的状态,这个状态下操作并不都是立即执行的(通常情况下语句是立即执行的)。而在 commit 时,会将延缓执行的操作都执行进去,并将状态回归到及时写入状态。同样的, rollback 时会把延缓写入的操作抛弃掉,此间申请的锁释放掉,并将状态回归到及时写入状态。
    执行 rollback 的关键在于释放 申请的锁 和 回归及时写入状态,而并不是放弃未写入的操作(你关心的点在未写入的操作,然而执行与不执行 rollback 都没有操作写进去,所有你感觉执行或不执行都没什么区别)。
    有时候你不执行 rollback ,影响并不会马上提现,毕竟你下一次调用 startTransaction 的时候还是会重置一下状态。但是如果你在事务之中申请了锁,或者是其他一些关联操作,那就会响应你其他与之关联操作的执行。这就好比是关闭程序,rollback 是正常的关闭流程,你不执行 rollback 就好像是强行关闭程序,难免发生奇怪的问题。

    2019-07-17 18:56:26
    赞同 展开评论 打赏
问答排行榜
最热
最新

相关电子书

更多
One Box: 解读事务与分析一体化数据库 HybridDB for MySQL 立即下载
One Box:解读事务与分析一体化数据库HybridDB for MySQL 立即下载
如何支撑HTAP场景-HybridDB for MySQL系统架构和技术演进 立即下载

相关镜像