JDBC使用
一、JDBC原理:
我们可以通过接口方式或者抽象方法来查看该实现类都有哪些方法。
应用程序通过sun公司的提供的统一规范JDBC接口和类规范,第三方(数据库厂商)通过JDBC规范分别实现相应的接口和类(通过多态来重写接口)来操作数据库。
jdbc实现原理:
分三个步骤:1、加载数据库驱动 2、获取数据库的连接 3、发送sql语句操作数据库。
1 加载数据库驱动 使用Class.forName方法,调用这个方法会加载数据库驱动 com.mysql.jdbc.driver(以mysql为例)。
驱动其实就是sun公司的定义的JDBC规范,各个厂商实现规范(接口)来进行操作数据库。在访问相应的数据库的时候需要引用相应的第三方的类库的jar包。
二、JDBC开发步骤
1:注册驱动
告知jvm使用哪个数据库驱动
2:获得数据库连接
使用JDBC类,获取数据库的连接
3:获得语句执行平台
通过连接对象获取语句执行对象
4:执行sql语句
使用执行对象,向数据库执行数据库语句
5:获取执行结果
获取执行语句的执行结果
6:释放资源(tcp连接需要关掉)
通过close()方法来关闭连接。
例子:
1 package day31; 2 3 4 5 import java.sql.*; 6 7 public class jdbc_demo { 8 public static void main(String ... str) throws Exception{ 9 set_Db(); 10 11 } 12 public static void set_Db() throws ClassNotFoundException,SQLException{ 13 /* 14 1:注册驱动 15 因为查看java.sql的registerdriver(Driver driver)的时候,Driver是接口被第三方的初始化,查看第三方的库的时候: 16 package com.mysql.jdbc; 17 18 import java.sql.DriverManager; 19 import java.sql.SQLException; 20 21 public class Driver extends NonRegisteringDriver implements java.sql.Driver { 22 public Driver() throws SQLException { 23 } 24 25 static { 26 try { 27 DriverManager.registerDriver(new Driver()); 28 } catch (SQLException var1) { 29 throw new RuntimeException("Can't register driver!"); 30 } 31 } 32 } 33 其中静态代码块中有新的Drvier的注册,这样 我直接使用方法:registerDriver(Driver driver)相当于注册2次。所以使用Class.for 34 Name("")来初始化类 以达到实例化。 35 */ 36 Class.forName("com.mysql.jdbc.Driver"); 37 /* 38 2:获取数据库连接。 39 通过DriverManger.getConnection(String url, String user, String password) 方法来获取连接,该方法返回Connection 实现类。 40 url:数据库连接方式串,连接方式:协议//IP:port/databasename 41 user:数据库账号 42 password:数据库密码。 43 */ 44 String url="jdbc:mysql://192.168.147.146:3306/homework_day13"; 45 46 String user="test"; 47 48 String password="123456"; 49 50 Connection con=DriverManager.getConnection(url,user,password); 51 System.out.print(con); 52 53 /* 54 3:通过连接获取执行语句平台,通过connection来获取执行平台statement。查看connection的接口方法,查找createment()方法。 55 Statement createStatement() Creates a Statement object for sending SQL statements to the database. 56 */ 57 Statement sta=con.createStatement(); 58 /* 59 4:执行sql。 60 查看下Statememt方法。 61 int executeUpdate(String sql) 62 Executes the given SQL statement, which may be an INSERT, UPDATE, 63 or DELETE statement or an SQL statement that returns nothing, 64 such as an SQL DDL statement. 65 通过该方法可以执行insert、update、delete语句,放回是操作数据库影响的语句数目。 66 */ 67 int row=sta.executeUpdate("INSERT INTO system_user (username, password) VALUES (\"ff\",123)"); 68 System.out.print(row); 69 /* 70 5:关闭资源 71 */ 72 sta.close(); 73 con.close(); 74 } 75 }
注意:
在执行sql中,如果是字符串类型的时候 在拼接sql的时候,需要使用转义符\进行书写。
查询例子:
1 package day31; 2 3 4 import java.sql.*; 5 6 public class jdbc_demo1 { 7 public static void main(String ... args)throws Exception{ 8 query_Demo(); 9 } 10 public static void query_Demo()throws ClassNotFoundException,SQLException{ 11 Class.forName("com.mysql.jdbc.Driver"); 12 String url="jdbc:mysql://192.168.147.146:3306/homework_day13"; 13 String username="test"; 14 String password="123456"; 15 Connection con = DriverManager.getConnection(url,username,password); 16 Statement sta=con.createStatement(); 17 ResultSet res=sta.executeQuery("select * from system_user"); 18 while (res.next()){ 19 String col_str=res.getInt("nid")+ 20 res.getString("username")+ 21 res.getString("password")+"\n"; 22 System.out.print(col_str); 23 } 24 res.close(); 25 sta.close(); 26 con.close(); 27 } 28 }
通过ResultSet的next()方法来判断当前结果急是否有查询值。executeQuery方法
ResultSet executeQuery(String sql)throws SQLException
通过ResultSet方法来进行查询结果集。
然后通过get*来取对应列的值。
也可以通过列的索引获取对应的值,需要注意的是:索引的起始值是1.
1 while (res.next()){ 2 String col_str=res.getInt(1)+ 3 res.getString(2)+ 4 res.getString(3)+"\n"; 5 System.out.print(col_str); 6 }
三:sql注入
在java程序开发中,我们设计用户登录的时候,用户输入账号和密码的时候,如果后台采用的statement的进行语句查询的时候,会出现sql漏洞,出现sql注入的情况。
例子:
1 package day31; 2 3 import java.sql.*; 4 import java.util.Scanner; 5 6 public class sql_in { 7 public static void main(String[] args)throws Exception{ 8 sql_In(); 9 } 10 public static void sql_In()throws SQLException,ClassNotFoundException{ 11 Class.forName("com.mysql.jdbc.Driver"); 12 String url="jdbc:mysql://192.168.147.146:3306/homework_day13"; 13 String username="test"; 14 String password="123456"; 15 Connection con= DriverManager.getConnection(url,username,password); 16 Statement sta=con.createStatement(); 17 Scanner sca=new Scanner(System.in); 18 String user=sca.nextLine(); 19 String pwd=sca.nextLine(); 20 String sql="select * from system_user where username='"+user+"' and password='"+pwd+"'"; 21 System.out.print(sql); 22 ResultSet ret=sta.executeQuery(sql); 23 System.out.print("\n"+ret.next()); 24 ret.close(); 25 sta.close(); 26 con.close(); 27 } 28 }
输入:
1 222 2 111 'or '1=1
输出:
1 select * from system_user where username='222' and password='111 'or '1=1' 2 true
数据库表内容:
1 mysql> select * from system_user; 2 +-----+----------+----------+ 3 | nid | username | password | 4 +-----+----------+----------+ 5 | 1 | root | 123 | 6 | 2 | evil | 123 | 7 | 3 | tom | 123 | 8 | 4 | jack | 123 | 9 | 11 | 11 | 123 | 10 | 12 | ff | 123 | 11 +-----+----------+----------+ 12 6 rows in set (0.00 sec)
通过拼接sql 用sql执行平台statement的时候利用'or '1=1' 永远成立的特性,导致用户验证通过。(注意在sql语句中单引号的使用 单引号相当于字符串在java中是字符。)
解决sql注入:
1 package day31; 2 3 import java.sql.*; 4 import java.util.Scanner; 5 6 public class sql_so { 7 public static void main(String[] args)throws Exception{ 8 sql_So(); 9 } 10 public static void sql_So()throws ClassNotFoundException,SQLException{ 11 Class.forName("com.mysql.jdbc.Driver"); 12 String url="jdbc:mysql://192.168.147.146:3306/homework_day13"; 13 String username="test"; 14 String password="123456"; 15 Connection con= DriverManager.getConnection(url,username,password); 16 Scanner sca=new Scanner(System.in); 17 String user=sca.nextLine(); 18 String pwd=sca.nextLine(); 19 /* 20 使用preparestatement的时候 拼接sql的使用的问号?占位符。 21 然后进行填充参数的手使用set列的类型。 22 或者直接写setobject方便。 23 set的参数中第一个是索引 就是第几个参数 索引起始是1. 24 */ 25 String sql="select * from system_user where username=? and password=?"; 26 PreparedStatement pst=con.prepareCall(sql); 27 pst.setString(1, user); 28 pst.setString(2, pwd); 29 ResultSet ret=pst.executeQuery(); 30 System.out.print(ret.next()); 31 ret.close(); 32 pst.close(); 33 con.close(); 34 35 } 36 }
结果:
1 11 2 111 'or '1=1 3 false
以后使用preparestatmennt来代替statment,这样有效的解决sql注入问题。