zoukankan      html  css  js  c++  java
  • Java -- JDBC学习笔记6、事务

    1、事务

    数据库系统保证在一个事务中的所有SQL要么全部执行成功,要么全部不执行。就像转账一样、任何一方出现异常,那么转账就无法成功。

    1.1、JDBC事务

    JDBC事务,就是在Java中用来控制数据库事务的。JDBC的一切行为包括事务是基于一个Connection的,通过Connection对象进行事务管理。常用的和事务相关的方法是: setAutoCommit、commit、rollback等。

    1.1.1、setAutoCommit()

    • 开启事务的关键代码是conn.setAutoCommit(false),表示关闭自动提交。

    1.1.2、commit()

    • 提交事务的代码在执行完指定的若干条SQL语句后,调用conn.commit()提交事务。

    1.1.3、rollback()

    • 如果出现异常,就使用rollback()方法回滚事务。

    2、案列

    新建Java项目、模拟银行转账功能、使用JDBC事务保证数据的完整性。

    2.1、具体实现

    • 在数据库中新建Account表,里边四个字段、分别是:主键(卡号)、密码、金额、姓名。再添加两条数据,如图:
    • 新建实体类,添加字段、get和set方法、构造方法。
    • 完善DBTutils工具类,再添加三个方法、分别是:开启事务、提交事务、回滚事务。另外,将首次获取的连接对象存放到ThreadLocal中,那么本次操作至始至终就用这一个连接对象。
    public class DBUtils
    {
        private static final ResourceBundle resourceBundle;
        private static ThreadLocal<Connection> threadLocal = new ThreadLocal<>();
    
        static
        {
            resourceBundle = ResourceBundle.getBundle("db");
            try
            {
                Class.forName(resourceBundle.getString("dirver"));
            }
            catch (ClassNotFoundException e)
            {
                e.printStackTrace();
            }
        }
    
        public static Connection getConnection()
        {
            Connection conn = threadLocal.get();
            try
            {
                if (conn == null)
                {
                    conn = DriverManager.getConnection(resourceBundle.getString("url"), resourceBundle.getString("user"), resourceBundle.getString("password"));
                    threadLocal.set(conn);
                }
            }
            catch (SQLException sqlException)
            {
                sqlException.printStackTrace();
            }
            return conn;
        }
    
        public static void closeDb(Connection conn, Statement statement, ResultSet rs)
        {
            try
            {
                if (conn != null)
                {
                    conn.close();
                    threadLocal.remove();//释放连接后,将threadlocal中的连接对象移除
                }
                if (statement != null)
                {
                    statement.close();
                }
                if (rs != null)
                {
                    rs.close();
                }
            }
            catch (SQLException sqlException)
            {
                sqlException.printStackTrace();
            }
        }
        //开启事务
        public static void begin()
        {
            try
            {
                Connection conn = getConnection();
                conn.setAutoCommit(false);
            }
            catch (SQLException sqlException)
            {
                sqlException.printStackTrace();
            }
        }
        public static void commit()
        {
            Connection conn = null;
            try
            {
                conn = getConnection();
                conn.commit();
            }
            catch (SQLException sqlException)
            {
                sqlException.printStackTrace();
            }
            finally
            {
                //提交事务后释放连接资源
                closeDb(conn, null, null);
            }
        }
        public static void rollback()
        {
            Connection conn = null;
            try
            {
                conn = getConnection();
                conn.rollback();
            }
            catch (SQLException sqlException)
            {
                sqlException.printStackTrace();
            }
            finally
            {
                //回滚后释放连接资源
                closeDb(conn, null, null);
            }
        }
    
    • 在Dao层新建接口AccountDao,定义两个方法、分别是查询和修改,如下:
    public interface AccountDao
    {
        //根据id查询表数据
        public Account select(int id);
        //修改Account表数据
        public int update(Account account);
    }
    
    • 实现AccountDao接口
    public class AccountDaoImpl implements AccountDao
    {
        @Override
        public Account select(int id)
        {
            //实例化Account对象
            Account account = new Account();
            PreparedStatement preparedStatement = null;
            ResultSet rs = null;
            try
            {
                //根据卡号查询表数据
                String sql = "select id,pwd,balance,name from Account where id=?";
                Connection conn = DBUtils.getConnection();
                preparedStatement = conn.prepareStatement(sql);
                preparedStatement.setInt(1, id);
    
                rs = preparedStatement.executeQuery();
    
                while (rs.next())
                {
                    int aid = rs.getInt(1);
                    String pwd = rs.getString(2);
                    double balance = rs.getDouble(3);
                    String name = rs.getString(4);
                    account.setId(aid);
                    account.setPwd(pwd);
                    account.setBalance(balance);
                    account.setName(name);
                }
            }
            catch (SQLException sqlException)
            {
                sqlException.printStackTrace();
            }
            finally
            {
                DBUtils.closeDb(null, preparedStatement, rs);
            }
            return account;
        }
    
        public int update(Account account)
        {
            Connection conn = null;
            PreparedStatement preparedStatement = null;
            String sql = "update Account set pwd=?,balance=?,name=? where id=?";
            try
            {
                conn = DBUtils.getConnection();
                preparedStatement = conn.prepareStatement(sql);
                preparedStatement.setString(1, account.getPwd());
                preparedStatement.setDouble(2, account.getBalance());
                preparedStatement.setString(3, account.getName());
                preparedStatement.setInt(4, account.getId());
                int result = preparedStatement.executeUpdate();
                return result;
            }
            catch (SQLException sqlException)
            {
                sqlException.printStackTrace();
            }
            finally
            {
                DBUtils.closeDb(null, preparedStatement, null);
            }
            return 0;
        }
    
    • 在service层中创建接口AccountService
    public interface AccountService
    {
        /**
         *
         * @param fromId:转账卡号
         * @param toId:接收转账卡号
         * @param pwd:密码
         * @param money:转账金额
         */
        public void transfer(int fromId, int toId, String pwd, double money);
    }
    
    • 实现service接口,如下:
    @Override
        public void transfer(int fromId, int toId, String pwd, double money)
        {
            AccountDao accountDao = new AccountDaoImpl();
            try
            {
                //开启事务
                DBUtils.begin();
    
                Account account = accountDao.select(fromId);
                //判断卡号是否正确
                if (account == null)
                {
                    throw new RuntimeException("卡号有误");
                }
                //判断密码是否正确
                if (!pwd.equals(account.getPwd()))
                {
                    throw new RuntimeException("密码有误");
                }
                //判断金额是否充足
                if (account.getBalance() < money)
                {
                    throw new RuntimeException("余额不足");
                }
                Account toAccount = accountDao.select(toId);
                //判断对方卡号是否正确
                if (toAccount == null)
                {
                    throw new RuntimeException("对方卡号不存在");
                }
                //修改账户金额、减去转账金额
                account.setBalance(account.getBalance() - money);
                accountDao.update(account);
    
                //修改对方账户金额,加上转入金额
                toAccount.setBalance(toAccount.getBalance() + money);
                accountDao.update(toAccount);
                System.out.println("转账成功");
    
                //提交事务
                DBUtils.commit();
            }
            catch (RuntimeException e)
            {
                System.out.println("转账失败");
                DBUtils.rollback();//回滚事务
                e.printStackTrace();
            }
        }
    

    概括来讲、就是先设置conn.setAutoCommit(false)、代码顺利执行完成后使用conn.commit()提交事务,如果有异常就rollback()回滚事务。另外、不管是提交事务还是回滚事务,都要将连接对象释放。

  • 相关阅读:
    base.View.OpenParameter.CreateFrom打开历史单据的值是default
    创建日期时间大于启动日期时间
    下拉列表不显示空白选项的原因
    复制、下推、选单时计算类的实体服务规则不会执行
    选单返回数据以后会执行的事件方法
    判断单据体是否录入行
    供应商协同平台
    .net core获取运行时文件绝对路径
    gmock函数参数输出 备忘录
    リバース 終章
  • 原文地址:https://www.cnblogs.com/dcy521/p/14731144.html
Copyright © 2011-2022 走看看