事务应用-Dao的综合应用

一、事务应用

1、事务定义

​ 用于完成一件事件的独立单元 例如:我们在数据库操作的时候,对数据库的一次更新可以认为是一个事务,业务中银行转账也可以是一个事务(余额的变更)

2、事务的四个特性

​ a、原子性: 一个事务在执行过程中, 要么全部执行,要么全部不执行,不可能停滞了中途,及时中途失败了,也会回滚到初始状态, 事务是一个不可分割的独立单元

​ b、一致性: 事务体现在数据库操作中,在事务开始前和结束后,它们的完整性约束没有被破坏,保持前后一致

​ c、隔离性: 同一时间 ,只允许一个事务处理同一条数据 , 事务和事务相互独立并隔离, 多个事务之间处理同一条数据 必须考虑事务的隔离级别问题

​ d、持久性: 事务可以提交(commit),也可以回滚(rollbck) ,事务一旦提交将永久生效,事务的回滚可以返回到修改之前的状态。

3、MySql中事务演示

​ 默认情况下,MySql的事务是自动提交 ,

​ 查询事务的提交方式

show variables  like 'autocommit';

​ ON:自动 OFF:关闭

更改事务的提交方式

set @@autocommit =0 ;

​ 注意 以上只能更改当前窗口的事务提交方式,如果需要全局更改 ,需要在my.ini下 添加如下

set @@autocommit =0 ; 然后重启mysql服务

-- 手动提交事务 
select * from t_user;
update t_user set money =400 where userid =1;
-- 对于没有提交的记录 ,会锁行(行级锁)
commit;
rollback;

事务的并发产生的问题

1、 脏读: 事务A 读取了 事务B未提交的数据 ,假如事务B 对数据更新后,事务A读取了一次,事务B对数据回滚了, 事务A再次读取一次,事务A发现 第一次读的数据是脏数据。

2、不可重复读: 事务A多次读取同一条记录,事务B在期间进行提交了,到时事务A读取的数据前后不一致,这是属于 不可重复读 。

3、幻读: 对于新增记录而言, 事务A第一次读取 与第二个读取的表数据总行数 不一致 ,不一致原因是 在期间事务B可能添加了记录 ,导致事务A出现 幻觉多了一条记录。

MySql的默认隔离级别: 可重复读取

select @@transaction_isolation

REPEATABLE-READ

修改MySql的隔离级别:

	set session transaction isolation level read committed ;

隔离级别 脏读 不可重复读 幻读
读未提交数据(read uncommitted)
读已提交数据(read committed)
可重复读(repeatable-read )
序列化(serializable)

4、JDBC中 事务的手动提交

默认情况下 JDBC的事务是自动提交的, 由于在特定的业务场景下 一个事务需要执行多个sql语句 ,例如转账业务 ,账户A给账户B转账100元, 账户A的余额需要减少100 , 而账户B的余额要增加100 (2个sql)

  public static void main(String[] args) {
          // 账户A  给账户B 转账
        MyUser fromUser = new MyUser();
        fromUser.setUserid(1);

        MyUser toUser = new MyUser();
        toUser.setUserid(2);
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入转账的金额");
        double money  = sc.nextDouble();

        // 获取连接对象
       Connection conn  = null;
        PreparedStatement ps = null;
       // 设置该连接为 手动提交事务
        try {
            conn =  DBUtil.getConn();
            conn.setAutoCommit(false);
            String sql1 = "update t_user set money = money-"+money +" where userid = ?";
            ps = conn.prepareStatement(sql1);
            // 设置参数
            ps.setInt(1,fromUser.getUserid());
            // 执行
           int count1=   ps.executeUpdate();
            System.out.println("count1----"+count1);

           //模拟突然断电
            System.out.println(10/0);

           //  另一个账户的钱 增多
            sql1 =  "update t_user set money = ifnull(money,0)+"+money +" where userid = ?";
            ps = conn.prepareStatement(sql1);
            ps.setInt(1,toUser.getUserid());
            //执行
            int count2 = ps.executeUpdate();
            System.out.println("count2----"+count2);

            // 提交事务
            conn.commit();;
            System.out.println("转账成功");
        } catch (Exception e) {
            e.printStackTrace();
            // 回滚
            try {
                conn.rollback();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
            System.out.println("转账失败");
        } finally {
            //关闭连接
            DBUtil.closeAll(conn , ps , null);
        }
    }

二、DAO的综合应用

​ 创建图书表和 用户表 ,完成后台图书管理系统。

1、建立独立项目: 项目包括 dao 、entity、 util包

​ dao中不同的表提供不同的接口 和 实现类

​ entity中提供对应表的实体类

​ util包装 提供 DBUtil类

写一个控制台程序,调用 dao的实现类 (BookDaoImpl、UserDaoImpl)

完成功能:

​ 1、用户登录,用户注册(注册时验证用户是否存在)

​ 2、图书管理: 添加图书,删除图书,修改图书,查询所有图书,根据ID查询图书。

b_user : 用户id 用户名 密码 状态

book :图书id ,图书名,图书作者,图书价格,图书发布时间 ,图书所属的userid (外键)

项目分层:

项目名

​ -|src

​ -| com.j2008

​ -|util : DBUtil.java

​ -| entity: XXX.java ...

​ -|dao: XXXDao.java

​ XXXDaoImpl.java

​ -| client : 测试类 控制台输入

posted @ 2020-11-28 18:23  落雨♡̶初晴  阅读(131)  评论(0编辑  收藏  举报