11、JDBC

JDBC由来

我们的程序要去操作数据库时,都需要通过驱动进行操作。不同的数据库对应不同的数据库驱动,比如MySQL和Oracle会有不同的数据库驱动,这些驱动都是由各自的数据库公司开发。

在这里插入图片描述
SUN公司为了简化操作人员的操作,提供了一个JAVA操作数据库的规范,称为JDBC。它是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口,提供了诸如查询和更新数据库中数据的方法。数据库厂商也都会遵守这个规范,因此开发人员只需要管如何使用JDBC

在这里插入图片描述

要学习的是java自带的java.sql和javax.sql,除此之外还要导入一个数据库驱动包 mysql-connector-java-5.1.42.jar。包的版本根据数据库版本来

第一个JDBC程序

这个程序要去获取已经创建好的school数据库中的account表的信息
1、用SQLyog创建一个数据库和表,库名为school,表名为account
在这里插入图片描述
2、导入mysql-connector-java-5.1.42.jar包
可以在项目目录下新建lib文件夹(与src同级),将jar包放入,之后右键lib文件夹,选择ADD AS Library,这样就将jar包导入了

3、编写JAVA代码,读取数据并显示

import com.mysql.jdbc.Driver;
import java.sql.*;
//我的第一个JDBC程序
public class JdbcFirstDemo {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        // 1、加载驱动
        // 也可以DriverManager.registerDriver(new com.mysql.jdbc.Driver());  ,但是会加载两次注册驱动
        Class.forName("com.mysql.jdbc.Driver");
        // 2、登录信息和URL
        String url = "jdbc:mysql://localhost:3306/school?useUnicode=true&characterEncoding=utf8&useSSL=true";
        String user = "root";
        String password = "123456";
        // 3、建立连接  获得的是数据库对象
        Connection connection = DriverManager.getConnection(url, user, password);
        // 4、获取执行sql的对象
        Statement statement = connection.createStatement();
        // 5、执行sql,可能存在结果,查看结果
        String sql = "select * from account";
        ResultSet resultSet = statement.executeQuery(sql);
        while(resultSet.next()){
            System.out.println("id:"+resultSet.getObject("id"));
            System.out.println("id:"+resultSet.getObject("name"));
            System.out.println("id:"+resultSet.getObject("money"));
            System.out.println("===========================");
        }
        // 6、断开连接
        resultSet.close();
        statement.close();
        connection.close();
    }
}

第一步:加载驱动
com.mysql.jdbc.Driver类就是一个空的构造函数和一个静态代码块,静态代码块中进行DriverManager.registerDriver(new Driver()),所以归根到底我们直接加载这个类就可以了,让它执行静态代码块,因此推荐用上面代码中的方法Class.forName("com.mysql.jdbc.Driver");

public class Driver extends NonRegisteringDriver implements java.sql.Driver {
    public Driver() throws SQLException {
    }

    static {
        try {
            DriverManager.registerDriver(new Driver());
        } catch (SQLException var1) {
            throw new RuntimeException("Can't register driver!");
        }
    }
}

第二步:定义URL、用户名、密码变量
URL是固定格式jdbc:mysql://localhost:3306/school?useUnicode=true&characterEncoding=utf8&useSSL=true
3306一般是MySQL默认端口;school是你的数据库名,锁定数据库;后面是一些设置,开启Unicode,用utf8编码,进行安全认证

第三步:建立连接 获得数据库对象
Connection connection = DriverManager.getConnection(url, user, password);利用URL、用户名和密码,我们可以连接上数据库,获得Connection对象

第四步:获取可以执行sql语句的对象
利用Connection对象可以创建能执行SQL语句的Statement对象

第五步:执行sql语句
executeQuery可以执行查询语句,executeUpdate可以执行其他增删改语句,execute可以执行所有操作语句,但是需要判断SQL语句的类型。
其中查询语句获得ResultSet对象,可以用执行next方法获得下一行数据,getObject方法可以获得具体字段的值。如果知道字段类型的话,可以用更具体的数据类型,比如getString()。
其他比如插入、删除语句会返回整数,代表被修改的行数。

第六步:断开连接
查询结果对象、Statement对象、Connection对象

程序改进

改进一:新建一个properties文件,里面存放URL、用户名和密码,将这些信息单独放在一起,方便修改调用,也简化代码。
改进二:新建一个工具类,第一是通过一个静态代码块来获取properties文件中的信息,第二是定义连接和释放连接的方法,方便调用。

db.properties

src目录下

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/school?useUnicode=true&characterEncoding=utf8&useSSL=false
user=root
password=123456

