JDBC

JDBC简述

JDBC(Java DataBase Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。JDBC提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序 。

注册驱动→获取连接→创建执行SQL语句对象→返回结果集

DriverManager→Connection→Statement→ResultSet

JDBC(java database connectivity)驱动程序是对JDBC规范完整的实现,它的存在在JAVA程序与数据库系统之间建立了一条通信的渠道。

案例一:读取数据库信息显示到控制台

名为hh的数据库student表下有如下内容

SNO     SNAME   SSEX    SBIRTHDAY   CLASS   
------  ------  ------  ----------  --------
108     曾华      男       1977-09-01  95033   
105     匡明      男       1975-10-02  95031   
107     王丽      女       1976-01-23  95033   
101     李军      男       1976-02-20  95033   
109     王芳      女       1975-02-10  95031   
103     陆君      男       1974-06-03  95031   

代码如下:

package ink.longpress.www;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import com.mysql.jdbc.Driver;

public class One {
	public static void main(String[] args) throws SQLException {
//	注册驱动
		DriverManager.registerDriver(new Driver());
//	获取连接
		String url = "jdbc:mysql://localhost:3306/hh";
		String userName = "root";
		String password = "chen1588";
		Connection connection = DriverManager.getConnection(url, userName, password);
//	创建Statement
		Statement statement =connection.createStatement();
//	创建发送执行SQL
		String sqlString = "select * from student";
		ResultSet res = statement.executeQuery(sqlString);
//	操作结果集
		while (res.next()) {
			String string ="学号:" + res.getString("sno") + ",姓名:" + res.getString("sname") + ",性别:" + res.getString("ssex") + ",生日:" + res.getString("sbirthday") + ",班级:" + res.getString("class");
			System.out.println(string);
		}
		
		res.close();
		statement.close();
		connection.close();
	}
}

控制台输出:

学号:108,姓名:曾华,性别:男,生日:1977-09-01,班级:95033
学号:105,姓名:匡明,性别:男,生日:1975-10-02,班级:95031
学号:107,姓名:王丽,性别:女,生日:1976-01-23,班级:95033
学号:101,姓名:李军,性别:男,生日:1976-02-20,班级:95033
学号:109,姓名:王芳,性别:女,生日:1975-02-10,班级:95031
学号:103,姓名:陆君,性别:男,生日:1974-06-03,班级:95031

注册数据库驱动

作用:注册驱动,获取连接对象。
开发过程中一般不使用以上方法注册,以上方式注册会重复注册,
在Driver中有静态代码块,注册时会运行两次。
一般使用反射来注册驱动。

Class.forName("com.sql.jdbc.Driver");

优化后代码:

package ink.longpress.www;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;


public class Two {
	public static void main(String[] args) throws SQLException, Exception {
//	注册驱动
		Class.forName("com.mysql.jdbc.Driver");
		//DriverManager.registerDriver(new Driver());
//	获取连接
		String url = "jdbc:mysql://localhost:3306/hh";
		String userName = "root";
		String password = "chen1588";
		Connection connection = DriverManager.getConnection(url, userName, password);
//	创建Statement
		Statement statement =  connection.createStatement();
//	创建发送执行SQL
		String sqlString = "select * from student";
		ResultSet res = statement.executeQuery(sqlString);
//	操作结果集
		while (res.next()) {
			String string ="学号:" + res.getString("sno") + ",姓名:" + res.getString("sname") + ",性别:" + res.getString("ssex") + ",生日:" + res.getString("sbirthday") + ",班级:" + res.getString("class");
			System.out.println(string);
		}
		res.close();
		statement.close();
		connection.close();
	}
}

获取连接:

Connection:连接对象,所有java需要操作数据库的操作都要使用。

方法:getConnection(String url,String user,String password)
url格式如下"jdbc:mysql://localhost:3306/hh";

createStatament(); 创建一个Statement对象,用于发送SQL语句对象

prepareStatament();创建一个 PreparedStatement 对象来将参数化的 SQL 语句发送到数据库。

获取发送SQL语句的对象
Statement

方法:

excute(Strin sql); 可以执行任意SQL语句,select语句返回true,可通过getResultSet()获取。
如果执行的insert,update,delete语句,返回结果是false;
getUpdateCount() 以更新计数的形式获取当前结果;如果结果为 ResultSet 对象或没有更多结果,则返回 -1

excuteQuery(Strin sql);执行查询语句,执行给定的 SQL 语句,该语句返回单个 ResultSet 对象。

excuteUpdate (Strin sql); 执行给定 SQL 语句,该语句可能为 INSERT、UPDATE 或 DELETE 语句,或者不返回任何内容的 SQL 语句(如 SQL DDL 语句)。

package ink.longpress.www;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;


public class Three {
	public static void main(String[] args) throws Exception {
		//驱动
		Class.forName("com.mysql.jdbc.Driver");
		
		//连接
		String url = "jdbc:mysql://localhost:3306/hh";
		String userName = "root";
		String password = "chen1588";
		Connection connection = DriverManager.getConnection(url, userName, password);
		
		//使用executeUpdate修改数据
		Statement statement = connection.createStatement();
		int i = statement.executeUpdate("update student set class = '95031' where sno = '107'");
		System.out.println(i);
		
		//使用execute查询数据,查询数据返回true
		boolean flag = statement.execute("select * from student where class = '95031'");
		if (flag) {
			ResultSet resultSet = statement.getResultSet();
			while (resultSet.next()) {
				//按列名获取值
				System.out.println(resultSet.getString("sno") + "\t" + resultSet.getString("sname") + "\t" + resultSet.getString("ssex") + "\t" + resultSet.getString("sbirthday") + "\t" + resultSet.getString("class"));
				//按序号获取值,序号从1开始
				System.out.println(resultSet.getString(1) + "\t" + resultSet.getString(2) + "\t" + resultSet.getString(3) + "\t" + resultSet.getString(4) + "\t" + resultSet.getString(5));
			}
		}
	}
}

结果集的处理:

.next()

第一次调用指向→		SNO     SNAME   SSEX    SBIRTHDAY   CLASS   
				------  ------  ------  ----------  --------
				108     曾华      男       1977-09-01  95033   
				105              匡明                男       1975-10-02  95031   
				107     王丽      女       1976-01-23  95033   
				101    	李军                男       1976-02-20  95033   
				109              王芳                女       1975-02-10  95031   
最后指向,返回false→	103               陆君               男       1974-06-03  95031   

get???(int index);使用查询结果的序号获取内容
get???(String columnName);根据查询字段的列名获取内容

释放资源:

后开先关,先开后关

增删改查:

创建如下用户信息表:

CREATE DATABASE user_password;

CREATE TABLE userInfo(
	userId INT PRIMARY KEY AUTO_INCREMENT,
	userName VARCHAR(50) UNIQUE NOT NULL,
	userpassword VARCHAR(50) NOT NULL
);
userId  userName  userpassword  
------  --------  --------------
//完成JDBC增删改查操作

package ink.longpress.www;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class Four {
	public static void main(String[] args) {
		Connection connection = null;
		Statement statement = null;

		try {
			// 注册驱动
			Class.forName("com.mysql.jdbc.Driver");
			// 创建连接
			connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/user_password", "root", "chen1588");
			// 创建Statement对象
			statement = connection.createStatement();
		} catch (ClassNotFoundException e1) {
			e1.printStackTrace();
		} catch (SQLException e1) {
			e1.printStackTrace();
		}
		// 增加用户
		addUser(connection, statement);

		// 将jack的密码修改为abc
		changeUser(connection, statement);

		// 删除用户
		deleteUser(connection, statement);

		// 查询数据
		checkUser(connection, statement);
	}

	private static void checkUser(Connection connection, Statement statement) {
		ResultSet resultSet = null;
		try {
			resultSet = statement.executeQuery("select * from userinfo where username = 'queen'");
			while (resultSet.next()) {
				System.out.println(resultSet.getInt(1) + "\t" + resultSet.getString(2) + "\t"
						+ resultSet.getString("userpassword"));
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			try {
				if (statement != null) {
					statement.close();
				}
				if (connection != null) {
					connection.close();
				}
				if (resultSet != null) {
					resultSet.close();
				}
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}

	private static void deleteUser(Connection connection, Statement statement) {
		// 需求:将用户编号是4的删除
		// 先向表中插入五行数据
		/*
		 * INSERT INTO userinfo VALUES(NULL,'Queen','jack123'); INSERT INTO userinfo
		 * VALUES(NULL,'King','jack123'); INSERT INTO userinfo
		 * VALUES(NULL,'Acer','jack123'); INSERT INTO userinfo
		 * VALUES(NULL,'Joker','jack123'); INSERT INTO userinfo
		 * VALUES(NULL,'Toker','jack123');
		 */
		try {
			int num = statement.executeUpdate("delete from userinfo where userid = 4");
			System.out.println("删除了" + num + "行");
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			try {
				if (statement != null) {
					statement.close();
				}
				if (connection != null) {
					connection.close();
				}
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}

	private static void changeUser(Connection connection, Statement statement) {
		try {
			int num = statement.executeUpdate("update userinfo set userpassword = 'abc' where username = 'jack'");
			System.out.println("修改了" + num + "行");
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			try {
				if (statement != null) {
					statement.close();
				}
				if (connection != null) {
					connection.close();
				}
			} catch (SQLException e) {
				e.printStackTrace();
			} finally {
				try {
					if (statement != null) {
						statement.close();
					}
					if (connection != null) {
						connection.close();
					}
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
		}
	}

	private static void addUser(Connection connection, Statement statement) {
		try {
			// 需求:向用户表中添加用户,用户名叫“jack”,密码是”jack123”;
			int num = statement.executeUpdate("INSERT INTO userinfo  VALUES(NULL,'jack','jack123')");
			System.out.println("添加了" + num + "行");
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			try {
				if (statement != null) {
					statement.close();
				}
				if (connection != null) {
					connection.close();
				}
			} catch (SQLException e) {
				e.printStackTrace();
			} finally {
				try {
					if (statement != null) {
						statement.close();
					}
					if (connection != null) {
						connection.close();
					}
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
		}
	}
}

抽取工具类

为减少频繁写相同的连接,关闭资源等操作,可以将这些操作抽取成一个工具类:

package ink.longpress.www;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class JDBC {

	static {
		try {
			Class.forName("com.mysql.jdbc.Driver");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}

	public static Connection getConnectionObject(String url, String user, String password) {
		Connection connection = null;
		try {
			connection = DriverManager.getConnection(url, user, password);
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return connection;
	}

	public static void closeJDBC(Connection connection, Statement statement, ResultSet resultSet) {
		try {
			if (resultSet != null) {
				resultSet.close();
			}
			if (statement != null) {
				statement.close();
			}
			if (connection != null) {
				connection.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

	public static void closeJDBC(Connection connection, Statement statement) {
		try {
			if (statement != null) {
				statement.close();
			}
			if (connection != null) {
				connection.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
}

使用工具类:

package ink.longpress.www;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Scanner;

public class Five {
	static Connection connection;
	static Statement statement;
	static ResultSet resultSet;

	public static void main(String[] args) {
		
		Scanner scanner = new Scanner(System.in);
		System.out.println("用户名");
		String userString = scanner.nextLine();
		System.out.println("班级");
		String classString = scanner.nextLine();
		scanner.close();
		
		//调用工具的连接类,获取Connection对象
		connection = JDBC.getConnectionObject("jdbc:mysql://localhost:3306/hh", "root", "chen1588");
		
		try {
			statement = connection.createStatement();
			String sqlString = "select * from student where sno = " + userString + " AND class = " + classString;
			resultSet = statement.executeQuery(sqlString);

		} catch (SQLException e) {
			e.printStackTrace();
		}
		
		//判断resultSet是否为空,确定用户是否存在
		if (resultSet != null) {
			System.out.println(userString + "登陆成功");
		} else {
			System.out.println("输入错误");
		}
		//关闭资源
		JDBC.closeJDBC(connection, statement, resultSet);
	}
}

SQL的注入问题

Sql注入对用户输入的数据没有验证,并且sql语句是拼接成的,sql语句执行的时候跟java语言一样需要先编译,再执行。如果用户输入关键字,改变sql运行结果,达到恶意攻击效果。

详见:https://baike.baidu.com/item/sql%E6%B3%A8%E5%85%A5/150289?fr=aladdin

JDBC预处理对象(PreparedSatement)

Pstmt = prepareStatement(“select * from `user` where username=? and password = ?”);

Pstmt.setString(1,”张三”); 
Pstmt.setString(2,”1234”); 
Pstmt.executeQuery();

Pstmt.setString(1,”李四”); 
Pstmt.setString(2,”1234”); 
Pstmt.executeQuery();

第一次执行的时候会进行编译,第二次执行的时候,只是参数不同,sql语句没变,第二次不会编译,直接执行。如果执行一万次sql语句,只在第一次执行编译,后面直接执行,无需编译。

优点:
1:如果再次执行,sql语句没有变化,无需编译,直接执行,执行效率高。
2:可读性更高。
3:解决sql注入问题。

setInt(int parameterIndex, int x)
          
将指定参数设置为给定的占位符。 第一个参数是占位符,占位符从1开始。 第二个参数是参数值。
setString(int parameter,Index, String x)
          
将指定参数设置为给定占位符。 第一个参数是占位符,占位符从1开始。 第二个参数是参数值。
executeQuery()
          
在此 PreparedStatement 对象中执行 SQL 查询,并返回该查询生成的 ResultSet 对象。
executeUpdate()
          
在此 PreparedStatement 对象中执行 SQL 语句,该语句必须是一个 SQL 数据操作语言(Data Manipulation Language,DML)语句,比如 INSERTUPDATEDELETE 语句;或者是无返回内容的 SQL 语句,比如 DDL 语句。

使用PreparedStatement完成增删改查操作

package ink.longpress.www;

import java.sql.Connection;
import java.sql.PreparedStatement;

public class Six {
	static Connection connection;
	static PreparedStatement preparedStatement;
	
	public static void main(String[] args) throws Exception {
		
		//使用工具类创建Connection对象
		connection = JDBC.getConnectionObject("jdbc:mysql://localhost:3306/hh", "root", "chen1588");
		
		//创建preparedStatement对象
		preparedStatement = connection.prepareStatement("insert into student values(?,?,?,?,?)");
		
		//给预编译的对象空值处赋值
		preparedStatement.setString(1, "110");
		preparedStatement.setString(2, "张三");
		preparedStatement.setString(3, "男");
		preparedStatement.setString(4, "1995-09-07");
		preparedStatement.setString(5, "99999");
		
		//发送执行
		preparedStatement.execute();
		
		System.out.println(preparedStatement.getUpdateCount());
		
		connection.close();
		preparedStatement.close();
	}
}

jingsongchan

发表评论

电子邮件地址不会被公开。 必填项已用*标注