Java JDBC的使用




JDBC的介绍:

  • JDBC(Java Database Connection)为java开发者使用数据库提供了统一的编程接口,它由一组java类和接口组成。是java程序与数据库系统通信的标准API。JDBC API使得开发人员可以使用纯java的方式来连接数据库,并执行操作。
  • sun公司由于不知道各个主流商用数据库的程序代码,因此无法自己写代码连接各个数据库,因此, sun公司决定,自己提供一套api ,凡是数据库想与Java进行连接的,数据库厂商自己必须实现JDBC这套接口。而数据库厂商的JDBC实现,我们就叫他此数据库的数据库驱动


访问数据库流程:

在这里插入图片描述



JDBC常用接口

Driver接口
  • Driver接口由数据库厂家提供,对于java开发者而言,只需要使用Driver接口就可以了。
  • 在编程中要连接数据库,必须先装载特定厂商的数据库驱动程序。不同的数据库有不同的装载方法。
  • 驱动:就是各个数据库厂商实现的Sun公司提出的JDBC接口。 即对Connection等接口的实现类的jar文件
  • 装载MySq|驱动
    Class.forName(“com.mysql.jdbc.Driver”);
    加载驱动类, jdk13后会自动加载 8.0后的写法 :
    Class.forName(“com.mysql.cj.jdbc.Driver”);
  • 装载Oracle驱动
    Class.forName(“oraclejdbc.driver.OracleDriver”);
DriverManager接口
  • DriverManager是JDBC的管理层,作用于用户和驱动程序之间。
  • DriverManager跟踪可用的驱动程序,并在数据库和相应的驱动程序之间建立连接。
Connection接口
  • Connection与特定数据库的连接(会话) ,在连接上下文中执行SQL语句并返回结果。
  • DriverManager的getConnection()方法建立在JDBC URL中定义的数据库Connection连接上
  • 连接MYSQL数据库:
Connection con =
DriverManager.getConnection("jdbc:mysq://host:port/database","user","tpassword");


Statement接口

  • 用于执行静态SQL语句并返回它所生成结果的对象。

三种Statement类 :

  • Statement:
    由createStatement创建,用于发送简单的SQL语句。(不带参数的)
  • PreparedStatement :
    继承自Statement接口,由prepareStatement创建,用于发送含有一个或多个输入参数的sq|语句。PreparedStatement对象比Statement对象的效率更高,并且可以防止SQL注入。我们一般都用PreparedStatement.
  • CallableStatement :
    继承自PreparedStatement。由方法prePareCall创建,用于调用存储过程。

常用的Statement方法:

  • execute():运行语句,返回是否有结果集。使用较少。
  • executeQuery() :运行select语句,返回ResultSet结果集。
  • executeUpdate() : 运行insert/update/delete操作,返回更新的行数。


测试数据库的连接和SQL注入

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
/**
 * 测试与数据库的连接
 */
