- JDBC入门案例
- JDBC连接介绍
- 使用JDBC查询数据,并封装到对象中
- 模拟登录(存在SQL注入风险)
- 使用预编译操作对象防止SQL注入
- 编写JDBC工具类
- 批处理
- 在Java程序中调用存储过程
- java中调用数据库的内置函数
- 自增长键
1.JDBC入门案例
JDBC:Java DataBase Connectivity Java 连接数据库
JDBC,其实就是Java定义的一套和数据库建立连接的规范(接口),那么各家数据库厂商,想要Java去操作各家的数据库,必须实现这套接口,我们把数据库厂商写的这套实现类,称之为数据库驱动。
MySQL 8.0 注意以下
加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=UTF-8&userSSL=false&serverTimezone=GMT%2B8";
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class MyTest {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
/*
* JDBC: Java连接数据库, 他是一个规范,也就是说Java提供的一套接口
*
* JDBC:Java DataBase Connectivity Java 连接数据库
JDBC,其实就是Java定义的一套和数据库建立连接的规范(接口),
* 那么各家数据库厂商,想要Java去操作各家的数据库,必须实现这套接口,我们把数据库厂商写的这套实现类,称之为数据库驱动。
* */
//JDBC的快速入门
//1. 引入MySQL的数据库驱动jar包,记得依赖
//2. 加载驱动
//3. 获取连接对象
//4. 获取操作对象
//5. 执行SQL语句
//6. 释放资源
//加载驱动
Class.forName("com.mysql.jdbc.Driver");
//获取连接对象,用户名,密码,库的路径
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "root", "123456");
//获取操作对象
Statement statement = conn.createStatement();
//使用操作对象,发送sql语句
String sql = "insert into user values(null,'jdbc',password('123456'))";
//执行增删改的SQL语句,返回的是你影响的行数
int i = statement.executeUpdate(sql);
if (i > 0) {
System.out.println("插入成功");
} else {
System.out.println("插入失败");
}
//释放资源
conn.close();
statement.close();
// MySQL 8.0 注意以下
//加载驱动
//Class.forName("com.mysql.cj.jdbc.Driver");
// String url = "jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=UTF-8&userSSL=false&serverTimezone=GMT%2B8";
}
}
2.JDBC连接介绍
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
public class MyTest2 {
public static void main(String[] args) throws Exception {
//1.加载驱动 其实也可以省略不写,建议写上
Class<?> aClass = Class.forName("com.mysql.jdbc.Driver");
/* public class Driver extends NonRegisteringDriver implements java.sql.Driver {
public Driver() throws SQLException {
}
//静态代码块
static {
try {
//注册驱动
//static void registerDriver(Driver driver) 向 DriverManager 注册给定驱动程序。
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
} catch (SQLException var1) {
throw new RuntimeException("Can't register driver!");
}
}
}*/
// 2.获取连接对象
//获取连接对象,用户名,密码,库的路径
//java.sql
// 类 DriverManager 管理一组 JDBC 驱动程序的基本服务。
// static Connection getConnection (String url, String user, String password)
// 试图建立到给定数据库 URL 的连接。
//如果你是本地连接:可以省略 localhost:3306
String url = "jdbc:mysql:///mydb";
Connection conn = DriverManager.getConnection(url, "root", "123456");
// Connection 连接对象
// java.sql 接口 Connection 与特定数据库的连接(会话)。在连接上下文中执行 SQL 语句并返回结果。
//com.mysql.jdbc.JDBC4Connection@2e5d6d97
System.out.println(conn);
//获取操作对象
// Statement createStatement () 创建一个 Statement 对象来将 SQL 语句发送到数据库。
//Statement 数据库的操作对象
//java.sql 接口 Statement 用于执行静态 SQL 语句并返回它所生成结果的对象。
Statement statement = conn.createStatement();
//com.mysql.jdbc.StatementImpl@238e0d81
System.out.println(statement);
//使用操作对象,发送sql语句
String sql = "insert into user values(null,'jdbc',password('123456'))";
// ResultSet executeQuery (String sql)
// 执行给定的 SQL 语句,该语句返回单个 ResultSet 对象。
// int executeUpdate (String sql)
// 执行给定 SQL 语句,该语句可能为 INSERT、UPDATE 或 DELETE 语句,或者不返回任何内容的 SQL 语句(如 SQL DDL 语句)。
//执行增删改的SQL语句,返回的是你影响的行数
int i = statement.executeUpdate(sql);
if (i > 0) {
System.out.println("插入成功");
} else {
System.out.println("插入失败");
}
//释放资源
conn.close();
statement.close();
}
}
3.使用JDBC查询数据,并封装到对象中
结果集对象ResultSet
结果集对象,是我们执行了查询语句之后返回的一个查询结果对象
ResultSet 对象具有指向其当前数据行的光标。 最初,光标被置于第一行之前。next 方法将光标移动到下一行;因为该方法在 ResultSet 对象没有下一行时返回 false,所以可以在 while循环中使用它来迭代结果集。
Emp类:
import java.math.BigDecimal;
import java.util.Date;
//这个实体类----对应----数据中的 emp 表
//注意:实体类的成员变量名和数据类型,要和表中的列名以及数据类型保持一致。
public class Emp {
private Integer empno; //null
private String ename;
private String job;
private Integer mgr;
private Date hiredate;
private BigDecimal sal;
private BigDecimal comm;
private Integer deptno;
public Emp() {
}
public Emp(Integer empno, String ename, String job, Integer mgr, Date hiredate, BigDecimal sal, BigDecimal comm, Integer deptno) {
this.empno = empno;
this.ename = ename;
this.job = job;
this.mgr = mgr;
this.hiredate = hiredate;
this.sal = sal;
this.comm = comm;
this.deptno = deptno;
}
public Integer getEmpno() {
return empno;
}
public void setEmpno(Integer empno) {
this.empno = empno;
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
public Integer getMgr() {
return mgr;
}
public void setMgr(Integer mgr) {
this.mgr = mgr;
}
public Date getHiredate() {
return hiredate;
}
public void setHiredate(Date hiredate) {
this.hiredate = hiredate;
}
public BigDecimal getSal() {
return sal;
}
public void setSal(BigDecimal sal) {
this.sal = sal;
}
public BigDecimal getComm() {
return comm;
}
public void setComm(BigDecimal comm) {
this.comm = comm;
}
public Integer getDeptno() {
return deptno;
}
public void setDeptno(Integer deptno) {
this.deptno = deptno;
}
@Override
public String toString() {
return "Emp{" +
"empno=" + empno +
", ename='" + ename + '\'' +
", job='" + job + '\'' +
", mgr=" + mgr +
", hiredate=" + hiredate +
", sal=" + sal +
", comm=" + comm +
", deptno=" + deptno +
'}';
}
}
测试类:
import java.math.BigDecimal;
import java.sql.*;
import java.util.ArrayList;
public class MyTest {
public static void main(String[] args) throws Exception {
ArrayList<Emp> list = new ArrayList<>();
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydemodb", "root", "123456");
Statement statement = conn.createStatement();
String sql = "select * from emp";
//执行查询操作,返回的是查询的结果集对象
ResultSet resultSet = statement.executeQuery(sql);
//遍历结果集对象,取出数据
while (resultSet.next()) {
int empno = resultSet.getInt("empno");
String ename = resultSet.getString(2);
String job = resultSet.getString("job");
int mgr = resultSet.getInt("mgr");
Date hiredate = resultSet.getDate("hiredate");
BigDecimal sal = resultSet.getBigDecimal("sal");
BigDecimal comm = resultSet.getBigDecimal("comm");
int deptno = resultSet.getInt("deptno");
System.out.println(empno);
System.out.println(ename);
System.out.println(job);
System.out.println(mgr);
System.out.println(hiredate);
System.out.println(sal);
System.out.println(comm);
System.out.println(deptno);
//注意查出的数据,要封装起来
Emp emp = new Emp(empno, ename, job, mgr, hiredate, sal, comm, deptno);
//把每个emp对象再放到集合中
list.add(emp);
}
//System.out.println(list);
for (Emp emp : list) {
System.out.println(emp);
}
//释放资源
conn.close();
statement.close();
resultSet.close();
}
}
4.模拟登录(存在SQL注入风险)
port java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Scanner;
public class MyTest {
public static void main(String[] args) throws Exception {
Scanner sc = new Scanner(System.in);
System.out.println("请输入你的用名");
String username = sc.nextLine();
System.out.println("请输入你的密码");
String password = sc.nextLine();
//登录
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "root", "123456");
Statement statement = conn.createStatement();
String sql = "select * from user where username='" + username + "' and password='" + password + "'";
ResultSet resultSet = statement.executeQuery(sql);
if (resultSet.next()) {
System.out.println("登录成功");
} else {
System.out.println("登录失败");
}
conn.close();
statement.close();
resultSet.close();
//存在 SQL注入的风险
}
}
5.使用预编译操作对象防止SQL注入
1. 代码层防止sql注入攻击的最佳方案就是sql预编译
2. 确认每种数据的类型,比如是数字,数据库则必须使用int类型来存储
3. 规定数据长度,能在一定程度上防止sql注入
4. 严格限制数据库权限,能最大程度减少sql注入的危害
5. 避免直接响应一些sql异常信息,sql发生异常后,自定义异常进行响应
6. 过滤参数中含有的一些数据库关键词
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Scanner;
public class MyTest2 {
public static void main(String[] args) throws Exception {
Scanner sc = new Scanner(System.in);
System.out.println("请输入你的用名");
String username = sc.nextLine();
System.out.println("请输入你的密码");
String password = sc.nextLine();
// String username = "1' or '1'='1";
// String password = "1' or '1'='1";
//登录
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "root", "123456");
//为了防止SQL注入,我们使用预编译操作对象
//Statement statement = conn.createStatement(); //不使用这个操作对象
//注意:参数值,用?占位
String sql = "select * from user where username=? and password=?";
//PreparedStatement 预编译操作对象 可以防止SQL注入
PreparedStatement preparedStatement = conn.prepareStatement(sql);
//给问号赋值 问号编号从开始数
preparedStatement.setString(1, username);
preparedStatement.setString(2, password);
ResultSet resultSet = preparedStatement.executeQuery();
if (resultSet.next()) {
System.out.println("登录成功");
} else {
System.out.println("登录失败");
}
conn.close();
preparedStatement.close();
resultSet.close();
//存在 SQL注入的风险
//我们在Java程序中,如果拼接SQL语句就存在SQL注入的风险。
}
}
6.编写JDBC工具类
JDBC工具类:
import java.sql.*;
public class JDBCUtils_old {
private static String url;
private static String username;
private static String password;
private JDBCUtils_old() {
}
//耦合度太高,让程序和数据解耦,配合配置文件
static {
url = "jdbc:mysql://localhost:3306/mydb";
username = "root";
password = "123456";
//登录
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
//获取连接对象的方法
public static Connection getConnection() throws SQLException {
Connection conn = DriverManager.getConnection(url, username, password);
return conn;
}
//释放资源的方法
public static void close(Connection conn, Statement statement, ResultSet resultSet) throws SQLException {
if (conn != null) {
conn.close();
}
if (statement != null) {
statement.close();
}
if (resultSet != null) {
resultSet.close();
}
}
public static void close(Connection conn, Statement statement) throws SQLException {
if (conn != null) {
conn.close();
}
if (statement != null) {
statement.close();
}
}
}
测试类:
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class MyTest {
public static void main(String[] args) throws SQLException {
Connection conn = JDBCUtils_old.getConnection();
System.out.println(conn);
PreparedStatement preparedStatement = conn.prepareStatement("select * from user");
ResultSet resultSet = preparedStatement.executeQuery();
JDBCUtils_old.close(conn, preparedStatement, resultSet);
}
}
JDBCConfig.properties配置文件:
className=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mydb
username=root
password=123456
JDBC工具类:
import java.io.FileInputStream;
import java.sql.*;
import java.util.Properties;
public class JDBCUtils {
private static String url;
private static String username;
private static String password;
private JDBCUtils() {
}
//耦合度太高,让程序和数据解耦,配合配置文件
static {
//登录
try {
Properties properties = new Properties();
properties.load(new FileInputStream("JdbcConfig.properties"));
url = properties.getProperty("url");
username = properties.getProperty("username");
password = properties.getProperty("password");
Class.forName(properties.getProperty("className"));
} catch (Exception e) {
e.printStackTrace();
}
}
//获取连接对象的方法
public static Connection getConnection() throws SQLException {
Connection conn = DriverManager.getConnection(url, username, password);
return conn;
}
//释放资源的方法
public static void close(Connection conn, Statement statement, ResultSet resultSet) throws SQLException {
if (conn != null) {
conn.close();
}
if (statement != null) {
statement.close();
}
if (resultSet != null) {
resultSet.close();
}
}
public static void close(Connection conn, Statement statement) throws SQLException {
if (conn != null) {
conn.close();
}
if (statement != null) {
statement.close();
}
}
}
测试类:
import java.sql.Connection;
import java.sql.SQLException;
public class MyTest {
public static void main(String[] args) throws SQLException {
Connection connection = JDBCUtils.getConnection();
System.out.println(connection);
}
}
7.批处理
插入大量数据时,建议使用批处理来做
statement.addBatch();//添加批处理,先将数据缓存起来
statement.executeBatch();//执行批处理
statement.clearBatch();//清空缓存
User类:
public class User {
private Integer id;
private String username;
private String password;
public User() {
}
public User(Integer id, String username, String password) {
this.id = id;
this.username = username;
this.password = password;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
测试类:
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
public class MyTest {
public static void main(String[] args) throws SQLException {
ArrayList<User> list = new ArrayList<>();
for (int i = 10; i <= 3000; i++) {
User user = new User(i, "测试用户", "aaabbbbcccc");
list.add(user);
}
Connection connection = JDBCUtils.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement("insert into user values (?,?,?)");
for (User user : list) {
preparedStatement.setInt(1, user.getId());
preparedStatement.setString(2, user.getUsername());
preparedStatement.setString(3, user.getPassword());
//preparedStatement.executeUpdate();
//添加批处理
preparedStatement.addBatch();
}
//一次性执行
preparedStatement.executeBatch(); //执行批处理
//清空批处理
preparedStatement.clearBatch();
JDBCUtils.close(connection, preparedStatement);
}
}
8.在Java程序中调用存储过程
import org.westos.demo6.JDBCUtils;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Types;
public class MyTest {
public static void main(String[] args) throws SQLException {
//在Java程序中调用存储过程
Connection conn = JDBCUtils.getConnection();
String sql = "{call mydemo2(?,?)}"; //输入或输出参数用?占位
//获取这个操作对象,来调用存储过程或者函数
CallableStatement prepareCall = conn.prepareCall(sql);
//给输入参数设置值
prepareCall.setInt(1, 7782);
//注册输出参数
prepareCall.registerOutParameter(2, Types.INTEGER);
//执行
int i = prepareCall.executeUpdate();
System.out.println(i);
//获取输出参数的值
if (i > 0) {
int out = prepareCall.getInt(2);
System.out.println(out);
}
//释放资源
JDBCUtils.close(conn, prepareCall);
}
}
9.Java中调用数据库的内置函数
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Types;
public class MyTest2 {
public static void main(String[] args) throws SQLException {
//Java中调用数据库的内置函数
//在Java程序中调用存储过程
Connection conn = JDBCUtils.getConnection();
//第一个? 表示函数的返回值
String sql = "{?=call md5(?)}";
CallableStatement callableStatement = conn.prepareCall(sql);
//设置输入参数
callableStatement.setString(2, "123456");
//注册返回值
callableStatement.registerOutParameter(1, Types.VARCHAR);
//执行
callableStatement.execute();
//获取返回的结果
String r = callableStatement.getString(1);
System.out.println("结果是:" + r);
//释放资源
JDBCUtils.close(conn, callableStatement);
}
}
10.自增长键
import java.sql.*;
public class MyTest {
public static void main(String[] args) throws SQLException {
Connection conn = JDBCUtils.getConnection();
//Statement.RETURN_GENERATED_KEYS 加上这个参数等会,可以获取你插入一条数据后,然后获取自增长键的值
PreparedStatement preparedStatement = conn.prepareStatement("insert into user values (null,'aaa','bbbbbbbb')",
Statement.RETURN_GENERATED_KEYS);
int i = preparedStatement.executeUpdate();
//获取自增长键的值
ResultSet generatedKeys = preparedStatement.getGeneratedKeys();
while (generatedKeys.next()) {
int id = generatedKeys.getInt(1);
System.out.println(id);
}
JDBCUtils.close(conn, preparedStatement, generatedKeys);
}
}