Java个人总结——JDBC的批处理、事务和二进制文件存储

版权声明:以上所有博客均为冷漠的小猿所有,引用请注明出处 https://blog.csdn.net/lyf1997115/article/details/82531742

JDBC批处理

批量处理允许你将相关的SQL语句分组到批处理中,并通过对数据库的一次调用提交它们。
当需要一次向数据库发送多个SQL语句时,可以减少连接数据库的开销,从而提高性能。

1.1 Statement批处理

以下是使用语句对象的批处理的典型步骤序列

  • 使用createStatement()方法创建Statement对象。
  • 使用setAutoCommit()将auto-commit设置为false 。(可选)
  • 使用addBatch()方法在创建的语句对象上添加您喜欢的SQL语句到批处理中。
  • 在创建的语句对象上使用executeBatch()方法执行所有SQL语句。
  • 最后,使用commit()方法提交所有更改。(可选)

setAutoCommit () : 自动提交事务。默认为true 即自动提交事务,一般将其改为手动提交。

实例:

// 获得statement对象
Statement stmt = conn.createStatement();

// 设置自动提交为false
conn.setAutoCommit(false);

// 新建SQL语句
String SQL = "INSERT INTO Employees (id, first, last, age) " +
             "VALUES(200,'Zia', 'Ali', 30)";
// 向批处理添加SQL语句 
stmt.addBatch(SQL);

// 新建SQL语句
String SQL = "INSERT INTO Employees (id, first, last, age) " +
             "VALUES(201,'Raj', 'Kumar', 35)";
// 向批处理添加SQL语句
stmt.addBatch(SQL);

// 新建SQL语句
String SQL = "UPDATE Employees SET age = 35 " +
             "WHERE id = 100";
// 向批处理添加SQL语句
stmt.addBatch(SQL);

// 执行批处理
int[] count = stmt.executeBatch();

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

1.2 PrepareStatement批处理

  1. 使用占位符创建SQL语句。
  2. 使用prepareStatement() 方法创建PrepareStatement对象。
  3. 使用setAutoCommit()将auto-commit设置为false 。
  4. 使用addBatch()方法在创建的语句对象上添加您喜欢的SQL语句到批处理中。
  5. 在创建的语句对象上使用executeBatch()方法执行所有SQL语句。
  6. 最后,使用commit()方法提交所有更改。
// Create SQL statement
String SQL = "INSERT INTO Employees (id, first, last, age) " +
             "VALUES(?, ?, ?, ?)";

// Create PrepareStatement object
PreparedStatemen pstmt = conn.prepareStatement(SQL);

//Set auto-commit to false
conn.setAutoCommit(false);

// Set the variables
pstmt.setInt( 1, 400 );
pstmt.setString( 2, "Pappu" );
pstmt.setString( 3, "Singh" );
pstmt.setInt( 4, 33 );
// Add it to the batch
pstmt.addBatch();

// Set the variables
pstmt.setInt( 1, 401 );
pstmt.setString( 2, "Pawan" );
pstmt.setString( 3, "Singh" );
pstmt.setInt( 4, 31 );
// Add it to the batch
pstmt.addBatch();

//add more batches

//Create an int[] to hold returned values
int[] count = stmt.executeBatch();

//Explicitly commit statements to apply changes
conn.commit();

JDBC操作二进制

PreparedStatement对象可以使用输入和输出流来提供参数数据。这使您可以将整个文件放入可以保存大值的数据库列,例如Text和BLOB数据类型。

有以下方法可用于流式传输数据 -

  • setAsciiStream():此方法用于使用ASCII码的形式来传输数据
  • setCharacterStream():此方法使用UNICODE编码来传输数据
  • setBinaryStream():此方法使用二进制的方式传输数据,(常用于传输图片、音频等)

setXXXStream()方法除了参数占位符之外还需要传入一个流和一个长度[长度可选]。
考虑我们要将XML文件Emp.xml上传到数据库表中。
这是XML文件的内容:

<?xml version="1.0" encoding="UTF-8"?>
<Employee>
  <id>100</id>
  <first>Zara</first>
  <last>Ali</last>
  <Salary>10000</Salary>
  <Dob>18-08-1978</Dob>
</Employee>

既然是文件的传输,那我们必然会用到流的操作。