public class Demo01 {
	public static void main(String[] args) {
		try {
			//加载驱动类, jdk13后会自动加载  8.0后的写法:com.mysql.cj.jdbc.Driver
			Class.forName("com.mysql.jdbc.Driver");
			long start = System.currentTimeMillis();
			//建立链接(链接对象内部其实包含了Socket对象,是一个远程的连接,所以建立链接是比较耗时的)
			//为了提好效率可以使用连接池来管理链接对象!
			Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/create","root","hc199854");
			long end = System.currentTimeMillis();
			System.out.println(conn);
			//这是进行本地链接,如果是远程链接会更加耗时
			System.out.println("建立链接花费的时间:"+(end-start));
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
}

执行结果:
com.mysql.jdbc.JDBC4Connection@181afa3
建立链接花费的时间:372

测试Statement和SQL注入:

  SQL注入, 这是使用Statement的一个严重缺点,因为使用的参数,比如id参数是其他人传进来的,如果传进的是来一个恶意的参数可能会破坏我们的数据库。

/**
 * 测试执行SQL语句,以及SQL注入问题
 */
public class Demo02 {
	public static void main(String[] args) {
		try {
			//加载驱动类, jdk13后会自动加载
			Class.forName("com.mysql.jdbc.Driver");
			//建立链接(链接对象内部其实包含了Socket对象,是一个远程的连接,所以建立链接是比较耗时的)
			//为了提好效率可以使用连接池来管理链接对象!
			Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/testjdbc","root","hc199854");
			Statement stmt = conn.createStatement();
			//字符串最后不需要添加分号
//			String sql = "insert into t_user(username, pwd, regTime) values('赵六',6666,now())";
//			stmt.execute(sql);
			
			//测试SQL注入, 这是使用Statement的一个严重缺点,因为使用的参数,比如id参数
			//是其他人传进来的,如果传进的是来一个恶意的参数比如id = "5 or 1=1"
			//然后我们把参数拼接执行,会把所有的数据都删除(由于1=1恒为真)
			String id = "5";
			String sql = "delete from t_user where id=" + id;
			stmt.execute(sql);
			
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
}

测试执行PreparedStatement的基本用法

import java.sql.Connection;
import java.sql.Date;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
/**
 * 测试执行PreparedStatement的基本用法
 */
public class Demo03 {
	public static void main(String[] args) {
		try {
			//加载驱动类, jdk13后会自动加载
			Class.forName("com.mysql.jdbc.Driver");
			Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/testjdbc","root","hc199854");
			String sql = "insert into t_user(username, pwd, regTime) values(?,?,?)";  //?表示占位符,后面再设置
			PreparedStatement ps = conn.prepareStatement(sql);
			//防止SQL注入
			ps.setString(1, "会程");//参数索引是从1开始的,而不是0
			ps.setString(2, "12345678");    
			//也可以使用ps.setObject(2, "12345678");从而不需要考虑数据类型问题
			ps.setObject(3, new Date(System.currentTimeMillis()));
			ps.execute();
			
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
}


ResultSet接口

  • Statement执行SQL语句时返回ResultSet结果集。
  • ResultSet提供的检索不同类型字段的方法,常用的有:
    getString():获得在数据库里是varchar. char等数据类型的对象。
    getFloat():获得杂数据库里是Float类型的对象。
    getDate():获得在数据库里面是Date类型的数据。
    getBoolean():获得在数据库里面是Boolean类型的数据

关闭使用对象及连接的顺序
ResultSet→Statement→Connection

测试ResultSet的基本用法

import java.sql.Connection;
import java.sql.Date;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
/**
 * 测试ResultSet的基本用法
 */
public class Demo04 {
	public static void main(String[] args) {
		Connection conn = null;
		PreparedStatement ps = null;
		ResultSet rs = null; 
		try {
			//加载驱动类, jdk13后会自动加载
			Class.forName("com.mysql.jdbc.Driver");
			conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/testjdbc","root","hc199854");
			String sql = "select * from t_user where id>?";  //?表示占位符,后面再设置
			ps = conn.prepareStatement(sql);
			ps.setObject(1, 2);  //查询id大于2的用户数据
			
			rs = ps.executeQuery();   //获取SQL语句执行后的结果集
			
			while(rs.next()){ //查看是否有下一行,每执行一次表示行号的游标就会加一,游标从0开始
				//getInt(i)表示获取第i列的数据
				System.out.println(rs.getInt(1)+"--"+rs.getString(2)+"--"+rs.getString(3));
			}
			
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		}finally{
			//关闭顺序:resultset-->statment-->connection 三个try catch一定要分开写
			try {
				if(rs!=null)
					rs.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			try {
				if(ps!=null)
					ps.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			try {
				if(conn!=null)
					conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
}

测试结果:
3–赵六–6666
4–赵六–6666
5–会程–12345678



批处理

  • Batch
  • 对于大量的批处理,建议使用Statement ,因为PreparedStatement的预编译空间有限,当数据星特别大时 ,会发生异常。

测试批处理Batch的基本用法

import java.sql.Connection;
import java.sql.Date;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
/**
 * 测试批处理Batch的基本用法
 */
public class Demo05 {
	public static void main(String[] args) {
		Connection conn = null;
		Statement stmt = null;
		ResultSet rs = null; 
		try {
			//加载驱动类, jdk13后会自动加载
			Class.forName("com.mysql.jdbc.Driver");
			conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/testjdbc","root","hc199854");
			
			conn.setAutoCommit(false);  //设置为手动提交
			stmt = conn.createStatement();
			long start = System.currentTimeMillis();
			
			for(int i=0; i<20000; i++){
				stmt.addBatch("insert into t_user(username,pwd,regTime) values('hc"+i+"', '123',now())");
			}
			
			stmt.executeBatch(); 
			conn.commit();//提交事务
			long end = System.currentTimeMillis();
			System.out.println("插入20000条需要的时间:"+(end-start));
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		}finally{
			//关闭顺序:resultset-->statment-->connection 三个try catch一定要分开写
			try {
				if(rs!=null)
					rs.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			try {
				if(stmt!=null)
					stmt.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			try {
				if(conn!=null)
					conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
}

测试结果:
插入20000条需要的时间:5773



事务介绍

概念:

  • 组要么同时执行成功,要么同时执行失败的SQL语句。是数据库操作的一个执行单元!

事务开始于:

  • 连接到数据库上,并执行一条DML语句(INSERT、UPDATE或DELETE)。
  • 前一个事务结束后,又输入了另外-条DML语句。

事务结束于:

  • 执行COMMIT或ROLLBACK语句。
  • 执行条DDL语句,例如CREATE TABLE语句;在这种情况下,会自动执,行COMMIT语句。
  • 执行条DCL语句,例如GRANT语句;在这种情况下,会自动执行COMMIT语句。
  • 断开与数据库的连接。
  • 执行了一条DML语句,该语句却失败了;在这种情况中,会为这个无效的DML语句执行ROLLBACK语句。

SQL语句的分类:
数据定义语言DDL
数据查询语言DQL
数据操纵语言DML
数据控制功能DCL
分类详情

事务的四大特点( ACID )

  • atomicity (原子性)
    表示一个事务内的所有操作是一个整体,要么全部成功,要么全失败。
  • consistency ( 一致性)
    表示个事务内有一 个操作失败时,所有的更改过的数据都必须回滚到修改前的状态。
  • isolation (隔离性)
    事务查看数据时数据所处的状态,要么是另一 并发事务修改它之前的状态,要么是另一事务修改它之后的状态,事务不会查看中间状态的数据。
  • durability (持久性)
    持久性事务完成之后,它对于系统的影响是永久性的。

注:JDBC里默认自动提交事务。

事务隔离级别从低到高:

  • 读取未提交( Read Uncommitted)
  • 读取已提交(Read Committed)
  • 可重复读( Repeatable Read)
  • 序列化( serializable)
import java.sql.Connection;
import java.sql.Date;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
/**
 * 测试事务
 */
public class Demo06 {
	public static void main(String[] args) {
		Connection conn = null;
		PreparedStatement ps1 = null; 
		PreparedStatement ps2 = null;
		ResultSet rs = null; 
		try {
			//加载驱动类, jdk13后会自动加载
			Class.forName("com.mysql.jdbc.Driver");
			conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/testjdbc","root","hc199854");
			
			conn.setAutoCommit(false);   //设置手动提交(JDBC默认自动提交)
			
			ps1 = conn.prepareStatement("insert into t_user(username, pwd) values(?,?)");
			ps1.setObject(1, "张三");
			ps1.setObject(2, "12345");
			ps1.execute();
			
			System.out.println("已插入一条数据");
			try {
				Thread.sleep(3000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			
			ps2 = conn.prepareStatement("insert into t_user(username, pwd) values(?,?,?)");
			ps2.setObject(1, "李四");
			ps2.setObject(2, "12345");
			ps2.execute();
			System.out.println("已插入第二条数据");
			
			conn.commit();  //提交事务
			
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
			//当插入发生异常时,进行回滚(这是进行模拟,由于设置了手动提交,一个事务中发生错误时,会自动发生回滚)
			try {
				conn.rollback();  //回滚
			} catch (SQLException e1) {
				e1.printStackTrace();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}finally{
			//关闭顺序:resultset-->statment-->connection 三个try catch一定要分开写
			try {
				if(rs!=null)
					rs.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			try {
				if(ps1!=null)
					ps1.close();
				if(ps2!=null)
					ps2.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			try {
				if(conn!=null)
					conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
}

测试结果:
当插入第二条数据发生错误时,发生回滚,第一条数据也不会插入数据库中。



JDBC中的Date操作

插入随机的日期:

/**
 * 向数据库中插入随机的日期
 */
public class Demo07 {
	public static void main(String[] args) {
		Connection conn = null;
		PreparedStatement ps = null; 
		ResultSet rs = null; 
		try {
			//加载驱动类, jdk13后会自动加载
			Class.forName("com.mysql.jdbc.Driver");
			conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/testjdbc","root","hc199854");
			
			for(int i=0; i<1000; i++){
				ps = conn.prepareStatement("insert into t_user(username,pwd,regTime) values(?,?,?)");
				ps.setString(1, "hc");
				ps.setString(2, "12345678");
				
				int rmd = 100000000 + new Random().nextInt(1000000000); //产生一个100000000到1000000000的数
				
				java.sql.Date date = new Date(System.currentTimeMillis() - rmd);
				
				ps.setObject(3, date);
				ps.execute();
			}
			
			System.out.println("插入完成");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
			//当插入发生异常时,进行回滚(这是进行模拟,由于设置了手动提交,一个事务中发生错误时,会自动发生回滚)
			try {
				conn.rollback();  //回滚
			} catch (SQLException e1) {
				e1.printStackTrace();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}finally{
			//关闭顺序:resultset-->statment-->connection 三个try catch一定要分开写
			try {
				if(rs!=null)
					rs.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			try {
				if(ps!=null)
					ps.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			try {
				if(conn!=null)
					conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
}

查询指定日期范围的数据:

import java.sql.Connection;
import java.sql.Date;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Random;
/**
 * 查找指定日期范围的数据
 */
public class Demo08 {
	
	/**
	 * 将字符串代表的日期转换为long类型数字(格式:yyyy-MM-dd hh:mm:ss)
	 */
	public static long str2Date(String dateStr){
		DateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
		try {
			return format.parse(dateStr).getTime();
		} catch (ParseException e) {
			e.printStackTrace();
			return 0;
		}
	}
	public static void main(String[] args) {
		Connection conn = null;
		PreparedStatement ps = null; 
		ResultSet rs = null; 
		try {
			//加载驱动类, jdk13后会自动加载
			Class.forName("com.mysql.jdbc.Driver");
			conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/testjdbc","root","hc199854");
			
			ps = conn.prepareStatement("select * from t_user where regTime>? and regTime<?");
			java.sql.Date start = new java.sql.Date(str2Date("2020-7-08 00:00:00"));
			java.sql.Date end = new java.sql.Date(str2Date("2020-7-10 00:00:00"));
			ps.setObject(1, start);
			ps.setObject(2, end);
			
			rs = ps.executeQuery();
			
			while(rs.next()){
				System.out.println(rs.getInt("id")+"--"+ rs.getString("username")+"--"+ rs.getObject("regTime"));
			}
			
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
			//当插入发生异常时,进行回滚(这是进行模拟,由于设置了手动提交,一个事务中发生错误时,会自动发生回滚)
			try {
				conn.rollback();  //回滚
			} catch (SQLException e1) {
				e1.printStackTrace();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}finally{
			//关闭顺序:resultset-->statment-->connection 三个try catch一定要分开写
			try {
				if(rs!=null)
					rs.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			try {
				if(ps!=null)
					ps.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			try {
				if(conn!=null)
					conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
}


CLOB ( Character Large Object )

  • 用于存储大量的文本数据。
  • 大字段有些特殊,不同数据库处理的方式不一样,大字段的操作常常是以流的方式来处理的。而非一般的字段,一次即可读出数据。

Mysql中相关类型:

  • TINYTEXT最大长度为255字符的TEXT列。
  • TEXT[(M)]最大长度为65,535字符的TEXT列。
  • MEDIUMTEXT最大长度为16,777.215字符的TEXT列。
  • LONGTEXT最大长度为4,294,967,295或4GB字符的TEXT列。

测试CLOB 文本大对象的使用

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.io.Reader;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.Date;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Random;
/**
 * 测试CLOB 文本大对象的使用
 * 包含:将字符串、文件内容插入数据库中的CLOB字段、将CLOB字段值取出来的操作
 */
public class Demo09 {
	
	
	public static void main(String[] args) {
		Connection conn = null;
		PreparedStatement ps = null; 
		ResultSet rs = null; 
		try {
			//加载驱动类, jdk13后会自动加载
			Class.forName("com.mysql.jdbc.Driver");
			conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/testjdbc","root","hc199854");
			
//			//将文件内容输入到数据库的CLOB字段中
//			ps = conn.prepareStatement("insert into t_user(username,myInfo) values(?,?)");
//			ps.setString(1, "HC");
//			ps.setClob(2, new FileReader(new File("d:/a.txt")));  //将文本内容总结输入到数据库中
			
			//将程序中的字符串输入到数据库的CLOB字段中
//			ps = conn.prepareStatement("insert into t_user(username,myInfo) values(?,?)");
//			ps.setString(1, "HC");
//			ps.setClob(2, new BufferedReader(new InputStreamReader(new ByteArrayInputStream("aaaaabbbbb".getBytes()))));
//			ps.execute();
			
			//将数据库中的CLOB字段读出
			ps = conn.prepareStatement("select * from t_user");
			rs = ps.executeQuery();
			
			while(rs.next()){
				Clob c = rs.getClob("myInfo");
				Reader r = c.getCharacterStream();
				int temp = 0;
				while((temp=r.read())!=-1){
					System.out.print((char)temp);
				}
			}
			
			
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
			//当插入发生异常时,进行回滚(这是进行模拟,由于设置了手动提交,一个事务中发生错误时,会自动发生回滚)
			try {
				conn.rollback();  //回滚
			} catch (SQLException e1) {
				e1.printStackTrace();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			//关闭顺序:resultset-->statment-->connection 三个try catch一定要分开写
			try {
				if(rs!=null)
					rs.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			try {
				if(ps!=null)
					ps.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			try {
				if(conn!=null)
					conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
}

测试结果:
aaaaabbbbb



BLOB ( Binary Large Object )

  • 用于存储大量的二进制数据。
  • 大字段有些特殊,不同数据库处理的方式不-样,大字段的操作常常是以流的方式来处理的。而非一般的字段,一次即可读出数据。

Mysgl中相关类型:

  • TINYBLOB最大长度为255字节的BLOB列。
  • BLOB[(M)]最大长度为65,535字节的BLOB列。
  • MEDIUMBLOB最大长度为16,777,215字节的BLOB列。
  • LONGBLOB最大长度为4, 294,967,295或4GB字节的BLOB列。

测试BLOB 二进制大对象的使用

package jdbc;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Reader;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.Date;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Random;
/**
 * 测试BLOB 二进制大对象的使用
 */
public class Demo10 {
	
	
	public static void main(String[] args) {
		Connection conn = null;
		PreparedStatement ps = null; 
		ResultSet rs = null; 
		InputStream is = null;
		OutputStream os = null;
		try {
			//加载驱动类, jdk13后会自动加载
			Class.forName("com.mysql.jdbc.Driver");
			conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/testjdbc","root","hc199854");
			
//			//将图片存入数据库BLOB字段
//			ps = conn.prepareStatement("insert into t_user(username,headImg) values(?,?)");
//			ps.setString(1, "HC");
//			ps.setBlob(2, new FileInputStream("E:/text.jpg"));
//			ps.execute();
			
			ps = conn.prepareStatement("select * from t_user");
			rs = ps.executeQuery();
			
			while(rs.next()){
				Blob b = rs.getBlob("headImg");
				is = b.getBinaryStream();
				
				int temp  =0; 
				while((temp=is.read())!=-1){
					System.out.print((char)temp);
				}
			}
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
			//当插入发生异常时,进行回滚(这是进行模拟,由于设置了手动提交,一个事务中发生错误时,会自动发生回滚)
			try {
				conn.rollback();  //回滚
			} catch (SQLException e1) {
				e1.printStackTrace();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			//关闭顺序:resultset-->statment-->connection 三个try catch一定要分开写
			try {
				if(rs!=null)
					rs.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			try {
				if(ps!=null)
					ps.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			try {
				if(conn!=null)
					conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

逍遥自在”

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值