JavaWeb-Jdbc中使用事物

2020-01-06  本文已影响0人  Tian_Peng

原文连接: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控制事务语句:

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();
            }
        }
    }
上一篇下一篇

猜你喜欢

热点阅读