1.JDBC概念:Java Data Base Connectivity,java数据库连接,Sun公司为Java连接数据库提供的一套api。
2.Sun公司由于不知道各个主流商用数据库的程序代码,因此无法自己写代码连接各个数据库,因此,sun公司决定,自己提供一套api,凡是数据库想与Java进行连接的,数据库厂商自己必须实现JDBC这套接口。而数据库厂商的JDBC实现,我们就叫他此数据库的数据库驱动。
3.JDBC主要api,5个常用接口,多数来之java.sql.*与javax.sql.*
Connection
Statement
PreparedStatement
CallableStatement
ResultSet
4.Java连接数据库的步骤:
a)加载驱动(驱动:就是各个数据库厂商实现的Sun公司提出的JDBC。即对Connection等接口的实现类的jar文件)
b)获取数据库连接(就是用Java连接数据库)
c)操作数据库
d)关闭数据库的相应资源
5.Connection
6.说明:java.sql.Connection接口,数据库连接对象
static Connection getConnection(String url) 试图建立到给定数据库 URL 的连接。
static Connection getConnection(String url, Properties info) 试图建立到给定数据库 URL 的连接。Info可以利用properties文件方式记录用户名密码。
static Connection getConnection(String url, String user, String password) 试图建立到给定数据库 URL 的连接,把连接字符串,用户名,密码隔离,推荐使用。
例: String driver = "com.mysql.jdbc.Driver";
Class.forName(driver); //把一个类加载到内存中,方便程序使用此类
String url = "jdbc:mysql://localhost:3306/jdbcdb"; //数据库连接字符串
String user = "root"; //数据库用户名
String password = "123456"; //密码
Connection conn = DriverManager.getConnection(url, user, password);
7.代码实现—Java查询数据库表
public class JDBCDemo1 {
public static void main(String[] args) {
try {
// 加载驱动(驱动:就是各个数据库厂商实现的Sun公司提出的JDBC。即对Connection等接口的实现类的jar文件)
String driver = "com.mysql.jdbc.Driver";
Class.forName(driver); //把一个类加载到内存中,方便程序使用此类
// 获取数据库连接(就是用Java连接数据库)对象
//Url解释:
//jdbc:mysql://----是Java连接MySQL的固定用法
//localhost----数据库所在机器的ip地址
//3306------MySQL数据库的默认端口号
//jdbcdb------MySQL数据库中需要操作的数据库名
String url = "jdbc:mysql://localhost:3306/jdbcdb"; //数据库连接字符串
String user = "root"; //数据库用户名
String password = "123456"; //密码
Connection conn = DriverManager.getConnection(url, user, password);
// 操作数据库
//操作数据库的步骤:
//1.创建Statement对象,用于操作数据库
Statement stmt = conn.createStatement();
//2.利用Statement对象的相关方法,操作数据库
//3.如果执行查询语句,需创建ResultSet对象,此对象为查询结果集
String sql = "select * from student";
ResultSet rs = stmt.executeQuery(sql); //结果集就是用于存放查询数据库表的结果用的
while(rs.next()){
System.out.println(rs.getInt("id"));
System.out.println(rs.getString("sname"));
System.out.println(rs.getString("spassword"));
System.out.println("------------------------");
}
// 关闭数据库的相应资源
if(rs != null){
rs.close();
}
if(stmt != null){
stmt.close();
}
if(conn != null){
conn.close();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
8.Statement
说明:java.sql.Statement接口,用于操作数据库
1)执行查询时:使用executeQuery方法。
ResultSet executeQuery(String sql) throws SQLException其中sql为执行的查询语句,ResultSet为查询的结果集。
例:Statement stmt = conn.createStatement();
String sql = "select * from student";
ResultSet rs = stmt.executeQuery(sql);
2)执行添删改操作:使用executeUpdate方法
例:Connection conn = DriverManager.getConnection(url, user, password);
Statement stmt = conn.createStatement();
String sql = "insert into student values(4,'tom','654321','m',8)";
int n = stmt.executeUpdate(sql);
if(n != 0){
System.out.println("success!");
}
9.ResultSet
说明:java.sql.ResultSet接口,用于存储查询后的结果。注意:结果集类似数据库中的游标,使用前必须调用其next方法。
1)next方法
boolean next()throws SQLException把结果集的指针移到下一条记录,返回结果为是否有下一条记录,true为有,false为无。常与while一起使用用于遍历结果集(一般有多条记录,查询表信息时使用)。与if一起使用,判断结果集中是否有记录(一般只有一条满足条件的记录,或没有记录,多用于登录判断,用户名是否合法)。
while(rs.next()){
System.out.println(rs.getInt("id"));
System.out.println(rs.getString("sname"));
System.out.println(rs.getString("spassword"));
System.out.println("------------------------");
}
2). getXxxx方法
说明:用于获取查询结果集中的相应信息。其中Xxxx为具体的数据类型,此类型要与数据库中表中字段的类型一致。如,getInt,getString等
以getString为例:
String getString(String 列名)throws SQLException获取指定列名的内容。
例:while(rs.next()){
System.out.println(rs.getInt("id"));
System.out.println(rs.getString("sname"));
System.out.println(rs.getString("spassword"));
}
String getString(int 列的位置)throws SQLException根据数据库表中,列所在的位置,获取相应的数据,其中参数为,某一列的位置,从1开始。返回值为响应的数据。
例:while(rs.next()){
System.out.println(rs.getInt(1)); //注意,如果此处是整型,则为数据库中列所在的位置,从1开始
System.out.println(rs.getString(2));
System.out.println(rs.getString(3));
System.out.println("------------------------");
}
10.关闭数据库
注意:对于操作数据库,文件,各种流的程序,使用结束后,必须关闭相应的资源。
对于数据库的关闭,建议关闭的顺序从下向上关闭,即ResultSet,Statement,Connection。
注意:在关闭各类资源之前,注意判断资源对象是否为空,代码如下。
if(rs != null){
rs.close();
}
if(stmt != null){
stmt.close();
}
if(conn != null){
conn.close();
}
11.Java EE分层(J2EE分层)
表示层:负责页面显示,用户交互,信息输出等。
业务逻辑层:定义该领域的核心业务
数据库操作层:对数据库的操作
12.J2EE分层包的实现
例:com.px1987.studentms.ui;
//com.px1987表示公司域名
//studentms为项目名称(工程名称)
//ui为功能名(模块名)其中,J2EE分层即体现在此。
com.px1987.studentms.dao:即数据库操作层,操作数据库的代码程序
com.px1987.studentms.service:即业务逻辑层,定义核心业务逻辑
com.px1987.studentms.ui:即表示层,定义用户界面(也有叫做,view,gui等)
13.贫血模式
只对数据的简单封装(即提供get/set方法的pojo类),而把业务逻辑封装在业务组件或dao组件中,即对象与业务相分离。常见的表模式就为贫血模式,即一个数据库表对应一个dao类。
例:数据库中有一个Student表,在程序中就存在一个StudentDAO接口等。
优点:简单易学,可以简单的认为一个表对应一个“表对象DAO”,适用面较广。
缺点:最大的缺点违背面向对象的设计原则
14.PreparedStatement
java.sql.PreparedStatement接口
说明:预编译的Statement,为Statement的子接口。
用法:
conn = this.getConnection();
String sql = "select * from student where sname=? and spassword=?";
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, username);
pstmt.setString(2, password);
rs = pstmt.executeQuery();
while(rs.next()){
System.out.println(rs.getString("sname"));
}
注意:
1.与Statement不同PreparedStatement由Connection的prepareStatement方法创建,其中需要传入sql语句,即conn.prepareStatement(sql),原因是其为预编译,因此在创建对象时,sql语句就已经编译好了,因此,当执行多次操作时,其效率比Statement要好。
2.创建PreparedStatement时,传入的sql语句如果有参数时,需用“?”作为占位符。但是,在执行sql语句之前,必须为占位符赋值,其数据类型跟数据库一致,例:数据库中姓名用sname表示,varchar(45),那么在赋值时要选择相应的类型 ,pstmt.setString(问号所在的位置,具体赋值的内容)----其中问号的位置从1开始。
执行查询利用pstmt.executeQuery()---注意:无参数,pstmt.executeUpdate();
3.PreparedStatement可以避免简单的sql注入,如:在Statement中,sql语句为“select * from student where sname=’任何内容’ and pwd=’’ or ‘1’=’1’”即可利用sql注入成功,安全性较低。PreparedStatement可以避免,因为PreparedStatement为预编译sql,其sql语句已经可以执行,比对只是数据库中的内容,因为数据库中没有’ or ‘1’=’1内容,因此无法查询。
4.PreparedStatement的可读性要比Statement高。
15.小技巧:
改名快捷键:利用Eclipse中,集体改名,选中要改名的变量。利用快捷键“Alt+Shift+R”。
导包快捷键:“Ctrl+Shift+M”,但是一般不用,一般利用整理包的快捷键。
整理包的快捷键:“Ctrl+Shift+O”,与导包的区别在于,有用的留着,没用的删除。
16.MVC模式
MVC—模型,视图,控制器。
MVC的好处:强制性把模型与视图向分离。
控制器的作用:接收页面用户输入的信息,进行整理,并调用相应的模型,根据模型返回的结果,在调用相应的视图。
在程序中包的体现:一般可以起名为:controller,action,servlet等。
如:com.px1987.studentms.action;
17. 自定义类BaseDAO,用于获取连接,以及关闭资源,为抽象类。(必须会)
public abstract class BaseDAO {
public Connection getConnection() {
Connection conn = null;
try {
// Class.forName("org.gjt.mm.mysql.Driver");
Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/employee?user=root&password=123456&useUnicode=true&characterEncoding=utf-8";
conn = DriverManager.getConnection(url);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
public void free(Connection conn, Statement stmt, ResultSet rs) {
try {
if (rs != null) {
rs.close();
}
if (stmt != null) {
stmt.close();
}
if (conn != null) {
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
18. PreparedStatement的用法(必须会)
public class PreparedStatementDemo extends BaseDAO {
/**
* 根据用户名密码判断用户是否存在
* @param emp
* @return
*/
public boolean selectOneDataByNameAndPassword(Employee emp) {
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
boolean key = false;
try {
conn = this.getConnection();
String sql = "select * from employees where ename=? and epassword=?";
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, emp.getEname());
pstmt.setString(2, emp.getEpassword());
rs = pstmt.executeQuery();
if (rs.next()) {
key = true;
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
free(conn, pstmt, rs);
}
return key;
}
/**
* 查询所用用户信息
* @return
*/
public List Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; boolean key = false; List try { conn = this.getConnection(); String sql = "select * from employees"; pstmt = conn.prepareStatement(sql); rs = pstmt.executeQuery(); while (rs.next()) { Employee emp = new Employee(); emp.setEid(rs.getInt("eid")); emp.setEname(rs.getString("ename")); emp.setEpassword(rs.getString("epassword")); emp.setEage(rs.getInt("eage")); emp.setEsex(rs.getString("esex")); list.add(emp); } } catch (SQLException e) { e.printStackTrace(); } finally { free(conn, pstmt, rs); } return list; } /** * 插入一条记录 * @param employee * @return */ public boolean insertOneData(Employee employee) { Connection conn = null; PreparedStatement pstmt = null; boolean key = false; try { conn = this.getConnection(); String sql = "insert into employees(eid,ename,epassword,eage,esex) values(?,?,?,?,?)"; pstmt = conn.prepareStatement(sql); pstmt.setInt(1, createPrimaryKey()); pstmt.setString(2, employee.getEname()); pstmt.setString(3, employee.getEpassword()); pstmt.setInt(4, employee.getEage()); pstmt.setString(5, employee.getEsex()); int n = pstmt.executeUpdate(); if(n > 0){ key = true; } } catch (SQLException e) { e.printStackTrace(); } finally { this.free(conn, pstmt, null); } return key; } /** * 更新一条记录 * @param employee * @return */ public boolean updateOneData(Employee employee) { Connection conn = null; PreparedStatement pstmt = null; boolean key = false; try { conn = this.getConnection(); String sql = "update employees set ename=?,epassword=?,eage=?,esex=? where eid=?"; pstmt = conn.prepareStatement(sql); pstmt.setString(1, employee.getEname()); pstmt.setString(2, employee.getEpassword()); pstmt.setInt(3, employee.getEage()); pstmt.setString(4, employee.getEsex()); pstmt.setInt(5, employee.getEid()); int n = pstmt.executeUpdate(); if(n > 0){ key = true; } } catch (SQLException e) { e.printStackTrace(); } finally { this.free(conn, pstmt, null); } return key; } /** * 删除一条记录 * @param employee * @return */ public boolean deleteOneData(Employee employee) { Connection conn = null; PreparedStatement pstmt = null; boolean key = false; try { conn = this.getConnection(); String sql = "delete from employees where eid=?"; pstmt = conn.prepareStatement(sql); pstmt.setInt(1, employee.getEid()); int n = pstmt.executeUpdate(); if(n > 0){ key = true; } } catch (SQLException e) { e.printStackTrace(); } finally { this.free(conn, pstmt, null); } return key; } 19.想数据库表中插入日期类型的数据 public class DateDemo extends BaseDAO { public void insertTimestamp(){ Connection conn = null; PreparedStatement pstmt = null; try { conn = this.getConnection(); String sql = "insert into book(bookname,bookdate) values(?,?)"; pstmt = conn.prepareStatement(sql); pstmt.setString(1, "三毛流浪记"); // pstmt.setDate(2, new java.sql.Date(new java.util.Date().getTime())); pstmt.setTimestamp(2, new java.sql.Timestamp(new java.util.Date().getTime())); int n = pstmt.executeUpdate(); if(n > 0){ System.out.println("success!"); }else{ System.out.println("failure!"); } } catch (SQLException e) { e.printStackTrace(); } finally { this.free(conn, pstmt, null); } } public void selectTimestamp(){ Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; try { conn = this.getConnection(); String sql = "select * from book"; pstmt = conn.prepareStatement(sql); rs = pstmt.executeQuery(); while(rs.next()){ java.sql.Timestamp time = rs.getTimestamp("bookdate"); java.util.Date date = new java.util.Date(time.getTime()); System.out.println(date); } } catch (SQLException e) { e.printStackTrace(); } finally { this.free(conn, pstmt, null); } } public void insertDate(){ Connection conn = null; PreparedStatement pstmt = null; try { conn = this.getConnection(); String sql = "insert into book(bookname,bookdate) values(?,?)"; pstmt = conn.prepareStatement(sql); pstmt.setString(1, "三毛流浪记"); pstmt.setDate(2, new java.sql.Date(new java.util.Date().getTime())); int n = pstmt.executeUpdate(); if(n > 0){ System.out.println("success!"); }else{ System.out.println("failure!"); } } catch (SQLException e) { e.printStackTrace(); } finally { this.free(conn, pstmt, null); } } public void selectDat(){ Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; try { conn = this.getConnection(); String sql = "select * from book"; pstmt = conn.prepareStatement(sql); rs = pstmt.executeQuery(); while(rs.next()){ java.sql.Date d = rs.getDate("bookdate"); java.util.Date date = new java.util.Date(d.getTime()); System.out.println(date); } } catch (SQLException e) { e.printStackTrace(); } finally { this.free(conn, pstmt, null); } } } 20.插入大的二进制文件,Oracle中对应clob,MySQL中对应longtext 由于MySQL的默认缓存较小,因此操作大文件时,会出现内存泄露问题,建议使用Oracle数据库。 public class ClobDemo extends BaseDAO{ public void insertClob(){ Connection conn = null; PreparedStatement pstmt = null; try { conn = this.getConnection(); String sql = "insert into notepad(content) values(?)"; pstmt = conn.prepareStatement(sql); File f = new File("c:/11.txt"); BufferedReader br = new BufferedReader(new FileReader(f)); pstmt.setCharacterStream(1, br,(int)f.length()); int n = pstmt.executeUpdate(); if(n > 0){ System.out.println("success!"); }else{ System.out.println("failure!"); } br.close(); } catch (SQLException e) { e.printStackTrace(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { this.free(conn, pstmt, null); } } public void selectClob(){ Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; int n = 1; try { conn = this.getConnection(); String sql = "select * from notepad"; pstmt = conn.prepareStatement(sql); rs = pstmt.executeQuery(); while(rs.next()){ Reader reader = rs.getCharacterStream("content"); Writer writer = new PrintWriter(new FileWriter(new File("C:/clob/" + n + ".txt"))); char[] ch = new char[1024]; int i = 0; while((i = reader.read(ch)) > 0){ writer.write(ch, 0, i); } writer.flush(); writer.close(); reader.close(); n++; } } catch (SQLException e) { e.printStackTrace(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { this.free(conn, pstmt, null); } } } 21.插入大的二进制文件,Oracle中为blob,MySQL中为longblob 由于MySQL的默认缓存较小,因此操作大文件时,会出现内存泄露问题,建议使用Oracle数据库。 public class BlobDemo { public void insertBlob(){ String driver = "oracle.jdbc.driver.OracleDriver"; try { Class.forName(driver); } catch (ClassNotFoundException e1) { e1.printStackTrace(); } String url = "jdbc:oracle:thin:@localhost:1521:orcl"; String user = "lfy"; String password = "lfy"; Connection conn = null; PreparedStatement pstmt = null; try { conn = DriverManager.getConnection(url, user, password); String sql = "insert into moive values(?,?)"; pstmt = conn.prepareStatement(sql); pstmt.setInt(1, 1); File f = new File("c:/艋甲cd1.rmvb"); DataInputStream is = new DataInputStream(new FileInputStream(f)); pstmt.setBinaryStream(2, is,(int)f.length()); int n = pstmt.executeUpdate(); if(n > 0){ System.out.println("success!"); }else{ System.out.println("failure!"); } } catch (SQLException e) { e.printStackTrace(); } catch (FileNotFoundException e) { e.printStackTrace(); } finally { try { if(pstmt != null){ pstmt.close(); } if(conn != null){ conn.close(); } } catch (SQLException e) { e.printStackTrace(); } } } public void selectBlob(){ String driver = "oracle.jdbc.driver.OracleDriver"; try { Class.forName(driver); } catch (ClassNotFoundException e1) { e1.printStackTrace(); } String url = "jdbc:oracle:thin:@localhost:1521:orcl"; String user = "lfy"; String password = "lfy"; Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; try { conn = DriverManager.getConnection(url, user, password); String sql = "select * from moive"; pstmt = conn.prepareStatement(sql); rs = pstmt.executeQuery(); while(rs.next()){ File f = new File("d:/艋甲cd1.rmvb"); InputStream is = rs.getBinaryStream("content"); DataOutputStream dos = new DataOutputStream(new FileOutputStream(f)); byte[] b = new byte[1024]; int i = 0; while((i = is.read(b)) > 0){ dos.write(b, 0, i); } dos.flush(); dos.close(); is.close(); } } catch (SQLException e) { e.printStackTrace(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { if(pstmt != null){ pstmt.close(); } if(conn != null){ conn.close(); } } catch (SQLException e) { e.printStackTrace(); } } } } 22.批处理 对于批处理,与数据库有很大关系,如果一次插入的数据量特别大,建议使用Oracle等数据库,对于大量的批处理,建议使用Statement,因为PreparedStatement的预编译空间有限,当数据量特别大时,会发生异常。 主要利用Statement的addBatch与executeBatch方法。 public class BatchDemo extends BaseDAO { public void insertSomeDatas1(){ long start = System.currentTimeMillis(); Connection conn = null; PreparedStatement pstmt = null; int n = 0; try { Class.forName("oracle.jdbc.driver.OracleDriver"); String url="jdbc:oracle:thin:@localhost:1521:orcl"; //orcl为数据库的SID String user="lfy"; String password="lfy"; conn= DriverManager.getConnection(url,user,password); conn.setAutoCommit(false); String sql = "insert into test(content) values(?)"; pstmt = conn.prepareStatement(sql); for(int i = 0; i < 1000000; i++){ n++; pstmt.setString(1, i + ""); pstmt.addBatch(); } n = pstmt.executeBatch().length; if(n != 1000000){ conn.rollback(); }else{ conn.commit(); } } catch (SQLException e) { try { conn.rollback(); } catch (SQLException e1) { e1.printStackTrace(); } e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } finally { this.free(conn, pstmt, null); } long end = System.currentTimeMillis(); System.out.println(n); System.out.println((end - start) / 1000); } public void insertSomeDatas2(){ Connection conn = null; Statement stmt = null; int n = 0; try { Class.forName("oracle.jdbc.driver.OracleDriver"); String url="jdbc:oracle:thin:@localhost:1521:orcl"; //orcl为数据库的SID String user="lfy"; String password="lfy"; conn= DriverManager.getConnection(url,user,password); conn.setAutoCommit(false); stmt = conn.createStatement(); String sql = "insert into test(content) values('" + 1 + "')"; for(int i = 0; i < 1000000; i++){ n++; stmt.addBatch(sql); } n = stmt.executeBatch().length; if(n != 1000000){ conn.rollback(); }else{ conn.commit(); } } catch (SQLException e) { try { conn.rollback(); } catch (SQLException e1) { e1.printStackTrace(); } e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } finally { this.free(conn, stmt, null); } System.out.println(n); } public static void main(String[] args) { new BatchDemo().insertSomeDatas4(); } } 23.事务处理