JDBC基础学习笔记
第一章:JDBC 概述
第一节:JDBC 简介
JDBC(Java Data Base Connectivity,java 数据库连接)是一种用于执行 SQL 语句的 JavaAPI,可以为多种关系 数据库提供统一访问,它由一组用 Java 语言编写的类和接口组成。JDBC 提供了一种基准,据此可以构建更高 级的工具和接口,使数据库开发人员能够编写数据库应用程序。
第二节:JDBC 原理
JDBC 原理:JDBC 是以前 SUN 公司定义的一套访问数据库的接口(没有具体实现),一套标准,具体的实现是由 各大数据库厂家去实现,每个数据库厂家都有自己的 JDBC 实现,也就是 JDBC 驱动实现类,Java 应用程序连接 指定数据库,需要使用厂家提供的 JDBC 驱动才能连接。(这里其实就是 java 多态的一种体现,一个接口可以有 很多具体的实现)
第二章:JDBC 连接数据库
第一节:JDBC 连接数据库步骤
第一步:加载驱动;
第二步:连接数据库;
第三步:使用语句操作数据库;
第四步:关闭数据库连接,释放资源;
第二节:在项目里配置数据库驱动
右击项目 -> Build Path -> Configure Build Path -> Add Exteranl JARs..
第三节:加载数据驱动
Mysql 驱动名:com.mysql.jdbc.Driver
加载方式: Class.forName(驱动名);即Class.forName("com.mysql.jdbc.Driver");
第四节:连接及关闭数据库
1,DriverManager 驱动管理类,主要负责获取一个数据库的连接;
static Connection getConnection(String url, String user, String password) 试图建立到给定数据库 URL 的连 接。
例如Connection con=DriverManager.getConnection("jdbc:mysql://localhost:3306/db_book", "root", "123456");
2,MySQL 数据库的连接地址格式
jdbc:mysql://IP 地址:端口号/数据库名称
jdbc 协议:JDBC
URL 中的协议总是 jdbc ;
子协议:驱动程序名或数据库连接机制(这种机制可由一个或多个驱动程序支持)的名称,如 mysql; 子
名称:一种标识数据库的方法。必须遵循“//主机名端口/子协议”的标准 URL 命名约定,如 //localhost:3306/db_book3,Connection 接口 与特定数据库的连接(会话)。
void close() 立即释放此 Connection 对象的数据库和 JDBC 资源,而不是等待它们被自动释放
第三章:使用 Statement 接口实现增,删,改操作
作用:用于执行静态 SQL 语句并返回它所生成结果的对象。
利用Statement stmt=con.createStatement(); 获取Statement对象。
int executeUpdate(String sql) 执行给定 SQL 语句,该语句可能为 INSERT、UPDATE 或DELETE 语句,或 者不返回任何内容的 SQL 语句(如 SQL DDL 语句)。
void close() 立即释放此 Statement 对象的数据库和 JDBC 资源,而不是等待该对象自动关闭时发生此操作。
注:1.可以将Statemant与Connection的close写在一个方法中
如:
public void close(Statement stmt,Connection con)throws Exception{ if(stmt!=null){ stmt.close(); if(con!=null){ con.close(); } } }
2.stmt.executeUpdate(sql);会返回一个int类型的result,可以用这个判断是否语句是否成功,成功的话会返回1。
第四章:使用 PreparedStatement 接口实现增,删,改操作
PreparedStatement 是 Statement 的子接口,属于预处理操作,与直接使用 Statement 不同的是,PreparedStatement 在操作时,是先在数据表中准备好了一条 SQL 语句,但是此 SQL 语句的具体内容暂时不设置,而是之后再进 行设置。
(以后开发一般用 PreparedStatement,不用 Statement)
写入数据时可以这么做
private static int addBook(Book book)throws Exception{
Connection con=dbUtil.getCon(); // 获取连接
String sql="insert into t_book values(null,?,?,?,?)";
PreparedStatement pstmt=con.prepareStatement(sql);
pstmt.setString(1, book.getBookName()); // 给第一个坑设置值
pstmt.setFloat(3, book.getPrice()); // 给第二个坑设置值
pstmt.setString(2, book.getAuthor()); // 给第三个坑设置值
pstmt.setInt(4, book.getBookTypeId()); // 给第四个坑设置值
int result=pstmt.executeUpdate();
dbUtil.close(pstmt, con);
return result;
}
第五章: ResultSet 结果集
第一节:ResultSet 结果集的引入
当我们查询数据库时,返回的是一个二维的结果集,我们这时候需要使用 ResultSet 来遍历结果集,获取每一行 的数据。
第二节:使用 ResultSet 遍历查询结果
boolean next() 将光标从当前位置向前移一行。 String getString(int columnIndex) 以 Java 编程语言中 String 的形式获取此 ResultSet 对象的当前行中指定列 的值。 String getString(String columnLabel) 以 Java 编程语言中 String 的形式获取此 ResultSet 对象的当前行中指 定列的值。
读取数据时可以分别以这三种形式:利用index,关键字,或者直接获取一个对象。
private static void listBook() throws Exception { Connection con = dbUtil.getCon(); // 获取连接 String sql = "select * from t_book"; PreparedStatement pstmt = con.prepareStatement(sql); ResultSet rs = pstmt.executeQuery(); // 返回结果集ResultSet//默认在第0行 while (rs.next()) { int id = rs.getInt(1); // 获取第一个列的值 编号id String bookName = rs.getString(2); // 获取第二个列的值 图书名称 bookName float price = rs.getFloat(4); // 获取第三列的值 图书价格 price String author = rs.getString(3); // 获取第四列的值 图书作者 author int bookTypeId = rs.getInt(5); // 获取第五列的值 图书类别id System.out.println("图书编号:" + id + " 图书名称:" + bookName + " 图书价格:" + price + " 图书作者:" + author + " 图书类别id:" + bookTypeId); System.out .println("======================================================================="); } }
private static void listBook2() throws Exception { Connection con = dbUtil.getCon(); // 获取连接 String sql = "select * from t_book"; PreparedStatement pstmt = con.prepareStatement(sql); ResultSet rs = pstmt.executeQuery(); // 返回结果集ResultSet while (rs.next()) { int id = rs.getInt("id"); // 获取第一个列的值 编号id String bookName = rs.getString("bookName"); // 获取第二个列的值 图书名称 bookName float price = rs.getFloat("price"); // 获取第三列的值 图书价格 price String author = rs.getString("author"); // 获取第四列的值 图书作者 author int bookTypeId = rs.getInt("bookTypeId"); // 获取第五列的值 图书类别id System.out.println("图书编号:" + id + " 图书名称:" + bookName + " 图书价格:" + price + " 图书作者:" + author + " 图书类别id:" + bookTypeId); System.out .println("======================================================================="); } }
private static List<Book> listBook3()throws Exception{ List<Book> bookList=new ArrayList<Book>(); Connection con = dbUtil.getCon(); // 获取连接 String sql = "select * from t_book"; PreparedStatement pstmt = con.prepareStatement(sql); ResultSet rs = pstmt.executeQuery(); // 返回结果集ResultSet while (rs.next()) { int id = rs.getInt("id"); // 获取第一个列的值 编号id String bookName = rs.getString("bookName"); // 获取第二个列的值 图书名称 bookName float price = rs.getFloat("price"); // 获取第三列的值 图书价格 price String author = rs.getString("author"); // 获取第四列的值 图书作者 author int bookTypeId = rs.getInt("bookTypeId"); // 获取第五列的值 图书类别id Book book=new Book(id, bookName, price, author, bookTypeId); bookList.add(book); } return bookList; }
第六章: 处理大数据对象
大数据对象处理主要有 CLOB(character large object)和 BLOB(binary large object)两种类型的字段;在 CLOB 中可以存储大字符数据对象,比如长篇小说;在 BLOB 中可以存放二进制大数据对象,比如图片,电影,音乐;
第一节:处理 CLOB 数据
package com.java1234.jdbc.chap06.sec01; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.sql.Clob; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import com.java1234.jdbc.model.Book; import com.java1234.jdbc.util.DbUtil; public class Demo1 { private static DbUtil dbUtil=new DbUtil(); /** * 添加图书 * @param book * @return * @throws Exception */ private static int addBook(Book book)throws Exception{ Connection con=dbUtil.getCon(); // 获取连接 String sql="insert into t_book values(null,?,?,?,?,?)"; PreparedStatement pstmt=con.prepareStatement(sql); pstmt.setString(1, book.getBookName()); // 给第一个坑设置值 pstmt.setFloat(3, book.getPrice()); // 给第二个坑设置值 pstmt.setString(2, book.getAuthor()); // 给第三个坑设置值 pstmt.setInt(4, book.getBookTypeId()); // 给第四个坑设置值 File context=book.getContext(); // 获取文件 InputStream inputStream=new FileInputStream(context); pstmt.setAsciiStream(5, inputStream,(int)context.length()); // 给第五个坑设置值 int result=pstmt.executeUpdate(); dbUtil.close(pstmt, con); return result; } public static void getBook(int id)throws Exception{ Connection con=dbUtil.getCon(); String sql="select * from t_book where id=?"; PreparedStatement pstmt=con.prepareStatement(sql); pstmt.setInt(1, id); ResultSet rs=pstmt.executeQuery(); if(rs.next()){ String bookName=rs.getString("bookName"); float price=rs.getFloat("price"); String author=rs.getString("author"); int bookTypeId=rs.getInt("bookTypeId"); Clob c=rs.getClob("context"); String context=c.getSubString(1, (int) c.length()); System.out.println("图书名称:"+bookName); System.out.println("图书价格:"+price); System.out.println("图书作者:"+author); System.out.println("图书类型ID:"+bookTypeId); System.out.println("图书内容:"+context); } dbUtil.close(pstmt, con); } public static void main(String[] args)throws Exception { // String str="C:\\152.txt"; // String location=str.replace("\\\\", "/"); // File context=new File(location); // System.out.println(location); // Book book=new Book("helloWorld", 100, "小锋", 1,context); // int result=addBook(book); // if(result==1){ // System.out.println("添加成功!"); // }else{ // System.out.println("添加失败!"); // } getBook(6); } }
第二节:处理 BLOG 数据
package com.java1234.jdbc.chap06.sec02; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.sql.Blob; import java.sql.Clob; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import com.java1234.jdbc.model.Book; import com.java1234.jdbc.util.DbUtil; public class Demo1 { private static DbUtil dbUtil=new DbUtil(); /** * 添加图书 * @param book * @return * @throws Exception */ private static int addBook(Book book)throws Exception{ Connection con=dbUtil.getCon(); // 获取连接 String sql="insert into t_book values(null,?,?,?,?,?,?)"; PreparedStatement pstmt=con.prepareStatement(sql); pstmt.setString(1, book.getBookName()); // 给第一个坑设置值 pstmt.setFloat(3, book.getPrice()); // 给第二个坑设置值 pstmt.setString(2, book.getAuthor()); // 给第三个坑设置值 pstmt.setInt(4, book.getBookTypeId()); // 给第四个坑设置值 File context=book.getContext(); // 获取文件 InputStream inputStream=new FileInputStream(context); pstmt.setAsciiStream(5, inputStream,(int)context.length()); // 给第五个坑设置值 File pic=book.getPic(); // 获取图片文件 InputStream inputStream2=new FileInputStream(pic); pstmt.setBinaryStream(6, inputStream2, (int)pic.length()); // 给第六个坑设置值 int result=pstmt.executeUpdate(); dbUtil.close(pstmt, con); return result; } public static void getBook(int id)throws Exception{ Connection con=dbUtil.getCon(); String sql="select * from t_book where id=?"; PreparedStatement pstmt=con.prepareStatement(sql); pstmt.setInt(1, id); ResultSet rs=pstmt.executeQuery(); if(rs.next()){ String bookName=rs.getString("bookName"); float price=rs.getFloat("price"); String author=rs.getString("author"); int bookTypeId=rs.getInt("bookTypeId"); Clob c=rs.getClob("context"); String context=c.getSubString(1, (int)c.length()); Blob b=rs.getBlob("pic"); FileOutputStream out=new FileOutputStream(new File("d:/pic2.jpg")); out.write(b.getBytes(1, (int)b.length())); out.close(); System.out.println("图书名称:"+bookName); System.out.println("图书价格:"+price); System.out.println("图书作者:"+author); System.out.println("图书类型ID:"+bookTypeId); System.out.println("图书内容:"+context); } dbUtil.close(pstmt, con); } public static void main(String[] args)throws Exception { // String str="C:\\152.txt"; // String location=str.replace("\\\\", "/"); // File context=new File(location); // String str1="C:\\123.jpg"; // String str2=str1.replace("\\\\", "/"); // File pic=new File(str2); // Book book=new Book("helloWorld", 100, "小锋", 1,context,pic); // int result=addBook(book); // if(result==1){ // System.out.println("添加成功!"); // }else{ // System.out.println("添加失败!"); // } getBook(11); } }
注意:1.利用下面这种方式对文件进行读取,防止目录出现问题,一般出现问题,除了是文件名错误外,还有就是复制会带来额外的东西,我们需要手打。
String str="C:\\152.txt"; String location=str.replace("\\\\", "/"); File context=new File(location);
2.写入数据时,注意第三行的第三个值要强转成int类型,而且对于CLOG数据,使用setAsciiStream,对于BLOG 数据,要使用setBinaryStream进行写入
File context=book.getContext(); // 获取文件 InputStream inputStream=new FileInputStream(context); pstmt.setAsciiStream(5, inputStream,(int)context.length());
File context=book.getContext(); // 获取文件 InputStream inputStream=new FileInputStream(context); pstmt.setAsciiStream(5, inputStream,(int)context.length()); // 给第五个坑设置值 File pic=book.getPic(); // 获取图片文件 InputStream inputStream2=new FileInputStream(pic); pstmt.setBinaryStream(6, inputStream2, (int)pic.length()); // 给第六个坑设置值
3.读取数据时,对于CLOG数据,用下面这种方法。
Clob c=rs.getClob("context"); String context=c.getSubString(1, (int) c.length());
对于BLOG 数据,用接下来这种方法,也就是直接写成多媒体格式。
Blob b=rs.getBlob("pic"); FileOutputStream out=new FileOutputStream(new File("d:/pic2.jpg")); out.write(b.getBytes(1, (int)b.length())); out.close();
第七章: 使用 CallableStatement 接口调用存储过程
CallableStatement 主要是调用数据库中的存储过程,CallableStatement 也是 PreparedStatement 接口的子接口。在使用 CallableStatement 时可以接收存储过程的返回值。
void registerOutParameter(int parameterIndex, int sqlType) 按顺序位置 parameterIndex 将 OUT 参数注册为 JDBC 类型 sqlType。
private static String getBookNameById(int id)throws Exception{ Connection con=dbUtil.getCon(); // 获取数据库连接 String sql="{CALL pro_getBookNameById1(?,?)}"; CallableStatement cstmt=con.prepareCall(sql); cstmt.setInt(1, id); // 设置第一个参数 cstmt.registerOutParameter(2, Types.VARCHAR); // 设置返回类型 cstmt.execute(); String bookName=cstmt.getString(1); // 获取返回值//这里不仅可以利用index,利用关键字也可以。 dbUtil.close(cstmt, con); return bookName; }
注意:sql语句外的大括号。
第八章: 使用元数据分析数据库
第一节:使用 DatabaseMetaData 获取数据库基本信息
DatabaseMetaData 可以得到数据库的一些基本信息,包括数据库的名称、版本,以及得到表的信息。
String getDatabaseProductName() 获取此数据库产品的名称。 int getDriverMajorVersion() 获取此 JDBC 驱动程序的主版本号。
int getDriverMinorVersion() 获取此 JDBC 驱动程序的次版本号。
public static void main(String[] args)throws Exception { DbUtil dbUtil=new DbUtil(); Connection con=dbUtil.getCon(); DatabaseMetaData dmd=con.getMetaData(); // 获取元数据 System.out.println("数据库名称:"+dmd.getDatabaseProductName()); System.out.println("数据库版本:"+dmd.getDriverMajorVersion()+"."+dmd.getDriverMinorVersion()); }
第二节:使用 ResultSetMetaData 获取 ResultSet
ResultSetMetaData 可获取关于 ResultSet 对象中列的基本信息;
int getColumnCount() 返回此 ResultSet 对象中的列数。
String getColumnName(int column) 获取指定列的名称。
int getColumnTypeName(int column) 获取指定列的 SQL 类型名称。
public static void main(String[] args) throws Exception{ DbUtil dbUtil=new DbUtil(); Connection con=dbUtil.getCon(); String sql="select * from t_book"; PreparedStatement pstmt=con.prepareStatement(sql); ResultSetMetaData rsmd=pstmt.getMetaData(); int num=rsmd.getColumnCount(); // 获取元数据列的总数 for(int i=1;i<=num;i++){ System.out.println(rsmd.getColumnName(i)+","+rsmd.getColumnTypeName(i)); } }
第九章: JDBC 事务处理
第一节:事务的概念
事务处理在数据库开发中有着非常重要的作用,所谓事务就是所有的操作要么一起成功,要么一起失败,事务 本身具有原子性(Atomicity)、一致性(Consistency)、隔离性或独立性(Isolation)、持久性(Durability)4 个特 性,这 4 个特性也被称为 ACID 特征。
原子性:原子性是事务最小的单元,是不可再分隔的单元,相当于一个个小的数据库操作,这些操作必须同时 成功,如果一个失败了,则一切的操作将全部失败。
一致性:指的是在数据库操作的前后是完全一致的,保证数据的有效性,如果事务正常操作则系统会维持有效 性,如果事务出现了错误,则回到最原始状态,也要维持其有效性,这样保证事务开始时和结束时系统处于一 致状态。
隔离性:多个事务可以同时进行且彼此之间无法访问,只有当事务完成最终操作时,才可以看到结果;
持久性:事务完成之后,它对于系统的影响是永久性的。该修改即使出现致命的系统故障也将一直保持。
package com.java1234.jdbc.chap09.sec04; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; import java.sql.Savepoint; import com.java1234.jdbc.util.DbUtil; public class Demo1 { private static DbUtil dbUtil=new DbUtil(); /** * 转出 * @param con * @param accountName * @param account * @throws Exception */ private static void outCount(Connection con,String accountName,int account)throws Exception{ String sql="update t_account set accountBalance=accountBalance-? where accountName=?"; PreparedStatement pstmt=con.prepareStatement(sql); pstmt.setInt(1, account); pstmt.setString(2, accountName); pstmt.executeUpdate(); } /** * 转入 * @param con * @param accountName * @param account * @throws Exception */ private static void inCount(Connection con,String accountName,int account)throws Exception{ String sql="update t_account set account=accountBalance+? where accountName=?"; PreparedStatement pstmt=con.prepareStatement(sql); pstmt.setInt(1, account); pstmt.setString(2, accountName); pstmt.executeUpdate(); } public static void main(String[] args) { Connection con=null; Savepoint sp=null; try { con=dbUtil.getCon(); con.setAutoCommit(false); // 取消自动提交 System.out.println("张三开始向李四转账!"); int account=500; outCount(con, "张三", account); //sp=con.setSavepoint(); // 设置一个保存点 inCount(con, "李四", account); System.out.println("转账成功!"); } catch (Exception e) { try { con.rollback(); // 回滚到sp保存点 } catch (SQLException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } // TODO Auto-generated catch block e.printStackTrace(); }finally{ try { con.commit(); // 提交事务 con.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
第二节:MySQL 对事务的支持