[MySql 三] 事務(wù)&數(shù)據(jù)庫連接池&DBUtils

1. 事務(wù)

Transaction 其實(shí)指的一組操作,里面包含許多個(gè)單一的邏輯。只要有一個(gè)邏輯沒有執(zhí)行成功,那么都算失敗。 所有的數(shù)據(jù)都回歸到最初的狀態(tài)(回滾)

  • 為什么要有事務(wù)?

為了確保邏輯的成功。 例子: 銀行的轉(zhuǎn)賬。

1.1 使用命令行方式演示事務(wù)。

  • 開啟事務(wù)
start transaction;
  • 提交或者回滾事務(wù)
commit; 提交事務(wù), 數(shù)據(jù)將會寫到磁盤上的數(shù)據(jù)庫
rollback ;  數(shù)據(jù)回滾,回到最初的狀態(tài)。
  1. 關(guān)閉自動(dòng)提交功能。


    img01.png
  2. 演示事務(wù)


    img02.png

1.2 使用代碼方式演示事務(wù)

代碼里面的事務(wù),主要是針對連接來的。

  1. 通過conn.setAutoCommit(false )來關(guān)閉自動(dòng)提交的設(shè)置。
  2. 提交事務(wù) conn.commit();
  3. 回滾事務(wù) conn.rollback();
@Test
    public void testTransaction(){
        
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            conn = JDBCUtil.getConn();
            
            //連接,事務(wù)默認(rèn)就是自動(dòng)提交的。 關(guān)閉自動(dòng)提交。
            conn.setAutoCommit(false);
            
            String sql = "update account set money = money - ? where id = ?";
            ps = conn.prepareStatement(sql);
            
            //扣錢, 扣ID為1 的100塊錢
            ps.setInt(1, 100);
            ps.setInt(2, 1);
            ps.executeUpdate();
            
            
            int a = 10 /0 ;
            
            //加錢, 給ID為2 加100塊錢
            ps.setInt(1, -100);
            ps.setInt(2, 2);
            ps.executeUpdate();
            
            //成功: 提交事務(wù)。
            conn.commit();
            
        } catch (SQLException e) {
            try {
                //事變: 回滾事務(wù)
                conn.rollback();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
            e.printStackTrace();
            
        }finally {
            JDBCUtil.release(conn, ps, rs);
        }
    }

1.3 事務(wù)的特性

  • 原子性

指的是 事務(wù)中包含的邏輯,不可分割。

  • 一致性

指的是 事務(wù)執(zhí)行前后。數(shù)據(jù)完整性

  • 隔離性

指的是 事務(wù)在執(zhí)行期間不應(yīng)該受到其他事務(wù)的影響

  • 持久性

指的是 事務(wù)執(zhí)行成功,那么數(shù)據(jù)應(yīng)該持久保存到磁盤上。

1.4 事務(wù)的安全隱患

不考慮隔離級別設(shè)置,那么會出現(xiàn)以下問題。

  • 臟讀:一個(gè)事務(wù)讀到另外一個(gè)事務(wù)還未提交的數(shù)據(jù)。
  • 不可重復(fù)讀:一個(gè)事務(wù)讀到了另外一個(gè)事務(wù)提交的數(shù)據(jù) ,造成了前后兩次查詢結(jié)果不一致。
  • 幻讀:一個(gè)事務(wù)讀到了另一個(gè)事務(wù)insert的數(shù)據(jù) ,造成前后查詢結(jié)果不一致 。

  • 丟失更新

1.5 可串行化

如果有一個(gè)連接的隔離級別設(shè)置為了串行化 ,那么誰先打開了事務(wù), 誰就有了先執(zhí)行的權(quán)利, 誰后打開事務(wù),誰就只能得著,等前面的那個(gè)事務(wù),提交或者回滾后,才能執(zhí)行。 但是這種隔離級別一般比較少用。 容易造成性能上的問題。 效率比較低。

1.6 總結(jié)

分類

  • 按效率劃分,從高到低

讀未提交 > 讀已提交 > 可重復(fù)讀 > 可串行化

  • 按攔截程度 ,從高到底

可串行化 > 可重復(fù)讀 > 讀已提交 > 讀未提交

問題
讀未提交

引發(fā)問題: 臟讀

讀已提交

解決: 臟讀 , 引發(fā): 不可重復(fù)讀

可重復(fù)讀

解決: 臟讀 、 不可重復(fù)讀 , 未解決: 幻讀

可串行化

解決: 臟讀、 不可重復(fù)讀 、 幻讀。

mySql 默認(rèn)的隔離級別是 可重復(fù)讀
Oracle 默認(rèn)的隔離級別是 讀已提交

2. 數(shù)據(jù)庫連接池

2.1 DBCP

  1. 導(dǎo)入jar文件

不使用配置文件方式:

    public void testDBCP01(){
    
        
        Connection conn = null;
        PreparedStatement ps = null;
        try {
            
            //1. 構(gòu)建數(shù)據(jù)源對象
            BasicDataSource dataSource = new BasicDataSource();
            //連的是什么類型的數(shù)據(jù)庫, 訪問的是哪個(gè)數(shù)據(jù)庫 , 用戶名, 密碼。。
            //jdbc:mysql://localhost/bank 主協(xié)議:子協(xié)議 ://本地/數(shù)據(jù)庫
            dataSource.setDriverClassName("com.mysql.jdbc.Driver");
            dataSource.setUrl("jdbc:mysql://localhost/bank");
            dataSource.setUsername("root");
            dataSource.setPassword("root");
            
            
            //2. 得到連接對象
            conn = dataSource.getConnection();
            String sql = "insert into account values(null , ? , ?)";
            ps = conn.prepareStatement(sql);
            ps.setString(1, "admin");
            ps.setInt(2, 1000);
            
            ps.executeUpdate();
            
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JDBCUtil.release(conn, ps);
        }
        
    }

