1、JDBC简介
(1)数据库驱动
(2)Sun公司为简化数据库开发,定义了一套jdbc接口,这套接口由数据库厂商去实现,这样,开发人员只需要学习jdbc接口,并通过jdbc加载具体的驱动,就可以操作数据库。
(3)JDBC全称为:Java Data Base Connectivity(java数据库连接),它主要由接口组成。
(4)组成JDBC的2个包:
java.sql
javax.sql
(5)开发JDBC应用需要以上2个包的支持外,还需要导入相应JDBC的数据库实现(即数据库驱动)。
2、第一个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.excuteQuery(sql);
五、从代表结果集的ResultSet中取出数据,打印到命令行窗口
六、断开与数据库的连接,并释放相关资源
1、注册驱动
SUN公司定义了JDBC只是一些接口,用户要想操作数据库,需要先把数据库的驱动,也就是JDBC的实现类拿到程序里来,这个操作称之为注册驱动。Sun公司定义了DriveManager类用于完成驱动程序的注册,示例:
DriverManager.registerDrive(new com.jdbc.mysql.Driver());
2、驱动注册后,就可以创建与数据库的连接了。
Connection connection = DriverManager.getConnection();
3、获得连接后,就可以在此连接上创建一条SQL语句,并发送给数据库
Statement st = connection.createStatement();
ResultSet set = St.excute(“select * from user”);
package com.itheima;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import org.junit.Test;
import com.mysql.jdbc.Driver;
public class JDBCDemo1 {
@Test
/**
* JDBC快速入门
*/
public void test1() {
Connection conn = null;
Statement stat = null;
ResultSet rs = null;
try{
//1.注册驱动管理器
//DriverManager.registerDriver(new Driver());
Class.forName("com.mysql.jdbc.Driver");
//2.获取数据库的连接
conn = DriverManager.getConnection("jdbc:mysql:///day10?user=root&password=root");
//3.通过Connection获取传输器对象
stat = conn.createStatement();
//4.通过传输器对象发送sql语句到数据库中执行
rs = stat.executeQuery("select * from user");
//5.遍历结果集获取要查询的结果
rs.next();
rs.next();
rs.next();
rs.previous();
String name = rs.getString("name");
System.out.println(name);
// while(rs.next()){
// String name = rs.getString("name");
// System.out.println(name);
// }
}catch (Exception e) {
e.printStackTrace();
}finally{
//6.关闭资源
if(rs != null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
} finally {
rs = null;
}
}
if(stat != null){
try {
stat.close();
} catch (SQLException e) {
e.printStackTrace();
} finally {
stat = null;
}
}
if(conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
} finally {
conn = null;
}
}
}
}
}
3、程序详解—DriverManager
(1)Jdbc程序中的DriverManager用于加载驱动,并创建与数据库的链接,这个API的常用方法:
DriverManager.registerDriver(new Driver())
DriverManager.getConnection(url, user, password),
(2)注意:在实际开发中并不推荐采用registerDriver方法注册驱动。原因有二:
一、查看Driver的源代码可以看到,如果采用此种方式,会导致驱动程序注册两次,也就是在内存中会有两个Driver对象。
二、程序依赖mysql的api,脱离mysql的jar包,程序将无法编译,将来程序切换底层数据库将会非常麻烦。
(3)推荐方式:Class.forName(“com.mysql.jdbc.Driver”);
采用此种方式不会导致驱动对象在内存中重复出现,并且采用此种方式,程序仅仅只需要一个字符串,不需要依赖具体的驱动,使程序的灵活性更高。
(4)同样,在开发中也不建议采用具体的驱动类型指向getConnection方法返回的connection对象。
4、数据库URL
(1)URL用于标识数据库的位置,程序员通过URL地址告诉JDBC程序连接哪个数据库,URL的写法为:
jdbc:mysql:[]//localhost:3306/test ?参数名:参数值
(2)常用数据库URL地址的写法:
Oracle写法:jdbc:oracle:thin:@localhost:1521:sid
SqlServer—jdbc:microsoft:sqlserver://localhost:1433; DatabaseName=sid
MySql—jdbc:mysql://localhost:3306/sid
(3)Mysql的url地址的简写形式: jdbc:mysql:///sid
常用属性:useUnicode=true&characterEncoding=UTF-8
5、程序详解—Connection
Jdbc程序中的Connection,它用于代表数据库的链接,Connection是数据库编程中最重要的一个对象,客户端与数据库所有交互都是通过connection对象完成的,这个对象的常用方法:
(1)createStatement():创建向数据库发送sql的statement对象。
(2)prepareStatement(sql) :创建向数据库发送预编译sql的PrepareSatement对象。
(3)prepareCall(sql):创建执行存储过程的callableStatement对象。
(4)setAutoCommit(boolean autoCommit):设置事务是否自动提交。
(5)commit() :在链接上提交事务。
(6)rollback() :在此链接上回滚事务。
6、程序详解—Statement
Jdbc程序中的Statement对象用于向数据库发送SQL语句, Statement对象常用方法:
(1)executeQuery(String sql) :用于向数据发送查询语句。
(2)executeUpdate(String sql):用于向数据库发送insert、update或delete语句
(3)execute(String sql):用于向数据库发送任意sql语句
(4)addBatch(String sql) :把多条sql语句放到一个批处理中。
(5)executeBatch():向数据库发送一批sql语句执行。
7、程序详解—ResultSet
(1)Jdbc程序中的ResultSet用于代表Sql语句的执行结果。Resultset封装执行结果时,采用的类似于表格的方式。ResultSet 对象维护了一个指向表格数据行的游标,初始的时候,游标在第一行之前,调用ResultSet.next() 方法,可以使游标指向具体的数据行,进行调用方法获取该行的数据。
(2)ResultSet既然用于封装执行结果的,所以该对象提供的都是用于获取数据的get方法:
获取任意类型的数据
getObject(int index)
getObject(string columnName)
获取指定类型的数据,例如:
getString(int index)
getString(String columnName)
提问:数据库中列的类型是varchar,获取该列的数据调用什么方法?Int类型呢?bigInt类型呢?Boolean类型?
(3)ResultSet还提供了对结果集进行滚动的方法:
next():移动到下一行
Previous():移动到前一行
absolute(int row):移动到指定行
beforeFirst():移动resultSet的最前面。
afterLast() :移动到resultSet的最后面。
8、常用数据类型转换表
9、程序详解—释放资源
(1)Jdbc程序运行完后,切记要释放程序在运行过程中,创建的那些与数据库进行交互的对象,这些对象通常是ResultSet, Statement和Connection对象。
(2)特别是Connection对象,它是非常稀有的资源,用完后必须马上释放,如果Connection不能及时、正确的关闭,极易导致系统宕机。Connection的使用原则是尽量晚创建,尽量早的释放。
(3)为确保资源释放代码能运行,资源释放代码也一定要放在finally语句中。
(4)conn是一个有限的资源,用完立即要释放表
stat占用内存,所以使用完后也要释放
rs占用内存,所以使用完后也要释放
释放时后创建的先释放
if(rs != null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
} finally{
rs = null;
}
}
if(stat != null){
try {
stat.close();
} catch (SQLException e) {
e.printStackTrace();
} finally{
stat = null;
}
}
if(conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
} finally{
conn = null;
}
}
10、使用JDBC对数据库进行CRUD
(1)Jdbc中的statement对象用于向数据库发送SQL语句,想完成对数据库的增删改查,只需要通过这个对象向数据库发送增删改查语句即可。
(2)Statement对象的executeUpdate方法,用于向数据库发送增、删、改的sql语句,executeUpdate执行完后,将会返回一个整数(即增删改语句导致了数据库几行数据发生了变化)。
(3)Statement.executeQuery方法用于向数据库发送查询语句,executeQuery方法返回代表查询结果的ResultSet对象。
练习:编写程序对User表进行增删改查操作。
练习:编写工具类简化CRUD操作。(异常暂不处理)
11、CRUD操作-create
使用executeUpdate(String sql)方法完成数据添加操作,示例操作:
Statement st = conn.createStatement();
String sql = "insert into user(….) values(…..) ";
int num = st.executeUpdate(sql);
if(num>0){
System.out.println("插入成功!!!");
}
/**
* JDBC的添加
*/
public void add() {
Connection conn = null;
Statement stat = null;
try {
//1.2
conn = DaoUtil.getConnenction();
// 3.获取传输器对象
stat = conn.createStatement();
// 4.利用传输器执行sql,获取结果集
int count = stat
.executeUpdate("insert into user values (null,'zhaoliu','123456','zhaoliu@qq.com','2000-01-01')");
// 5.获取结果
if (count == 0) {
System.out.println("执行失败!");
} else {
System.out.println("执行成功!影响行数:" + count);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
DaoUtil.close(conn, stat, null);
}
}
12、CRUD操作-update
使用executeUpdate(String sql)方法完成数据修改操作,示例操作:
Statement st = conn.createStatement();
String sql = “update user set name=‘’ where name=‘’";
int num = st.executeUpdate(sql);
if(num>0){
System.out.println(“修改成功!!!");
}
/**
* JDBC的更新
*/
public void update() {
Connection conn = null;
Statement stat = null;
try {
// 1.注册数据库驱动
Class.forName("com.mysql.jdbc.Driver");
// 2.获取数据库连接
conn = DriverManager
.getConnection("jdbc:mysql:///day10?user=root&password=root");
// 3.获取传输器对象
stat = conn.createStatement();
// 4.利用传输器执行sql,获取结果集
int count = stat
.executeUpdate("update user set password='999999' where name='zhaoliu'");
// 5.获取结果
if (count == 0) {
System.out.println("执行失败!");
} else {
System.out.println("执行成功!影响行数:" + count);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (stat != null) {
try {
stat.close();
} catch (SQLException e) {
e.printStackTrace();
} finally {
stat = null;
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
} finally {
conn = null;
}
}
}
}
13、CRUD操作-delete
使用executeUpdate(String sql)方法完成数据删除操作,示例操作:
Statement st = conn.createStatement();
String sql = “delete from user where id=1;
int num = st.executeUpdate(sql);
if(num>0){
System.out.println(“删除成功!!!");
}
/**
* JDBC的删除
*/
public void delete() {
Connection conn = null;
Statement stat = null;
try {
// 1.注册数据库驱动
Class.forName("com.mysql.jdbc.Driver");
// 2.获取数据库连接
conn = DriverManager
.getConnection("jdbc:mysql:///day10?user=root&password=root");
// 3.获取传输器对象
stat = conn.createStatement();
// 4.利用传输器执行sql,获取结果集
int count = stat
.executeUpdate("delete from user where name='zhaoliu'");
// 5.获取结果
if (count == 0) {
System.out.println("执行失败!");
} else {
System.out.println("执行成功!影响行数:" + count);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (stat != null) {
try {
stat.close();
} catch (SQLException e) {
e.printStackTrace();
} finally {
stat = null;
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
} finally {
conn = null;
}
}
}
}
}
14、CRUD操作-read
使用executeQuery(String sql)方法完成数据查询操作,示例操作:
Statement st = conn.createStatement();
String sql = “select * from user where id=1;
ResultSet rs = st.executeUpdate(sql);
while(rs.next()){
//根据获取列的数据类型,分别调用rs的相应方法
//映射到java对象中
}
/**
* JDBC 的查询
*/
public void find() {
Connection conn = null;
Statement stat = null;
ResultSet rs = null;
try {
//1.2
conn = DaoUtil.getConnenction();
// 3.获取传输器对象
stat = conn.createStatement();
// 4.利用传输器执行sql,获取结果集
rs = stat.executeQuery("select * from user where id=1");
// 5.遍历结果集获取数据
while (rs.next()) {
String name = rs.getString(2);
System.out.println(name);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
DaoUtil.close(conn, stat, rs);
}
}
15、PreparedStatement
PreperedStatement是Statement的孩子,它的实例对象可以通过调用Connection.preparedStatement()方法获得,相对于Statement对象而言:
PreperedStatement可以避免SQL注入的问题。
Statement会使数据库频繁编译SQL,可能造成数据库缓冲区溢出。PreparedStatement 可对SQL进行预编译,从而提高数据库的执行效率。
并且PreperedStatement对于sql中的参数,允许使用占位符的形式进行替换,简化sql语句的编写。
16、使用JDBC处理大数据
(1)在实际开发中,程序需要把大文本 Text 或二进制数据 Blob保存到数据库。
(2)Text是mysql叫法,Oracle中叫Clob
(3)基本概念:大数据也称之为LOB(Large Objects),LOB又分为:
clob和blob
clob用于存储大文本。Text
blob用于存储二进制数据,例如图像、声音、二进制文等。
(4)对MySQL而言只有blob,而没有clob,mysql存储大文本采用的是Text,Text和blob分别又分为:
TINYTEXT(255)、TEXT(64k)、MEDIUMTEXT(16M)和LONGTEXT(4G)
TINYBLOB、BLOB、MEDIUMBLOB和LONGBLOB
(4)BLOB或TEXT对象的最大大小由其类型确定,但在客户端和服务器之间实际可以传递的最大值由可用内存数量和通信缓存区大小确定。你可以通过更改[mysqld]位置下:max_allowed_packet变量的值更改消息缓存区的大小
17、使用JDBC处理大文本
插入大文本:
ps = conn.prepareStatement("insert into Demo2Text values(null,?,?)");
ps.setString(1, "钢铁是怎样练成");
File file = new File("1.txt");
ps.setCharacterStream(2, new FileReader(file), (int) file.length());
//1.Exception in thread "main" java.lang.AbstractMethodError: com.mysql.jdbc.PreparedStatement.setCharacterStream(ILjava/io/Reader;J)V
//ps.setCharacterStream(2, new FileReader(file), file.length());第三个参数是long型的是从1.6才开始支持的,驱动里还没有开始支持。
//解决方案:ps.setCharacterStream(2, new FileReader(file), (int)file.length());
//2.Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
//文件大小过大,导致PreparedStatement中数据多大占用内存,内存溢出
//-Xms256M-Xmx256M
//3.com.mysql.jdbc.PacketTooBigException: Packet for query is too large (10886466 > 1048576). You can change this value on the server by setting the max_allowed_packet' variable.
//数据库连接传输用的包不够大,传输大文本时报此错误
//在my.ini中配置max_allowed_packet指定包的大小
~查询大文本:
Reader rd = rs.getCharacterStream("content");
package com.itheima.text;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.Reader;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import org.junit.Test;
import com.itheima.util.DaoUtil;
/**
* create table mytext( id int primary key auto_increment, name varchar(40),
* content MEDIUMTEXT ); java.lang.AbstractMethodError:
* com.mysql.jdbc.PreparedStatement.setCharacterStream(ILjava/io/Reader;J)V
* java.lang.OutOfMemoryError: Java heap space
* com.mysql.jdbc.PacketTooBigException: Packet for query is too large (10886471 >
* 1048576). You can change this value on the server by setting the
* max_allowed_packet' variable.
*
*/
public class TextDemo1 {
@Test
public void write() {
Connection conn = null;
PreparedStatement ps = null;
try {
conn = DaoUtil.getConnenction();
ps = conn.prepareStatement("insert into mytext values (null,?,?)");
ps.setString(1, "钢铁是怎样练成的.txt");
File file = new File("a.txt");
ps.setCharacterStream(2, new FileReader(file), (int) file.length());
ps.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
DaoUtil.close(conn, ps, null);
}
}
@Test
public void read() {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = DaoUtil.getConnenction();
ps = conn.prepareStatement("select * from mytext where id=?");
ps.setInt(1, 1);
rs = ps.executeQuery();
while(rs.next()){
Reader reader = rs.getCharacterStream("content");
File file = new File(rs.getString("name"));
FileWriter writer = new FileWriter(file);
char [] cs = new char [1024];
int i = 0;
while((i = reader.read(cs))!=-1){
writer.write(cs,0,i);
}
reader.close();
writer.close();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
DaoUtil.close(conn, ps, null);
}
}
}
18、使用JDBC处理二进制数据
~插入:
ps = conn.prepareStatement("insert into Demo3Blob values(null,?,?)");
ps.setString(1, "梦想的力量");
File file = new File("1.mp3");
ps.setBinaryStream(2, new FileInputStream(file), (int) file.length());
~查询
InputStream in = rs.getBinaryStream("content");
package com.itheima.blob;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import org.junit.Test;
import com.itheima.util.DaoUtil;
/**
create table myblob (
id int primary key auto_increment,
name varchar(40),
content LONGBLOB
)
*/
public class BlobDemo1 {
@Test
public void write(){
Connection conn = null;
PreparedStatement ps = null;
try {
conn = DaoUtil.getConnenction();
ps = conn.prepareStatement("insert into myblob values (null,?,?)");
ps.setString(1, "洛天依.mp3");
File file = new File("1.mp3");
ps.setBinaryStream(2, new FileInputStream(file), (int)file.length());
ps.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
DaoUtil.close(conn, ps, null);
}
}
@Test
public void read(){
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = DaoUtil.getConnenction();
ps = conn.prepareStatement("select * from myblob where id=1");
rs = ps.executeQuery();
while(rs.next()){
InputStream in = rs.getBinaryStream("content");
File file = new File(rs.getString("name"));
FileOutputStream fos = new FileOutputStream(file);
byte [] bs = new byte[1024];
int i = 0;
while((i=in.read(bs))!=-1){
fos.write(bs,0,i);
}
in.close();
fos.close();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
DaoUtil.close(conn, ps, null);
}
}
}
19、使用JDBC进行批处理
(1)业务场景:当需要向数据库发送一批SQL语句执行时,应避免向数据库一条条的发送执行,而应采用JDBC的批处理机制,以提升执行效率。
(2)实现批处理有两种方式,第一种方式:
Statement.addBatch(sql)
执行批处理SQL语句
executeBatch()方法:执行批处理命令
clearBatch()方法:清除批处理命令
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','abc@sina.com','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);
}
=====================================================================
package com.itheima.batch;
import java.sql.Connection;
import java.sql.Statement;
import org.junit.Test;
import com.itheima.util.DaoUtil;
/**
create database mybatch;
use mybatch;
create table batchtab(
id int primary key auto_increment,
name varchar(20),
age int
);
insert into batchtab values (null,'郭富城',55);
*/
public class Batch1 {
@Test
public void test1(){
Connection conn = null;
Statement stat = null;
try{
conn = DaoUtil.getConnenction();
stat = conn.createStatement();
stat.addBatch("create database mybatch");
stat.addBatch("use mybatch");
stat.addBatch("create table batchtab( id int primary key auto_increment, name varchar(20),age int)");
stat.addBatch("insert into batchtab values (null,'郭富城',55)");
stat.executeBatch();
}catch (Exception e) {
e.printStackTrace();
}finally{
DaoUtil.close(conn, stat, null);
}
}
}
(4)采用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’);
(5)实现批处理的第二种方式:
PreparedStatement.addBatch()
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();
package com.itheima.batch;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.Statement;
import org.junit.Test;
import com.itheima.util.DaoUtil;
/**
create table batch2(
id int primary key ,
name varchar(10)
)
*/
public class Bathc2 {
@Test
public void test1(){
Connection conn = null;
PreparedStatement ps = null;
try{
conn = DaoUtil.getConnenction();
ps = conn.prepareStatement("insert into batch2 values (?,?)");
for(int i = 1;i<=10000;i++){
ps.setInt(1, i);
ps.setString(2, "name"+i);
ps.addBatch();
if(i%100==0){
ps.executeBatch();
ps.clearBatch();
}
}
ps.executeBatch();
ps.clearBatch();
}catch (Exception e) {
e.printStackTrace();
}finally{
DaoUtil.close(conn, ps, null);
}
}
}
(6)采用PreparedStatement.addBatch()实现批处理
优点:发送的是预编译后的SQL语句,执行效率高。
缺点:只能应用在SQL语句相同,但参数不同的批处理中。因此此种形式的批处理经常用于在同一个表中批量插入数据,或批量更新表的数据。