JDBC概述 Java Database connectivity,Java与数据库连接的操作规范。不同的数据库都要遵循这个规范(接口)。
JDBC规范 掌握四个核心对象:
DriverManager:用于注册驱动。
Connection:表示与数据库创建的连接。
Statement:操作数据库SQL语句的对象。
ResultSet:结果集 或 一张虚拟表。
JDBC的准备工作 JDBC接口放在JDK中的 java.sql 和 javax.sql。
下载jdbc的jar包。
导入jar包到项目中。
实现JDBC操作
注册驱动
创建连接
得到执行SQL语句的Statement对象
执行SQL语句,并返回结果
处理结果
关闭资源
DriverManager java.sql.DriverManager类:注册驱动,创建连接。
这个类在加载时就会注册驱动,所以在使用时,只需要使用Class.forName("com.mysql.jdbc.Driver");
来加载一下这个类即可完成注册驱动。使用DriverManager.registerDriver(new Driver());
会造成二次注册驱动。
Connection 有三种创建连接的方法:
Connection conn = DriverManager.getConnection(url,user,password);
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test1?user=root&password=123456");
String url = "jdbc:mysql://localhost:3306/test1" ;
Properties info = new Properties();
info.setProperty("user" ,"root" );
info.setProperty("password" ,"passwo2d@CQ" );
Connection conn = DriverManager.getConnection(url, info);
<!--0 -->
java的数据类型与数据库中类型的对应关系
java
数据库
byte
tityint
short
smallint
int
int
long
bigint
float
float
double
double
String
char varchar
Date
date
resultSet用游标记录了当前在哪一行。
next()将游标移动到下一行。previous()将游标移动到上一行。afterLast()将光标移动到末尾,位于最后一行之后。beforeFirst()将光标移动到开头,正好位于第一行之前。
正确关闭资源 因为程序中有可能抛出异常,而抛出异常会导致后面的资源无法关闭,所以将close方法放到finally中。再用一套try/catch包裹close来处理close的方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 public static void main (String[] args) { Connection conn = null ; Statement stmt = null ; ResultSet rs = null ; try { String url = "jdbc:mysql://localhost:3306/test1?serverTimezone=GMT" ; Properties info = new Properties(); info.setProperty("user" , "root" ); info.setProperty("password" , "passwo2d@CQ" ); conn = DriverManager.getConnection(url, info); stmt = conn.createStatement(); rs = stmt.executeQuery("select * from user;" ); while (rs.next()) { System.out.print(rs.getObject(1 ) + " - " ); System.out.print(rs.getObject(2 ) + " - " ); System.out.print(rs.getObject(3 ) + " - " ); System.out.print(rs.getObject(4 ) + " - " ); System.out.print(rs.getObject(5 ) + " - " ); System.out.println(); } }catch (Exception e){ }finally { if (rs != null ){ try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } } if (stmt != null ){ try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); } } if (conn != null ){ try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } }
抽取工具类(简化连接数据库和关闭资源操作) 创建一个同级工具类包,内放一个工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 package com.Retur0.util;import java.sql.*;public class DBUtils { private static String url = "jdbc:mysql://localhost:3306/test1?serverTimezone=GMT" ; private static String user = "root" ; private static String password = "passwo2d@CQ" ; public static Connection getConnection () throws SQLException { return DriverManager.getConnection(url,user,password); } public static void close (Connection conn, ResultSet rs, Statement stmt) { if (rs!=null ) { try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } } if (conn!=null ) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } if (stmt!=null ) { try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); } } } }
之后连接和操作数据库的代码就简化如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 package demo;import com.Retur0.util.DBUtils;import java.sql.*;public class demo02 { public static void main (String[] args) { Connection conn = null ; Statement stmt = null ; ResultSet rs = null ; try { conn = DBUtils.getConnection(); stmt = conn.createStatement(); rs = stmt.executeQuery("select * from user" ); while (rs.next()) { System.out.print(rs.getObject(1 )+"\t" ); System.out.print(rs.getObject(2 )+"\t" ); System.out.print(rs.getObject(3 )+"\t" ); System.out.print(rs.getObject(4 )+"\t" ); System.out.println(rs.getObject(5 )+"\t" ); } }catch (Exception e){ e.printStackTrace(); }finally { DBUtils.close(conn, rs, stmt); } } }
插入数据 使用预处理的Statement对象,用占位符代替要处理的数据。使用设置方法挨个设置占位符处的数据。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public static void main (String[] args) { Connection conn = null ; PreparedStatement ps = null ; try { conn = DBUtils.getConnection(); String sql = "insert into user (id,name,password,email,birthday) values (?,?,?,?,?)" ; ps = conn.prepareStatement(sql); ps.setInt(1 , 4 ); ps.setString(2 , "name03" ); ps.setString(3 , "123456" ); ps.setString(4 , "11111@qq.com" ); ps.setDate(5 , new java.sql.Date(System.currentTimeMillis())); int r = ps.executeUpdate(); System.out.println("受影响的行数:" +r); }catch (Exception e){ e.printStackTrace(); }finally { DBUtils.close( conn, null , ps); } }
更改数据 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public static void main (String[] args) { Connection conn = null ; PreparedStatement ps = null ; try { conn = DBUtils.getConnection(); String sql = "update user set password=?, email=? where name=?" ; ps = conn.prepareStatement(sql); ps.setString(1 , "000000" ); ps.setString(2 , "xxx@qq.com" ); ps.setString(3 , "name02" ); int r = ps.executeUpdate(); System.out.println("受影响的行数:" +r); }catch (Exception e){ e.printStackTrace(); }finally { DBUtils.close( conn, null , ps); } }
删除数据 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public static void main (String[] args) { Connection conn = null ; PreparedStatement ps = null ; try { conn = DBUtils.getConnection(); String sql = "delete from user where id=?" ; ps = conn.prepareStatement(sql); ps.setInt(1 , 4 ); int r = ps.executeUpdate(); System.out.println("受影响的行数:" +r); }catch (Exception e){ e.printStackTrace(); }finally { DBUtils.close( conn, null , ps); } }
查询数据 查询不使用预处理Statement。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 public static void main (String[] args) { Connection conn = null ; Statement stmt = null ; ResultSet rs = null ; try { conn = DBUtils.getConnection(); stmt = conn.createStatement(); rs = stmt.executeQuery("select * from user" ); List<User> list = new ArrayList<User>(); while (rs.next()){ User user = new User(); user.setId(rs.getInt("id" )); user.setName(rs.getString("name" )); user.setEmail((rs.getString("email" ))); user.setBirthday((rs.getDate("birthday" ))); list.add(user); } for (User u : list){ System.out.println(u.toString()); } }catch (Exception e){ e.printStackTrace(); }finally { DBUtils.close(conn, rs, stmt); } }
将数据封装成的模型起码要保存数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 public class User { private int id; private String name; private String password; private String email; private Date birthday; public int getId () { return id; } public String getName () { return name; } public String getPassword () { return password; } public String getEmail () { return email; } public Date getBirthday () { return birthday; } public void setId (int id) { this .id = id; } public void setName (String name) { this .name = name; } public void setPassword (String password) { this .password = password; } public void setEmail (String email) { this .email = email; } public void setBirthday (Date birthday) { this .birthday = birthday; } public String toString () { return id + " " + name + " " + password + " " + email + " " + birthday; } }
SQL注入 如果把占位符换成字符串变量,用拼接的方法完成sql语句,会有注入的问题。
这个问题就是,如果输入的字符串利用了sql语句的规则成为了字符串的一部分,导致信息校验出现问题(比如查询出不存在的数据)。被注入了其它的sql语句进来。
解决办法就是使用预加载Statement和占位符。