JDBC
作用:可以通过Java来操作数据库。
解耦:进行jdbc规范,若不进行规范,那么程序员学习将会变得困难。
JDBC入门程序
jdbc的入门步骤:
1.导入jar包
2.注册驱动
3.获取数据库连接
4.获取执行者对象
5.执行sql语句,并且接受sql语句返回结果
6.处理结果
7.释放资源
package com.jdbc;
import java.sql.*;
public class Demo1 {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//1.导入jar包
//2.注册驱动
Class.forName("com.mysql.jdbc.Driver");
//3.获取数据库连接
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/db9", "root", "root");
String sql="select * from student";
//4.获取执行者对象
Statement stmt = con.createStatement();
//5.执行sql语句,并且接受sql语句返回结果
ResultSet count = stmt.executeQuery(sql);
//6.处理结果
while (count.next()){
System.out.println(count.getInt("sid")+"\t"+count.getString("name")+"\t"+count.getInt("age"));
}
//7.释放资源
stmt.close();
count.close();
}
}
什么情况会触发类加载
1.new
2.使用静态方法
3.加载子类的时候父类被加载
DriverManager(驱动管理器)
1.加载驱动
Class.forName("com.mysql.jdbc.Driver");
2.获取连接,返回Connection对象
①.ip(ping ip)
②.数据库端口
③.数据库名称
④.账号密码
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/db9", "root", "root");
Connecton
1.创建statement对象
2.管理事务
①.原子性
②.一致性
③.隔离性
④.持久性
Statement
1.封装sql
2.执行DML语句
.executeUpdate
3.执行DQL语句
.executeQuery
4.释放资源
ResultSet
1.存储结构
2.作用:封装mysql服务器响应的数据
三层结构
1.dao
2.service
3.web
查询所有信息
1.查询所有信息需要用ArrayList来存储信息,集合类型为T,同时数据需要封装
2.DQL:
executeQuery
/*
查询所有信息
*/
@Override
public ArrayList<Student> findAll() {
ArrayList<Student> list = new ArrayList<>();
Connection con = null;
Statement stat = null;
ResultSet rs = null;
try {
//获取连接
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/db9", "root", "root");
String sql = "select * from student";
//4.获取执行者对象
stat = con.createStatement();
//5.执行sql语句,并且接受sql语句返回结果
rs = stat.executeQuery(sql);
//6.处理结果
while (rs.next()) {
int sid = rs.getInt("sid");
String name = rs.getString("name");
int age = rs.getInt("age");
java.sql.Date birthday = rs.getDate("birthday");
//封装Student对象
Student stu = new Student(sid,name,age,birthday);
//将student对象保存到集合中
list.add(stu);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
//7.释放资源
if (con != null) {
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (stat != null) {
try {
stat.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return list;
}
根据id查询信息
1.变化:和普通查询所有唯一不同的是SQL语句
2.sql语句的参数拼接:
只有数据为字符串类型时需要用上单引号
3.索引失效
如果在数字类型的id加上单引号,则mysql会认为那是一个字符串,所以索引会失效
4.DQL:
executeQuery
/*
条件查询,根据id查询信息
*/
@Override
public Student findById(Integer sid) {
Student stu = new Student();
Connection con = null;
Statement stat = null;
ResultSet rs = null;
try {
//获取连接
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/db9", "root", "root");
String sql = "select * from student where sid=" + sid;
//4.获取执行者对象
stat = con.createStatement();
//5.执行sql语句,并且接受sql语句返回结果
rs = stat.executeQuery(sql);
//6.处理结果
while (rs.next()) {
stu.setSid(rs.getInt("sid"));
stu.setName(rs.getString("name"));
stu.setAge(rs.getInt("age"));
stu.setBirthday(rs.getDate("birthday"));
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
//7.释放资源
if (con != null) {
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (stat != null) {
try {
stat.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return stu;
}
添加信息
1.添加信息无需处理结果
2.DML:
executeUpdate
3.释放资源只需释放con和stat
4.由于date时间类型比较特殊,我们需要用SimpleDateFormat把时间设置为我们想要的格式
/*
添加信息
*/
@Override
public int insert(Student stu) {
Connection con = null;
Statement stat = null;
int result = 0;
try {
//获取连接
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/db9", "root", "root");
Date d = stu.getBirthday();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String birthday = sdf.format(d);
String sql = "insert into student values(sid,'" + stu.getName() + "','" + stu.getAge() + "','" + birthday + "')";
//4.获取执行者对象
stat = con.createStatement();
//5.执行sql语句,并且接受sql语句返回结果
result = stat.executeUpdate(sql);
} catch (Exception e) {
e.printStackTrace();
} finally {
//6.释放资源
if (con != null) {
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (stat != null) {
try {
stat.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
//将结果返回
return result;
}
修改信息
1.修改信息和添加信息唯一不同的就是sql语句
2.DML:
executeUpdate
3.释放资源只需释放con和stat
/*
修改信息
*/
@Override
public int update(Student stu) {
Connection con = null;
Statement stat = null;
int result = 0;
try {
//2获取连接
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/db9", "root", "root");
//3获取执行者对象
stat = con.createStatement();
//4.执行sql语句,并且接受sql语句返回结果
Date d = stu.getBirthday();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String birthday = sdf.format(d);
//UPDATE student SET sid=6, NAME='周七',age=52,birthday='2020-08-08' WHERE sid=4
String sql = "UPDATE student SET sid='" + stu.getSid() + "',name='" + stu.getName() + "',age='" + stu.getAge() + "',birthday='" + birthday + "' WHERE sid='" + stu.getSid() + "'";
result = stat.executeUpdate(sql);
} catch (Exception e) {
e.printStackTrace();
} finally {
//6.释放资源
if (con != null) {
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (stat != null) {
try {
stat.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
//将结果返回
return result;
}
删除信息
1.删除信息比较简单,和修改信息唯一不同的就是sql语句。
2.DML:
executeUpdate
3.释放资源只需释放con和stat
/*
删除学生信息
*/
@Override
public int delete(Integer sid) {
Connection con = null;
Statement stat = null;
int result = 0;
try {
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/db9", "root", "root");
//3.获取执行者对象
stat = con.createStatement();
//4.执行sql语句,并且接收返回的结果集
String sql = "DELETE FROM student WHERE sid='" + sid + "'";
result = stat.executeUpdate(sql);
} catch (Exception e) {
e.printStackTrace();
} finally {
//6.释放资源
if (con != null) {
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (stat != null) {
try {
stat.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
//将结果返回
return result;
}
代码问题
1.代码重复度太高
2.需要修改Java代码
3.会长时间的占用JVM内存,甚至会出现缓存的问题
解决方式
为什么配置信息写在配置文件会好一些?
1.不用去修改Java代码
2.解决代码重复度太高的问题
3.配置文件不会长时间占用jvm,只有在需要的时候才会占用jvm
4.当更改配置文件时,配置文件进入jvm会载入最新的配置文件
driverClass=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/db9
username=root
password=root
工具类的目的
1.去掉重复代码
2.实现步骤
1.编写配置文件
2.加载配置文件
3.编写方法获取连接
4.释放资源
package com.jdbc.demo3.utils;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
/*
JDBC工具类
*/
public class JDBCUtils {
//1.私有构造方法
private JDBCUtils(){}
//2.声明所需要的配置变量
private static String driverClass;
private static String url;
private static String username;
private static String password;
private static Connection con;
//3.提供静态代码块。读取配置文件的信息为变量赋值,注册驱动
static{
try {
//读取配置文件的信息为变量赋值
InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("config.properties");
Properties prop = new Properties();
prop.load(is);
driverClass = prop.getProperty("driverClass");
url = prop.getProperty("url");
username = prop.getProperty("username");
password = prop.getProperty("password");
//注册驱动
Class.forName(driverClass);
} catch (Exception e) {
e.printStackTrace();
}
}
//4.提供获取数据库连接方法
public static Connection getConnection() {
try {
con = DriverManager.getConnection(url,username,password);
} catch (SQLException e) {
e.printStackTrace();
}
return con;
}
//5.提供释放资源的方法
public static void close(Connection con, Statement stat, ResultSet rs) {
if(con != null) {
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(stat != null) {
try {
stat.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void close(Connection con, Statement stat) {
if(con != null) {
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(stat != null) {
try {
stat.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
优化后的代码
/*
查询所有学生信息
*/
@Override
public ArrayList<Student> findAll() {
ArrayList<Student> list = new ArrayList<>();
Connection con = null;
Statement stat = null;
ResultSet rs = null;
try{
con = JDBCUtils.getConnection();
//3.获取执行者对象
stat = con.createStatement();
//4.执行sql语句,并且接收返回的结果集
String sql = "SELECT * FROM student";
rs = stat.executeQuery(sql);
//5.处理结果集
while(rs.next()) {
Integer sid = rs.getInt("sid");
String name = rs.getString("name");
Integer age = rs.getInt("age");
Date birthday = rs.getDate("birthday");
//封装Student对象
Student stu = new Student(sid,name,age,birthday);
//将student对象保存到集合中
list.add(stu);
}
} catch(Exception e) {
e.printStackTrace();
} finally {
//6.释放资源
JDBCUtils.close(con,stat,rs);
}
//将集合对象返回
return list;
}
/*
条件查询,根据id查询学生信息
*/
@Override
public Student findById(Integer id) {
Student stu = new Student();
Connection con = null;
Statement stat = null;
ResultSet rs = null;
try{
con = JDBCUtils.getConnection();
//3.获取执行者对象
stat = con.createStatement();
//4.执行sql语句,并且接收返回的结果集
String sql = "SELECT * FROM student WHERE sid='"+id+"'";
rs = stat.executeQuery(sql);
//5.处理结果集
while(rs.next()) {
Integer sid = rs.getInt("sid");
String name = rs.getString("name");
Integer age = rs.getInt("age");
Date birthday = rs.getDate("birthday");
//封装Student对象
stu.setSid(sid);
stu.setName(name);
stu.setAge(age);
stu.setBirthday(birthday);
}
} catch(Exception e) {
e.printStackTrace();
} finally {
//6.释放资源
JDBCUtils.close(con,stat,rs);
}
//将对象返回
return stu;
}
/*
添加学生信息
*/
@Override
public int insert(Student stu) {
Connection con = null;
Statement stat = null;
int result = 0;
try{
con = JDBCUtils.getConnection();
//3.获取执行者对象
stat = con.createStatement();
//4.执行sql语句,并且接收返回的结果集
Date d = stu.getBirthday();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String birthday = sdf.format(d);
String sql = "INSERT INTO student VALUES ('"+stu.getSid()+"','"+stu.getName()+"','"+stu.getAge()+"','"+birthday+"')";
result = stat.executeUpdate(sql);
} catch(Exception e) {
e.printStackTrace();
} finally {
//6.释放资源
JDBCUtils.close(con,stat);
}
//将结果返回
return result;
}
/*
修改学生信息
*/
@Override
public int update(Student stu) {
Connection con = null;
Statement stat = null;
int result = 0;
try{
con = JDBCUtils.getConnection();
//3.获取执行者对象
stat = con.createStatement();
//4.执行sql语句,并且接收返回的结果集
Date d = stu.getBirthday();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String birthday = sdf.format(d);
String sql = "UPDATE student SET sid='"+stu.getSid()+"',name='"+stu.getName()+"',age='"+stu.getAge()+"',birthday='"+birthday+"' WHERE sid='"+stu.getSid()+"'";
result = stat.executeUpdate(sql);
} catch(Exception e) {
e.printStackTrace();
} finally {
//6.释放资源
JDBCUtils.close(con,stat);
}
//将结果返回
return result;
}
/*
删除学生信息
*/
@Override
public int delete(Integer id) {
Connection con = null;
Statement stat = null;
int result = 0;
try{
con = JDBCUtils.getConnection();
//3.获取执行者对象
stat = con.createStatement();
//4.执行sql语句,并且接收返回的结果集
String sql = "DELETE FROM student WHERE sid='"+id+"'";
result = stat.executeUpdate(sql);
} catch(Exception e) {
e.printStackTrace();
} finally {
//6.释放资源
JDBCUtils.close(con,stat);
}
//将结果返回
return result;
}
SQL注入攻击
作用:利用sql的注释把后面的内容注释掉,就可以登录用户
SELECT * FROM user WHERE loginname= '' or 1 = 1 -- AND password='" + password + "'
prepareStatement解决SQL注入攻击
作用:预编译SQL语句,以防止SQL注入问题
使用:
创建:
PrepareStatement ps = connection.prepareStatement("select * from student where id = ?");
ps.setInt(1, 22);
事务管理
使用对象:Connection对象
事务方法:
开启事务:setAutoCommit(false)
提交事务:commit()
回滚事务:rollback()