java26-JDBC

JDBC概述

  • JDBC ,是一种用于执行SQL语句的javaAPI,为多种数据库提供同一访问,它由一组Java语言编写的类和接口组成
  • SUN公司是规范制定者,制定了规范JDBC
    • DriverManager类 作用:管理各种不同的JDBC驱动
    • Connection接口
    • Statement接口和PreparedStatement接口
    • ResultSet接口

使用

package com.xpc.test;

import com.mysql.cj.jdbc.Driver;

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

public class Test1 {
    public static void main(String[] args) throws SQLException {
        // 加载驱动
        Driver driver = new com.mysql.cj.jdbc.Driver();
        // 注册到驱动
        DriverManager.registerDriver(driver);
        // 获得连接
        /**
         * url 同一资源定位符
         *  1. 协议 jdbc:mysql
         *  2. IP
         *  3. 端口号
         *  4. 数据库名字
         *  5. 参数
         * name
         * password
         */
        String url = "jdbc:mysql://127.0.0.1:3306/mytestdb?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai";
        Connection connection = DriverManager.getConnection(url, "root", "123456");
        // 获得语句对象
        Statement statement = connection.createStatement();
        // 执行sql语句返回结果
        String sql = "INSERT INTO account VALUES (NULL,'jack',1000)";
        int i = statement.executeUpdate(sql);
        System.out.println("影响行数"+i);
        // 释放资源
        statement.close();
        connection.close();
    }
}

驱动加载

在Driver中有个静态代码块,会自动new实例并注册,所以可以直接用反射加载字节码文件到内存中就可以完成驱动加载和注册

package com.xpc.test;


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

public class Test1 {
    public static void main(String[] args) throws SQLException, ClassNotFoundException {
        // 加载驱动 注册到驱动
        Class.forName("com.mysql.cj.jdbc.Driver");
        // 获得连接
        /**
         * url 同一资源定位符
         *  1. 协议 jdbc:mysql
         *  2. IP
         *  3. 端口号
         *  4. 数据库名字
         *  5. 参数
         * name
         * password
         */
        String url = "jdbc:mysql://127.0.0.1:3306/mytestdb?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai";
        Connection connection = DriverManager.getConnection(url, "root", "123456");
        // 获得语句对象
        Statement statement = connection.createStatement();
        // 执行sql语句返回结果
        String sql = "INSERT INTO account VALUES (NULL,'jack',1000)";
        int i = statement.executeUpdate(sql);
        System.out.println("影响行数"+i);
        // 释放资源
        statement.close();
        connection.close();
    }
}

查询数据

  • 通过executeQuery查询数据库,返回一个结果集
  • 通过next()判断有无下一行并移动指针
package com.xpc.test;


import java.sql.*;

public class Test1 {
    public static void main(String[] args) throws SQLException, ClassNotFoundException {
        // 加载驱动 注册到驱动
        Class.forName("com.mysql.cj.jdbc.Driver");
        // 获得连接
        /**
         * url 同一资源定位符
         *  1. 协议 jdbc:mysql
         *  2. IP
         *  3. 端口号
         *  4. 数据库名字
         *  5. 参数
         * name
         * password
         */
        String url = "jdbc:mysql://127.0.0.1:3306/mytestdb?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai";
        Connection connection = DriverManager.getConnection(url, "root", "123456");
        // 获得语句对象
        Statement statement = connection.createStatement();
        // 执行sql语句返回结果
        String sql = "select * from account;";
        ResultSet result = statement.executeQuery(sql);
        System.out.println("影响行数"+result);
        boolean next = result.next();
        System.out.println(next);
        while (result.next()){
            int id = result.getInt("id");
            System.out.println(id);
            String uname = result.getString("uname");
            System.out.println(uname);
        }
        // 释放资源
        result.close();
        statement.close();
        connection.close();
    }
}

实体类

  • ResultSet在结束后要关闭,那么别的类不能用到查询到的数据,别的类想用需要用实体类转接
  • 实体类主要用处是存储从数据库查询出来的数据
  • 见名知义,实体类类名和数据库表名对应,属性个数和列数对应,属性类型和列的类型保持一致,所有属性私有化
  • getter和setter方法
  • 最好实现Serializable接口

SQL注入攻击和防范

  • SQL注入攻击指的是通过构建特殊的输入作为参数传入web应用程序,而参数大多是SQL语法的一些组合
select * from account where username = 'xxx' and password = 'xxx'
-- 注入攻击如下 密码后面拼接参数or'a'='a'
select * from account where username = 'xxx' and password = 'xxx'or'a'='a'
  • 防止注入攻击,不参用参数拼接,使用’?'作为占位符
    String sql = "select * from account where username = ? and password = ?";
    PreparedStatement ps = connection.prepareStatement(sql);
    ps.setString(1,"XXX");
    ps.setString(2,"XXX");
    ResultSet resultSet = ps.executeQuery();

PreparedStatement批处理

  • 有多条SQL语句给数据库执行时,可以发送一个SQL集合给数据库
  • 需要开启预处理
package com.xpc.test;

import com.xpc.untity.Account;

import java.sql.*;
import java.util.ArrayList;