使用配置文件方式:

    Connection conn = null;
    PreparedStatement ps = null;
    try {
        BasicDataSourceFactory factory = new BasicDataSourceFactory();
        Properties properties = new Properties();
        InputStream is = new FileInputStream("src//dbcpconfig.properties");
        properties.load(is);
        DataSource dataSource = factory.createDataSource(properties);
        
        //2. 得到連接對象
        conn = dataSource.getConnection();
        String sql = "insert into account values(null , ? , ?)";
        ps = conn.prepareStatement(sql);
        ps.setString(1, "liangchaowei");
        ps.setInt(2, 100);
        
        ps.executeUpdate();
        
    } catch (Exception e) {
        e.printStackTrace();
    }finally {
        JDBCUtil.release(conn, ps);
    }

2.2 C3P0

1 .拷貝jar文件 到 lib目錄

不使用配置文件方式

    Connection conn = null;
    PreparedStatement ps = null;
    try {
        //1. 創(chuàng)建datasource
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        //2. 設(shè)置連接數(shù)據(jù)的信息
        dataSource.setDriverClass("com.mysql.jdbc.Driver");
        
        //忘記了---> 去以前的代碼 ---> jdbc的文檔
        dataSource.setJdbcUrl("jdbc:mysql://localhost/bank");
        dataSource.setUser("root");
        dataSource.setPassword("root");
        
        //2. 得到連接對象
        conn = dataSource.getConnection();
        String sql = "insert into account values(null , ? , ?)";
        ps = conn.prepareStatement(sql);
        ps.setString(1, "admi234n");
        ps.setInt(2, 103200);
        
        ps.executeUpdate();
        
    } catch (Exception e) {
        e.printStackTrace();
    }finally {
        JDBCUtil.release(conn, ps);
    }

使用配置文件方式

        //默認(rèn)會找 xml 中的 default-config 分支。 
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        
        // 得到連接對象
        conn = dataSource.getConnection();
        String sql = "insert into account values(null , ? , ?)";
        ps = conn.prepareStatement(sql);
        ps.setString(1, "admi234n");
        ps.setInt(2, 103200);

3. DBUtils

3.1 增刪改

            //dbutils 只是幫我們簡化了CRUD 的代碼, 但是連接的創(chuàng)建以及獲取工作。 不在他的考慮范圍
    QueryRunner queryRunner = new QueryRunner(new ComboPooledDataSource());

    
    //增加
    //queryRunner.update("insert into account values (null , ? , ? )", "aa" ,1000);
    
    //刪除
    //queryRunner.update("delete from account where id = ?", 5);
    
    //更新
    //queryRunner.update("update account set money = ? where id = ?", 10000000 , 6);

3.2 查詢

  1. 直接new接口的匿名實(shí)現(xiàn)類
    QueryRunner queryRunner = new QueryRunner(new ComboPooledDataSource());


    Account  account =  queryRunner.query("select * from account where id = ?", new ResultSetHandler<Account>(){

        @Override
        public Account handle(ResultSet rs) throws SQLException {
            Account account  =  new Account();
            while(rs.next()){
                String name = rs.getString("name");
                int money = rs.getInt("money");
                
                account.setName(name);
                account.setMoney(money);
            }
            return account;
        }
         
     }, 6);
    
    System.out.println(account.toString());
  1. 直接使用框架已經(jīng)寫好的實(shí)現(xiàn)類。
* 查詢單個(gè)對象

    QueryRunner queryRunner = new QueryRunner(new ComboPooledDataSource());
    //查詢單個(gè)對象
    Account account = queryRunner.query("select * from account where id = ?", 
            new BeanHandler<Account>(Account.class), 8);


* 查詢多個(gè)對象

    QueryRunner queryRunner = new QueryRunner(new ComboPooledDataSource());
    List<Account> list = queryRunner.query("select * from account ",
            new BeanListHandler<Account>(Account.class));

3.3 ResultSetHandler 常用的實(shí)現(xiàn)類

以下兩個(gè)是使用頻率最高的
BeanHandler, 查詢到的單個(gè)數(shù)據(jù)封裝成一個(gè)對象
BeanListHandler, 查詢到的多個(gè)數(shù)據(jù)封裝 成一個(gè)List<對象>


ArrayHandler, 查詢到的單個(gè)數(shù)據(jù)封裝成一個(gè)數(shù)組
ArrayListHandler, 查詢到的多個(gè)數(shù)據(jù)封裝成一個(gè)集合 ,集合里面的元素是數(shù)組。

MapHandler, 查詢到的單個(gè)數(shù)據(jù)封裝成一個(gè)map
MapListHandler,查詢到的多個(gè)數(shù)據(jù)封裝成一個(gè)集合 ,集合里面的元素是map。

ColumnListHandler
KeyedHandler
ScalarHandler

c3p0_demo

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容