文档版本 | 开发工具 | 测试平台 | 工程名字 | 日期 | 作者 | 备注 |
---|---|---|---|---|---|---|
V1.0 | 2016.05.11 | lutianfei | none |
JDBC
JDBC介绍
- JDBC是什么?
- JDBC(Java Data Base Connectivity,java数据库连接)
- SUN公司为了简化、统一对数据库的操作,定义了一套Java操作数据库的规范,称之为JDBC。
- 简单说,就是可以直接通过java语言去操作数据库。
- jdbc是一套标准,它是由一些接口与类组成的。
组成JDBC的类和接口
- java.sql
- 类:DriverManger
- 接口
Connection
Statement
ResultSet
PreparedStatement
CallableStatement
(它是用于调用存储过程)
- javax.sql
- 接口 DataSource(数据源)
- 什么是驱动?
- 两个设备要进行通信,满足一定通信数据格式,数据格式由设备提供商规定,设备提供商为设备提供驱动软件,通过软件可以与该设备进行通信。
JDBC入门
第一个JDBC程序
- 编程从user表中读取数据,并打印在命令行窗口中。
- 一、搭建实验环境 :
- 1、在mysql中创建一个库,并创建user表和插入表的数据。
- 2、新建一个Java工程,并导入数据驱动。
- 二、编写程序,在程序中加载数据库驱动
- DriverManager. registerDriver(Driver driver)
- 三、建立连接(Connection)
- Connection conn = DriverManager.getConnection(url,user,pass);
- 四、创建用于向数据库发送SQL的Statement对象,并发送sql
- Statement st = conn.createStatement();
- ResultSet rs = st.executeQuery(sql);
- 五、从代表结果集的ResultSet中取出数据,打印到命令行窗口
- 六、断开与数据库的连接,并释放相关资源
- 一、搭建实验环境 :
create table user(
id int primary key auto_increment,
username varchar(20) unique not null,
password varchar(20) not null,
email varchar(40) not null
);
INSERT INTO USER VALUES(NULL,‘tom‘,‘123‘,‘[email protected]‘);
INSERT INTO USER VALUES(NULL,‘fox‘,‘123‘,‘[email protected]‘);
- 1.加载驱动
- 将驱动jar包复制到lib下.
- 2.创建一个JdbcDemo1类
public static void main(String[] args) throws SQLException {
// 1.注册驱动
// DriverManager.registerDriver(new Driver()); //加载了两个驱动
Class.forName("com.mysql.jdbc.Driver"); // 加载mysql驱动
// 2.获取连接对象
Connection con = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/day17", "root", "abc");
// 3.通过连接对象获取操作sql语句Statement
Statement st = con.createStatement();
// 4.操作sql语句
String sql = "select * from user";
// 操作sql语句(select语句),会得到一个ResultSet结果集
ResultSet rs = st.executeQuery(sql);
// 5.遍历结果集
// boolean flag = rs.next(); // 向下移动,返回值为true,代表有下一条记录.
// int id = rs.getInt("id");
// String username=rs.getString("username");
// System.out.println(id);
// System.out.println(username);
while(rs.next()){
int id=rs.getInt("id");
String username=rs.getString("username");
String password=rs.getString("password");
String email=rs.getString("email");
System.out.println(id+" "+username+" "+password+" "+email);
}
//6.释放资源
rs.close();
st.close();
con.close();
}
JDBC操作详解
1.注册驱动
- JDBC程序中的
DriverManager
是java.sql
包下的一个驱动管理的工具类,可以理解成是一个容器(Vector),可以装入很多数据库驱动,并创建与数据库的链接,这个API的常用方法:- DriverManager.registerDriver(new Driver())
- DriverManager.getConnection(url, user, password),
registDriver方法
分析- public static synchronized void registerDriver(java.sql.Driver driver)
- 参数:java.sql.Driver
- 我们传递的是 : com.mysql.jdbc.Driver;
- 在com.mysql.jdbc.Driver类中有一段静态代码块:
- public static synchronized void registerDriver(java.sql.Driver driver)
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can‘t register driver!");
}
}
- 上述代码的问题:
- 1.在驱动管理器中会装入两个mysql驱动.
- 解决方案:使用反射
Class.forName("com.mysql.jdbc.Driver");
- 分析:使用反射的方式来加载驱动有什么好处?
- 一、查看Driver的源代码可以看到,如果采用此种方式,会导致驱动程序注册两次,也就是在内存中会有两个Driver对象。
- 二、程序依赖mysql的api,脱离mysql的jar包,程序将无法编译,将来程序切换底层数据库将会非常麻烦。
- 解决方案:使用反射
- 2.可以通过DriverManager来获取连接对象
Connection con=DriverManager.getConection(String url,String user,String password);
- url作用:就是用于确定使用哪一个驱动.
- mysql url:
jdbc: mysql ://localhsot:3306/数据库名
- oralce url:
jdbc : oracle :thin :@ localhost :1521 :sid
- mysql url:
- 1.在驱动管理器中会装入两个mysql驱动.
- DriverManager作用总结:
- 1.注册驱动
- 2.获取连接Connection
数据库URL
- URL用于标识数据库的位置,程序员通过URL地址告诉JDBC程序连接哪个数据库,URL的写法为:
jdbc : mysql : // localhost :3306/test ?key=value
- url格式
- 主协议 子协议 主机 端口 数据库
jdbc : mysql ://localhost:3306/day17
- mysql的url可以简写
- 前提:主机是:localhost 端口是 :3306
jdbc : mysql : ///day17
- 在url后面可以带参数
- eg: useUnicode=true&characterEncoding=UTF-8
2.Connection详解
java.sql.Connection
,它代表的是一个连接对象。简单说,就是我们程序与数据库连接。- Connection作用:
- 1.可以通过Connection获取操作SQL的Statement对象。
- Statement createStatement() throws SQLException
- 示例:
- Statement st=con.createStatement();
- 2.操作事务
- setAutoCommit(boolean flag);开启事务,设置事务是否自动提交。
- rollback();事务回滚,在此链接上回滚事务。
- commit();事务提交,在链接上提交事务。 —与事务相关!!
- 了解:
- 1.可以获取执行预处理的
PreparedStatement对象
.创建向数据库发送预编译sql的PrepareSatement对象- PreparedStatement prepareStatement(String sql) throws SQLException
- 2.可以获取执行存储过程的
CallableStatement
,创建执行存储过程的callableStatement对象。- CallableStatement prepareCall(String sql) throws SQLException
- 1.可以获取执行预处理的
- 1.可以通过Connection获取操作SQL的Statement对象。
3.Statement详解
java.sql.Statement
用于向数据库发送SQL语句,执行sql语句。
Statement作用
- 1.执行SQL
- DML :
insert
update
delete
- int executeUpdate(String sql) :用于向数据库发送insert、update或delete语句
- 利用返回值判断非0来确定sql语句是否执行成功。
- int executeUpdate(String sql) :用于向数据库发送insert、update或delete语句
- DQL :
select
- ResultSet executeQuery(String sql) : 用于向数据发送查询语句。
- execute(String sql):用于向数据库发送任意SQL语句
- DML :
- 2.批处理操作
- addBatch(String sql); 将SQL语句添加到批处理
- executeBatch(); 向数据库发送一批SQl语句执行。
- clearBatch(); 清空批处理。
4.ResultSet详解
java.sql.ResultSet
它是用于封装select语句执行后查询的结果。Resultset封装执行结果时,采用的类似于表格的方式。ResultSet 对象维护了一个指向表格数据行的游标cursor
,初始的时候,游标在第一行之前,调用ResultSet.next() 方法
,可以使游标指向具体的数据行,进而调用方法获取该行的数据。
ResultSet常用API
- 1.next()方法
- public boolean next();
- 用于判断是否有下一条记录。如果有返回true,并且让游标向下移动一行。
- 如果没有返回false.
- 2.可以通过ResultSet提供的getXxx()方法来获取当前游标指向的这条记录中的列数据。
- 常用:
- getInt()
- getString(int index)
- getString(String columnName):也可以获得int,Data等类型
- getDate()
- getDouble()
- 参数有两种
- 1.getInt(int columnIndex);
- 2.getInt(String columnName);
- 常用:
- 如果列的类型不知道,可以通过下面的方法来操作
- getObject(int columnIndex);
- getObject(String columnName);
- 常用数据类型转换表
释放资源
- JDBC程序运行完后,切记要释放程序在运行过程中,创建的那些与数据库进行交互的对象,这些对象通常是ResultSet, Statement和Connection对象。
- 特别是
Connection对象
,它是非常稀有的资源,用完后必须马上释放,如果Connection不能及时、正确的关闭,极易导致系统宕机。 - Connection的使用原则是尽量晚创建,尽量早的释放。
- 为确保资源释放代码能运行,资源释放代码也一定要放在
finally
语句中。 - 完整版JDBC示例代码:
public static void main(String[] args) {
Connection con = null;
Statement st = null;
ResultSet rs = null;
try {
// 1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
// 2.获取连接
con = DriverManager.getConnection("jdbc:mysql:///day17", "root",
"abc");
// 3.获取操作sql语句对象Statement
st = con.createStatement();
// 4.执行sql
rs = st.executeQuery("select * from user");
// 5.遍历结果集
while (rs.next()) {
int id = rs.getInt("id");
String username = rs.getString("username");
String password = rs.getString("password");
String email = rs.getString("email");
System.out.println(id + " " + username + " " + password
+ " " + email);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 6.释放资源
try {
if (rs != null) {
rs.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (st != null)
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (con != null)
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
使用JDBC对数据库进行CRUD
- Jdbc中的statement对象用于向数据库发送SQL语句,想完成对数据库的增删改查,只需要通过这个对象向数据库发送增删改查语句即可。
- Statement对象的
executeUpdate方法
,用于向数据库发送增、删、改的sql语句,executeUpdate执行完后,将会返回一个整数(即增删改语句导致了数据库几行数据发生了变化)。 Statement.executeQuery方法
用于向数据库发送查询语句,executeQuery方法返回代表查询结果的ResultSet对象。- 1.查询
- 1.查询全部
- 2.条件查询—根据id
- 2.修改
- 3.删除
- 4.添加
- 练习:编写程序对User表进行增删改查操作。
- 练习:编写工具类简化CRUD操作。(异常暂不处理)
JdbcUtils工具类
- 只抽取到Connection
//jdbc.properties
driverClass=com.mysql.jdbc.Driver
url=jdbc:mysql:///day17
username=root
password=abc
public class JdbcUtils {
private static final String DRIVERCLASS;
private static final String URL;
private static final String USERNAME;
private static final String PASSWORD;
static {
DRIVERCLASS = ResourceBundle.getBundle("jdbc").getString("driverClass");
URL = ResourceBundle.getBundle("jdbc").getString("url");
USERNAME = ResourceBundle.getBundle("jdbc").getString("username");
PASSWORD = ResourceBundle.getBundle("jdbc").getString("password");
}
static {
try {
// 将加载驱动操作,放置在静态代码块中.这样就保证了只加载一次.
Class.forName(DRIVERCLASS);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static Connection getConnection() throws SQLException {
// 2.获取连接
Connection con = DriverManager.getConnection(URL, USERNAME, PASSWORD);
return con;
}
//关闭操作
public static void closeConnection(Connection con) throws SQLException{
if(con!=null){
con.close();
}
}
public static void closeStatement(Statement st) throws SQLException{
if(st!=null){
st.close();
}
}
public static void closeResultSet(ResultSet rs) throws SQLException{
if(rs!=null){
rs.close();
}
}
}
- JDBC CURD
//jdbc的crud操作
public class JdbcDemo6 {
@Test
public void findByIdTest() {
// 1.定义sql
String sql = "select * from user where id=1";
Connection con = null;
Statement st = null;
ResultSet rs = null;
try {
// 1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
// 2.获取连接
con = DriverManager.getConnection("jdbc:mysql:///day17", "root",
"abc");
// 3.获取操作sql语句对象Statement
st = con.createStatement();
// 4.执行sql
rs = st.executeQuery(sql);
// 5.遍历结果集
while (rs.next()) {
int id = rs.getInt("id");
String username = rs.getString("username");
String password = rs.getString("password");
String email = rs.getString("email");
System.out.println(id + " " + username + " " + password
+ " " + email);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 6.释放资源
try {
if (rs != null) {
rs.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (st != null)
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (con != null)
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
// 添加操作
@Test
public void addTest() {
// 定义sql
String sql = "insert into user values(null,‘张三‘,‘123‘,‘[email protected]‘)";
Connection con = null;
Statement st = null;
ResultSet rs = null;
try {
// 1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
// 2.获取连接
con = DriverManager.getConnection("jdbc:mysql:///day17", "root",
"abc");
// 3.获取操作sql语句对象Statement
st = con.createStatement();
// 4.执行sql
int row = st.executeUpdate(sql);
if (row != 0) {
System.out.println("添加成功");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 6.释放资源
try {
if (rs != null) {
rs.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (st != null)
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (con != null)
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
// update操作
@Test
public void updateTest() {
// 将id=3的人的password修改为456
String password = "456";
String sql = "update user set password=‘" + password + "‘ where id=3";
// 1.得到Connection
Connection con = null;
Statement st = null;
try {
con = JdbcUtils1.getConnection();
// 3.获取操作sql语句对象Statement
st = con.createStatement();
// 4.执行sql
int row = st.executeUpdate(sql);
if (row != 0) {
System.out.println("修改成功");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 关闭资源
try {
if (st != null)
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (con != null)
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
// delete测试
@Test
public void deleteTest() {
// 将id=3的人删除
String sql = "delete from user where id=2";
// 1.得到Connection
Connection con = null;
Statement st = null;
try {
con = JdbcUtils.getConnection();
// 3.获取操作sql语句对象Statement
st = con.createStatement();
// 4.执行sql
int row = st.executeUpdate(sql);
if (row != 0) {
System.out.println("删除成功");
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 关闭资源
try {
JdbcUtils.closeStatement(st);
JdbcUtils.closeConnection(con);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
ResultSet 滚动结果集
- 默认得到的ResultSet它只能向下遍历(next()),对于ResultSet它可以设置成是滚动的,可以向上遍历,或者直接定位到一个指定的物理行号。
- 设置滚动结果集的方法
- 在创建Statement对象时,不使用
createStatement()
;而使用带参数的createStatement(int,int)
- 在创建Statement对象时,不使用
Statement createStatement(int resultSetType,
int resultSetConcurrency)
throws SQLException
、
Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
- 第一个参数值,
resultSetType
- ResultSet.TYPE_FORWARD_ONLY 该常量指示光标只能向前移动的 ResultSet 对象的类型。
- ResultSet.TYPE_SCROLL_INSENSITIVE 该常量指示可滚动但通常不受 ResultSet 底层数据更改影响的 ResultSet 对象的类型。
- ResultSet.TYPE_SCROLL_SENSITIVE 该常量指示可滚动并且通常受 ResultSet 底层数据更改影响的 ResultSet 对象的类型。
- 第二个参数值,
resultSetConcurrency
- ResultSet.CONCUR_READ_ONLY 该常量指示不可以更新的 ResultSet 对象的并发模式。
- ResultSet.CONCUR_UPDATABLE 该常量指示可以更新的 ResultSet 对象的并发模式。
- 以上五个值,可以有三种搭配方式
- ResultSet.TYPE_FORWARD_ONLY ResultSet.CONCUR_READ_ONLY 默认,不受底层影响
- ResultSet.TYPE_SCROLL_INSENSITIVE ResultSet.CONCUR_READ_ONLY
- ResultSet.TYPE_SCROLL_SENSITIVE ResultSet.CONCUR_UPDATABLE 滚动的,可以并发更新的
- 常用API
- next():移动到下一行
- previous():移动到前一行
- absolute(int row):移动到指定行
- beforeFirst():移动resultSet的最前面
- afterLast() :移动到resultSet的最后面
- updateRow() :更新行数据
DAO模式——JavaEE模式
DAO模式
(Data Access Object 数据访问对象):在持久层通过DAO将数据源操作完全封装起来,业务层通过操作Java对象,完成对数据源操作- 业务层无需知道数据源底层实现 ,通过java对象操作数据源
DAO模式结构
- 1、DataSource数据源(MySQL数据库)
- 2、Business Object 业务层代码,调用DAO完成 对数据源操作 (代表数据的使用者)
- 3、DataAccessObject 数据访问对象,持久层DAO程序,封装对数据源增删改查,提供方法参数都是Java对象
- 4、TransferObject 传输对象(值对象) 业务层通过向数据层传递 TO对象,完成对数据源的增删改查(表示数据的Java Bean)
使用dao模式完成登录操作
- 需求:
- 1、把文件换成数据库
- 2、使用DAO模式
- 3、防范sql注入攻击
- 1.web层
- login.jsp LoginServlet User
- 2.service层
- UserService(实际应是接口)
- 3.dao层
- UserDao(实际应是接口)
- 具体代码见工程
day17_2
。 - 用户注册流程
sql注入
- 由于没有对用户输入进行充分检查,而SQL又是拼接而成,在用户输入参数时,在参数中添加一些SQL 关键字,达到改变SQL运行结果的目的,也可以完成恶意攻击。
- 1、statement存在sql注入攻击问题
- 例如登陆用户名采用
xxx’ or ‘1’=‘1
- 使用mysql注释
- 例如登陆用户名采用
- 2、对于防范 SQL 注入,可以采用
PreparedStatement
取代Statement
。- 它是一个预处理的Statement,它是java.sql.Statement接口的一个子接口。
- PreparedStatement是Statement的子接口,它的实例对象可以通过调
Connection.preparedStatement(sql)
方法获得 - Statement会使数据库频繁编译SQL,可能造成数据库缓冲区溢出。PreparedStatement 可对SQL进行预编译,从而提高数据库的执行效率。
- PreperedStatement对于sql中的参数,允许使用占位符的形式进行替换,简化sql语句的编写。
- PreparedStatement使用总结
- 1.在sql语句中,使用
?
占位- String sql=”select * from user where username=? and password=?”;
- 2.得到PreparedStatement对象
- PreparedStatement pst=con.prepareStatement(String sql);
- 3.对占位符赋值
- pst.setXxx(int index,Xxx obj);
- 例如:
- setInt()
- setString();
- 参数index,代表的是”
?
“的序号.注意:从1开始。
- 4.执行sql
- DML: pst.executeUpdate();
- DQL: pst.executeQuery();
- 注意:这两方法无参数
- 1.在sql语句中,使用
- 关于PreparedStatement优点:
- 1.解决sql注入(具有预处理功能)
- 2.不需要再拼sql语句。
jdbc处理大数据
- 在实际开发中,程序需要把大文本
Text
或二进制数据Blob
保存到数据库。Text
是mysql叫法,Oracle中叫Clob
大数据
也称之为LOB
(Large Objects),LOB又分为:- clob用于存储大文本。Text
- blob用于存储二进制数据,例如图像、声音、二进制文等。
- Text和blob分别又分为:
- Text(clob)
- TINYTEXT(255B)、TEXT(64kb)、MEDIUMTEXT(16M)和LONGTEXT(4G)
- blob
- TINYBLOB(255B)、BLOB(64kb)、MEDIUMBLOB(16M)和LONGBLOB(4G)
- Text(clob)
- 对于大数据操作,我们一般只有两种: insert select
- 演示1: 大二进制操作
create table myblob(
id int primary key auto_increment,
content longblob
)
public class MyBlobTest {
// 添加
@Test
public void save() throws SQLException, IOException {
String sql = "insert into myblob values(null,?)";
// 1.获取Connection
Connection con = JdbcUtils.getConnection();
// 2.获取PreparedStatement
PreparedStatement pst = con.prepareStatement(sql);
// 3.插入值
File file = new File("D:\\java1110\\day17-jdbc\\视频\\3.jdbc快速入门.avi");
FileInputStream fis = new FileInputStream(file);
pst.setBinaryStream(1, fis, (int) (file.length())); //MySQL驱动只支持最后一个参数为int类型的方法
int row = pst.executeUpdate();
if (row != 0) {
System.out.println("插入成功");
}
// 4.释放资源
fis.close();
pst.close();
con.close();
}
// 获取
@Test
public void get() throws SQLException, IOException {
String sql = "select * from myblob where id=?";
// 1.获取Connection
Connection con = JdbcUtils.getConnection();
// 2.获取PreparedStatement
PreparedStatement pst = con.prepareStatement(sql);
pst.setInt(1, 1);
// 3.得到结果集
ResultSet rs = pst.executeQuery();
// 4.遍历结果集
if (rs.next()) {
// System.out.println(rs.getInt("id"));
InputStream is = rs.getBinaryStream("content");// 得到的这个输入流它的源可以理解成就是数据库中的大二进制信息
FileOutputStream fos = new FileOutputStream("d:/a.avi");
int len = -1;
byte[] b = new byte[1024 * 100];
while ((len = is.read(b)) != -1) {
fos.write(b, 0, len);
fos.flush();
}
fos.close();
is.close();
}
// 5.关闭
rs.close();
pst.close();
con.close();
}
}
- 向表中插入数据可能出现的问题
- 问题1:java.lang.AbstractMethodError: com.mysql.jdbc.PreparedStatement.setBinaryStream(ILjava/io/InputStream;)
- 原因:mysql驱动不支持setBinaryStream(int,InputStream);
- 修改成 pst.setBinaryStream(1, fis,file.length());
- 原因:因为mysql驱动不支 setBinaryStream(int,InputStream,long);
- 解决: mysql驱动支持setBinaryStream(int,InputStream,int);
- 注意:如果文件比较大,那么需要在my.ini文件中配置
- max_allowed_packet=64M
- 总结:
- 存:pst.setBinaryStream(1, fis, (int) (file.length()));
- 取:InputStream is = rs.getBinaryStream(“content”);
使用JDBC处理大文本
- 对于MySQL中的Text类型,可调用如下方法
设置
:
PreparedStatement.setCharacterStream(index, reader, length);
//注意length长度须设置,并且设置为int型
//当包过大时修改配置:[mysqld] max_allowed_packet=64M
- 对MySQL中的Text类型,可调用如下方法
获取
:
reader = resultSet. getCharacterStream(i);
等价于
reader = resultSet.getClob(i).getCharacterStream();
- 演示:存储大文本
create table mytext(
id int primary key auto_increment,
content longtext
)
//存储
File file = new File("D:\\java1110\\workspace\\day17_3\\a.txt");
FileReader fr = new FileReader(file);
pst.setCharacterStream(1, fr, (int) (file.length()));
//获取:
Reader r = rs.getCharacterStream("content");
使用JDBC处理二进制数据
- 对于MySQL中的BLOB类型,可调用如下方法
设置
:PreparedStatement. setBinaryStream(i, inputStream, length);
- 对MySQL中的BLOB类型,可调用如下方法
获取
:InputStream in = resultSet.getBinaryStream(i);
InputStream in = resultSet.getBlob(i).getBinaryStream();
public class MyTextTest {
// 存储
@Test
public void save() throws SQLException, FileNotFoundException {
String sql = "insert into mytext values(null,?)";
// 1.获取Connection
Connection con = JdbcUtils.getConnection();
// 2.获取PreparedStatement
PreparedStatement pst = con.prepareStatement(sql);
// 3.插入值
File file = new File("D:\\java1110\\workspace\\day17_3\\a.txt");
FileReader fr = new FileReader(file);
pst.setCharacterStream(1, fr, (int) (file.length()));
pst.executeUpdate();
// 4.释放资源
pst.close();
con.close();
}
// 获取
@Test
public void get() throws SQLException, IOException {
String sql = "select * from mytext where id=?";
// 1.获取Connection
Connection con = JdbcUtils.getConnection();
// 2.获取PreparedStatement
PreparedStatement pst = con.prepareStatement(sql);
pst.setInt(1, 1);
// 3.得到结果集
ResultSet rs = pst.executeQuery();
// 4.遍历结果集
if (rs.next()) {
Reader r = rs.getCharacterStream("content");
FileWriter fw = new FileWriter("d:/笔记.txt");
int len = -1;
char[] ch = new char[1024 * 100];
while ((len = r.read(ch)) != -1) {
fw.write(ch, 0, len);
fw.flush();
}
fw.close();
r.close();
}
pst.close();
con.close();
}
}
JDBC批处理
- 业务场景:当需要向数据库发送一批SQL语句执行时,应避免向数据库一条条的发送执行,而应采用JDBC的批处理机制,以提升执行效率。
- 实现批处理有两种方式,第一种方式:
- Statement.addBatch(sql)
- executeBatch()方法:执行批处理命令
- clearBatch()方法:清除批处理命令
- 采用Statement.addBatch(sql)方式实现批处理:
- 优点:可以向数据库发送多条不同的SQL语句。
- 缺点:
- SQL语句没有预编译。
- 当向数据库发送多条语句相同,但仅参数不同的SQL语句时,需重复写上很多条SQL语句。例如:
- Insert into user(name,password) values(‘aa’,’111’);
- Insert into user(name,password) values(‘bb’,’222’);
- Insert into user(name,password) values(‘cc’,’333’);
- Insert into user(name,password) values(‘dd’,’444’);
- 实现批处理的第二种方式
- PreparedStatement.addBatch()
- addBatch();
- executeBatch();
- clearBatch();
- PreparedStatement.addBatch()
- 采用PreparedStatement.addBatch()实现批处理
- 优点:发送的是预编译后的SQL语句,执行效率高。
- 缺点:只能应用在SQL语句相同,但参数不同的批处理中。因此此种形式的批处理经常用于在同一个表中批量插入数据,或批量更新表的数据。
- 两个对象执行批处理区别?
- 1.Statement它更适合执行不同sql的批处理。它没有提供预处理功能,性能比较低。
- 2.PreparedStatement它适合执行相同sql的批处理,它提供了预处理功能,性能比较高。
- eg:第一种方式
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
conn = JdbcUtil.getConnection();
String sql1 = "insert into person(name,password,email,birthday)
values(‘kkk‘,‘123‘,‘[email protected]‘,‘1978-08-08‘)";
String sql2 = "update user set password=‘123456‘ where id=3";
st = conn.createStatement();
st.addBatch(sql1); //把SQL语句加入到批命令中
st.addBatch(sql2); //把SQL语句加入到批命令中
st.executeBatch();
} finally{
JdbcUtil.free(conn, st, rs);
}
- eg:第二种方式
conn = JdbcUtil.getConnection();
String sql = "insert into person(name,password,email,birthday) values(?,?,?,?)";
st = conn.prepareStatement(sql);
for(int i=0;i<50000;i++){
st.setString(1, "aaa" + i);
st.setString(2, "123" + i);
st.setString(3, "aaa" + i + "@sina.com");
st.setDate(4,new Date(1980, 10, 10));
st.addBatch();
if(i%1000==0){
st.executeBatch();
st.clearBatch();
}
}
st.executeBatch();
- 注意;mysql默认情况下,批处理中的预处理功能没有开启,需要开启
- 1.在 url下添加参数
- url=jdbc :mysql :///day17?
useServerPrepStmts=true&cachePrepStmts=true&rewriteBatchedStatements=true
- url=jdbc :mysql :///day17?
- 2.注意驱动版本
- Mysql驱动要使用mysql-connector-java-5.1.13以上
- 1.在 url下添加参数
- 作业:
- 1.注册+登录案例
- 采用dao模式 使用PreparedStatement操作
- 2.使用PreparedStatement完成CRUD
- 客户信息表DAO编写
- 创立如下数据库表customer,并编写DAO进行crud操作
时间: 2024-11-10 01:33:50