游标操作方式-分批查询
游标提供一种客户端读取部分服务器端结果集的机制。
当 sql 语句的匹配条件太弱时,sql 结果会返回大量的数据,就有可能导出出现内存溢出。所以就出现了将结果分批处理的方式;
流程:
1.在配置 JDBC URL 时,在最后加上参数: useCursorFetch=true
开启游标属性
static String DB_URL = "jdbc:mysql://localhost:3306/test?useCursorFetch=true"
2.创建 preparedSatement 对象,在使用 prepareStatement 方法创建对象时,预编译 sql 语句。
conn.prepareStatement(sql,游标类型,能否更新记录);
游标类型:
ResultSet.TYPE_FORWORD_ONLY:只进游标
ResultSet.TYPE_SCROLL_INSENSITIVE:可滚动。但是不受其他用户对数据库更改的影响。
ResultSet.TYPE_SCROLL_SENSITIVE:可滚动。当其他用户更改数据库时这个记录也会改变。
能否更新记录:
ResultSet.CONCUR_READ_ONLY,只读
ResultSet.CONCUR_UPDATABLE,可更新
3.使用 setFetchSize 方法,设置分批处理的结果数
4.通过 setString 方法传入条件参数,第一个参数表示 参数位置,第二个参数为条件值
preparedSatement 可以写动态参数化查询
preparedSatement 可以预编译 sql 语句
preparedSatement 可以防止SQL注入式攻击
代码实例:
import java.sql.*;
public class Main {
static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
static String DB_URL = "jdbc:mysql://localhost:3306/test?useSSL=true";
static final String USER = "root";
static final String PASSWORD = "admin";
public static void main(String[] args) throws ClassNotFoundException{
Connection conn = null;
Statement statement = null;
PreparedStatement preparedStatement = null;
ResultSet rs = null;
// 1. 装载数据库驱动程序;
Class.forName(JDBC_DRIVER);
// 2. 通过JDBC建立数据库连接;
try {
//在 url 中 开启 游标属性
DB_URL = DB_URL + "&useCursorFetch=true";
conn = DriverManager.getConnection(DB_URL,USER,PASSWORD);
// 3.访问数据库,执行SQL语句;
// statement = conn.createStatement();
// rs = statement.executeQuery("select name from test.user ");
// 对 preparedStatement 的 sql 语句进行预编译, ? 表示参数
preparedStatement = conn.prepareStatement("select * from test.ipdata where id=? and startip = ?");
// 通过 preparedStatement 使用游标 进行分批查询语句
preparedStatement.setFetchSize(1);
// 通过setInt 或者 setString 将,预编译的 sql 语句中的 条件参数传递进去
preparedStatement.setInt(1,13);
preparedStatement.setString(2,"16844800");
rs = preparedStatement.executeQuery();
// 4.获得执行结果
while(rs.next()) {
System.out.println("Hello " + rs.getString("country"));
}
} catch (SQLException e) {
// 异常处理
e.printStackTrace();
} finally {
// 5. 断开数据库连接,清理环境
try {
if(conn != null) {
conn.close();
}
if(statement != null) {
statement.close();
}
if(rs != null) {
rs.close();
}
} catch (SQLException e) {
// pass
}
}
}
}
大对象读取-流方式
当读取大对象时,有可能出现对象内容太大,内存放不下,从而出现的内存溢出问题。
主要涉及方法 ResultSet.getBinaryStream() 方法。
流程
- 通过对 ResultSet 对象使用 getBinaryStream() 获取流对象。
- 每次读取流对象中的一行内容输出到外部文件中
- 重复2 步骤,直至读取完流对象内容。
public static void main(String[] args) throws ClassNotFoundException {
Connection conn = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
Class.forName(JDBC_DRIVER);
try {
conn = DriverManager.getConnection(JDBC_URL, USER, PASSWORD);
// 创建 preparedStatement 对象
preparedStatement = conn.prepareStatement("select * from blog where id = ?");
preparedStatement.setInt(1, 1);
// 执行 sql
resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
// 获取对象流
InputStream in = resultSet.getBinaryStream("context");
// 将对象流写入文件
File f = new File(FILE_URL);
OutputStream out = new FileOutputStream(f);
int temp = 0;
while ((temp = in.read()) != -1) {//边读边写
out.write(temp);
}
in.close();
out.close();
}
} catch (SQLException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (conn != null)
conn.close();
if (preparedStatement != null)
preparedStatement.close();
if (resultSet != null)
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
一条语句多条执行- sql 的批处理
流程:
- statement 对象使用 addBatch() 方法添加 sql 语句
- statement 对象使用 executeBatch() 方法执行所有添加的 sql 语句
- statement 对象使用 clearBatch() 方法清空已执行的 sql 语句
public class HelloBatch {
static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
static String DB_URL = "jdbc:mysql://localhost:3306/test?useSSL=true";
static final String USER = "root";
static final String PASSWORD = "admin";
static void insertUsers(Set<String> users) throws ClassNotFoundException{
Connection conn = null;
Statement statement = null;
ResultSet rs = null;
// 1. 装载数据库驱动程序;
Class.forName(JDBC_DRIVER);
// 2. 通过JDBC建立数据库连接;
try {
conn = DriverManager.getConnection(DB_URL,USER,PASSWORD);
// 3.访问数据库,执行SQL语句;
statement = conn.createStatement();
// 添加 sql 语句到 Batch
for (String user : users) {
statement.addBatch("insert into user(name) values ('" + user + "')");
System.out.println("insert into user(name) values (" + user + ")");
}
// 批执行 sql 语句
statement.executeBatch();
// 清空已执行语句
statement.clearBatch();
} catch (SQLException e) {
// 异常处理
e.printStackTrace();
} finally {
// 5. 断开数据库连接,清理环境
try {
if(conn != null) {
conn.close();
}
if(statement != null) {
statement.close();
}
if(rs != null) {
rs.close();
}
} catch (SQLException e) {
// pass
}
}
}
public static void main(String[] args) throws ClassNotFoundException {
Set<String> users = new HashSet<>();
users.add("GuoYi");
users.add("GuoEi");
users.add("GuoSi");
insertUsers(users);
}
}
jdbc 设置字符集
在 JDBC URL 中添加参数 characterEncoding=utf8