[Java]JDBC简介 & 获取数据库连接

[Java]JDBC简介 & 获取数据库连接_第1张图片


数据库使用MySQL


文章目录

  • 1. JDBC简介
  • 2. JDBC程序访问数据库步骤
  • 3. 获取数据库连接
    • 3.0 导入jar包
    • 3.1 Driver 接口
    • 3.2 JDBC URL
    • 3.3 方式1:
    • 3.4 方式2:
    • 3.5 方式3:
    • 3.5 方式4:
    • 3.6 方式5(final版):
    • 连接报错:
      • 1. Cause: java.sql.SQLException: Unknown initial character set index '255' received from server.
  • 4. 使用Statement操作数据表的弊端【了解】


1. JDBC简介

JDBC(Java Database Connectivity)是一个独立于特定数据库管理系统、通用的SQL数据库存取和操作的公共接口(一组API),定义了用来访问数据库的标准Java类库,(java.sql,javax.sql)使用这个类库可以以一种标准的方法、方便地访问数据库资源

[Java]JDBC简介 & 获取数据库连接_第2张图片
[Java]JDBC简介 & 获取数据库连接_第3张图片

JDBC驱动为对JDBC中定义的接口的实现。不同的数据库厂商,需要针对这套接口,提供不同实现。不同的实现的集合,即为不同数据库的驱动。

JDBC接口(API)包括两个层次:

  • 面向应用的API:Java API,抽象接口,供应用程序开发人员使用(连接数据库,执行SQL语句,获得结果)。
  • 面向数据库的API:Java Driver API,供开发商开发数据库驱动程序用。

JDBC API 是一系列的接口,它使得应用程序能够进行数据库连接,执行SQL语句,并且得到返回结果。Java程序员只需要面向这套接口编程即可。

2. JDBC程序访问数据库步骤

[Java]JDBC简介 & 获取数据库连接_第4张图片

  1. 导入对应的包和驱动
  2. 创建连接数据库的驱动对象
  3. 加载注册连接数据库的驱动
  4. 通过驱动获取连接数据库的对象
  5. 通过连接数据库的对象获取执行SQL语句的对象
  6. 执行SQL语句得到结果集对象
  7. 关闭对应的对象和连接

3. 获取数据库连接

3.0 导入jar包

【MySQL JDBC下载官网】
[Java]JDBC简介 & 获取数据库连接_第5张图片
压缩包下载到本地后解压,在IDE项目根目录下新建lib目录
[Java]JDBC简介 & 获取数据库连接_第6张图片
把下载的压缩包解压后的jar包复制到lib目录下
[Java]JDBC简介 & 获取数据库连接_第7张图片
复制完成后鼠标右键jar包,添加为库
[Java]JDBC简介 & 获取数据库连接_第8张图片

3.1 Driver 接口

java.sql.Driver 接口是所有 JDBC 驱动程序需要实现的接口。这个接口是提供给数据库厂商使用的,不同数据库厂商提供不同的实现

在程序中不需要直接去访问实现了 Driver 接口的类,而是由驱动程序管理器类(java.sql.DriverManager)去调用这些Driver实现

  • Oracle的驱动:oracle.jdbc.driver.OracleDriver
  • mySql的驱动: com.mysql.jdbc.Driver

3.2 JDBC URL

JDBC URL 用于标识一个被注册的驱动程序,驱动程序管理器通过这个 URL 选择正确的驱动程序,从而建立到数据库的连接。

JDBC URL的标准由三部分组成,各部分间用冒号分隔。

  • jdbc:子协议:子名称
  • 协议:JDBC URL中的协议总是jdbc
  • 子协议:子协议用于标识一个数据库驱动程序
  • 子名称:一种标识数据库的方法。子名称可以依不同的子协议而变化,用子名称的目的是为了定位数据库提供足够的信息。包含主机名(对应服务端的ip地址),端口号,数据库名

[Java]JDBC简介 & 获取数据库连接_第9张图片

  • 对于 Oracle 数据库连接,采用如下形式:
    jdbc:oracle:thin:@localhost:1521:atguigu
  • 对于 SQLServer 数据库连接,采用如下形式:
    jdbc:microsoft:sqlserver//localhost:1433; DatabaseName=sid
  • 对于 MYSQL 数据库连接,采用如下形式:
    jdbc:mysql://localhost:3306/atguigu

3.3 方式1:

如有报错后面的解决方法可能会有帮助

    @Test
    public void testConnection1() throws Exception {
        // 获取 Driver 驱动对象
        Driver driver = new com.mysql.jdbc.Driver();
        // 配置获取连接数据对象需要的信息
        // url:http://localhost:8080/gmall/keyboard.jpg
        // jdbc:mysql:协议
        // localhost:ip地址
        // 3306:默认mysql的端口号
        // test:test数据库
        
        // 字符集与数据库不一致  ?characterEncoding=utf8  设置字符集
        String url = "jdbc:mysql://localhost:3306/test?characterEncoding=utf8";
        // 将用户名和密码封装到Properties对象中
        Properties info = new Properties();
        info.setProperty("user", "root");
        info.setProperty("password", "123456");
        // 通过驱动对象根据配置信息获取连接数据库的对象
        Connection connection = driver.connect(url, info);
        // 打印连接对象,查看是否连接成功
        System.out.println(connection);
    }

[Java]JDBC简介 & 获取数据库连接_第10张图片

3.4 方式2:

对方式一的迭代:在如下的程序中不出现第三方的api,使得程序具有更好的可移植性

    @Test
    public void testConnection2() throws Exception {
        // 获取 Driver 驱动对象
        // 使用反射
        // 获取连接数据库驱动的类
        Class clazz = Class.forName("com.mysql.jdbc.Driver");
        // 通过连接驱动的类创建连接驱动Driver对象
        Driver driver = (Driver) clazz.newInstance();
        // 数据库的url
        String url = "jdbc:mysql://localhost:3306/test?characterEncoding=utf8";
        // 连接数据库需要的用户信息配置对象
        Properties info = new Properties();
        info.setProperty("user", "root");
        info.setProperty("password", "123456");
        // 获取连接数据库的对象
        Connection connection = driver.connect(url, info);
        System.out.println(connection);
    }

[Java]JDBC简介 & 获取数据库连接_第11张图片

3.5 方式3:

使用DriverManager替换Driver

DriverManager 类是驱动程序管理器类,负责管理驱动程序

  • DriverManager.registerDriver(com.mysql.jdbc.Driver);
  • 通常不用显式调用 DriverManager 类的 registerDriver() 方法来注册驱动程序类的实
    例,因为 Driver 接口的驱动程序类都包含了静态代码块,在这个静态代码块中,会
    调用 DriverManager.registerDriver() 方法来注册自身的一个实例
	@Test
    public void testConnection3() throws Exception {
        // 获取 Driver 驱动对象
        // 使用反射
        Class clazz = Class.forName("com.mysql.jdbc.Driver");
        Driver driver = (Driver) clazz.newInstance();
        // 连接数据库的配置信息
        String url = "jdbc:mysql://localhost:3306/test?characterEncoding=utf8";
        String user = "root";
        String password = "285013";
        // 通过 DriverManager 注册驱动
        DriverManager.registerDriver(driver);
        // 通过 DriverManager 获取连接对象
        Connection connection = DriverManager.getConnection(url, user, password);
        System.out.println(connection);
    }

[Java]JDBC简介 & 获取数据库连接_第12张图片

3.5 方式4:

可以只是加载驱动,不用显示的注册驱动,因为在加载驱动时候就会进行驱动的注册。

    @Test
    public void testConnection4() throws Exception {
        // 连接需要的三个基本信息
        String url = "jdbc:mysql://localhost:3306/test?characterEncoding=utf8";
        String user = "root";
        String password = "123456";

        // 使用反射加载驱动
        Class.forName("com.mysql.jdbc.Driver");
        // 相较于方式3,省略了如下操作
        // Driver driver = (Driver) clazz.newInstance();
        // 通过 DriverManager 注册驱动
        // DriverManager.registerDriver(driver);

        // 通过驱动管理获取数据库的连接
        Connection connection = DriverManager.getConnection(url, user, password);
        System.out.println(connection);
    }

[Java]JDBC简介 & 获取数据库连接_第13张图片

可以省略的原因:
在mysql的Driver实现类中,声明了如下的操作:

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

3.6 方式5(final版):

将数据库连接需要的4个基本信息声明在配置文件中,通过读取配置文件的方式,获取连接

此种方式的好处:

  1. 实现了数据与代码的分离。实现了解耦
  2. 如果需要修改配置文件信息,可以避免程序重新打包。

配置文件:
配置文件在src下,等号两边不能有空格!!!!!!

user=root
password=123456
url=jdbc:mysql://localhost:3306/test?characterEncoding=utf8
driverClass=com.mysql.jdbc.Driver

[Java]JDBC简介 & 获取数据库连接_第14张图片

    @Test
    public void testConnection5() throws Exception {
        // 通过反射获取读取配置文件的输入流
        InputStream is = ConnectionTest.class.getClassLoader().getResourceAsStream("jdbc.properties");
        // 配置信息对象
        Properties properties = new Properties();
        properties.load(is); // 加载配置信息
        // 得到配置信息
        String user = properties.getProperty("user");
        String password = properties.getProperty("password");
        String url = properties.getProperty("url");
        String driverClass = properties.getProperty("driverClass");
        // 加载驱动
        Class.forName(driverClass);
        // 获取连接
        Connection connection = DriverManager.getConnection(url, user, password);
        System.out.println(connection);
    }