public class test2 {
    public static void main(String[] args) throws SQLException, ClassNotFoundException {
        ArrayList<Account> accounts = new ArrayList<>();
        // 加载驱动 注册到驱动
        Class.forName("com.mysql.cj.jdbc.Driver");
        // 获得连接
        String url = "jdbc:mysql://127.0.0.1:3306/mytestdb?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai";
        Connection connection = DriverManager.getConnection(url, "root", "123456");
        // 获得语句对象
        Statement statement = connection.createStatement();
        String sql = "insert into account values (default,?,?)";
        PreparedStatement ps = connection.prepareStatement(sql);
        int row = 0;
        for (int i = 0; i < 1000; i++) {
            ps.setString(1,"name");
            ps.setString(2,"password");
//            int i1 = ps.executeUpdate();
//            row += i1;
            
            // 将SQL语句放入批次中
            ps.addBatch();
            // 如果数据过多,可以每隔100清理一次
//            if(i%100==0){
//                ps.executeBatch();
//                ps.clearBatch();
//            }
        }
        int[] ints = ps.executeBatch();
        // 释放资源
        statement.close();
        connection.close();
    }
}

jdbc中使用事务

  • jdbc是自动提交事务的,设置connection.setAutoCommit(false);为手动提交
  • 设置回滚点 connection.setSavepoint();
package com.xpc.test;
import java.sql.*;

public class test3 {
    public static void main(String[] args) {
        // 加载驱动 注册到驱动
        Connection connection = null;
        Statement statement = null;
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            // 获得连接
            String url = "jdbc:mysql://127.0.0.1:3306/mytestdb?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai";
            connection = DriverManager.getConnection(url, "root", "123456");
            // 不主动提交事务
            connection.setAutoCommit(false);
            // 获得语句对象
            statement = connection.createStatement();
            String sql = "update account set money = money - ? where id = ?";
            PreparedStatement ps = connection.prepareStatement(sql);
            ps.setDouble(1, 200);
            ps.setInt(2, 1);
//            int i=1/0;
            // 不提交事务了
            ps.executeUpdate();
            ps.setDouble(1, -200);
            ps.setInt(2, 2);
            // 不提交事务了
            ps.executeUpdate();
        } catch (Exception e) {
            System.out.println(e);
            if(null!=connection){
                try {
                    connection.rollback();
                } catch (SQLException ex) {
                    throw new RuntimeException(ex);
                }
            }

        } finally {
            if(null!=connection){
                try {
                    connection.commit();
                } catch (SQLException e) {
                    throw new RuntimeException(e);
                }
            }

            // 释放资源
            try {
                statement.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
            try {
                connection.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }

    }
}

连接池

  • Connection对象每次用完关闭很浪费资源,创建一个连接池,使用的时候从连接池取,完成放回连接池
  • 某次从集合中获取Connection对象时,集合空了,这时创建一个新的连接对象返回
  • 连接归还的数量,超过了连接池设置的规定上限,将多余的连接释放掉就可以了
package com.xpc.com.xpc.poll;

import com.mysql.cj.jdbc.Driver;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.LinkedList;

public class MyContectionPoll {
    private static String driver = "com.mysql.cj.jdbc.Driver";
    private static String url = "jdbc:mysql://127.0.0.1:3306/mytestdb?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai";
    private static String user = "root";
    private static String password = "123456";
    private static LinkedList<Connection>  poll;
    private static int inntSize = 5;
    private static int maxSize = 10;
    static {
        try {
            Class.forName(driver);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
        // 初始化poll
        poll = new LinkedList<Connection>();
        for (int i = 0; i < inntSize; i++) {
            Connection connection = initConnection();
            if(null != connection){
                poll.add(connection);
            }
        }
    }
    private static Connection initConnection(){
        try {
            return DriverManager.getConnection(url,user,password);
        }catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
    // 向外界提供方法
    public Connection getConnection(){
        Connection connection = null;
        if(poll.size()>0){
            connection = poll.remove();
        }else {
            connection = initConnection();
        }
        return  connection;
    }
    // 归还方法
    public void returnConnection(Connection connection){
        if(null!=connection){
            try {
             if(!connection.isClosed()){
                 try {
                     // 调整事务状态
                     connection.setAutoCommit(true);
                 } catch (SQLException e) {
                     throw new RuntimeException(e);
                 }
                 if(poll.size()<maxSize){
                     poll.addLast(connection);
                 }else {
                     try {
                         connection.close();
                     } catch (SQLException e) {
                         throw new RuntimeException(e);
                     }
                 }
             }
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }

        }

    }
}

log4j日志处理

  • 日志指的是异常信息,登陆成功失败的信息,其他重要信息
  • 记录日志方式
    • System.out.printIn() e.printStackTrace() 缺点不能保存到文件,不能长久存储
    • IO流 缺点操作繁琐,容易阻塞线程
    • 使用日志框架如log4j
  • log4j日志级别
    • FATAL:指出现非常严重的错误,这些错误可能影响程序执行
    • ERROR:虽有错误,但允许程序继续执行
    • WARN:指运行环境潜藏这危害
    • INFO:指报告信息
    • DEBUG:指细粒度信息事件,对于调试程序是最有用的
  • 使用log4j记录日志
    • 加入jar包 log4j-1.2.8.jar
    • 加入属性文件src下log4j.properties
log4j.rootLogger=error,logfile

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.target=System.err
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout

log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=e:/xpc.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %l %F %p %m%n

你可能感兴趣的:(JAVA基础,java)