使用Java程序,完成对数据库进行操作CRUD操作
1.JDBC配置
先把MySQL驱动包导入,Build Path->Configure Build Path->libraries->add->apply
//定义好要用的元素
Connection conn = null;
Statement s = null;
ResultSet rs = null;
1.1 导入JDBC驱动包
// 1. 导入JDBC驱动包
Class.forName("com.mysql.cj.jdbc.Driver");
1.2 建立数据库连接
// 2. 建立数据库连接
String url = "jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai";
String user = "root";
String password = "123456";
conn = DriverManager.getConnection(url, user, password);
- jdbc:mysql://:指定连接的数据库类型为MySQL。
- localhost:指定连接的MySQL服务器地址,这里是本地地址。
- 3306:指定连接的MySQL服务器端口号,默认为3306。
- test:指定连接的MySQL数据库名称,这里是test。
- useunicode=true" 通常是在 JDBC 连接字符串中设置的一个参数,用于指示 MySQL JDBC 驱动程序在通信时使用 Unicode 编码。
characterEncoding=utf8
是指定 MySQL 数据库连接使用 UTF-8 编码字符集进行通信,这样可以确保在传输数据时不会出现中文乱码等问题。- "serverTimezone=Asia/Shanghai" 是用于指定 MySQL 数据库时区的配置属性。它表示将 MySQL 数据库时区设置为 "Asia/Shanghai",即上海时区。这个配置属性通常用于解决 Java 应用程序连接 MySQL 数据库时出现的时区不匹配问题。如果不指定该属性,可能会导致时间戳在 Java 应用程序和 MySQL 数据库之间不一致的问题。
2.使用JDBC语句
2.1创建Statement对象
// 3. 创建Statement对象
s = conn.createStatement();
当需要执行的操作的值为Java中变量的时候需要
2.2执行SQL语句
Statement的常用方法: | |
execute(String sql) | 可以执行任何类型的SQL语句,返回一个Boolean值,表示执行该SQL语句是否返回ResultSet对象 |
executeQuery(String sql) | 用于执行Select语句,返回一个ResultSet对象,其中包含查询的结果集。 |
executeUpdate(String sal) | 用于执行Insert、Update、Delete语句,返回一个int类型的值,表示影响的记录数。 |
// 4. 执行SQL语句
String sql = "SELECT * FROM users"; //定义一个要执行的操作的SQL语句
rs = s.executeQuery(sql); //Statement接口中的方法
2.3处理查询结果
// 5. 处理查询结果
while (rs.next()) {
int id = rs.getInt("id");
String name = rs.getString("name");
int age = rs.getInt("age");
System.out.println("id: " + id + ", name: " + name + ", age: " + age);
}
2.4关闭连接
// 6. 关闭连接
rs.close();
s.close(); //先关闭statement
conn.close(); //后关闭connection
2.5使用try-with-resource自动关闭连接
其实就是在try块中创建statement和connection等,那么try块执行完,连接也就自动关闭了
try (resource1; resource2; ...){
// some code
} catch (Exception e) {
// some code
}
2.7获取自增长id
在Statement通过execute或者executeUpdate执行完插入语句后,MySQL会为新插入的数据分配一个自增长id,(前提是这个表的id设置为了自增长,在Mysql创建表的时候,AUTO_INCREMENT就表示自增长)
CREATE TABLE hero ( //创建表的时候设置id的自增长
id int(11) AUTO_INCREMENT,
...
}
//设置插入语句
String sql = "INSERT INTO student(name, age) VALUES(?,?)";
//创建PreparedStatement对象,并设置参数,
PreparedStatement ps = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
ps.setString(1, "Tom");
ps.setInt(2, 20);
// 执行插入操作
ps.executeUpdate();
// 获取自增长id
ResultSet rs = ps.getGeneratedKeys();
3.预处理对象
创建 PreparedStatement 对象并执行 SQL 语句
相对Statement的优点:
1.使用参数设置,可读性好,不易犯错
2.PreparedStatement有预编译机制,性能比Statement更快
3.防止SQL注入式攻击
public static void TestPerformance(int in) {
try {
Class.forName("com.mysql.cj.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai";
String user = "root";
String password = "123456";
Connection conn;
try {
conn = DriverManager.getConnection(url, user, password);
switch (in) {
case 0:
/**
* statement存入100条数据
*/
long l1 = System.currentTimeMillis();
for(int i = 101;i<=200;i++) {
Statement s = conn.createStatement();
String sql = "INSERT INTO hero VALUES ("+i+",'英雄"+i+"',400,30)";
s.execute(sql);
}
System.out.println("Statement耗时为:");
System.out.println(System.currentTimeMillis()-l1);
break;
case 1:
/**
* prepareStatement存入100条数据
*/
long l2 = System.currentTimeMillis();
String sql = "INSERT INTO hero VALUES (?,?,400,30)";
PreparedStatement s = conn.prepareStatement(sql);
for(int i = 201;i<=300;i++) {
s.setInt(1, i);
s.setString(2, "英雄"+i);
int r = s.executeUpdate();
}
System.out.println("PreparedStatement耗时为:");
System.out.println(System.currentTimeMillis()-l2);
break;
default:
break;
}
} catch (SQLException e) {
e.printStackTrace();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
PreparedStatement 对象,该对象表示一个预编译的 SQL 语句的参数化查询。
通过使用参数化查询,可以将参数化的值传递给 SQL 语句,这有助于提高查询的性能和安全性,因为它可以避免 SQL 注入攻击。
? 是一个占位符,表示需要从用户输入中获取一个值。ps.setString(1, "John") 方法将值 "John" 绑定到第一个占位符上。
4.封装JDBC工具类
使用属性文件将JDBC获取MySQL连接的四个属性封装起来(驱动:Class.forName("com.mysql.cj.jdbc.Driver")、url、username、password)
4.1属性文件
使用.properties扩展名,由一系列键值对组成,每行表示一个键值对,
①使用等号或冒号将键和值分隔;
②键和值都是字符串类型,不需要使用引号或括号括起来;
③空行将被忽略;
④属性文件不支持多行值,每行只能表示一个键值对;
⑤可以使用#
或!
作为注释符号,从该符号到行尾的内容将被视为注释。
key1=value1
key2=value2
key3=value3
...
4.2Properties类
一种用于处理属性文件的工具类
常用方法:
1.创建和加载属性文件
// 创建一个 Properties 对象
Properties properties = new Properties();
try (InputStream inputStream = new FileInputStream("config.properties")) {
//加载属性文件
properties.load(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
2.获取属性值
String value = properties.getProperty("key");
3.设置属性值
properties.setProperty("key", "value");
4.遍历属性
for (String key : properties.stringPropertyNames()) {
String value = properties.getProperty(key);
System.out.println(key + " = " + value);
}
5.保存属性文件
try (OutputStream outputStream = new FileOutputStream("config.properties")) {
properties.store(outputStream, "Configuration");
} catch (IOException e) {
e.printStackTrace();
}
5.事务
一个事务是最小的执行单元,在事务中包含多条sql语句,在事务中sql语句要么全部执行成功要么全部执行失败,一般一个事务就是完整业务流程。
5.1事务的特征
1.原子性:事务是一个不可分割的操作单元,要么全部执行成功,要么全部失败回滚。
2.一致性:事务在执行前后,数据库的状态必须保持一致。事务的执行不能违反数据库中定义的约束和规则,保证数据的完整性和正确性。
3.隔离性:多个并发执行的事务之间应该互不干扰,每个事务都应该感觉到它是在独立执行的,即使在实际执行过程中可能存在并发冲突。
4.持久性:一旦事务提交成功,其对数据库的修改应该永久保存,即使系统发生故障或重启,数据也不会丢失。
5.2JDBC中事务
1.开启事务:通过将Connection
对象的setAutoCommit()
方法设置为false
来开启事务。默认情况下,每个SQL语句都会自动提交到数据库,但在事务中,我们可以手动控制提交。
connection.setAutoCommit(false);
2.提交事务:通过调用Connection
对象的commit()
方法来提交事务。提交后,数据库将保存所有已执行的SQL语句。
connection.commit();
3.回滚事务:如果在事务过程中发生错误或出现异常,可以使用Connection
对象的rollback()
方法来回滚事务。回滚将撤销事务中所有未提交的SQL语句。
connection.rollback();
4.设置保存点(Savepoint):保存点是在事务中设置的一个标记,可以在事务过程中对特定位置进行回滚。可以使用Connection
对象的setSavepoint()
方法创建保存点,并使用rollback()
方法进行回滚。
Savepoint savepoint = connection.setSavepoint("savepoint1");
// 在事务过程中的某个点出现错误,可以回滚到保存点
connection.rollback(savepoint);
这些方法允许您在JDBC中管理事务,确保数据库操作的原子性和一致性。在事务中,您可以执行多个SQL语句,并在所有操作完成后进行提交或回滚。