Java基础知识-JDBC

目录

前言

一、连接数据库步骤【理解】

1、加载驱动类

2、创建数据库连接

3、创建SQL语句

4、创建PreparedStatement

5、替换占位符

6、执行SQL

7、如果是读操作(查询),处理结果集

8、关闭相关流

二、CRUD完整代码【理解】

1、增加(Create)

2、删除(Delete)

3、修改(Update)

4、查询(Read)

5、DBUtils

前言

Java数据库连接,(Java Database Connectivity,简称JDBC)是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口,提供了诸如查询和更新数据库中数据的方法。JDBC也是Sun Microsystems的商标。我们通常说的JDBC是面向关系型数据库的。

一句话说明:JDBC是Java操作数据库的技术。

一、连接数据库步骤【理解】

1、加载驱动类

2、创建数据库连接

3、创建SQL语句

4、创建PreparedStatement

5、替换占位符

6、执行SQL

7、如果是读操作(查询),处理结果集

8、关闭相关流

1、加载驱动类

private static String driver = "com.mysql.cj.jdbc.Driver";
Class.forName(driver);

com.mysql.cj.jdbc.Driver是MySQL的驱动类,利用反射的方式加载驱动类,是固定的写法。

2、创建数据库连接

private static String url = "jdbc:mysql://127.0.0.1:3308/dbname?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true";
private static String username = "root";
private static String password = "";
Connection connection = DriverManager.getConnection(url, username, password);

url是数据库连接地址,username是数据库用户名,password是数据库密码。

url说明:

数据库连接地址是固定写法,不同的数据库写法不同。

url还有简单写法,url = "jdbc:mysql://127.0.0.1:3308/dbname"。

127.0.0.1是数据库服务的ip地址。

3308是数据库端口号,注意:MySQL默认端口号是3306,我们安装的版本是解压版,修改了端口号为3308。

dbname是数据库名称,我们现在学习时统一取名叫dbname,减小学习难度。

问号后面的是添加数据库的其它参数,参数不写不会报错,但参数可以解决中文乱码、统一时区等问题。

3、创建SQL语句

String sql = "INSERT INTO student(name,age) VALUES (?,?)";

问号是占位符,后面会替换占位符。

4、创建PreparedStatement

PreparedStatement preparedStatement = connection.prepareStatement(sql);

PreparedStatement是Java JDBC API提供的一个接口,它用于编译和执行SQL语句,提供了一种更有效率和安全的方式来向SQL语句传递参数。

5、替换占位符

preparedStatement.setString(1, student.getName());
preparedStatement.setInt(2, student.getAge());

将第1个问号替换成student的name属性值,第2个替换成student的age属性值。

注意:在程序中的索引通常从0开始,此处是一个特例,索引从1开始。

除此之外还要知道PreparedStatement的父接口Statement,也可以编译和执行SQL语句,但是它不能做占位符的替换,需要在定义SQL时就把具体数据写到语句中:

String sql = "INSERT INTO student(name,age) VALUES (" + student.getName() + "," + student.getAge() + ")";
Statement statement = connection.getStatement(sql);

Statement是不推荐使用的,学习它的目的基本为了两个面试题

PreparedStatement相较于Statement的优势是什么?
​
- 更高的执行效率。当需要执行多次相同的SQL语句时,PreparedStatement能够将SQL语句预编译,从而提高执行效率。PreparedStatement对象在创建时,会将SQL语句编译成一种可重用的二进制格式,当调用execute()方法时,直接传递参数即可执行SQL语句,而Statement当参数不同时也会认为是全新的SQL,会再次编译,Statement的每次都需要解析SQL语句导致了它的效率要低很多。
​
- 防止SQL注入攻击。使用Statement执行动态SQL语句时,需要将参数值拼接到SQL语句中,这样容易受到SQL注入攻击。而PreparedStatement通过参数化查询的方式,将参数值作为参数传递给SQL语句,从而避免了SQL注入攻击。
​
- 增加了代码的可读性。PreparedStatement的代码更加简洁明了,可以使代码更易于理解和维护。
什么是SQL注入?
​
SQL注入即是指web应用程序对用户输入数据的合法性没有判断或过滤不严,攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步得到相应的数据信息。
​
例如:
​
登录功能,假定用户的账号和密码分别是123和abc。
​
登录时输入账号和密码分别为123和def,那么SQL为 select * from user where username=123 and password='def',执行SQL时查询不到数据,登录失败。
​
但如果用户输入的密码改为:(def' or '1'='1),那么SQL为 select * from user where username=123 and password='def' or '1'='1',即使密码输入的是错误的也可以查询到数据,就可以登录系统,这种情况就是SQL注入。
​
如果用PreparedStatement处理,生成的SQL为:select * from user where username=123 and password='def\' or \'1\'=\'1',输入的英文单引号会被转移,这样就查询不到数据,登录仍然失败。
​
当然,实际工作中用户登录的会应用更多的技术以提高安全性,现在只是举一个例子。

