学习java—第四十二天学习笔记

147 阅读5分钟

2019.8.27 NIIT第四十二天 /*问题:? Properties ps = new Properties();

ps.load(this.getClass().getClassLoader().getResourceAsStream("db.properties")); */

事务管理

事务概述

  • 事务指的是逻辑上的一组操作,组成这组操作的各个单元要么全都成功,要么全都失败.
  • 事务作用:保证在一个事务中多次操作要么全都成功,要么全都失败. 关键字:start transactions

commit判断sql是否都执行成功,如果不成功,把数据刷到数据表中,如果执行失败,不去更新表 rollback将数据回滚到修改前

sql语句在内存中运行,然后通过commit将内存中的数据与数据库中的数据同步,发生sql错误则不同步 测试的时候可以使用cmd进行演示

JDBC事务操作

Connection对象的方法名 描述 conn.setAutoCommit(false) 开启事务 conn.commit() 提交事务 conn.rollback() 回滚事务

事务代码: 如果要进行事务操作,需要把事务操作的代码,放在try-catch 之内

package com.igeek1;

import org.junit.Test;

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;

public class TesTrancation {
    @Test
    public void m1(){
        Connection conn=null;
        Statement st=null;
       
        try {
            //获取连接
            conn=JDBCTools.getConn();
            //开启事务,设置自动提交
            conn.setAutoCommit(false);
            st=conn.createStatement();
            //执行sql语句
            String sql="";
            sql="update account set money=money-1000 where name='冠希'";
            st.executeUpdate(sql);
            sql="update account set money=money+1000 where name='美美'";
            st.executeUpdate(sql);
            //提交数据
            conn.commit();
        } catch (SQLException e) {
            //5、一旦出错,回滚事务
            try {
                conn.rollback();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
            e.printStackTrace();
        }finally {
            //关闭连接
            JDBCTools.closeCon(conn,st);
        }

    }

}

DBUtils事务操作

Connection对象的方法名 描述 conn.setAutoCommit(false) 开启事务 new QueryRunner() 创建核心类,不设置数据源(手动管理连接) query(conn , sql , handler, params ) 或 update(conn, sql , params) 手动传递连接 DbUtils.commitAndClose(conn) 提交并关闭连接 DbUtils.rollbackAndClose(conn) 回顾并关闭连接 使用DbUtils操作事务

package com.igeek1;

import org.apache.commons.dbutils.DbUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.junit.Test;

import java.sql.Connection;
import java.sql.SQLException;

public class TestDBUtils {
    @Test
    public void m1(){
        //通过连接池获取连接
        Connection conn=JDBCTools.getConn();

        QueryRunner qr=new QueryRunner();
        String sql="";

        try {
            conn.setAutoCommit(false);
            sql="update account set money=money-1000 where name='冠希'";
            qr.update(conn,sql);
            sql="update account set money=money+1000 where name='美美'";
            qr.update(conn,sql);
            DbUtils.commitAndClose(conn);

        } catch (SQLException e) {
            e.printStackTrace();
            try {
                DbUtils.rollbackAndClose(conn);
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
        }
    }
}

tips:使用DbUtils.commitAndCloseQuietly();不会产生异常

分层思想

  •  开发中,常使用分层思想
  •  不同的层次结构分配不同的解决过程,各个层次间组成严密的封闭系统
  •  不同层级结构彼此平等
  •  分层的目的是:
  •  解耦 降低模块间的关联度
  •  可维护性
  •  可扩展性
  •  可重用性
  •  不同层次,使用不同的包表示
  •  com.igeek 公司域名倒写
  •  com.igeek.dao dao层//data access object 把数据库操作代码都写在dao中(各种操作数据库的java类,放在同一个包下)
  •  com.igeek.service service层//业务层 把各种业务代码都写在server层(各种业务类,放在同一个包下)
  •  com.igeek.domain javabean
  •  com.igeek.utils 工具 分层思想实现登录操作:

转账案例

事务操作:dao层必须抛出异常,在service层去处理异常

ThreadLocal:可以在层共享数据的一个容器(Map<k,v>) 测试层

@Test
    public void testTransfer(){
        accountService as=new accountService();

        as.transfer();
    }

service层

 public void transfer(){
        accountDao adao=new accountDao();
        Connection conn=JDBCTools.getConnection();
        JDBCTools.local.set(conn);

        try {
            conn.setAutoCommit(false);
            double money=1000;

            adao.out("冠希",money);
            adao.in("美美",money);

            DbUtils.commitAndClose(conn);

        } catch (SQLException e) {
            e.printStackTrace();
            try {
                DbUtils.rollbackAndClose(conn);
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
        }
    }

dao层

 public void out(String outName, double v) throws SQLException {
        QueryRunner qr=new QueryRunner();
        String sql="update account set money=money-? where name=?";
        System.out.println("out"+JDBCTools.local.get());
        qr.update(JDBCTools.local.get(),sql,v,outName);
    }

    public void in(String inName, double v) throws SQLException {
        QueryRunner qr=new QueryRunner();
        String sql="update account set money=money+? where name=?";
        System.out.println("in"+JDBCTools.local.get());
        qr.update(JDBCTools.local.get(),sql,v,inName);
    }

事务特性:ACID

面试重点记忆

  •  原子性(Atomicity)原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
  •  一致性(Consistency)事务前后数据的完整性必须保持一致。
  •  隔离性(Isolation)事务的隔离性是指多个用户并发访问数据库时,一个用户的事务不能被其它用户的事务所干扰,多个并发事务之间数据要相互隔离。
  •  持久性(Durability)持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响。

并发访问问题

  • 如果不考虑隔离性,事务存在3种并发访问问题。
    1. 脏读:一个事务读到了另一个事务未提交的数据.
    1. 不可重复读:一个事务读到了另一个事务已经提交(update)的数据。引发另一个事务,在事务中的多次查询结果不一致。
    1. 虚读 /幻读:一个事务读到了另一个事务已经提交(insert)的数据。导致另一个事务,在事务中多次查询的结果不一致。

隔离级别:解决问题

  •  数据库规范规定了4种隔离级别,分别用于描述两个事务并发的所有情况。
    1. read uncommitted 读未提交,一个事务读到另一个事务没有提交的数据。
  • a) 存放:3个问题(脏读、不可重复读、虚读)。
  • b) 解决:0个问题
    1. read committed 读已提交,一个事务读到另一个事务已经提交的数据。
  • a) 存放:2个问题(不可重复读、虚读)。
  • b) 解决:1个问题(脏读)
    1. repeatable read :可重复读,在一个事务中读到的数据始终保持一致,无论另一个事务是否提交。
  • a) 存放:1个问题(虚读)。
  • b) 解决:2个问题(脏读、不可重复读)
    1. serializable 串行化,同时只能执行一个事务,相当于事务中的单线程。
  • a) 存放:0个问题。
  • b) 解决:3个问题(脏读、不可重复读、虚读)
  •  安全和性能对比
  •  安全性:serializable > repeatable read > read committed > read uncommitted
  •  性能 : serializable < repeatable read < read committed < read uncommitted
  •  常见数据库的默认隔离级别:
  •  MySql:repeatable read
  •  Oracle:read committed

查询数据库的隔离级别

show variables like '%isolation%'; 或 select @@tx_isolation;

设置数据库的隔离级别

set session transaction isolation level 级别字符串