public class Demo3 {
    public static void main(String[] args) throws Exception{
         insert();
         query();
    }
    public static void insert() throws Exception{
        //1创建连接
        Connection conn=DbUtils.getConnection();
        //2创建命令对象
        PreparedStatement pstat=conn.prepareStatement("insert into bigdata(data) values(?)");
        //3设置参数
        FileInputStream fis=new FileInputStream("src\\Emp.xml");
        FileReader fr=new FileReader("src\\Emp.xml");
        //pstat.setBinaryStream(1,fis) ; // 使用二进制传输,需要传入字节流
        //pstat.setAsciiStream(1,fis) ;  // 使用ASCII码传输,需要传入字节流
        pstat.setCharacterStream(1, fr); // 使用字符数据传入,需要传入字符流
        //4执行
        int count=pstat.executeUpdate();
        System.out.println(count);
        //5关闭
        pstat.close();
        conn.close();
        System.out.println("执行成功");
    }
    public static void query() throws Exception {
        //1创建连接
        Connection conn=DbUtils.getConnection();
        //2创建命令对象
        PreparedStatement pstat=conn.prepareStatement("select * from bigdata where id=2");
        //3执行
        ResultSet rs=pstat.executeQuery();
        //4处理
        if(rs.next()) {
            InputStream is=rs.getBinaryStream(2); //使用二进制方式读取,得到一个字节流对象
            //InputStream is=rs.getAsciiStream(2); //使用ASCII码方式读取,得到一个字节流对象
            //Reader r=rs.getCharacterStream(2); //使用字符编码方式读取,得到一个字符流对象
            FileOutputStream fos=new FileOutputStream("src\\Emp2.xml");
            byte[] buf=new byte[1024];
            int len=0;
            while((len=is.read(buf))!=-1) {
                fos.write(buf,0,len);
            }
            fos.close();
        }
        //5关闭
        rs.close();
        pstat.close();
        conn.close();
        System.out.println("执行成功。。。。。");
    }
}

三、 数据库事务

  • 数据库事务(Database Transaction) ,是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。
  • 事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不会永久更新面向数据的资源。
  • 通过将一组相关操作组合为一个要么全部成功要么全部失败的单元,可以简化错误恢复并使应用程序更加可靠。
  • 一个逻辑工作单元要成为事务,必须满足所谓的ACID(原子性、一致性、隔离性和持久性)属性。事务是数据库运行中的逻辑工作单位,由DBMS中的事务管理子系统负责事务的处理。

事务开始于

  • 连接到数据库上,并执行一条DML语句insert、update或delete
  • 前一个事务结束后,又输入了另一条DML语句

事务结束于

  • 执行commit或rollback语句。
  • 执行一条DDL语句,例如create table语句,在这种情况下,会自动执行commit语句。
  • 执行一条DDL语句,例如grant语句,在这种情况下,会自动执行commit。
  • 断开与数据库的连接
  • 执行了一条DML语句,该语句却失败了,在这种情况中,会为这个无效的DML语句执行rollback语句。

执行commit 将会提交事务中的所有数据,执行后无法退回
执行rollback 将会废除事务中所有操作,将数据还原到执行事务之前的状态。

事务的四大特点

(ACID)面试常见问题

  • Actomicity(原子性)

      表示一个事务内的所有操作是一个整体,要么全部成功,要么全部失败

  • Consistency(一致性)

      表示一个事务内有一个操作失败时,所有的更改过的数据都必须回滚到修改前状态

  • Isolation(隔离性)

      事务查看数据时数据所处的状态,要么是另一并发事务修改它之前的状态,要么是另一事务修改它之后的状态,事务不会查看中间状态的数据。

  • Durability(持久性)

      持久性事务完成之后,它对于系统的影响是永久性的。

事务的应用场景:转账

假设A要给B转账,而A将钱转出后,在B还没有转入前,如果银行机器出现了故障,则A将会丢失他所转出的前,且B收不到钱。
为了避免此类时间的发生,我们需要将转出和转入绑定到一起,要么一起成功,要么一起失败
public class Test_03 {

    public static void main(String[] args) {
        //使用自定义工具类获取数据库连接
        Connection conn = DBUtils.getConnection();
        Statement st = null;
        try {
            //开启事务
            conn.setAutoCommit(false);
            st = conn.createStatement();
            st.executeUpdate("UPDATE money SET money = money-1000 WHERE id=1");
            int a = 10 / 0; //出现异常
            st.executeUpdate("UPDATE money SET money = money+1000 WHERE id=2");
            System.out.println("转账成功");
            //全部成功则提交事务
            conn.commit();
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("转账失败");
            try {
            //出现异常则回滚事务
                conn.rollback();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
        } finally {
            ...
        }
    }

}

Savepoint
保存点 : 用于定位回滚的位置
即:当执行rollback的时候将不会回到事务的起点,而是回到保存点。

猜你喜欢

转载自blog.csdn.net/lyf1997115/article/details/82531742