6、执行SQL

/*写操作*/
preparedStatement.execute();
/*读操作*/
ResultSet rs = preparedStatement.executeQuery();

7、如果是读操作(查询),处理结果集

List<Student> result = new ArrayList<>();
ResultSet rs = preparedStatement.executeQuery();
while(rs.next()){
    Student s = new Student();
    s.setAge(rs.getInt("age"));
    s.setName(rs.getString("name"));
    s.setId(rs.getInt("id"));
    result.add(s);
}

ResultSet是查询的结果集,第一次执行next方法获取第一条数据,以后每次执行都会获取结果集中的下一条数据,当没有下一条数据时next方法会返回false。

8、关闭相关流

if(preparedStatement != null){
    try {
        preparedStatement.close();
    } catch (SQLException e) {
        e.printStackTrace();
    }
}

JDBC是流操作,所有流操作都要记得关闭流,否则资源会持续占用,关闭流的方式和学习IO流时方式相同,可以在finally中关闭,也可以通过try-with-resources的方式。

数据库连接Connection也是流,同样需要关闭,但不能提前关闭,否则会导致连接不到数据库。以后学习到框架后,各个流都交给框架管理,框架会统一处理流关闭问题。

二、CRUD完整代码【理解】

1、增加(Create)

public void add(Student student){
    Connection connection = DBUtils.getConnection();
    PreparedStatement preparedStatement = null;
    String sql = "INSERT INTO student(name,age) VALUES (?,?)";
    try(PreparedStatement preparedStatement = connection.prepareStatement(sql)) {
        /*替换占位符*/
        preparedStatement.setString(1, student.getName());
        preparedStatement.setInt(2, student.getAge());
        preparedStatement.execute();
    } catch (SQLException e) {
        e.printStackTrace();
    }
}

2、删除(Delete)

public void delete(int id){
    Connection connection = DBUtils.getConnection();
    PreparedStatement preparedStatement = null;
    try {
        String sql = "DELETE FROM student WHERE id=?";
        preparedStatement = connection.prepareStatement(sql);
        /*替换占位符*/
        preparedStatement.setInt(1, id);
        preparedStatement.execute();
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        if(preparedStatement != null){
            try {
                preparedStatement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

3、修改(Update)

public void update(Student student){
    Connection connection = DBUtils.getConnection();
    PreparedStatement preparedStatement = null;
    try {
        String sql = "UPDATE student SET name=?, age=? WHERE id=?";
        System.out.println(sql);
        preparedStatement = connection.prepareStatement(sql);
        /*替换占位符*/
        preparedStatement.setString(1, student.getName());
        preparedStatement.setInt(2, student.getAge());
        preparedStatement.setInt(3, student.getId());
        preparedStatement.execute();
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        if(preparedStatement != null){
            try {
                preparedStatement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

4、查询(Read)

public List<Student> select(Student student){
    List<Student> result = new ArrayList<>();
    Connection connection = DBUtils.getConnection();
    PreparedStatement preparedStatement = null;
    List<Object> params = new ArrayList<>();
    try {
        String sql = "SELECT * FROM student WHERE 1=1 ";
        if(student.getId() != null){
            sql += " AND id=? ";
            params.add(student.getId());
        }
        if(student.getAge() != null){
            sql += " AND age=? ";
            params.add(student.getAge());
        }
        if(student.getName() != null){
            sql += " AND name=? ";
            params.add(student.getName());
        }
        preparedStatement = connection.prepareStatement(sql);
        if(params != null && params.size() > 0){
            for(int i = 0; i < params.size(); i++){
                Object obj = params.get(i);
                if(obj instanceof String){
                    preparedStatement.setString(i + 1, (String) obj);
                }else if(obj instanceof Integer){
                    preparedStatement.setInt(i + 1, (Integer)obj);
                }
            }
        }
        ResultSet rs = preparedStatement.executeQuery();
        while(rs.next()){
            Student s = new Student();
            s.setAge(rs.getInt("age"));
            s.setName(rs.getString("name"));
            s.setId(rs.getInt("id"));
            result.add(s);
        }
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        if(preparedStatement != null){
            try {
                preparedStatement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    return result;
}

5、DBUtils

public class DBUtils{

    private static final String DRIVER = "com.mysql.cj.jdbc.Driver";
    private static final String URL = "jdbc:mysql://127.0.0.1:3308/dbname?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true";
    private static final String USERNAME = "root";
    private static final String PASSWORD = "";
    private static Connection connection;

    static {
        Class.forName(DRIVER);
        connection = DriverManager.getConnection(URL, USERNAME, PASSWORD);
    }

    public static Connection getConnection(){
        return connection;
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值