JDBC事务测试未解决的问题--已解决


:测试过程中出现了多处未主动释放链接的情况,这是不对的,仅仅是为了测试而这样做的。

测试目的:想测试事务的脏读

  • 正确执行过程
  1. 先执行testTransactionSelect()
    结果为:

com.mysql.cj.jdbc.ConnectionImpl@3c130745
4
User{user=‘CC’, password=‘abcd’, balance=5000}

  1. 再执行testTransactionUpdate()
    在获取链接后如下图:
    在这里插入图片描述
    此时以获取链接更新完数据,但是因为链接还未断开,这时再次执行testTransactionSelect() 即可检测出脏读
    结果为:

com.mysql.cj.jdbc.ConnectionImpl@3c130745
4
User{user=‘CC’, password=‘abcd’, balance=6600}

  1. 等待testTransactionUpdate() 方法执行结束后,再次查询testTransactionSelect()
    结果为:

com.mysql.cj.jdbc.ConnectionImpl@3c130745
4
User{user=‘CC’, password=‘abcd’, balance=5000}

方法结束,事务也未提交,可看见数据“回滚”了。

  • 正确执行过程
    错误的执行过程即方式二未检测出脏读,具体就不予演示了。

testTransactionSelect()为什么获取了两次连接?

手动创建了一个链接,方法中又创建了一个链接。
DeBug测试错误代码
错误详情

隔离级别 “修改不成功” ?

可以修改,但是setTransactionIsolation()修改的是当前会话的隔离级别。
有两个原因导致我为什么判断修改不成功:

  1. 这个测试事务始终未提交
  2. 测试有Bug,也就是建了两个链接,两个链接的事务等级还不同,测试不出想要的结果。

两个JunitTest是两个事务连接还是一个事务连接?

是一个事务链接!(至少每个JunitTest获取的第一个链接是相同的)

事务的提交与连接的关闭?

testTransactionSelectUpdate()方法执行结束后,自动回滚数据?

可以理解为自动回滚吧(不清楚原理是否和自动回滚一样,但是结果是一样的)。
事务的一致性,要么提交,要么回滚,这里什么都没操作,而且autocommit是false,结果和回滚一样的,什么都没发生。

可以见以下代码分析:

//设置不自动提交直接断开链接,结果和自动回滚一样,也就是什么都没做
//设置不自动提交也不断开链接也就是什么都不操作,让方法直接结束,结果和自动回滚一样,也就是什么都没做
//其实就是事务的一致性
@Test
    public void testUpdate() throws Exception {

        String sql1 = "update user_table set balance = balance - 100 where user = ?";
        Connection conn = JDBCUtils.getConnection();
        boolean autoCommit = conn.getAutoCommit();
        System.out.println(autoCommit);
        conn.setAutoCommit(false);
        update(conn,sql1, "AA");

        //模拟网络异常
//        System.out.println(10 / 0);

        String sql2 = "update user_table set balance = balance + 100 where user = ?";
        update(conn,sql2, "BB");

        JDBCUtils.closeResource(conn,null);
        System.out.println("转账成功!");

    }

以上问题均已解决…

错误测试时的代码

//********************************************
    @Test
    public void testTransactionSelect() throws Exception {
        Connection conn = JDBCUtils.getConnection();
        //获取当前连接的隔离级别
        System.out.println(conn.getTransactionIsolation());
        //设置数据库的隔离级别
        conn.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);
        //取消自动提交数据
        conn.setAutoCommit(false);

        String sql = "select * from user_table where user=?";
        User user = getInstance(conn,User.class, sql, "CC");
        System.out.println(user);

    }

    @Test
    public void testTransactionUpdate() throws Exception {
        Connection conn1 = JDBCUtils.getConnection();

        //取消自动提交数据
        conn1.setAutoCommit(false);

        String sql = "update user_table set balance = ? where user = ?";
        update(conn1,sql,6600,"CC");

        Thread.sleep(15000);
        System.out.println("修改结束");

    }

    //通用的查询操作,用于返回数据表中的一条记录(version 2.0 :考虑上事务)
    public <T> T getInstance(Connection conn,Class<T> clazz,String sql,Object... args){

        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            conn = JDBCUtils.getConnection();
            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();

            if (rs.next()) {
                T t = clazz.newInstance();
                for (int i = 0; i < rsmd.getColumnCount(); i++) {
                    //获取每个列的列值:通过ResultSet
                    Object columnValue = rs.getObject(i + 1);
                    //通过ResultSetMetaDate
                    //获取每个列的列名:getColumnName() -- 不推荐使用
//                    String columnName = rsmd.getColumnName(i + 1);
                    //获取列的别名:getColumnLabel()
                    String columnLabel = rsmd.getColumnLabel(i + 1);
                    //通过反射,将对象指定名columnName的属性值指定的值columnValue
                    Field field = t.getClass().getDeclaredField(columnLabel);
                    field.setAccessible(true);
                    field.set(t, columnValue);

                }
                return t;
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.closeResource(null, ps, rs);
        }
        return null;
    }

 //通用的增删改操作 ---version 2.0(考虑上事务)
    public int update(Connection conn, String sql, Object... args) {//sql中占位符的个数应与可变形参长度一致

        PreparedStatement ps = null;
        try {

            //1.预编译sql语句,返回PreparedStatement的实例Connection conn = JDBCUtils.getConnection();
            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.资源的关闭
            JDBCUtils.closeResource(null, ps);
        }

        return 0;
    }

public class JDBCUtils {



    /**
     * @return java.sql.Connection
     * @Author 
     * @Description 获取数据库的连接 //TODO
     * @Date  2020/11/6
     * @Param []
     */
    public static Connection getConnection() throws Exception {
        //1.读取配置文件中4个基本信息
        InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties");

        Properties pros = new Properties();
        pros.load(is);

        String password = pros.getProperty("password");
        String user = pros.getProperty("user");
        String url = pros.getProperty("url");
        String driverClass = pros.getProperty("driverClass");

        //2.加载驱动
        Class.forName(driverClass);

        //3.获取连接
        Connection connection = DriverManager.getConnection(url, user, password);
        System.out.println(connection);

        return connection;
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值