JDBC连接数据库基础

JDBC

.JDBC是java访问数据库的标准规范,真正操作数据库还需要具体的实现类,也就是数据库驱动。怎么把数据库驱动jar包导入编译工具在网上都能搜到具体的操作步骤,这里不再赘述。

1连接数据库

1.1加载和注册数据库驱动,JDBC3之后可以跳过此步骤;

public class Demo1 {
public static void main(String[] args) throws ClassNotFoundException {
// 抛出类找不到的异常,注册数据库驱动
Class.forName("com.mysql.jdbc.Driver");// Driver接口,所有数据库厂商必须实现的接口,表示这是一个驱动类
}
}

1.2DriverManager 作用:

1) 管理和注册驱动

2) 创建数据库的连接

类中的方法:

DriverManager 类中的静态方法 描述

Connection getConnection (String url, String user, String password)

通过连接字符串,用户名,密码来得到数据库的连接对象

Connection getConnection (String url, Properties info)

通过连接字符串,属性对象来得到连接对象

public class Demo2 {
public static void main(String[] args) throws SQLException {
String url = "jdbc:mysql://localhost:3306/day24";
//1) 使用用户名、密码、 URL 得到连接对象
Connection connection = DriverManager.getConnection(url, "root", "root");
//com.mysql.jdbc.JDBC4Connection@68de145
System.out.println(connection);
}

2操作数据库

2.1Connection 作用:

Connection 接口,具体的实现类由数据库的厂商实现,代表一个连接对象。

2.2JDBC 访问数据库的步骤

1) 注册和加载驱动(可以省略)

2) 获取连接

3) Connection 获取 Statement 对象

4) 使用 Statement 对象执行 SQL 语句

5) 返回结果集

6) 释放资源

2.3Statement 作用:

代表一条语句对象,用于发送 SQL 语句给服务器,用于执行静态 SQL 语句并返回它所生成结果的对象。

 

 2.4释放资源

1) 需要释放的对象:ResultSet 结果集,Statement 语句,Connection 连接

2) 释放原则:先开的后关,后开的先关。ResultSet à Statement à Connection

3) 放在哪个代码块中:finally

 

