JDBC: Database Connection Technology

JDBC: take it to love you again

(A) JDBC entry

(1 Overview

Java Database Connectivity, (Java Database Connectivity, referred to as JDBC) Java language is used to standardize the client program how to access the database application program interface that provides a method such as query and update data in a database. JDBC is also a trademark of Sun Microsystems'. JDBC is oriented relational database.

Simple explanation: the implementation of sql statement by the Java language, so that operation of the database

(2) reason

Want Java operations by different database, the database should be performed depending on the particular API, and for simplicity of the idea, Sun has defined a set of relational databases for all API that is JDBC, it provides only interface, go to the concrete realization of the database vendor to achieve, and we, as developers, we operate against the database, you just need to JDBC-based

(B) simple to use JDBC

We simply use JDBC to query the data in the database, and output to the console

For a quick demonstration, we create a very simple table

CREATE TABLE student(
    id INT PRIMARY KEY AUTO_INCREMENT,
    NAME VARCHAR(20),
    score DOUBLE(4,1)
);

INSERT student(id,NAME,score) VALUES (1,'张三',98);

INSERT student(id,NAME,score) VALUES (2,'李四',96);

INSERT student(id,NAME,score) VALUES (3,'王五',100);

We wrote a corresponding database based on the information in the student category

public class Student {
    private int id;
    private String name;
    private double score;
    //省略构造、Get、Set、toString方法
    ...... 
}

Here is a simple use of JDBC query function

package cn.ideal.jdbc;

import cn.ideal.domain.Student;

import java.sql.*;

public class JdbcDemo {
    public static void main(String[] args) {
        //导入数据库驱动包

        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;

        try {
            //加载驱动
            Class.forName("com.mysql.jdbc.Driver");
            //获取与数据库的连接对象
            connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/db1", "root", "root99");
            //定义sql语句
            String sql = "SELECT * FROM student";
            //获取执行sql语句的对象statement
            statement = connection.createStatement();
            //执行sql语句,获取结果集
            resultSet = statement.executeQuery(sql);

            //遍历获取到的结果集
            while (resultSet.next()) {
                int id = resultSet.getInt(1);
                String name = resultSet.getString(2);
                Double score = resultSet.getDouble(3);

                Student student = new Student();
                student.setId(id);
                student.setName(name);
                student.setScore(score);

                System.out.println(student.toString());
            }

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            //释放资源,后调用的先释放
            if (resultSet != null) {
                try {
                    resultSet.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }

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

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

//运行结果
Student{id=1, name='张三', score=98.0}
Student{id=2, name='李四', score=96.0}
Student{id=3, name='王五', score=100.0}

Here we begin to explain in detail the various objects used above

(C) JDBC objects Detailed

(1) DriverManager

A: Load Driver -> registration drive

First of all we need to know to load drivers and registration drives both what the word means, just when contacted, someone will always be a friend Class.forName(com.mysql.jdbc.Driver)as a registered database-driven statement, but actually not the case, its role is to load the Parametric Representation to memory and initialization , and wherein the static variable will be initialized, the static code block will be executed

  • Wondering: Can you use ClassLoader class loadClass () methods?

    • The answer is no, the characteristics of this method is loaded but not the class initialization
//Class类源码节选 -jdk8
* A call to {@code forName("X")} causes the class named
* {@code X} to be initialized.

About initialization problem here simply mention it, we still have to come back to our main line

Why not initialize class, you can not choose it?

This is because the real registration drive (which tells the program to use a database driver jar) are:

static void registerDriver(Driver driver)

In this category we find the Driver jar package, view the source code

//com.mysql.jdbc.Driver类中的静态代码块
static {
    try {
        DriverManager.registerDriver(new Driver());
    } catch (SQLException var1) {
        throw new RuntimeException("Can't register driver!");
    }
}

After the class is loaded, executed a static method of the DriverManager class is registered drivers

We may also have seen the code below 2, but actually drive will be loaded twice, because the execution

new com.mysql.jdbc.Driver() A driver has been loaded

//1.推荐
Class.forName("com.mysql.jdbc.Driver");
//2.不推荐
DriverManager.registerDriver(new com.mysql.jdbc.Driver())

So why bother it? new com.mysql.jdbc.Driver()Direct write not quite good yet?

But we chose to reject! why?

If we write, dependence jar package relatively heavy, and if we are faced with a number of projects, or the need to modify the database, you need to modify the code, recompile, but if you use Class class loading, both to ensure the static code block registration driving method included will be executed, but the parameters into a string, you can modify the configuration file "content" in the + Add more flexible ways jar package after we deal with the problem, and does not require recompile!

Note: The driver jar package mysql5 after registration drive this step can be omitted due to look into the jar package META-INF / services / java.sql.Driver file

com.mysql.jdbc.Driver
com.mysql.fabric.jdbc.FabricMySQLDriver

B: database connection

static Connection getConnection(String url, String user, String password) 
/*
    jdbc:mysql://ip地址(域名):端口号/数据库名称
    Eg:jdbc:mysql://localhost:3306/db1
    本地mysql,且端口为默认3306,则可简写:jdbc:mysql:///数据库名称
*/

(2) Connection (database connection object)

A: Get Object execution of sql

//创建向数据库发送sql语句的statement对象
Statement createStatement()

//创建向数据库发送预编译sql语句的PrepareStement对象
PreparedStatement prepareStatement(String sql)  

B: Management Services

//开启事务:设置参数为false,即开启事务
setAutoCommit(boolean autoCommit) 

//提交事务
commit() 

//回滚事务
rollback() 

(3) Statement (object to execute the sql statement)

//执行DQL(查询数据库中表的记录(数据))
ResultSet executeQuery(String sql)

//执行DML(对数据库中表的数据进行增删改)
int executeUpdate(String sql)

//执行任意sql语句,但是目标不够明确,较少使用
boolean execute(String sql)

//把多条sql的语句放到同一个批处理中
addBatch(String sql)

//向数据库总发送一批sql语句执行
executeBatch()

Code demonstrates (to add a data, for example)

package cn.ideal.jdbc;

import java.sql.*;

public class StatementDemo {
    public static void main(String[] args) {

        Connection connection = null;
        Statement statement = null;
        try {
            //加载驱动
            Class.forName("com.mysql.jdbc.Driver");

            //获取数据库连接对象
            connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/db1", "root", "root99");

            //定义sql语句
            String sql = "INSERT student(id,NAME,score) VALUES (NULL,'马六',88);";

            //获取执行sql语句的对象
            statement = connection.createStatement();

            //执行sql语句
            int count = statement.executeUpdate(sql);
            System.out.println(count);
            if (count > 0) {
                System.out.println("添加成功");
            } else {
                System.out.println("添加失败");
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            if(statement != null){
                try {
                    statement.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }

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

(4) ResultSet (result set objects, encapsulation query results)

ResultSet represents the result set sql statement - the results, when the Statement object to execute excuteQuery (), returns a ResultSet object

//游标向下移动一行,判断当前行是否是最后一行末尾(是否有数据)
//如果是,则返回false,如果不是则返回true
boolean next()

//获取数据,Xxx代表数据类型  
getXxx(参数)

Eg:int getInt() ,   String getString()
    
1. int:代表列的编号,从1开始   如: getString(1)
2. String:代表列名称。 如: getDouble("name")

Quick Reference may be cases beginning portion, the attempt to read its own data in the database is loaded with a set of frame

(D) multiplier - Tools

Encapsulated by some means, so that the emergence of a more general class of tool, we can profile properties, so that the information is more intuitive and easier to maintain

package cn.ideal.jdbc;

import java.io.FileReader;
import java.io.IOException;
import java.net.URL;
import java.sql.*;
import java.util.Properties;

public class JDBCUtils {
    private static String url;
    private static String user;
    private static String password;
    private static String driver;

    /**
     * 文件读取
     */
    static {

        try {
            //创建Properties集合类
            Properties pro = new Properties();
            //获取src路径下的文件
            ClassLoader classLoader = JDBCUtils.class.getClassLoader();
            URL res = classLoader.getResource("jdbc.properties");
            String path = res.getPath();

            //加载文件
            pro.load(new FileReader(path));
            //获取数据
            url = pro.getProperty("url");
            user = pro.getProperty("user");
            password = pro.getProperty("password");
            driver = pro.getProperty("driver");

            //注册驱动
            Class.forName(driver);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

    }

    /**
     * 获取连接
     *
     * @return 连接对象
     */
    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(url, user, password);
    }

    /**
     * 释放资源
     *
     * @param statement
     * @param connection
     */
    public static void close(Statement statement, Connection connection) {
        if (statement != null) {
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

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

    /**
     * 释放资源
     *
     * @param resultSet
     * @param statement
     * @param connection
     */
    public static void close(ResultSet resultSet, Statement statement, Connection connection) {
        if (resultSet != null) {
            try {
                resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

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

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

}

Tools test class

package cn.ideal.jdbc;

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

public class JDBCUtilsTest {
    public static void main(String[] args) {

        Connection connection = null;
        Statement statement = null;
        try {

            connection = JDBCUtils.getConnection();

            //定义sql语句
            String sql = "INSERT student(id,NAME,score) VALUES (NULL,'马六',88)";

            //获取执行sql语句的对象
            statement = connection.createStatement();

            //执行sql语句
            int count = statement.executeUpdate(sql);
            System.out.println(count);
            if (count > 0) {
                System.out.println("添加成功");
            } else {
                System.out.println("添加失败");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.close(statement,connection);
        }
    }
}

Previous article by the set were achieved, IO implementation, and after learning database, we can try to store database data, write a simple login Register little case! In the fifth-largest point mentioned roar

(E) supplement: PreparedStatment

//创建向数据库发送预编译sql语句的prepareStatement
PreparedStatement prepareStatement(String sql) 

prepareStatement inherited from Statement, All in all, it is compared to its parent, stronger and more simple!

(1) Advantages

A: Efficiency

Statement directly compiled SQL statements directly to the database to perform, and which repeatedly execute sql statement will PreparedStatement of precompiled SQL , then filling parameter, this would be more efficient ( pre-compiled SQL stored in the PreparedStatement )

B: readability

Custom SQL statement, I often need to use variables in Java, in some complex cases, the need for frequent use of the problem and single quotes, the more variable, more complex, and PreparedStatement can use placeholders ' ? "Instead of parameters, then the next parameter assignment, it is a good code readability

C: security

Because of precompiled PreparedStatement avoid Statement may be required to take concatenate strings and variables lead to SQL injection attacks [to write the equation forever, bypassing the password]

Let's follow our previous practice, write a simple login Demo, first create a table!

CREATE TABLE USER(
    id INT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(32),
    PASSWORD VARCHAR(32)
);

SELECT * FROM USER;

INSERT INTO USER VALUES(NULL,'admin','admin888');
INSERT INTO USER VALUES(NULL,'zhangsan','123456');

Then write code

package cn.ideal.login;

import cn.ideal.jdbc.JDBCUtils;

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

public class LoginDemo {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入用户名");
        String username = sc.nextLine();
        System.out.println("请输入密码");
        String password = sc.nextLine();
        
        boolean flag = new LoginDemo().login(username, password);

        if (flag) {
            System.out.println("登录成功");
        } else {
            System.out.println("用户名或密码错误");
        }
    }

    /**
     * 登录方法
     */
    public boolean login(String username, String password) {
        if (username == null || password == null) {
            return false;
        }

        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;

        try {
            connection = JDBCUtils.getConnection();
            //定义sql
            String sql = "SELECT * FROM USER WHERE username = '" + username + "' AND password = '" + password + "' ";
            //获取执行sql的对象
            statement = connection.createStatement();
            //执行查询
            resultSet = statement.executeQuery(sql);

            return resultSet.next();

        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JDBCUtils.close(resultSet,statement, connection);
        }
        return false;
    }
}

Simply put, such a simple login Demo was written, but this time, a situation arises the problem of SQL injection, perhaps you've heard, in the early years when the vulnerability is still quite common, Some hacker or script kiddie who often use some means of SQL injection invasion of the target site background, we are talking about this kind today, he is one of them, called a universal SQL injection (SQL universal password)

Let's take a look at the code above in the section on SQL statement

 String sql = "SELECT * FROM USER WHERE username = '" + username + "' AND password = '" + password + "' ";

That we will input usernameand passwordsynthesize SQL query, such as the database field is not present on behalf of a mistake, but there is a program for SQL injection vulnerability, it can by constructing a special string, to log on the purpose, first posted the test results

//运行结果
请输入用户名
admin
请输入密码
1' or '1' = '1
登录成功

If we take the above code password (username) part with them instead of our content is kind of how it

 String sql = "SELECT * FROM USER WHERE username = 'admin' AND PASSWORD = '1' or '1' = '1' ";

NOTE: In the SQL statement logic operator having priority, precedence = and, and precedence or

Therefore, the above formulas AND is performed first, of course, return error, or portion then performed, the equation for a permanent '1' = '1' for the return value is always true, so SQL query result is true, i.e., log success

//使用PrepareStemen替代主要部分

//定义sql
String sql = "SELECT * FROM USER WHERE username = ? AND password = ?";
//获取执行sql的对象
preparedStatement = connection.prepareStatement(sql);
//给?赋值
preparedStatement.setString(1, username);
preparedStatement.setString(2, password);

//执行查询
resultSet = preparedStatement.executeQuery();

//运行结果
请输入用户名
admin
请输入密码
1' or '1' = '1
用户名或密码错误

end:

If there are any deficiencies, or content in the wrong place, welcome to give me a shout advice, crab everyone! ^ _ ^

If you can help, then it is to pay attention to me! (Updated series of articles will be the first time the public number)

Here we are strangers, all in the dream and work for their own ❤

Push a stick original Java technology public numbers: more than ten days over two

Guess you like

Origin www.cnblogs.com/ideal-20/p/11297637.html