java牛马之路17-数据库的事务

事务

MySQL:每一条语句都属于独立事务,默认自动管理提交的。

如果需要把多条语句当成一个整体,那么就需要把多条语句放在一个事务里面

开启事务:start transaction

提交事务:commit;

回滚事务:rollback

JDBC控制事务语句

Connection.setAutoCommit(false);   start transaction

Connection.rollback();  rollback

Connection.commit();  commit

例子

模拟一个转账的功能,用事务来控制

public static void main(String[] args) {

        Connection connection = null;
        PreparedStatement statement1 = null;
        PreparedStatement statement2 = null;
        try {
            connection = DBUtil.getConnection();

            //开启事务
            connection.setAutoCommit(false);

            String sql1 = "UPDATE bank SET money=money-200 WHERE id=1;";
            statement1 = connection.prepareStatement(sql1);
            statement1.executeUpdate();

//            System.out.println(10/0);

            String sql2 = "UPDATE bank SET money=money+200 WHERE id=2;";
            statement2 = connection.prepareStatement(sql2);
            statement2.executeUpdate();

            //提交事务
            connection.commit();

        } catch (Exception e) {

            //回滚事务
            if(connection != null){
                try {
                    connection.rollback();
                } catch (SQLException ex) {
                    throw new RuntimeException(ex);
                }
            }


        } finally {
            DBUtil.close(null,statement2,null);
            DBUtil.close(connection,statement1,null);
        }





    }
}

事务的特点

事务的特性:ACID

原子性( Atomicity )、一致性( Consistency )、隔离性( Isolation )和持久性( Durability )

原子性:事务是数据库的逻辑工作单位,事务中包含的各操作要么都完成,要么都不完成

一致性:事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。因此当数据库只包含成功事务提交的结果时,就说数据库处于一致性状态。如果数据库系统 运行中发生故障,有些事务尚未完成就被迫中断,这些未完成事务对数据库所做的修改有一部分已写入物理数据库,这时数据库就处于一种不正确的状态,或者说是 不一致的状态。

隔离性:一个事务的执行不能其它事务干扰。即一个事务内部的操作及使用的数据对其它并发事务是隔离的,并发执行的各个事务之间不能互相干扰。

持久性:指一个事务一旦提交,它对数据库中的数据的改变就应该是永久性的。接下来的其它操作或故障不应该对其执行结果有任何影响。 

事务的隔离级别:

属于事务的。都已开启了事务为前提。

不考虑事务的隔离级别,会出现以下的情况

  1. 脏读:一个线程中的事务读到了另外一个线程中未提交的数据。
  2. 不可重复读:一个线程中的事务读到了另外一个线程中已经提交的update的数据。
  3. 虚读:一个线程中的事务读到了另外一个线程中已经提交的insert的数据。

要想避免以上现象,通过更改事务的隔离级别来避免:

  1. READ UNCOMMITTED 脏读、不可重复读、虚读有可能发生。
  2. READ COMMITTED 避免脏读的发生,不可重复读、虚读有可能发生。
  3. REPEATABLE READ 避免脏读、不可重复读的发生,虚读有可能发生。
  4. SERIALIZABLE 避免脏读、不可重复读、虚读的发生。

set transaction isolation level READ COMMITTED;

级别依次升高,效率依次降低。

MySQL:默认REPEATABLE READ

ORACLE:默认READ COMMITTED

MySQL:

SELECT @@SESSION.transaction_isolation;//查看当前的隔离级别

set transaction isolation level  级别;// 设置当前的事务隔离级别

练习:read uncommitted;

时间

T1

T2

说明

t1

start transaction

t2

select * from account where id=1;

1000

t3

start transaction

t4

update account set balance=balance+100 where id=1;

t5

select * from account where id=1;

1100

读到了另外一个线程中未提交的数据:脏读

t6

commit;

t7

select * from account where id=1;

1100

读到了另外一个线程中提交的update数据:不可重复读

t8

select count(*) from account;

2

t9

insert into account values(3,'wangwu',1000);

t10

select count(*) from account;

3

读到了另外一个线程中提交的insert数据:虚读(幻读)

t11

commit;

JDBC设置隔离级别

批处理 --- 批量处理sql语句

