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批处理
- 使用占位符创建SQL语句。
- 使用prepareStatement() 方法创建PrepareStatement对象。
- 使用setAutoCommit()将auto-commit设置为false 。
- 使用addBatch()方法在创建的语句对象上添加您喜欢的SQL语句到批处理中。
- 在创建的语句对象上使用executeBatch()方法执行所有SQL语句。
- 最后,使用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的时候将不会回到事务的起点,而是回到保存点。