package com.itheima;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
/**
* 创建一张学生表
*/
public class Demo4DDL {
public static void main(String[] args) {
//1. 创建连接
Connection conn = null;
Statement statement = null;
try {
conn = DriverManager.getConnection("jdbc:mysql:///day24", "root", "root");
//2. 通过连接对象得到语句对象
statement = conn.createStatement();
//3. 通过语句对象发送 SQL 语句给服务器
//4. 执行 SQL
statement.executeUpdate("create table student (id int PRIMARY key auto_increment, " +
"name varchar(20) not null, gender boolean, birthday date)");
//5. 返回影响行数(DDL 没有返回值)
System.out.println("创建表成功");
} catch (SQLException e) {
e.printStackTrace();
}
//6. 释放资源
finally {
//关闭之前要先判断
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}

 

package com.itheima;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
/**
* 向学生表中添加 4 条记录,主键是自动增长
*/
public class Demo5DML {
public static void main(String[] args) throws SQLException {
// 1) 创建连接对象
Connection connection = DriverManager.getConnection("jdbc:mysql:///day24", "root",
"root");
// 2) 创建 Statement 语句对象
Statement statement = connection.createStatement();
// 3) 执行 SQL 语句:executeUpdate(sql)
int count = 0;
// 4) 返回影响的行数
count += statement.executeUpdate("insert into student values(null, '孙悟空', 1, '1993-03-
24')");
count += statement.executeUpdate("insert into student values(null, '白骨精', 0, '1995-03-
24')");
count += statement.executeUpdate("insert into student values(null, '猪八戒', 1, '1903-03-
24')");
count += statement.executeUpdate("insert into student values(null, '嫦娥', 0, '1993-03-
11')");
System.out.println("插入了" + count + "条记录");
// 5) 释放资源
statement.close();
connection.close();
}
}

2.5ResultSet 接口中的方法 描述

boolean next()

1) 游标向下移动 1

2) 返回 boolean 类型,如果还有下一条记录,返回 true,否则返回 false

数据类型 getXxx() 1) 通过字段名,参数是 String 类型。返回不同的类型

2) 通过列号,参数是整数,从 1 开始。返回不同的类型

 

 //执行 SQL 语句得到结果集 ResultSet 对象
ResultSet rs = statement.executeQuery("select * from student");
 //循环遍历取出每一条记录
while(rs.next()) {
int id = rs.getInt("id");
String name = rs.getString("name");
boolean gender = rs.getBoolean("gender");
Date birthday = rs.getDate("birthday");
 //输出的控制台上
System.out.println("编号:" + id + ", 姓名:" + name + ", 性别:" + gender + ", 生日:" +
birthday);
}

3.数据库工具类 JdbcUtils

什么时候自己创建工具类?

如果一个功能经常要用到,我们建议把这个功能做成一个工具类,可以在不同的地方重用。

import java.sql.*;
import java.util.Scanner;

public class HelloJdbc {
private static final String USER = "root";
private static final String PWD = "root";
private static final String URL = "jdbc:mysql://localhost:3306/shop";
private static final String DRIVER= "com.mysql.jdbc.Driver";
private static Connection connection = null;
private static Statement st = null;
private static ResultSet rs = null;
/**
* 注册驱动
*/
static {
try {
Class.forName(DRIVER);
} catch (ClassNotFoundException e) {
System.out.println("ClassNotFoundExceptio");
}
}
/**
* 得到数据库的连接
*/
public static Connection getConnection() throws SQLException {
String s = "jdbc:mysql://192.168.20.116:3306/shop";
return DriverManager.getConnection(URL,USER,PWD);
}
/**
* 关闭所有打开的资源
*/
public static void toClose(){
if (st!=null) {
try {
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection!=null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
/**
* 关闭所有打开的资源
*/
public static void allClose() {
if (rs!=null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
toClose();
}

/*
* 得到praperStatement对象
*/
public static PreparedStatement getPs(String sql) throws SQLException {
return getConnection().prepareStatement(sql);
}

/*得到Statement对象*/
public static Statement getSt() throws SQLException {
return getConnection().createStatement();
}

/*得到字符串*/
public static String getWord(String ...str){
for (String s:str){
System.out.println(s);
}
Scanner scanner = new Scanner(System.in);
return scanner.nextLine();
}

/*执行SQL语句*/
public static void runSql(String sql) throws SQLException {
st = getConnection().createStatement();
st.executeUpdate(sql);
}

/*执行查询语句*/
public static ResultSet selectSql(String sql) throws SQLException {
st = getConnection().createStatement();
return st.executeQuery(sql);
}

}

以上是我在写第一个项目时编写的工具类,工具类可自行编写添加自己想要的功能,以便更方便地完成项目需求。

4.SQL 注入问题

l 当我们输入以下密码,我们发现我们账号和密码都不对竟然登录成功了

请输入用户名:

newboy

请输入密码:

a' or '1'='1

select * from user where name='newboy' and password='a' or '1'='1'

登录成功,欢迎您:newboy

l 问题分析:

select * from user where name='newboy' and password='a' or '1'='1'

name='newboy' and password='a' 为假

'1'='1'

相当于

select * from user where true; 查询了所有记录

我们让用户输入的密码和 SQL 语句进行字符串拼接。用户输入的内容作为了 SQL 语句语法的一部分,改变了原有 SQL 真正的意义,以上问题称为 SQL 注入。要解决 SQL 注入就不能让用户输入的密码和我们的 SQL 语句进行简单的字符串拼接。

5. PreparedStatement 接口

PreparedStatement Statement 接口的子接口,继承于父接口中所有的方法。它是一个预编译的 SQL 语句。

1) 因为有预先编译的功能,提高 SQL 的执行效率。

2) 可以有效的防止 SQL 注入的问题,安全性更高。

 

 PreparedSatement 的好处
1. prepareStatement()会先将 SQL 语句发送给数据库预编译。PreparedStatement 会引用着预编译后的结果。
可以多次传入不同的参数给 PreparedStatement 对象并执行。减少 SQL 编译次数,提高效率。
2. 安全性更高,没有 SQL 注入的隐患。
3. 提高了程序的可读性
8.6 使用 PreparedStatement 的步骤:
1) 编写 SQL 语句,未知内容使用?占位:"SELECT * FROM user WHERE name=? AND password=?";
2) 获得 PreparedStatement 对象
3) 设置实际参数:setXxx(占位符的位置, 真实的值)
4) 执行参数化 SQL 语句
5) 关闭资源
PreparedStatement 中设置参数的方法 描述
void setDouble(int parameterIndex, double x) 将指定参数设置为给定 Java double 值。
void setFloat(int parameterIndex, float x) 将指定参数设置为给定 Java REAL 值。
void setInt(int parameterIndex, int x) 将指定参数设置为给定 Java int 值。
void setLong(int parameterIndex, long x) 将指定参数设置为给定 Java long 值。
void setObject(int parameterIndex, Object x) 使用给定对象设置指定参数的值。
void setString(int parameterIndex, String x) 将指定参数设置为给定 Java String 值。
/**
* 使用 PreparedStatement
*/
public class Demo8Login {
//从控制台上输入的用户名和密码
public static void main(String[] args) throws SQLException {
Scanner sc = new Scanner(System.in);
System.out.println("请输入用户名:");
String name = sc.nextLine();
System.out.println("请输入密码:");
String password = sc.nextLine();
login(name, password);
}
/**
* 登录的方法
* @param name
* @param password
*/
private static void login(String name, String password) throws SQLException {
Connection connection = JdbcUtils.getConnection();
//写成登录 SQL 语句,没有单引号
String sql = "select * from user where name=? and password=?";
//得到语句对象
 Statement ps = connection.prepareStatement(sql);
//设置参数
ps.setString(1, name);
ps.setString(2,password);
ResultSet resultSet = ps.executeQuery();
if (resultSet.next()) {
System.out.println("登录成功:" + name);
}
else {
System.out.println("登录失败");
}
//释放资源,子接口直接给父接口
JdbcUtils.close(connection,ps,resultSet);
}
}

