目录
Blob类型字段
批量插入
数据库事务
Blob类型字段
概述:MySQL中,Blob是一个二进制大型对象,是一个可以存储大量数据的容器,它能容纳不同大小的数据。
说明:插入Blob类型的数据必须使用PreparedStatement,因为Blob类型的数据无法使用字符串拼接写。
介绍:MySQL的四种Blob类型 (除了在存储的最大信息量上不同外,他们是等同的),实际使用中根据需要存入的数据大小定义不同的Blob类型。
注意:
- 如果存储的文件过大,数据库的性能会下降
- 如果在指定了相关的Blob类型以后,还报错:xxx too large,那么在mysql的安装目录下,找my.ini文件加上如下的配置参数:max_allowed_packet=16M,同时注意:修改了my.ini文件之后,需要重新启动mysql服务
代码实现:插入、查询Blob类型的数据
//向数据表customers中插入Blob类型的字段
@Test
public void testInsert() throws Exception {
//获取连接
Connection conn = JDBCUtils.getConnection();
String sql = "insert into customers(name,email,birth,photo)values(?,?,?,?)";
PreparedStatement ps = conn.prepareStatement(sql);
//填充占位符
ps.setObject(1, "薛之谦");
ps.setObject(2, "xuezq@qq.com");
ps.setObject(3, "1983-7-17");
//操作Blob类型的变量
FileInputStream is = new FileInputStream(new File("x.jpg"));
ps.setBlob(4, is);
//执行
ps.execute();
JDBCUtils.closeResource(conn, ps);
}
//查询数据表customers中Blob类型的字段
@Test
public void testQuery() {
Connection conn = null;
PreparedStatement ps = null;
InputStream is = null;
FileOutputStream fos = null;
ResultSet rs = null;
try {
conn = JDBCUtils.getConnection();
String sql = "select id,name,email,birth,photo from customers where id=?";
ps = conn.prepareStatement(sql);
ps.setInt(1, 22);
//执行
rs = ps.executeQuery();
if (rs.next()) {
int id = rs.getInt("id");
String name = rs.getString("name");
String email = rs.getString("email");
Date birth = rs.getDate("birth");
Customer cust = new Customer(id, name, email, birth);
System.out.println(cust);
//将Blob类型的字段下载下来,以文件的方式保存在本地
Blob photo = rs.getBlob("photo");
is = photo.getBinaryStream();
fos = new FileOutputStream("xzq.jpg");
byte[] buffer = new byte[1024];
int len;
while ((len = is.read(buffer)) != -1) {
fos.write(buffer, 0, len);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (is != null)
is.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (fos != null)
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
JDBCUtils.closeResource(conn, ps, rs);
}
}
概述:MySQL中,Blob是一个二进制大型对象,是一个可以存储大量数据的容器,它能容纳不同大小的数据。
说明:插入Blob类型的数据必须使用PreparedStatement,因为Blob类型的数据无法使用字符串拼接写。
介绍:MySQL的四种Blob类型 (除了在存储的最大信息量上不同外,他们是等同的),实际使用中根据需要存入的数据大小定义不同的Blob类型。
注意:
- 如果存储的文件过大,数据库的性能会下降
- 如果在指定了相关的Blob类型以后,还报错:xxx too large,那么在mysql的安装目录下,找my.ini文件加上如下的配置参数:max_allowed_packet=16M,同时注意:修改了my.ini文件之后,需要重新启动mysql服务
代码实现:插入、查询Blob类型的数据
//向数据表customers中插入Blob类型的字段
@Test
public void testInsert() throws Exception {
//获取连接
Connection conn = JDBCUtils.getConnection();
String sql = "insert into customers(name,email,birth,photo)values(?,?,?,?)";
PreparedStatement ps = conn.prepareStatement(sql);
//填充占位符
ps.setObject(1, "薛之谦");
ps.setObject(2, "xuezq@qq.com");
ps.setObject(3, "1983-7-17");
//操作Blob类型的变量
FileInputStream is = new FileInputStream(new File("x.jpg"));
ps.setBlob(4, is);
//执行
ps.execute();
JDBCUtils.closeResource(conn, ps);
}
//查询数据表customers中Blob类型的字段
@Test
public void testQuery() {
Connection conn = null;
PreparedStatement ps = null;
InputStream is = null;
FileOutputStream fos = null;
ResultSet rs = null;
try {
conn = JDBCUtils.getConnection();
String sql = "select id,name,email,birth,photo from customers where id=?";
ps = conn.prepareStatement(sql);
ps.setInt(1, 22);
//执行
rs = ps.executeQuery();
if (rs.next()) {
int id = rs.getInt("id");
String name = rs.getString("name");
String email = rs.getString("email");
Date birth = rs.getDate("birth");
Customer cust = new Customer(id, name, email, birth);
System.out.println(cust);
//将Blob类型的字段下载下来,以文件的方式保存在本地
Blob photo = rs.getBlob("photo");
is = photo.getBinaryStream();
fos = new FileOutputStream("xzq.jpg");
byte[] buffer = new byte[1024];
int len;
while ((len = is.read(buffer)) != -1) {
fos.write(buffer, 0, len);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (is != null)
is.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (fos != null)
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
JDBCUtils.closeResource(conn, ps, rs);
}
}
批量插入
概述: 当需要成批插入或者更新记录时,可以采用Java的批量更新机制,这一机制允许多条语句一次性提交给数据库批量处理。
JDBC的批量处理语句包括三个方法:
- addBatch(String):添加需要批量处理的SQL语句或是参数
- executeBatch():执行批量处理语句
- clearBatch():清空缓存的数据
通常两种批量执行SQL语句的情况:
- 多条SQL语句的批量处理
- 一个SQL语句的批量传参
代码实现:向数据表中插入20000条数据
#数据库中提供一个goods表。创建如下:
CREATE TABLE goods(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAr(20)
);
@Test
public void testInsert4() {
Connection conn = null;
PreparedStatement ps = null;
try {
long start = System.currentTimeMillis();
conn = JDBCUtils.getConnection();
//设置不允许自动提交数据
conn.setAutoCommit(false);
String sql = "insert into goods(name)values(?)";
ps = conn.prepareStatement(sql);
for (int i = 1; i <= 20000; i++) {
ps.setObject(1, "name_" + i);
//1."攒"sql
ps.addBatch();
if (i % 500 == 0) {
//2.执行
ps.executeBatch();
//3.清空batch
ps.clearBatch();
}
}
//提交数据
conn.commit();
long end = System.currentTimeMillis();
System.out.println("执行的时间:" + (end - start)); //执行的时间:703
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(conn, ps);
}
}
概述: 当需要成批插入或者更新记录时,可以采用Java的批量更新机制,这一机制允许多条语句一次性提交给数据库批量处理。
JDBC的批量处理语句包括三个方法:
- addBatch(String):添加需要批量处理的SQL语句或是参数
- executeBatch():执行批量处理语句
- clearBatch():清空缓存的数据
通常两种批量执行SQL语句的情况:
- 多条SQL语句的批量处理
- 一个SQL语句的批量传参
代码实现:向数据表中插入20000条数据
#数据库中提供一个goods表。创建如下: CREATE TABLE goods( id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAr(20) );
@Test
public void testInsert4() {
Connection conn = null;
PreparedStatement ps = null;
try {
long start = System.currentTimeMillis();
conn = JDBCUtils.getConnection();
//设置不允许自动提交数据
conn.setAutoCommit(false);
String sql = "insert into goods(name)values(?)";
ps = conn.prepareStatement(sql);
for (int i = 1; i <= 20000; i++) {
ps.setObject(1, "name_" + i);
//1."攒"sql
ps.addBatch();
if (i % 500 == 0) {
//2.执行
ps.executeBatch();
//3.清空batch
ps.clearBatch();
}
}
//提交数据
conn.commit();
long end = System.currentTimeMillis();
System.out.println("执行的时间:" + (end - start)); //执行的时间:703
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(conn, ps);
}
}
数据库事务
说明:这里只介绍JDBC中的事务处理,基本的数据库事务介绍可以参考博主之前的文章。
概述:一组逻辑操作单元,使数据从一种状态变换到另一种状态。(一组逻辑操作单元,一个或多个DML操作)
特点:
- 数据一旦提交,就不可回滚
- 数据什么时候被提交?
- DDL操作一旦执行,会自动提交,set autocommit = false 对DDL操作失效
- DML默认情况下一旦执行,就会自动提交,通过set sutocommit = false,取消DML操作的自动提交
- 关闭数据库连接,数据就会自动的提交
- 当一个连接对象被创建时,默认情况下是自动提交事务
JDBC程序中让多个SQL语句作为一个事务执行:
- 调用Connection对象的setAutoCommit(false),以取消自动提交事务
- 在所有的SQL语句都成功执行后,调用commit(), 方法提交事务
- 在出现异常时,调用rollback()方法回滚事务
代码实现:用户AA向用户BB转账100
//**********考虑数据库事务情况下的转账操作****************
@Test
public void testUpdateWithTx() {
Connection conn = null;
try {
conn = JDBCUtils.getConnection();
System.out.println(conn.getAutoCommit()); //true
//1.取消数据的自动提交
conn.setAutoCommit(false);
String sql1 = "update user_table set balance = balance - 100 where user = ?";
update(conn,sql1,"AA");
//模拟网络异常
//System.out.println(10/0);
String sql2 = "update user_table set balance = balance + 100 where user = ?";
update(conn,sql2,"BB");
System.out.println("转账成功!");
//2.提交数据
conn.commit();
}catch (Exception e){
e.printStackTrace();
//3.回滚数据
try {
conn.rollback();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
finally {
//修改其为自动提交数据,主要针对于使用数据库连接池时
try {
conn.setAutoCommit(true);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
JDBCUtils.closeResource(conn,null);
}
}
//通用的增删改操作 ----version 2.0(考虑上事务)
public int update(Connection conn,String sql,Object ...args) {
PreparedStatement ps = null;
try {
//1.预编译sql语句,返回PreparedStatement实例
ps = conn.prepareStatement(sql);
//2.填充占位符
for (int i = 0; i < args.length; i++) {
ps.setObject(i+1,args[i]);
}
//3.执行
return ps.executeUpdate();
}catch (Exception e){
e.printStackTrace();
}finally {
//4.资源关闭
JDBCUtils.closeResource(null, ps);
}
return 0;
}
说明:这里只介绍JDBC中的事务处理,基本的数据库事务介绍可以参考博主之前的文章。
概述:一组逻辑操作单元,使数据从一种状态变换到另一种状态。(一组逻辑操作单元,一个或多个DML操作)
特点:
- 数据一旦提交,就不可回滚
- 数据什么时候被提交?
- DDL操作一旦执行,会自动提交,set autocommit = false 对DDL操作失效
- DML默认情况下一旦执行,就会自动提交,通过set sutocommit = false,取消DML操作的自动提交
- 关闭数据库连接,数据就会自动的提交
- 当一个连接对象被创建时,默认情况下是自动提交事务
JDBC程序中让多个SQL语句作为一个事务执行:
- 调用Connection对象的setAutoCommit(false),以取消自动提交事务
- 在所有的SQL语句都成功执行后,调用commit(), 方法提交事务
- 在出现异常时,调用rollback()方法回滚事务
代码实现:用户AA向用户BB转账100
//**********考虑数据库事务情况下的转账操作****************
@Test
public void testUpdateWithTx() {
Connection conn = null;
try {
conn = JDBCUtils.getConnection();
System.out.println(conn.getAutoCommit()); //true
//1.取消数据的自动提交
conn.setAutoCommit(false);
String sql1 = "update user_table set balance = balance - 100 where user = ?";
update(conn,sql1,"AA");
//模拟网络异常
//System.out.println(10/0);
String sql2 = "update user_table set balance = balance + 100 where user = ?";
update(conn,sql2,"BB");
System.out.println("转账成功!");
//2.提交数据
conn.commit();
}catch (Exception e){
e.printStackTrace();
//3.回滚数据
try {
conn.rollback();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
finally {
//修改其为自动提交数据,主要针对于使用数据库连接池时
try {
conn.setAutoCommit(true);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
JDBCUtils.closeResource(conn,null);
}
}
//通用的增删改操作 ----version 2.0(考虑上事务)
public int update(Connection conn,String sql,Object ...args) {
PreparedStatement ps = null;
try {
//1.预编译sql语句,返回PreparedStatement实例
ps = conn.prepareStatement(sql);
//2.填充占位符
for (int i = 0; i < args.length; i++) {
ps.setObject(i+1,args[i]);
}
//3.执行
return ps.executeUpdate();
}catch (Exception e){
e.printStackTrace();
}finally {
//4.资源关闭
JDBCUtils.closeResource(null, ps);
}
return 0;
}