JdbcUtils.class

工具类:1、获取配置文件数据 2、加载驱动 3、连接方法 4、释放连接方法

import java.io.InputStream;
import java.sql.*;
import java.util.Properties;

public class JdbcUtils {
    public static String driver = null;
    public static String url = null;
    public static String user = null;
    public static String password = null;
    
    //提取配置文件内的信息
    static{   
        try{
            //通过反射获取配置文件,并转为流的形式
            InputStream stream = JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");
            //新建配置对象,并加载数据
            Properties properties = new Properties();
            properties.load(stream);
			//获取数据
            driver = properties.getProperty("driver");
            url = properties.getProperty("url");
            user = properties.getProperty("user");
            password = properties.getProperty("password");
			//加载驱动
            Class.forName(driver);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
	//连接方法
    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(url, user, password);
    }
    
    //释放连接方法,如果没有结果就输入null即可
    public static void release(ResultSet resultSet, Statement statement, Connection connection) throws SQLException {
        if(resultSet!=null){
            resultSet.close();
        }
        if(statement!=null){
            statement.close();
        }
        if(connection!=null){
            connection.close();
        }
    }
}

JdbcUtilsInsert

测试插入操作

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

public class JdbcUtilsInsert {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;
        try {
            //连接
            connection = JdbcUtils.getConnection();
            //执行
            statement = connection.createStatement();
            String sql = "insert into `account`(id, name, money) values (10,'yqb',100)";
            int i = statement.executeUpdate(sql);
            if(i>0){
                System.out.println("插入成功");
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            JdbcUtils.release(resultSet, statement, connection);
        }
    }
}

SQL注入问题

在java中,我们的SQL语句就是一个字符串!我们通过将这个字符串传入Statement的execute方法中来进行执行。因为字符串是可以拼接的,因此会出现SQL注入的问题

举例:我们要根据idname字段去app_user表中去查询数据。我们的id和name都设置成了变量,我们准备通过字符串拼接的方法得到我们的SQL字符串,然后再执行这个SQL字符串

String id = "0 or 1=1 ";
String name = "yqb' or '1";
String sql = "select * from app_user where id = "+ id + " and name = '"+ name +"'";

拼接后,对应的SQL语句其实是:

SELECT * FROM app_user WHERE id = 0 OR 1=1  AND NAME = 'yqb' OR '1'

这样,这个Where永远成立,起不到查询的效果,而且这样也可以得到所有用户的数据,很不安全,这就是SQL注入问题

解决注入问题

利用PreparedStatement类替换Statement类可以解决SQL注入问题!这两个类的用法相似,但也有不同的地方

步骤:1、在定义sql字符串语句中,用占位符为变量进行占位 2、获得PreparedStatement对象的同时,对sql语句进行预编译 3、执行

举例(片段,其他地方与上面代码类似):

//定义sql字符串,?进行占位
String sql = "select * from account where id = ? and name = ?";
//对sql预编译
PreparedStatement preparedStatement = connection.prepareStatement(sql);
//赋值,第一个参数代表是第几个问号,第二个参数代表要赋的值
preparedStatement.setInt(1,1);
preparedStatement.setString(2,"A");
//执行,由于之前预编译,因此不再需要sql语句了
ResultSet resultSet = preparedStatement.executeQuery();

PreparedStatement防止SQL注入的本质在于:把传递进来的参数当作一个字符看待,即在整体外面加上引号。而内部本身的引号会被转义掉

JDBC操作事务

1、连接 2、关闭提交,开启事务 3、操作 4、提交 5、发生异常就会滚 6、释放
下面测试代码,需要前面的JdbcUtils.class和db.properties代码。在try中测试事务并提交,在catch中回滚,最终都要释放。

import Jdbc.lesson2.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class TestTransaction {
    public static void main(String[] args) throws SQLException {
        Connection connection = null;
        PreparedStatement statement = null;
        try {
            //获得连接
            connection = JdbcUtils.getConnection();
            //关闭自动提交,同时自动开启事务
            connection.setAutoCommit(false);
            //第一个事
            String sql1 = "update account set money = money - 500 where name = 'A'";
            statement = connection.prepareStatement(sql1);
            statement.executeUpdate();
            //第二个事
            String sql2 = "update account set money = money + 500 where name = 'B'";
            statement = connection.prepareStatement(sql2);
            statement.executeUpdate();
            //提交
            connection.commit();
        } catch (Exception throwables) {
            connection.rollback();
        } finally {
            JdbcUtils.release(null,statement,connection);
        }
    }
}

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值