JDBC
一 JDBC简介
JDBC(Java Data Base Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。JDBC提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序
1.JDBC基本实现步骤
1.创建一个Java项目
2.导入Mysql连接的jar包(驱动包)
3.注册驱动
4.获得与数据库的链接
5.创建代表发送和执行SQL语句的对象Statement
6.执行语句
7.如果执行的是查询语句,会返回一个结果集,可以对结果集进行操作。
8.释放占用的资源
2.典型JDBC范例
(错误直接抛出)
import java.io.FileInputStream;
import java.io.IOException;
import java.sql.*;
import java.util.Properties;
import java.util.Scanner;
public class MyJDBC {
public static void main(String[] args) throws SQLException, ClassNotFoundException, IOException {
Properties p = new Properties();
p.load(new FileInputStream("day01\\property\\mysql"));
//1.导入jar包
//2.注册驱动
Class.forName("com.mysql.jdbc.Driver");
//3.获取连接 固定写法 第一个参数固定 第二个参数登录名 第三个参数密码
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/sys", "root", "123456");
//4.获取执行sql语句的statement对象
Statement sta = conn.createStatement();
//5.执行SQL语句 返回一个结果集
while (true)
{
System.out.print("MySQL:");
Scanner sc = new Scanner(System.in);
String str = sc.nextLine();
ResultSet re = sta.executeQuery(str);
//5.1 处理结果集
System.out.println(re);
while (re.next()){
System.out.println(re.getInt(1)+"---"+re.getString(3)+re.getString("HIREDATE"));
}
re.close();
if (str.equals("out")){
break;
}
}
//6. 关闭资源
sta.close();
conn.close();
}
}
3.JDBC写入中文进行编译
- 在创建连接的地址后添加
?characterEncoding=utf-8
Connection conn = DriverManager.getConnection
("jdbc:mysql://localhost:3306/sys?characterEncoding=utf-8" , "root", "123456");
二 工具类的提取
1.JDBC相关类分析
1.1 Connection 接口
- (英译汉)connection — (两种事实、观念等的)联系,关联;联结;接通;连接;连接点
- 与特定数据库的连接(会话)。在连接上下文中执行 SQL 语句并返回结果。
- Connection 对象的数据库能够提供描述其表、所支持的 SQL 语法、存储过程、此连接功能等等的信息。
- 常用方法:
- Statement createStatement()
throws SQLException创建一个 Statement 对象来将 SQL 语句发送到数据库。不带参数的 SQL 语句通常使用 Statement 对象执行。如果多次执行相同的 SQL 语句,使用 PreparedStatement 对象可能更有效。
- PreparedStatement prepareStatement(String sql)
创建一个 PreparedStatement 对象来将参数化的 SQL 语句发送到数据库。
参数:
sql - 可能包含一个或多个 '?' IN 参数占位符的 SQL 语句
返回:
包含预编译 SQL 语句的新的默认 PreparedStatement 对象
1.2 Statement 接口
- (英译汉)Statement — 说明;说法;表态;声明;结算单;清单;报表
- 用于执行静态 SQL 语句并返回它所生成结果的对象。
- 常用方法:
- ResultSet executeQuery(String sql)
执行给定的 SQL 语句,该语句返回单个 ResultSet 对象。
参数:
sql - 要发送给数据库的 SQL 语句,通常为静态 SQL SELECT 语句
返回:
包含给定查询所生成数据的 ResultSet 对象;永远不能为 null
1.3 PreparedStatement 接口
- (英译汉)PreparedStatement — 准备报表
- 表示预编译的 SQL 语句的对象。
- SQL 语句被预编译并存储在 PreparedStatement 对象中。然后可以使用此对象多次高效地执行该语句。
- 常用方法:
- void setString(int parameterIndex, String x) throws SQLException
将指定参数设置为给定 Java String 值。在将此值发送给数据库时,驱动程序将它转换成一个 SQL VARCHAR 或 LONGVARCHAR 值(取决于该参数相对于驱动程序在 VARCHAR 值上的限制的大小)。
参数:
parameterIndex - 第一个参数是 1,第二个参数是 2,……
x - 参数值
1.4 ResultSet 接口
- (英译汉)ResultSet — 结果集
- 表示数据库结果集的数据表,通常通过执行查询数据库的语句生成。
- ResultSet 对象具有指向其当前数据行的光标。最初,光标被置于第一行之前。next 方法将光标移动到下一行;因为该方法在 ResultSet 对象没有下一行时返回 false,所以可以在 while 循环中使用它来迭代结果集。
- 常用方法
boolean next()
将光标从当前位置向前移一行。int getInt(String columnLabel)
以 Java 编程语言中 int 的形式获取此 ResultSet 对象的当前行中指定列的值。
2.使用工具类编写(登陆案例)
- 工具类(封装连接和关闭资源方法)
import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Properties;
public class Mysql_Method {
public static String DRIVER;
public static String URL;
public static String USERNAME;
public static String PASSWORD;
//获取连接
public static Connection getConn(){
Connection conn = null;
try {
Properties p = new Properties();
p.load(new FileInputStream("day01\\property\\mysql"));
DRIVER = p.getProperty("forName");
URL = p.getProperty("url");
USERNAME = p.getProperty("user");
PASSWORD = p.getProperty("password");
//注册驱动
Class.forName(DRIVER);
conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
}catch (Exception e){
e.printStackTrace();
}
return conn;
}
public static void clear(ResultSet re,Statement sta,Connection conn)
{
try {
re.close();
}catch (Exception e){
e.printStackTrace();
}finally {
try {
sta.close();
}catch (Exception e){
e.printStackTrace();
}finally {
try {
conn.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
}
- 配置文件
forName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/sys
user=root
password=123456
- 测试类
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
Connection conn = Mysql_Method.getConn();
Statement sta = null;
ResultSet res = null;
try {
Scanner sc = new Scanner(System.in);
while (true)
{
System.out.print("请输入用户名:");
String user = sc.nextLine();
System.out.print("请输入密码:");
String password = sc.nextLine();
sta = conn.createStatement();
res = sta.executeQuery("SELECT * FROM yonghu WHERE user='"+user+"' and password= '"+password+"'");
if (res.next()) {
System.out.println("恭喜你,登陆成功");
break;
}else {
System.out.println("登陆失败,请重试");
}
}
}catch (Exception e){
e.printStackTrace();
}finally {
Mysql_Method.clear(res,sta,conn);
}
}
}
三 SQL注入现象
1.SQL注入现象
-
什么叫做SQL注入呢?我们来看下面的现象
-
如图 这是我们数据库里存储的密码账号所有信息。接着 我们在登录案例中输入如下的值
-
为什么会出现这种现象呢?MySQL能编译通过查找成功说明错误一定发生在SQL语句传递前后,所以我们通过DEBUG看一下,MySQL收到的SQL语句到底是什么。
-
我们可以看到 这句话放到MySQL里能编译通过,所以SQL注入的原因找到了:
- 1.用户输入的信息中含有SQL关键字
- 2.更关键的,这个关键字被DBMS编译了,直接扭曲了原SQL语句的含义
2.SQL注入现象的解决办法
- 解决方法:只要用户提供的信息不参与编译过程。
- 我们将Statement换成preparedStatement 会进行预编译 这样就不会将值编译成SQL语句。
3.登陆案例代码演示
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Scanner;
public class Login {
public static void main(String[] args) {
//创建空的连接/报表/结果集,用以接收
Connection conn = null;
PreparedStatement pst = null;
ResultSet res = null;
try {
Scanner sc = new Scanner(System.in);
while (true)
{
//屏幕录入
System.out.print("请输入用户名:");
String user = sc.nextLine();
System.out.print("请输入密码:");
String password = sc.nextLine();
//调用工具类中的静态法方法,返回connection对象用conn接收
conn = Mysql_Method.getConn();
//调用connection对象的方法,传入需要执行的SQL语句,返回一个PreparedStatement对象
pst = conn.prepareStatement("SELECT * FROM yonghu WHERE user = ? and password = ?");
//向PreparedStatement对象中传入变量参数
pst.setString(1,user);
pst.setString(2,password);
//调用PreparedStatement对象的executeQuery方法,返回一个ResultSet对象
res = pst.executeQuery();
//进行判断
if (res.next()) {
System.out.println("恭喜你,登陆成功");
break;
}else {
System.out.println("登陆失败,请重试");
}
}
}catch (Exception e)
{
e.printStackTrace();
}finally {
Mysql_Method.clear(res,pst,conn);
}
}
}
4.注册案例
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Scanner;
public class Logon {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement pst = null;
ResultSet res = null;
try{
Scanner sc = new Scanner(System.in);
System.out.print("请输入需要注册的用户名:");
String user;
conn = Mysql_Method.getConn();
while(true){
user = sc.next();
PreparedStatement pst2 = conn.prepareStatement("SELECT * FROM yonghu WHERE ? = user");
pst2.setString(1,user);
res = pst2.executeQuery();
if (res.next()){
System.out.print("此用户名已被注册,请重新输入:");
}else {
pst2.close();
break;
}
}
System.out.print("请输入密码:");
String password = sc.next();
pst = conn.prepareStatement("INSERT INTO yonghu VALUES (?,?)");
pst.setString(1,user);
pst.setString(2,password);
pst.execute();
}catch (Exception e){
e.printStackTrace();
}finally {
Mysql_Method.clear(res,pst,conn);
}
}
}
四 数据库连接池
1.什么是数据库连接池
数据库的连接是比较消耗资源的,如果像之前一样,使用的时候创建,使用完后释放,频繁操作会造成一定的资源浪费。数据库连接池(Connection pooling)是程序启动时建立足够的数据库连接,并将这些连接组成一个连接池,由程序动态地对池中的连接进行申请,使用,释放。连接池应该有自动初始化,自动增长,自动缩减功能。
2.德鲁伊连接池——Java语言中最好的数据库连接池
2.1 如何使用德鲁伊连接池
- 通过Druid配置文件使用:
- 导入DRUID jar 包
- 拷贝配置文件到src目录
- 根据配置文件创建Druid连接池对象
- 从Druid连接池对象获得Connection
- 配置文件:(配置文件名:druid.properties)
数据库连接参数
url=jdbc:mysql://localhost:3306/[这里输入数据库文件名路径]
username=[这里输入数据库用户名]
password=[这里输入数据库密码]
driverClassName=com.mysql.jdbc.Driver//驱动
连接池的参数
initialSize=10//初始化连接数
maxActive=10//最大最大活动连接数
maxWait=2000//最大等待时间
2.1 德鲁伊连接池实例
public class demo_druid {
public static void main(String[] args) throws Exception {
Properties p = new Properties();
p.load(new FileInputStream("day02\\peizhi\\druid.properties"));
DruidDataSource dds = new DruidDataSource();
dds.setUrl(p.getProperty("url"));
dds.setUsername(p.getProperty("username"));
dds.setPassword(p.getProperty("password"));
dds.setInitialSize(Integer.parseInt(p.getProperty("initialSize")));
dds.setMaxActive(Integer.parseInt(p.getProperty("maxActive")));
dds.setMaxWait(Integer.parseInt(p.getProperty("maxWait")));
dds.setMinIdle(Integer.parseInt(p.getProperty("minIdle")));
DruidPooledConnection conn = dds.getConnection();
System.out.println(conn);//查看连接是否成功
}
}