[Java]JDBC简介 & 获取数据库连接_第15张图片

连接报错:

1. Cause: java.sql.SQLException: Unknown initial character set index ‘255’ received from server.

Cause: java.sql.SQLException: Unknown initial character set index '255' received from server.

【解决方法博客链接】

4. 使用Statement操作数据表的弊端【了解】

使用Statement的弊端:

  • 需要拼写sql语句
  • 存在SQL注入的问题

如何避免出现sql注入:只要用 PreparedStatement(从Statement扩展而来) 取代 Statement

SQL 注入是利用某些系统没有对用户输入的数据进行充分的检查,而在用户输入数据中注入非法的 SQL 语句段或命令

User 类:

public class User {

    private String user;
    private String password;

    public User() {
    }

    public User(String user, String password) {
        super();
        this.user = user;
        this.password = password;
    }

    @Override
    public String toString() {
        return "User [user=" + user + ", password=" + password + "]";
    }

    public String getUser() {
        return user;
    }

    public void setUser(String user) {
        this.user = user;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

}

StatementTest 测试类:

public class StatementTest {

    // 使用Statement的弊端:需要拼写sql语句,并且存在SQL注入的问题
    //如何避免出现sql注入:只要用 PreparedStatement(从Statement扩展而来) 取代 Statement
    @Test
    public void testLogin() {
        Scanner scanner = new Scanner(System.in);

        System.out.print("请输入用户名:");
        String user = scanner.nextLine();
        System.out.print("请输入密码:");
        String password = scanner.nextLine();
        //SELECT user,password FROM user_table WHERE user = '1' or ' AND password = '=1 or '1' = '1'
        String sql = "SELECT user,password FROM user_table WHERE user = '"+ user +"' AND password = '"+ password +"'";
        User returnUser = get(sql, User.class);
        if(returnUser != null){
            System.out.println("登录成功");
        }else{
            System.out.println("用户名不存在或密码错误");
        }
    }

    // 使用Statement实现对数据表的查询操作
    public <T> T get(String sql, Class<T> clazz) {
        T t = null;

        Connection conn = null;
        Statement st = null;
        ResultSet rs = null;
        try {
            // 1.加载配置文件
            InputStream is = StatementTest.class.getClassLoader().getResourceAsStream("jdbc.properties");
            Properties pros = new Properties();
            pros.load(is);

            // 2.读取配置信息
            String user = pros.getProperty("user");
            String password = pros.getProperty("password");
            String url = pros.getProperty("url");
            String driverClass = pros.getProperty("driverClass");

            // 3.加载驱动
            Class.forName(driverClass);

            // 4.获取连接
            conn = DriverManager.getConnection(url, user, password);

            st = conn.createStatement();

            rs = st.executeQuery(sql);

            // 获取结果集的元数据
            ResultSetMetaData rsmd = rs.getMetaData();

            // 获取结果集的列数
            int columnCount = rsmd.getColumnCount();

            if (rs.next()) {

                t = clazz.newInstance();

                for (int i = 0; i < columnCount; i++) {
                    // //1. 获取列的名称
                    // String columnName = rsmd.getColumnName(i+1);

                    // 1. 获取列的别名
                    String columnName = rsmd.getColumnLabel(i + 1);

                    // 2. 根据列名获取对应数据表中的数据
                    Object columnVal = rs.getObject(columnName);

                    // 3. 将数据表中得到的数据,封装进对象
                    Field field = clazz.getDeclaredField(columnName);
                    field.setAccessible(true);
                    field.set(t, columnVal);
                }
                return t;
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 关闭资源
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (st != null) {
                try {
                    st.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }

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

        return null;
    }

}

[Java]JDBC简介 & 获取数据库连接_第16张图片

当输入的用户名为:1' or 密码为:=1 or '1' = '1就会造成SQL注入问题

因为此时进行字符串拼接完成后,需要执行的SQL语句变为:

SELECT user,password 
FROM user_table 
WHERE user = '1' or ' AND password = '=1 or '1' = '1'

判断是否成立的条件有原来的两个条件相与变为三个条件相或:

   	user = '1' 
or 	' AND password = '=1 
or 	'1' = '1'

其中 '1' = '1'一定成立,此时不管账号密码是否正确一定可以登录系统。

以上就是SQL注入问题。

你可能感兴趣的:(Java,数据库,java,sql,mysql,jdbc)