2019.4.21学习周报

这周事情比较多,计划中是打算学习JDBC、并且开始Java Web的学习。但是实际上并没有达成目标,Java Web上只花了一点点时间。

一、JDBC

1、装载相应的数据库的JDBC驱动并进行初始化,并建立数据库连接

这里都以MySQL为例

Class.forName(“com.mysql.cj.jdbc.Driver”);(使用forName方法进行类的加载)

  • 然后通过DriverManager建立连接

Connection con = DriverManager.getConnection(“url”, “userName”, “passWorld”);

MySQL的JDBC URL编写方式:

jdbc:mysql://主机名称:连接端口/数据库的名称?参数=值&参数=值
这里需要在url种设置字符集和时区
完整的url为:jdbc:mysql://localhost:3306/demo?characterEncoding=UTF8&serverTimezone=UTC

建立链接都比较耗时,以后通常使用连接池来管理连接对象;

package textJDBC;

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

/**
 * author:Benjamin
 * date:2019.4.14
 */

public class TextDriver {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        Class.forName("com.mysql.cj.jdbc.Driver");
        Connection con = DriverManager.getConnection(
                "jdbc:mysql://localhost:3306/world",
                "root",
                "yourPassWorld");
    }
}

2、创建Statement或者PreparedStatement接口,执行SQL语句

Statement接口:用于执行静态的SQL语句并返回所执行的结果

  • Statement:由createStatement创建,用于发送简单SQL语句
    • PreparedStatement:继承自Statement,由PreparedStatement创建
      用于发送一个或多个有参数的SQL语句,且效率更高,一般使用这个
    • CallableStatement:继承自PreparedStatement,用于调用存储过程
常用Statement方法:
boolean execute(String str); 运行语句,返回是否有结果
ResultSet executeQuery(String str); 运行select语句,返回ResultSet结果集
int executeUpdate(String str); 运行insert/update/delete操作,返回更新的行数

在日常使用当中通常不使用Statement对象
Statement处理参数十分不方便,而且会发生SQL注入的危险
SQL注入:在SQL语句的拼接中,传入参数的不正确会造成歧义(例如,传入了where子句 id = 1 or 1 = 1;)
通常使用PreparedStatement
PreparedStatement pst = con.prepareStatement(str);
str中可以使用?进行占位,然后使用setObject()等函数进行完善

package textJDBC;

import java.sql.*;
import java.util.Scanner;

/**
 * author:Benjamin
 * date:2019.4.14
 */

public class TextStatement {
    public static void main(String[] args) throws SQLException, ClassNotFoundException {
        m2();
    }
    
	/**
	 * 使用Statement执行简单的SQL语句
	 */
    private static void m1() throws ClassNotFoundException, SQLException {
        Class.forName("com.mysql.cj.jdbc.Driver");
        Connection con = DriverManager.getConnection(
                "jdbc:mysql://localhost:3306/demo?characterEncoding=UTF8&serverTimezone=UTC",
                "root",
                "yourPassWorld");

        Statement sta = con.createStatement();
        String str = "insert into student (s_name, course) value ('lilili', 'web');";
        // Statement传入参数使用拼接字符串
        sta.execute(str);

    }
    
	/**
	 * 使用PreparedStatement构造有参数的SQL语句,并进行执行
	 */
    private static void m2() throws ClassNotFoundException, SQLException {
        Class.forName("com.mysql.cj.jdbc.Driver");
        Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/demo?characterEncoding=UTF8&serverTimezone=UTC", "root", "yourPassWorld");

        //使用?占位,然后调用setObject()等函数进行填充
        String str = "insert into student (s_name, course) value (?, ?);";
        PreparedStatement pst = con.prepareStatement(str);
        Scanner in = new Scanner(System.in);
        pst.setObject(1, in.nextLine());
        pst.setObject(2, in.nextLine());
        pst.execute();

    }
}

ResultSet 接收数据库返回的数据

executeQuery()返回的结果是ResultSet结果集

ResultSet提供方法来检索不提供类型的字段
getString();获得varchar,char等数据类型
getFloat();获得Float等数据类型
getDate();获得Date等数据类型
getBoolean();获得Boolean等数据类型
  • Statement.executeQuery()的返回值是ResultSet
    • ResultSet.next();返回值为Boolean,意为是否可以进行迭代,与迭代器中的hasNext()类似,且具有游标移动功能
    • getString(int col),getFloat(int col),getDate(int col),getBoolean(int col)得到每一行中下标为col的数据

ResultSet,Statement和Connection都需要关闭,关闭顺序:ResultSet->Statement->Connection

package textJDBC;

import java.sql.*;

/**
 * author:Benjamin
 * data:2019.4.15
 */

public class TextResultSet {
    public static void main(String[] args) throws SQLException, ClassNotFoundException {
        m1();
    }

