• 事务与隔离级别


    数据库事务

    TestTransaction

    package com.aff.transaction;
    import java.lang.reflect.Field;
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.ResultSetMetaData;
    import java.sql.SQLException;
    import org.junit.Test;
    import com.aff.util.JDBCUtils;
    
    /*
     * 1.什么叫数据库事务?
     *               事务:一组逻辑操作单元,使数据从一种状态变换到另一种状态。
     *                    一组逻辑操作单元:一个或多个DML操作。
     * 
     * 2.事务处理的原则:保证所有事务都作为一个工作单元来执行,即使出现了故障,都不能改变这种执行方式。
     *    当在一个事务中执行多个操作时,要么所有的事务都被提交(commit),那么这些修改就永久地保存下来;
     *    要么数据库管理系统将放弃所作的所有修改,整个事务回滚(rollback)到最初状态。
     * 
     * 3.数据一旦提交,就不可回滚
     * 
     * 4.哪些操作会导致数据的自动提交? 
     *             ①DDL操作一旦执行,都会自动提交。 
     *             ②set autocommit = false 对DDL操作失效
     *             ③DML默认情况下,一旦执行,就会自动提交。 
     *               我们可以通过 set autocommit = false 的方式取消DML操作的自动提交。
     *             ④默认在关闭连接时,会自动的提交数据
     */
    
    public class TestTransaction {
    
        // ******************未考虑数据库事务情况下的转账操作**************************
        /*
         * 针对于数据表user_table来说: AA用户给BB用户转账100
         * 
         * update user_table set balance = balance - 100 where user = 'AA'; update
         * user_table set balance = balance + 100 where user = 'BB';
         */
        @Test
        public void testUpdate() {
            String sql1 = "update user_table set balance = balance - 100 where user = ?";
            update(sql1, "AA");
    
            // 模拟网络异常
            // System.out.println(10 / 0);
    
            String sql2 = "update user_table set balance = balance + 100 where user = ?";
            update(sql2, "BB");
            System.out.println("转账成功");
        }
    
        // 通用的增删改操作---version 1.0
        public int update(String sql, Object... args) {// sql中占位符的个数与可变形参的长度相同!
            Connection conn = null;
            PreparedStatement ps = null;
            try {
                // 1.获取数据库的连接
                conn = JDBCUtils.getConnection();
                // 2.预编译sql语句,返回PreparedStatement的实例
                ps = conn.prepareStatement(sql);
                // 3.填充占位符
                for (int i = 0; i < args.length; i++) {
                    ps.setObject(i + 1, args[i]);// 小心参数声明错误!!
                }
                // 4.执行
                return ps.executeUpdate();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                // 5.资源的关闭
                // 主要针对数据库连接池的使用
                try {
                    conn.setAutoCommit(true);
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                JDBCUtils.closeResource(conn, ps);
            }
            return 0;
        }
    
        // ===================考虑数据库事务后的转账操作=========================================
        // ===================考虑数据库事务后的转账操作=========================================
        @Test
        public void testUpdateWithTransaction() {
            Connection conn = null;
            try {
                conn = JDBCUtils.getConnection();
                // System.out.println(conn.getAutoCommit());//true
                // 1.取消数据的自动提交功能
                conn.setAutoCommit(false);
    
                String sql1 = "update user_table set balance = balance - 100 where user = ?";
                update(conn, sql1, "AA");
    
                // 模拟网络异常
                System.out.println(10 / 0);
    
                String sql2 = "update user_table set balance = balance + 100 where user = ?";
                update(conn, sql2, "BB");
    
                System.out.println("转账成功");
    
                // 2.成功后,提交数据
                conn.commit();
            } catch (Exception e) {
                e.printStackTrace();
                // 3.出现异常了,就回滚数据
                try {
                    conn.rollback();
                } catch (Exception e1) {
                    e1.printStackTrace();
                }
            } finally {
                JDBCUtils.closeResource(conn, null);
            }
        }
    
        // 通用的增删改操作---version 2.0考虑事务
        public int update(Connection conn, String sql, Object... args) {
            PreparedStatement ps = null;
            try {
                // 1.预编译sql语句,返回PreparedStatement的实例
                ps = conn.prepareStatement(sql);
                // 2.填充占位符
                for (int i = 0; i < args.length; i++) {
                    ps.setObject(i + 1, args[i]);// 小心参数声明错误!!
                }
                // 3.执行
                return ps.executeUpdate();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                // 4.资源的关闭,外面传进来的连接 不用关闭,设为null
                // 主要针对数据库连接池的使用
                try {
                    conn.setAutoCommit(true);
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                JDBCUtils.closeResource(null, ps);
            }
            return 0;
        }
    
        // ===========================================================================
        // ==============通用的查询操作,用于返回数据表中的一条记录,varsion2.0===============
    
        @Test
        public void testTransactionSelect() throws Exception {
            Connection conn = JDBCUtils.getConnection();
            System.out.println(conn.getTransactionIsolation());// 返回1,查看隔离级别
            conn.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);
            // 读已提交,避免脏读问题
            // oraclew 默认的为 TRANSACTION_READ_COMMITTED
            // mysql 默认的为TRANSACTION_REPEATABLE_READ -----不可重复读
            conn.setAutoCommit(false);// 取消自动提交数据
            String sql = "select user,password,balance from user_table where user = ? ";
            User user = getInstance(conn, User.class, sql, "CC");
            System.out.println(user);
        }
    
        @Test
        public void testTransactionUpdate() throws Exception {
            Connection conn = JDBCUtils.getConnection();
            conn.setAutoCommit(false);// 取消自动提交数据
            String sql = "update  user_table set balance = ? where user = ? ";
            update(conn, sql, 5000, "CC");
            Thread.sleep(15000);
            System.out.println("修改结束");
    
        }
    
        public <T> T getInstance(Connection conn, Class<T> clazz, String sql, Object... args) {
            PreparedStatement ps = null;
            ResultSet rs = null;
            try {
                // 执行,获取结果集
                ps = conn.prepareStatement(sql);
                // 填充占位符
                for (int i = 0; i < args.length; i++) {
                    ps.setObject(i + 1, args[i]);
                }
                rs = ps.executeQuery();
                // 获取结果集的元数据
                ResultSetMetaData rsmd = rs.getMetaData();
                // 获取列数
                int columnCount = rsmd.getColumnCount();
                if (rs.next()) {
                    T t = clazz.newInstance();
    
                    for (int i = 0; i < columnCount; i++) {
                        // 获取每个列的列值
                        Object columnValue = rs.getObject(i + 1);
    
                        // 获取列的列名,列数 列名为元数据用来修饰ResultSet(结果集)的,
                        // String columnName = rsmd.getColumnName(i + 1);-- 不推荐使用
                        // 改为获取列的别名
                        String ColumnLabel = rsmd.getColumnLabel(i + 1);
    
                        // 通过反射将对象指定名columnName的属性赋给指定的值columnValue
                        // 先拿到class
                        Field field = clazz.getDeclaredField(ColumnLabel);
                        field.setAccessible(true);
                        field.set(t, columnValue);
                    }
                    return t;
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                JDBCUtils.closeResource(null, ps, rs);
            }
            return null;
        }
    }

     

    Oracle 支持的 2 种事务隔离级别:READ COMMITED,SERIALIZABLE。

    Oracle 默认的事务隔离级别为: READCOMMITED

     Mysql 支持 4 种事务隔离级别. Mysql 默认的事务隔离级别为: REPEATABLE READ

      conn.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);

        int TRANSACTION_READ_UNCOMMITTED = 1; 

        int TRANSACTION_READ_COMMITTED = 2;  

        int TRANSACTION_REPEATABLE_READ  = 4; 

        int TRANSACTION_SERIALIZABLE     = 8;

    All that work will definitely pay off
  • 相关阅读:
    Jenkins-maven项目的构建、部署
    配置管理规范-互联网配置管理特点
    Jenkins-权限控制
    Jira-角色和用户组
    Jira-权限管理
    bat命令生成目录树(包含或不包含文件夹)
    登录QQ出现R6030-CRT not initialized,安装QQ 9.2.0可解决
    pointofix快捷键
    卸载Windows的弹窗广告可尝试使用“广告清道夫”
    激活Windows10专业工作站版
  • 原文地址:https://www.cnblogs.com/afangfang/p/12682306.html
Copyright © 2020-2023  润新知