数据库事务

来源:互联网 发布:查找html源码 编辑:程序博客网 时间:2024/06/18 04:36

一.事务的概念

事务指的是逻辑上的一组操作,组成这组操作的各个单元要么全都成功执行,要么全都失败不执行
事务的作用:保证在一个事务中的多个操作的执行与否一致(都执行或都不执行)

二.常见事务操作

2.1 MySQL的事务操作:

和事务操作相关的SQL语句:

SQL语句 功能 start transaction 开启事务 commit 提交事务 rollback 回滚事务

MySQL的事务使用案例:

1.准备工作:

选择数据库表,并准备点数据(我用一个已有的库和表)

这里写图片描述

//查看所有数据库show databases;//选中shop库use shop//查询shop库中orders表中的所有数据(没有数据就搞一点)select * from orders;

开始时total=7926的数据name值为“lili”

2.设置事务是否自动提交

//查看MySQL事务提交方式show variables like '%commit%';

这里写图片描述

autocommit属性的值代表属性提交方式(OFF为不自动提交,ON为自动提交)

//设置事务不自动提交 0对应OFF关闭,1对应ON开启set autocommit = 0

3.事务手动提交示例:

这里写图片描述
3.1执行更新后执行回滚

start transaction;update orders set name='feifei' where total = 7926;rollback;

这里写图片描述

使用rollback后事务回滚,更新方法没有执行,lili的值没有变

3.2执行更新后不执行回滚

这里写图片描述

start transaction;update orders set name='feifei' where total = 7926;commit;

这里写图片描述

使用commit方法将事务提交,更新语句执行,lili变为feifei

2.2JDBC的事务操作

JDBC通过Connection类的方法进行事务开启/提交/回滚

方法 功能 setAutoCommit(false) 开启事务 commit( ) 提交事务 rollback( ) 回滚事务

2.3DBUtils的事务操作

DBUtils的事务操作涉及Connection类和QueryRunner类

方法 方法所属的类 功能 setAutoCommit(false) Connection类 开启事务,与JDBC相同 query(….)和update(…) QueryRunner类 手动传递连接 commitAndClose(Connection conn) QueryRunner类 提交事务,关闭连接 rollbackAndClose(Connection conn) QueryRunner类 回滚事务,关闭连接

三.事务使用案例:

黑马商城订单付款模块,向商家转账
1.我的订单页面order_list.jsp,点击付款

这里写图片描述

2.order_info.jsp确认订单

这里写图片描述

3.transfer.jsp确认付款

这里写图片描述

4.OrderServlet接受参数,调用后台OrderService
5.在OrderService中进行事务管理

    public void transfer(String name, String to, String money) throws SQLException, ClassNotFoundException {        int money_int = Integer.parseInt(money);        /**1.创建连接对象*/        Connection connection = null;        try {            /**2.开启数据库连接,整个事务操作中,只能有这一个数据库连接,若开启了多个连接,则无法正确的完成数据库事务的管理*/            connection = JDBCUtils.getDataSource();            /**3.开启事务*/            connection.setAutoCommit(false);            /**4.1 事务操作,转出,connection作为参数传递*/            orderDao.outMoney(connection,name,money_int);            /**4.2 事务操作,转入,connection作为参数传递*/            orderDao.inMoney(connection,to,money_int);            事务操作,转出            /**5.事务提交*/            connection.commit();        }catch (Exception e){            try{                if (connection != null){                    /**6.发生错误则事务回滚*/                    connection.rollback();                }            }catch (Exception e2){            }            throw new RuntimeException(e);        }finally {            /**7.关闭数据库资源*/            JDBCUtils.closeResouce(connection,null,null);        }    }

6.OrderDao中进行事务的数据库操作

@Override    public void outMoney(Connection connection, String username, int money) throws SQLException {        Statement statement = null;        PreparedStatement preparedStatement = null;        try {            String qsql = "SELECT name FROM user WHERE username = '"+  username + "'";            statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,CONCUR_READ_ONLY);            ResultSet resultSet = statement.executeQuery(qsql);            boolean bool = resultSet.first();            String name = resultSet.getString("name");            /**转出操作*/            String sql = "update useraccount set money = money - ? where name = ?";            preparedStatement = connection.prepareStatement(sql);            preparedStatement.setInt(1,money);            preparedStatement.setString(2,name);            int change = preparedStatement.executeUpdate();            System.out.println(change);        }catch (Exception e){            throw new RuntimeException(e);        }finally {            //关闭资源            JDBCUtils.closeResouce(null,preparedStatement,null);        }    }    @Override    public void inMoney(Connection connection, String to, int money) throws SQLException {        PreparedStatement preparedStatement = null;        try {            /**转入操作*/            String sql = "update selleraccount set money = money + ? where name = ?";            preparedStatement = connection.prepareStatement(sql);            preparedStatement.setInt(1,money);            preparedStatement.setString(2,to);            int change = preparedStatement.executeUpdate();            System.out.println(change);        }catch (Exception e){            throw new RuntimeException(e);        }finally {            /**关闭资源*/            JDBCUtils.closeResouce(null,preparedStatement,null);        }    }

优化:使用ThreadLocal代替传递数据库连接

在以上的代码中,Connection数据库连接对象在Service层创建,不符合分层管理的理念,可以使用ThreadLocal类来进行部分优化,不再将Connection对象作为参数进行传递

1.ThreadLocal简介:

该类提供了线程局部 (thread-local)变量。只有和该变量在同一线程中,才能访问该线程局部变量
ThreadLocal 实例通常是类中的 private static 字段,通常将状态与某一个线程(例如,用户 ID 或事务 ID)相关联,用于在一个线程中共享数据
ThreadLocal 的构造方法和普通方法:
这里写图片描述

2.改进转账程序:

1.改写utils层JDBCUtils类中的获取数据库连接的方法:

//创建静态私有变量ThreadLocalprivate static ThreadLocal<Connection> local = new ThreadLocal<Connection>();//创建获取数据库连接的方法public static Connection getConnection() throws ClassNotFoundException, SQLException {        Class.forName("com.mysql.jdbc.Driver");        try{            //从当前线程中获取连接对象            Connection connection = local.get();            //如果连接对象为空,则是第一次使用,调用DriverManager创建连接对象            if (connection == null){                connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/shop", "root", "123");                local.set(connection);            }            return connection;        }catch (Exception e){            throw new RuntimeException(e);        }    }

2.OrderService

Connection connection = null;        try {            connection = JDBCUtils.getConnection();            connection.setAutoCommit(false);            /**不再传递连接对象*/            orderDao.outMoney(name,money_int);            orderDao.inMoney(to,money_int);            connection.commit();        }

3.OrderDao
使用getConnection( )方法获取数据库连接

connection = JDBCUtils.getConnection();
原创粉丝点击