1.多条不一样的sql语句

  public static void main(String[] args) throws SQLException {

        Connection connection = DBUtil.getConnection();
        Statement statement = connection.createStatement();

        //将多条sql命令添加到Batch包中
        String sql1 = "insert into student(name,course_id,class_id,age) values('ccc',1,3,20)";
        String sql2 = "update student set age=19 where id=2";
        statement.addBatch(sql1);
        statement.addBatch(sql2);

        //发送Batch包
        statement.executeBatch();

        DBUtil.close(connection,statement,null);
    }
}

2.多条SQL命令一样但参数不一样

public static void main(String[] args) throws SQLException {

        Connection connection = DBUtil.getConnection();

        String sql = "insert into student(name,course_id,class_id,age) values(?,1,3,20)";
        PreparedStatement statement = connection.prepareStatement(sql);

        for (int i = 1; i <= 20; i++) {
            statement.setString(1,"小黑"+i);
            statement.addBatch();
        }

        statement.executeBatch();

        DBUtil.close(connection,statement,null);

    }
}

多条SQL命令一样但参数不一样- 大量数据

 public static void main(String[] args) throws SQLException {

        Connection connection = DBUtil.getConnection();

        connection.setAutoCommit(false);

        String sql = "insert into student(name,course_id,class_id,age) values(?,1,3,20)";
        PreparedStatement statement = connection.prepareStatement(sql);

        for (int i = 1; i <= 20000; i++) {
            statement.setString(1,"小红"+i);
            statement.addBatch();

            if(i%1000 == 0){
                statement.executeBatch();
                statement.clearBatch();//清空Batch包中的数据
            }
        }

        connection.commit();

        DBUtil.close(connection,statement,null);

    }
}

CBLob

JDBC可以向数据库存储二进制数据或长文本数据
* BLob - Binary(二进制)Lob - 存储二进制数据 - 注意:数据库字段类型 - BLOB/LONGBLOB
* CLob - Character(字符)Lob - 存储长文本数据 - 注意:数据库字段类型 - TEXT/LONGTEXT

blob

 public void test01() throws SQLException, FileNotFoundException {
        //将图片插入到数据库中

        Connection connection = DBUtil.getConnection();

        String sql = "insert into cblob(b_lob) values (?)";
        PreparedStatement statement = connection.prepareStatement(sql);

        InputStream in = new FileInputStream("葵司.jpg");
        statement.setBinaryStream(1,in);
        statement.executeUpdate();

        DBUtil.close(connection,statement,null);
    }

    @Test
    public void test02() throws SQLException, IOException {
        //将数据库中的图片读取到本地

        Connection connection = DBUtil.getConnection();

        String sql = "select * from cblob where id=1";
        PreparedStatement statement = connection.prepareStatement(sql);

        ResultSet resultSet = statement.executeQuery();
        if(resultSet.next()){

            InputStream in = resultSet.getBinaryStream("b_lob");
            FileOutputStream out = new FileOutputStream("copyImg.jpg");
            byte[] bs = new byte[1024];
            int len;
            while((len = in.read(bs)) != -1){
                out.write(bs,0,len);
            }

            in.close();
            out.close();
            DBUtil.close(connection,statement,resultSet);
        }


    }

}

clob

public void test01() throws SQLException, FileNotFoundException {
        //将长文本数据插入到数据库中

        Connection connection = DBUtil.getConnection();

        String sql = "insert into cblob(c_lob) values (?)";
        PreparedStatement statement = connection.prepareStatement(sql);

        FileReader reader = new FileReader("小说.txt");
        statement.setCharacterStream(1,reader);
        statement.executeUpdate();

        DBUtil.close(connection,statement,null);
    }

    @Test
    public void test02() throws SQLException, IOException {
        //将数据库中的长文本数据读取到本地

        Connection connection = DBUtil.getConnection();

        String sql = "select * from cblob where id=2";
        PreparedStatement statement = connection.prepareStatement(sql);

        ResultSet resultSet = statement.executeQuery();
        if(resultSet.next()){

            Reader reader = resultSet.getCharacterStream("c_lob");
            FileWriter writer = new FileWriter("copyText.txt");
            char[] cs = new char[1024];
            int len;
            while((len = reader.read(cs)) != -1){
                writer.write(cs,0,len);
            }

            reader.close();
            writer.close();
            DBUtil.close(connection,statement,resultSet);
        }


    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值