    private static void m1() throws ClassNotFoundException, SQLException {
        Class.forName("com.mysql.cj.jdbc.Driver");
        Connection con = DriverManager.getConnection(
                "jdbc:mysql://localhost:3306/demo?characterEncoding=UTF8&serverTimezone=UTC",
                "root",
                "yourPassWorld");

        String str = "select s_id, s_name, course from student where s_id < ?;";
        PreparedStatement pst = con.prepareStatement(str);
        pst.setObject(1, 10);
        // 使用ResultSet接受返回的结果集
        ResultSet rs = pst.executeQuery();
        while (rs.next()) {
            System.out.println("id = " + rs.getInt(1) +
                    ", name = " + rs.getString(2) +
                    ", course = " + rs.getString(3));
        }
        pst.close();
        con.close();
    }
}

使用JDBC完成事务

事务在MySQL中预警学习过,需要先设置状态为非自动提交
在JDBC中,通过try-catch完成事务中语句的正确性判断,并在catch中进行回滚

  1. 使用事务时需要使用Connection.setAutoCommit(false);将提交状态改为非自动提交
  2. 使用Statement或者PreparedStatement接口执行SQL语句
  3. Connection.commit();进行SQL语句的提交
package textJDBC;

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

/**
 * 本测试中将各种异常都进行了捕获,以前没有做过演示。
 * author:Benjamin
 * date:2019.4.15
 */