6.表与类的关系

使用 PreparedStatement 查询一条数据,封装成一个学生 Student 对象
package com.itheima;
import com.itheima.entity.Student;
import com.itheima.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class Demo9Student {
public static void main(String[] args) throws SQLException {
//创建学生对象
Student student = new Student();
Connection connection = JdbcUtils.getConnection();
PreparedStatement ps = connection.prepareStatement("select * from student where id=?");
//设置参数
ps.setInt(1,2);
ResultSet resultSet = ps.executeQuery();
if (resultSet.next()) {
//封装成一个学生对象
student.setId(resultSet.getInt("id"));
student.setName(resultSet.getString("name"));
student.setGender(resultSet.getBoolean("gender"));
student.setBirthday(resultSet.getDate("birthday"));
}
//释放资源
JdbcUtils.close(connection,ps,resultSet);
//可以数据
System.out.println(student);
}
}
public static void main(String[] args) throws SQLException {
//创建一个集合
List<Student> students = new ArrayList<>();
Connection connection = JdbcUtils.getConnection();
PreparedStatement ps = connection.prepareStatement("select * from student");
//没有参数替换
ResultSet resultSet = ps.executeQuery();
while(resultSet.next()) {
//每次循环是一个学生对象
Student student = new Student();
//封装成一个学生对象
student.setId(resultSet.getInt("id"));
student.setName(resultSet.getString("name"));
student.setGender(resultSet.getBoolean("gender"));
student.setBirthday(resultSet.getDate("birthday"));
//把数据放到集合中
students.add(student);
}
//关闭连接
JdbcUtils.close(connection,ps,resultSet);
//使用数据
for (Student stu: students) {
System.out.println(stu);
}
}
}

7.JDBC 事务的处理

 

API 介绍

 

Connection 接口中与事务有关的方法 说明

 

void setAutoCommit(boolean autoCommit) 参数是 true false

 

如果设置为 false,表示关闭自动提交,相当于开启事务

 

void commit() 提交事务

 

void rollback() 回滚事务

 

开发步骤

 

1) 获取连接

 

2) 开启事务

 

3) 获取到 PreparedStatement

 

4) 使用 PreparedStatement 执行两次更新操作

 

5) 正常情况下提交事务

 

6) 出现异常回滚事务

 

7) 最后关闭资源

 

 

 案例代码
package com.itheima;
import com.itheima.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class Demo12Transaction {
//没有异常,提交事务,出现异常回滚事务
public static void main(String[] args) {
//1) 注册驱动
Connection connection = null;
PreparedStatement ps = null;
try {
//2) 获取连接
connection = JdbcUtils.getConnection();
//3) 开启事务
connection.setAutoCommit(false);
//4) 获取到 PreparedStatement
//从 jack 扣钱
ps = connection.prepareStatement("update account set balance = balance - ? where
name=?");
ps.setInt(1, 500);
ps.setString(2,"Jack");
ps.executeUpdate();
//出现异常
System.out.println(100 / 0);
//给 rose 加钱
ps = connection.prepareStatement("update account set balance = balance + ? where
name=?");
ps.setInt(1, 500);
ps.setString(2,"Rose");
ps.executeUpdate();
//提交事务
connection.commit();
System.out.println("转账成功");
} catch (Exception e) {
e.printStackTrace();
try {
//事务的回滚
connection.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
System.out.println("转账失败");
}
finally {
//7) 关闭资源
JdbcUtils.close(connection,ps);
}
}
}

 8.加载准备文件

    /**
     * 读取配置文件,并根据其设置读取对应数据库的连接字符串
     */
    public void setConnectionString() {
        String path = "";
        try {
            String basePath = this.getClass().getClassLoader().getResource("/").toURI().getPath();
            path = basePath + "db.properties";
            Properties properties = new Properties();
            InputStream stream = new FileInputStream(path);
            properties.load(stream);
            stream.close();

            dbType = properties.getProperty("database.type");
            driver = properties.getProperty(dbType + ".driver");
            url = properties.getProperty(dbType + ".url");
            userName = properties.getProperty(dbType + ".username");
            password = properties.getProperty(dbType + ".password");
        } catch (Exception e) {
            System.out.println("获取配置文件中数据库连接字符串时错误:" + e.getMessage());
        }
    }

 

posted @ 2019-08-22 20:32  hsRick  阅读(288)  评论(0编辑  收藏  举报