时间:2021-07-01 10:21:17 帮助过:4人阅读
文档版本 开发工具 测试平台 工程名字 日期 作者 备注 V1.0 2016.05.11 lutianfei none JDBC JDBC介绍 JDBC是什么? JDBC(Java Data Base Connectivity,java数据库连接) SUN公司为了简化、统一对数据库的操作,定义了一套Java操作数据库的规范,称之为JDBC。
文档版本 | 开发工具 | 测试平台 | 工程名字 | 日期 | 作者 | 备注 |
---|---|---|---|---|---|---|
V1.0 | 2016.05.11 | lutianfei | none |
Connection
Statement
ResultSet
PreparedStatement
CallableStatement
(它是用于调用存储过程)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','tom@163.com');
INSERT INTO USER VALUES(NULL,'fox','123','fox@163.com');
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程序中的DriverManager
是java.sql
包下的一个驱动管理的工具类,可以理解成是一个容器(Vector),可以装入很多数据库驱动,并创建与数据库的链接,这个API的常用方法:
registDriver方法
分析
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}
上述代码的问题:
Class.forName("com.mysql.jdbc.Driver");
Connection con=DriverManager.getConection(String url,String user,String password);
jdbc: mysql ://localhsot:3306/数据库名
jdbc : oracle :thin :@ localhost :1521 :sid
DriverManager作用总结:
URL用于标识数据库的位置,程序员通过URL地址告诉JDBC程序连接哪个数据库,URL的写法为:
jdbc : mysql : // localhost :3306/test ?key=value
url格式
jdbc : mysql ://localhost:3306/day17
mysql的url可以简写
jdbc : mysql : ///day17
在url后面可以带参数
java.sql.Connection
,它代表的是一个连接对象。简单说,就是我们程序与数据库连接。
Connection作用:
PreparedStatement对象
.创建向数据库发送预编译sql的PrepareSatement对象 CallableStatement
,创建执行存储过程的callableStatement对象。 java.sql.Statement
用于向数据库发送SQL语句,执行sql语句。1.执行SQL
insert
update
delete
select
2.批处理操作
java.sql.ResultSet
它是用于封装select语句执行后查询的结果。Resultset封装执行结果时,采用的类似于表格的方式。ResultSet 对象维护了一个指向表格数据行的游标cursor
,初始的时候,游标在第一行之前,调用ResultSet.next() 方法
,可以使游标指向具体的数据行,进而调用方法获取该行的数据。1.next()方法
2.可以通过ResultSet提供的getXxx()方法来获取当前游标指向的这条记录中的列数据。
如果列的类型不知道,可以通过下面的方法来操作
常用数据类型转换表
JDBC程序运行完后,切记要释放程序在运行过程中,创建的那些与数据库进行交互的对象,这些对象通常是ResultSet, Statement和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中的statement对象用于向数据库发送SQL语句,想完成对数据库的增删改查,只需要通过这个对象向数据库发送增删改查语句即可。
Statement对象的executeUpdate方法
,用于向数据库发送增、删、改的sql语句,executeUpdate执行完后,将会返回一个整数(即增删改语句导致了数据库几行数据发生了变化)。
Statement.executeQuery方法
用于向数据库发送查询语句,executeQuery方法返回代表查询结果的ResultSet对象。
1.查询
4.添加
练习:编写程序对User表进行增删改查操作。
//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的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','zs@163.com')";
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它只能向下遍历(next()),对于ResultSet它可以设置成是滚动的,可以向上遍历,或者直接定位到一个指定的物理行号。
设置滚动结果集的方法
createStatement()
;而使用带参数的createStatement(int,int)
Statement createStatement(int resultSetType,
int resultSetConcurrency)
throws SQLException
、
Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
第一个参数值, resultSetType
第二个参数值,resultSetConcurrency
以上五个值,可以有三种搭配方式
常用API
DAO模式
(Data Access Object 数据访问对象):在持久层通过DAO将数据源操作完全封装起来,业务层通过操作Java对象,完成对数据源操作需求:
1.web层
具体代码见工程day17_2
。
用户注册流程
xxx’ or ‘1’=‘1
2、对于防范 SQL 注入,可以采用PreparedStatement
取代Statement
。
Connection.preparedStatement(sql)
方法获得PreparedStatement使用总结
?
占位 ?
“的序号.注意:从1开始。关于PreparedStatement优点:
在实际开发中,程序需要把大文本 Text
或二进制数据 Blob
保存到数据库。
Text
是mysql叫法,Oracle中叫Clob
大数据
也称之为LOB
(Large Objects),LOB又分为:
Text和blob分别又分为:
对于大数据操作,我们一般只有两种: 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文件中配置
总结:
设置
:PreparedStatement.setCharacterStream(index, reader, length);
//注意length长度须设置,并且设置为int型
//当包过大时修改配置:[mysqld] max_allowed_packet=64M
获取
: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");
设置
: PreparedStatement. setBinaryStream(i, inputStream, length);
获取
: 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();
}
}
业务场景:当需要向数据库发送一批SQL语句执行时,应避免向数据库一条条的发送执行,而应采用JDBC的批处理机制,以提升执行效率。
实现批处理有两种方式,第一种方式:
采用Statement.addBatch(sql)方式实现批处理:
实现批处理的第二种方式
采用PreparedStatement.addBatch()实现批处理
两个对象执行批处理区别?
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);
}
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();
useServerPrepStmts=true&cachePrepStmts=true&rewriteBatchedStatements=true
采用dao模式 使用PreparedStatement操作
2.使用PreparedStatement完成CRUD
客户信息表DAO编写