public class TextTransaction {
    public static void main(String[] args) throws ClassNotFoundException {
        // 连接数据库
        Class.forName("com.mysql.cj.jdbc.Driver");
        Connection con = null;
        PreparedStatement ps1 = null;
        PreparedStatement ps2 = null;

        try {
            con = DriverManager.getConnection(
                    "jdbc:mysql://localhost:3306/demo?characterEncoding=UTF8&serverTimezone=UTC",
                    "root",
                    "yourPassWorld");

            con.setAutoCommit(false);

            String str = "insert into student (s_name, course)value(?, ?);";
            ps1 = con.prepareStatement(str);
            ps1.setObject(1,"lll");
            ps1.setObject(2,"MySQL");
            ps1.execute();

            // 这里故意出错测试是否会回滚
            str = "insert into student (s_name, course)value(?, ?, ?);";
            ps2 = con.prepareStatement(str);
            ps2.setObject(1,"lllll");
            ps2.setObject(2,"MySQL_");
            ps2.execute();

            con.commit();
        } catch (SQLException e) {
            e.printStackTrace();
            try {
                con.rollback();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
        }finally {
            if(ps1 != null){
                try {
                    ps1.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(ps2 != null){
                try {
                    ps2.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(con != null){
                try {
                    con.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

CLOB

向数据库中存储或读取大字符数据时需要使用CLOB进行传输
主要思想就是使用流填充PreparedStatement中的空位
读取时得到CLOB对象,关联到流中即可输出到本地

package textJDBC;

import java.io.*;
import java.sql.*;

/**
 * 可以向MySQL数据库中写入大文本数据
 * 与寻常数据不同,大文本数据需要使用流向数据库中写入
 * author:Benjamin
 * date:2019.4.15
 */
public class TextCLOB {
    public static void main(String[] args) throws IOException, SQLException, ClassNotFoundException {
        read();
    }

    /**
     * 使用JDBC向MySQL数据库中写入大字符文件
     * @throws ClassNotFoundException
     * @throws SQLException
     * @throws FileNotFoundException
     */
    public static void write() throws ClassNotFoundException, SQLException, FileNotFoundException {
        // 连接数据库
        Class.forName("com.mysql.cj.jdbc.Driver");
        Connection con = DriverManager.getConnection(
                "jdbc:mysql://localhost:3306/demo?characterEncoding=UTF8&serverTimezone=UTC",
                "root",
                "yourPassWorld");
        // 执行SQL语句
        String str = "insert into test_clob (text)value(?);";
        PreparedStatement ps = con.prepareStatement(str);
        // 将读入流传入sql
        ps.setClob(1,
                new FileReader(
                        new File("src\\textJDBC\\one.txt")));
        ps.executeUpdate();
    }

    /**
     * 使用JDBC从MySQL读取大文本数据
     * @throws ClassNotFoundException
     * @throws SQLException
     * @throws IOException
     */
    public static void read() throws ClassNotFoundException, SQLException, IOException {
        // 连接数据库
        Class.forName("com.mysql.cj.jdbc.Driver");
        Connection con = DriverManager.getConnection(
                "jdbc:mysql://localhost:3306/demo?characterEncoding=UTF8&serverTimezone=UTC",
                "root",
                "yourPassWorld");
        String str = "select * from test_clob where id = ?;";
        PreparedStatement ps = con.prepareStatement(str);
        ps.setObject(1, 1);

        ResultSet rs = ps.executeQuery();

        // 通过Buffer提高效率,读取数据并写在本地
        while (rs.next()) {
            Clob clob = rs.getClob("text");
            BufferedReader bfr = new BufferedReader(clob.getCharacterStream());
            BufferedWriter bfw = new BufferedWriter(
                    new FileWriter("src\\textJDBC\\one(writeFromMySQL).txt"));

            String s;
            while ((s = bfr.readLine()) != null){
                bfw.write(s);
                bfw.newLine();
                bfw.flush();
            }
        }
    }
}

BLOB

存储或者读取大二进制数据,方法和CLOB相同,只不过关联的是字节流。

package textJDBC;

import java.io.*;
import java.sql.*;

/**
 * 向数据库中存入大二进制文件
 * 和CLOB一样,需要使用流进行文件的传输
 * 这里传输二进制文件。那么就需要使用字节流
 * 
 * git提交出现问题,本以为时与历史不符,试了半天发现我中间上传的一个文件太大了
 * 由3个多G,GitHub不支持上传这么大的一个文件,导致远程拒绝提交
 * 解决方案是先回档,将git中的commit回档到那一次提交之前,将本地的大文件删除之后
 * 重新进行commit,然后push
 * 
 * author:Benjamin
 * date:2019.4.16
 */
public class TextBLOB {

    public static void main(String[] args) throws IOException, SQLException, ClassNotFoundException {
        read();
    }

    /**
     * 通过JDBC向MySQL数据库中上传大二进制文件
     * @throws ClassNotFoundException
     * @throws SQLException
     * @throws FileNotFoundException
     */
    public static void write() throws ClassNotFoundException, SQLException, FileNotFoundException {
        // 连接数据库
        Class.forName("com.mysql.cj.jdbc.Driver");
        Connection con = DriverManager.getConnection(
                "jdbc:mysql://localhost:3306/demo?characterEncoding=UTF8&serverTimezone=UTC",
                "root",
                "yourPassWorld");

        String str = "insert into test_blob (png) value (?);";
        PreparedStatement ps = con.prepareStatement(str);
        ps.setBlob(1,
                new FileInputStream("src\\textJDBC\\lion.jpg"));
        ps.executeUpdate();
    }

    /**
     * 从MySQL数据库读取大二进制文件
     * @throws ClassNotFoundException
     * @throws SQLException
     * @throws IOException
     */
    public static void read() throws ClassNotFoundException, SQLException, IOException {
        // 连接数据库
        Class.forName("com.mysql.cj.jdbc.Driver");
        Connection con = DriverManager.getConnection(
                "jdbc:mysql://localhost:3306/demo?characterEncoding=UTF8&serverTimezone=UTC",
                "root",
                "yourPassWorld");

        String str = "select png from test_blob where id = 1;";
        PreparedStatement ps = con.prepareStatement(str);

        ResultSet rs = ps.executeQuery();
        while (rs.next()) {
            Blob blob = rs.getBlob("png");
            BufferedInputStream bi = new BufferedInputStream(blob.getBinaryStream());
            BufferedOutputStream bo = new BufferedOutputStream(new FileOutputStream("src\\textJDBC\\lion(writeFromMySQL).jpg"));

            int i;
            byte[] by = new byte[1024];
            while ((i = bi.read(by)) != -1) {
                bo.write(by, 0, i);
            }
        }
    }

}

批处理Batch

JDBC提供了数据库batch处理的能力,在数据大批量操作(新增、删除等)的情况下可以大幅度提升系统的性能
当进行批处理更新时,通常应该关闭自动执行。
相当于将SQL语句存起来,提交时一起提交,由DBMS统一处理

package textJDBC;

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

/**
 * author:Benjamin
 * date:2019.4.15
 */

public class TextBatch {

    public static void main(String[] args) throws SQLException, ClassNotFoundException {
        m1();
    }
    private static void m1() throws ClassNotFoundException, SQLException {
        // 连接数据库
        Class.forName("com.mysql.cj.jdbc.Driver");
        Connection con = DriverManager.getConnection(
                "jdbc:mysql://localhost:3306/demo?characterEncoding=UTF8&serverTimezone=UTC",
                "root",
                "yourPassWorld");

        // 获取Statement,这里不使用prepareStatement,原因是拼接SQL效率有些低
        Statement sta = con.createStatement();
        // 设置为不自动提交
        con.setAutoCommit(false);
        //循环插入20000行数据
        for(int i = 1; i <= 20000; i++){
            //将拼接得到的SQL语句添加到Batch中
            sta.addBatch("insert into table1 (name, time_) value ('name" + i + "', now());");
        }
        // 提交语句,到DBMS
        sta.executeBatch();
        // 执行语句
        con.commit();

        // 关闭资源
        sta.close();
        con.close();
    }
}

XML

XML,Extensible Markup Language,扩展性标识语言。文件的后缀名为:.xml。就像HTML的作用是显示数据,XML的作用是传输和存储数据。

是干啥用的?
为了便于不同应用、不同平台之间的数据共享和通信。

具体点的作用为:
(1)可作为一种简单的数据库,存储并检索数据;
(2)传输约定格式的文件;
(3)做软件的配置文件。【配置文件:保存软件设置的文件】

猜你喜欢

转载自blog.csdn.net/Benjalin_76_84/article/details/89436650