这周事情比较多,计划中是打算学习JDBC、并且开始Java Web的学习。但是实际上并没有达成目标,Java Web上只花了一点点时间。
一、JDBC
1、装载相应的数据库的JDBC驱动并进行初始化,并建立数据库连接
这里都以MySQL为例
- 如何添加jdbc的jar包:
https://blog.csdn.net/diligentkong/article/details/79587464 - 连接数据库首先要做的就是加载驱动类Driver
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,用于调用存储过程
- PreparedStatement:继承自Statement,由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中进行回滚
- 使用事务时需要使用Connection.setAutoCommit(false);将提交状态改为非自动提交
- 使用Statement或者PreparedStatement接口执行SQL语句
- 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)做软件的配置文件。【配置文件:保存软件设置的文件】