1、DriverManager
- 注册驱动
// 这个可以不用写,mysql驱动里面配置了 // 会自动加载jar包中META-INF/services/java.sql.Driver文件中的驱动类 Class.forName("com.mysql.cj.jdbc.Driver");
在com.mysql.cj.jdbc.Driver
这个类中,有个静态代码块,是用来注册驱动的,源码如下:
package com.mysql.cj.jdbc;
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
public Driver() throws SQLException {
}
static {
try {
DriverManager.registerDriver(new Driver());
} catch (SQLException var1) {
throw new RuntimeException("Can't register driver!");
}
}
}
- 获取数据库连接
//String url = "jdbc:mysql://127.0.0.1:3306/db1"; // 如果是本机的mysql并且端口是默认的3306,可以简化书写 String url = "jdbc:mysql:///db1"; String url = "jdbc:mysql:///db1"; String username = "root"; String password = "root1234"; // 2. 获取连接 Connection conn = DriverManager.getConnection(url, username, password);
2、Connection
数据库连接对象
- 获取执行的sql对象
- 获取普通执行sql对象
Statement statement = conn.createStatement();
- 获取预编译sql执行的sql对象:防止sql注入
PreparedStatement prepareStatement = conn.prepareStatement(sql);
- 获取普通执行sql对象
- 管理事务
- 开启事务
// true:设置成自动提交事务 // false:设置成手动提交事务 // 开启事务 setAutoCommit(false)
- 提交事务
commit()
- 回滚事务
rollback()
- 开启事务
例子
- 模拟数据
drop table if exists account; create table if not exists account ( id int primary key auto_increment, name varchar(10), money double(10, 2) ); insert into account(name, money) values ('张三', 1000), ('李四', 1000);
- java代码
// 如果是本机的mysql并且端口是默认的3306,可以简化书写 String url = "jdbc:mysql:///db1"; String username = "root"; String password = "root1234"; // 1. 注册驱动 // 这个可以不用写,mysql驱动里面配置了 // 会自动加载jar包中META-INF/services/java.sql.Driver文件中的驱动类 // Class.forName(className); // 2. 获取连接 Connection conn = DriverManager.getConnection(url, username, password); // 3. 定义sql语句 String sql1 = "update account set money = 111 where id = 1"; String sql2 = "update account set money = 111 where id = 2"; // 4. 获取执行sql的对象 statement Statement statement = conn.createStatement(); /** * ========事务管理================= */ try { // 开启事务 conn.setAutoCommit(false); // 5. 执行sql语句 int count1 = statement.executeUpdate(sql1); System.out.println("count: " + count1); // 模拟失败 int i = 1 / 0; int count2 = statement.executeUpdate(sql2); System.out.println("count: " + count2); // 提交事务 conn.commit(); } catch (Exception e) { // 回滚事务 conn.rollback(); e.printStackTrace(); } // 6. 处理结果 // 7. 释放资源 statement.close(); conn.close();
3、Statement
作用就是执行sql语句
int executeUpdate(String sql)
:执行DML、DDL语句- 返回值:DML语句返回的是影响的行数,DDL语句返回的是0
ResultSet executeQuery(String sql)
:执行DQL语句- 返回值:查询的结果集
例子
-
executeUpdate 执行DML语句
@Test public void testDML() throws Exception { //String url = "jdbc:mysql://127.0.0.1:3306/db1"; // 如果是本机的mysql并且端口是默认的3306,可以简化书写 String url = "jdbc:mysql:///db1"; String username = "root"; String password = "root1234"; String className = "com.mysql.cj.jdbc.Driver"; // 1. 注册驱动 // 这个可以不用写,mysql驱动里面配置了 // 会自动加载jar包中META-INF/services/java.sql.Driver文件中的驱动类 // Class.forName(className); // 2. 获取连接 Connection conn = DriverManager.getConnection(url, username, password); // 3. 定义sql语句 String sql = "insert into account(name, money) values ('张三丰', '2000');"; // 4. 获取执行sql的对象 statement Statement statement = conn.createStatement(); // 5. 执行sql语句 int count = statement.executeUpdate(sql); // 6. 处理结果 count 为 1 System.out.println("count: " + count); // 7. 释放资源 statement.close(); conn.close(); }
-
executeUpdate 执行DDL语句
@Test public void testDDL() throws Exception { //String url = "jdbc:mysql://127.0.0.1:3306/db1"; // 如果是本机的mysql并且端口是默认的3306,可以简化书写 String url = "jdbc:mysql:///db1"; String username = "root"; String password = "root1234"; String className = "com.mysql.cj.jdbc.Driver"; // 1. 注册驱动 // 这个可以不用写,mysql驱动里面配置了 // 会自动加载jar包中META-INF/services/java.sql.Driver文件中的驱动类 // Class.forName(className); // 2. 获取连接 Connection conn = DriverManager.getConnection(url, username, password); // 3. 定义sql语句 String sql = "create table if not exists tb_test_ddl\n" + "(\n" + " id int primary key auto_increment,\n" + " username varchar(20) not null unique,\n" + " password varchar(20) not null default 123456\n" + ");"; // 4. 获取执行sql的对象 statement Statement statement = conn.createStatement(); // 5. 执行sql语句 int count = statement.executeUpdate(sql); // 6. 处理结果 count 为 0 System.out.println("count: " + count); // 7. 释放资源 statement.close(); conn.close(); }
-
executeQuery 执行DQL语句
这里使用的是sql注入的例子
模拟数据
create table if not exists tb_user
(
id int primary key auto_increment,
username varchar(20),
password varchar(20)
);
insert into tb_user(username, password)
VALUES ('zhangsan', '123'),
('lisi', '123');
java 代码
@Test
public void testSqlInject() throws Exception {
String url = "jdbc:mysql:///db1";
String username = "root";
String password = "root1234";
Connection conn = DriverManager.getConnection(url, username, password);
String name = "asdafa";
String pwd = "' or '1' = '1";
// 3. 定义sql语句
String sql = "select * from tb_user where username='" + name + "' and password='" + pwd + "'";
// select * from tb_user where username='asdafa' and password='' or '1' = '1'
// 上面的语句相当于 select * from tb_user
System.out.println(sql);
Statement statement = conn.createStatement();
// 通过执行上面的sql语句,是查询所有的user数据
ResultSet rs = statement.executeQuery(sql);
if (rs.next()) {
System.out.println("登陆成功");
} else {
System.out.println("登陆失败");
}
// 释放资源
rs.close();
statement.close();
conn.close();
}
4、ResultSet
ResultSet 里面是封装了DQL查询语句的结果
boolean next()
- 将光标向下移动一位,判断当前行是否有效
- 返回值:
- true:有效行,当前行有数据
- false:无效行,当前行没有数据
xxx getXxx(param)
获取数据- xxx:数据类型
- 例如
int getInt(param)
和String getString(param)
- 例如
- param:参数,有两种
columnIndex
:列的序号,是从1开始columnLabel
:列的名称
- xxx:数据类型
例子
@Test
public void testResultSet() throws Exception {
String url = "jdbc:mysql:///db1";
String username = "root";
String password = "root1234";
Connection conn = DriverManager.getConnection(url, username, password);
// 3. 定义sql语句
String sql = "select * from account";
Statement statement = conn.createStatement();
ResultSet rs = statement.executeQuery(sql);
while (rs.next()) {
// 根据列的序号获取
// int id = rs.getInt(1);
// String name = rs.getString(2);
// double money = rs.getDouble(3);
// 根据列的名称获取
int id = rs.getInt("id");
String name = rs.getString("name");
double money = rs.getDouble("money");
System.out.println(id + " , " + name + " , " + money);
}
// 释放资源
rs.close();
statement.close();
conn.close();
}
5、PreparedStatement
预编译sql并执行sql语句
好处
- 预编译sql,性能更高
- 防止sql注入:将敏感字符进行了转义
原理
- 在获取
PreparedStatement
对象时,将sql语句发送给了mysql服务器进行检查,编译(这些步骤比较耗时) - 执行时就不用再进行这些步骤了,速度更快
- 如果sql模板一样,则只需要进行一次检查、编译
-
获取
PreparedStatement
对象// sql语句里面的参数值使用?占位符替代 String sql = "select * from tb_user where username= ? and password = ?"; // 通过Connection对象传入对应的sql语句获取 PreparedStatement prepareStatement = conn.prepareStatement(sql);
-
设置参数值 setXxx(p1,p2):给sql语句中?赋值
- Xxx数据类型,如setInt(p1,p2)、setString(p1,p2)
- 参数
- p1: ? 占位符的位置序号,从1开始
- p2: ?的值
-
执行sql
executeQuery()
/executeUpdate()
在这里就不需要传递sql语句了
例子
@Test
public void testPreparedStatement() throws Exception {
// useServerPrepStmts=true 开启预编译功能
String url = "jdbc:mysql:///db1?useServerPrepStmts=true";
String username = "root";
String password = "root1234";
Connection conn = DriverManager.getConnection(url, username, password);
String name = "zhangsan";
// String pwd = "' or '1' = '1";
String pwd = "123";
// 定义sql语句
String sql = "select * from tb_user where username= ? and password = ?";
// 获取 PreparedStatement 对象
PreparedStatement prepareStatement = conn.prepareStatement(sql);
// 给 ?设置值
prepareStatement.setString(1, name);
prepareStatement.setString(2, pwd);
// 执行sql
ResultSet rs = prepareStatement.executeQuery();
if (rs.next()) {
System.out.println("登陆成功");
} else {
System.out.println("登陆失败");
}
// 再次设置数据,并执行,在这里,就不需要进行检查编译了,
prepareStatement.setString(1, "aaa");
prepareStatement.setString(2, "pwd");
rs = prepareStatement.executeQuery();
if (rs.next()) {
System.out.println("登陆成功");
} else {
System.out.println("登陆失败");
}
rs.close();
prepareStatement.close();
conn.close();
}
这里用到了junit单元测试,需要在pom.xml
中导入junit
<dependencies>
<!-- mysql 驱动 -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.0.33</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
</dependencies>