美文网首页
JavaWeb-Jdbc中使用事物

JavaWeb-Jdbc中使用事物

作者: Tian_Peng | 来源:发表于2020-01-06 10:36 被阅读0次

    原文连接:http://www.cnblogs.com/xdp-gacl/p/3984001.html
    创建数据库和测试表

    create database if NOT EXISTS jdbcStudy character set utf8 collate utf8_general_ci;
    use jdbcStudy;
    drop TABLE if exists `account`;
    create table account(
                          id int primary key auto_increment,
                          name varchar(40),
                          money float
    )ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    insert into account(name,money) values('A',1000);
    insert into account(name,money) values('B',1000);
    insert into account(name,money) values('C',1000);
    

    当Jdbc程序向数据库获得一个Connection对象时,默认情况下这个Connection对象会自动向数据库提交在它上面发送的SQL语句
    若想关闭这种默认提交方式,让多条SQL在一个事务中执行,可使用下列的JDBC控制事务语句:

    • Connection.setAutoCommit(false); //开启事务(start transaction)
    • Connection.rollback(); //回滚事务(rollback)
    • Connection.commit(); //提交事务(commit)

    JDBC使用事务范例

    在JDBC代码中演示银行转帐案例,使如下转帐操作在同一事务中执行:
    update account set money=money-100 where name='A'
    update account set money=money+100 where name='B'
    代码如下:

    public class JdbcTransactionTest {
        /**
         * @Method: testTransaction1
         * @Description: 模拟转账成功时的业务场景
         * @Anthor:TP
         */
        @Test
        public void testTransaction1() {
            Connection conn = null;
            PreparedStatement st = null;
            ResultSet rs = null;
            try {
                conn = JdbcUtils.getConnection();
                conn.setAutoCommit(false);//通知数据库开启事务(start transaction)
                String sql1 = "update account set money=money-100 where name='A'";
                st = conn.prepareStatement(sql1);
                st.executeUpdate();
                String sql2 = "update account set money=money+100 where name='B'";
                st = conn.prepareStatement(sql2);
                st.executeUpdate();
                conn.commit();//上面的两条SQL执行Update语句成功之后就通知数据库提交事务(commit)
                System.out.println("成功!!!");  //log4j
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                JdbcUtils.release(conn, st, rs);
            }
        }
    
        /**
         * @Method: testTransaction2
         * @Description: 模拟转账过程中出现异常导致有一部分SQL执行失败后让数据库自动回滚事务
         * @Anthor:TP
         */
        @Test
        public void testTransaction2() {
            Connection conn = null;
            PreparedStatement st = null;
            ResultSet rs = null;
            try {
                conn = JdbcUtils.getConnection();
                conn.setAutoCommit(false);//通知数据库开启事务(start transaction)
                String sql1 = "update account set money=money-100 where name='A'";
                st = conn.prepareStatement(sql1);
                st.executeUpdate();
                //用这句代码模拟执行完SQL1之后程序出现了异常而导致后面的SQL无法正常执行,事务也无法正常提交,此时数据库会自动执行回滚操作
                int x = 1 / 0;
                String sql2 = "update account set money=money+100 where name='B'";
                st = conn.prepareStatement(sql2);
                st.executeUpdate();
                conn.commit();//上面的两条SQL执行Update语句成功之后就通知数据库提交事务(commit)
                System.out.println("成功!!!");
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                JdbcUtils.release(conn, st, rs);
            }
        }
    
        /**
         * @Method: testTransaction3
         * @Description: 模拟转账过程中出现异常导致有一部分SQL执行失败时手动通知数据库回滚事务
         * @Anthor:TP
         */
        @Test
        public void testTransaction3() {
            Connection conn = null;
            PreparedStatement st = null;
            ResultSet rs = null;
    
            try {
                conn = JdbcUtils.getConnection();
                conn.setAutoCommit(false);//通知数据库开启事务(start transaction)
                String sql1 = "update account set money=money-100 where name='A'";
                st = conn.prepareStatement(sql1);
                st.executeUpdate();
                //用这句代码模拟执行完SQL1之后程序出现了异常而导致后面的SQL无法正常执行,事务也无法正常提交
                int x = 1 / 0;
                String sql2 = "update account set money=money+100 where name='B'";
                st = conn.prepareStatement(sql2);
                st.executeUpdate();
                conn.commit();//上面的两条SQL执行Update语句成功之后就通知数据库提交事务(commit)
                System.out.println("成功!!!");
            } catch (Exception e) {
                try {
                    //捕获到异常之后手动通知数据库执行回滚事务的操作
                    conn.rollback();
                } catch (SQLException e1) {
                    e1.printStackTrace();
                }
                e.printStackTrace();
            } finally {
                JdbcUtils.release(conn, st, rs);
            }
        }
    }
    

    设置事务回滚点

    在开发中,有时候可能需要手动设置事务的回滚点,在JDBC中使用如下的语句设置事务回滚点

    Savepoint sp = conn.setSavepoint();
    Conn.rollback(sp);
    Conn.commit();//回滚后必须通知数据库提交事务
    

    设置事务回滚点范例:

    public class JdbcTransactionRollBackPointTest {
    
        /**
         * @Method: testTransaction1
         * @Description: 模拟转账成功时的业务场景
         * @Anthor:TP
         */
        @Test
        public void testTransaction1() {
            Connection conn = null;
            PreparedStatement st = null;
            ResultSet rs = null;
            Savepoint sp = null;
    
            try {
                conn = JdbcUtils.getConnection();
                conn.setAutoCommit(false);//通知数据库开启事务(start transaction)
    
                String sql1 = "update account set money=money-100 where name='A'";
                st = conn.prepareStatement(sql1);
                st.executeUpdate();
    
                //设置事务回滚点
                sp = conn.setSavepoint();
    
                String sql2 = "update account set money=money+100 where name='B'";
                st = conn.prepareStatement(sql2);
                st.executeUpdate();
    
                //程序执行到这里出现异常,后面的sql3语句执行将会中断
                int x = 1 / 0;
    
                String sql3 = "update account set money=money+100 where name='C'";
                st = conn.prepareStatement(sql3);
                st.executeUpdate();
    
                conn.commit();
    
            } catch (Exception e) {
                try {
                    /**
                     * 我们在上面向数据库发送了3条update语句,
                     * sql3语句由于程序出现异常导致无法正常执行,数据库事务而已无法正常提交,
                     * 由于设置的事务回滚点是在sql1语句正常执行完成之后,sql2语句正常执行之前,
                     * 那么通知数据库回滚事务时,不会回滚sql1执行的update操作
                     * 只会回滚到sql2执行的update操作,也就是说,上面的三条update语句中,sql1这条语句的修改操作起作用了
                     * sql2的修改操作由于事务回滚没有起作用,sql3由于程序异常没有机会执行
                     */
                    conn.rollback(sp);//回滚到设置的事务回滚点
                    conn.commit();//回滚了要记得通知数据库提交事务
                } catch (SQLException e1) {
                    e1.printStackTrace();
                }
                e.printStackTrace();
            } finally {
                JdbcUtils.release(conn, st, rs);
            }
        }
    }
    

    其中JdbcUtils.java代码如下:

    public class JdbcUtils {
        private static String driver;
        private static String url;
        private static String username;
        private static String password;
    
        static {
            try {
                //读取db.properties文件中的数据库连接信息
                InputStream in = JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");
                Properties prop = new Properties();
                prop.load(in);
    
                //获取数据库连接驱动
                driver = prop.getProperty("driver");
                //获取数据库连接URL地址
                url = prop.getProperty("url");
                //获取数据库连接用户名
                username = prop.getProperty("username");
                //获取数据库连接密码
                password = prop.getProperty("password");
    
                //加载数据库驱动
                Class.forName(driver);
    
            } catch (Exception e) {
                throw new ExceptionInInitializerError(e);
            }
        }
    
        /**
         * @return Connection 数据库连接对象
         * @throws SQLException
         * @Method: getConnection
         * @Description: 获取数据库连接对象
         * @Anthor:TP
         */
        public static Connection getConnection() throws SQLException {
            return DriverManager.getConnection(url, username, password);
        }
    
        /**
         * @param conn 数据库连接对象
         * @param st   Statement
         * @param rs   rs
         * @Method: release
         * @Description: 释放资源
         * 要释放的资源包括Connection数据库连接对象,负责执行SQL命令的Statement对象,存储查询结果的ResultSet对象
         * @Anthor:TP
         */
        public static void release(Connection conn, Statement st, ResultSet rs) {
            if (rs != null) {
                try {
                    //关闭存储查询结果的ResultSet对象
                    rs.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            if (st != null) {
                try {
                    //关闭负责执行SQL命令的Statement对象
                    st.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
    
            if (conn != null) {
                try {
                    //关闭Connection数据库连接对象
                    conn.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    

    相关文章

      网友评论

          本文标题:JavaWeb-Jdbc中使用事物

          本文链接:https://www.haomeiwen.com/subject/pzbhactx.html