JDBC:
- JDBC(Java DataBase Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系型数据库提供统一访问,它是由一组用Java语言编写的类和接口组成的。
- 其实就是java官方提供的一套规范(接口)。用于帮助开发人员快速实现不同关系型数据库的连接!
jdbc的快速入门程序:
需要先导入JDBC的jar包
public class JdbcDemo {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
// 注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
// 获取连接
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/db2", "root", "itzhuzhu");
// 获取执行者对象
Statement statement = connection.createStatement();
// 执行sql语句,并接收返回结果
String sql = "SELECT * FROM user";
ResultSet resultSet = statement.executeQuery(sql);
// 处理结果
while (resultSet.next()) {
System.out.println(resultSet.getInt("id") + "\t" + resultSet.getString("name"));
}
// 释放资源
connection.close();
statement.close();
resultSet.close();
}
}
运行异常:
提示“com.mysql.jdbc.Drive”已经被弃用了,有新的驱动类可以使用,换成这个就可以了“com.mysql.cj.jdbc.Driver”,即使不换也不会影响运行,只是会提示。
Loading class `com.mysql.jdbc.Driver'. This is deprecated. The new driver class is `com.mysql.cj.jdbc.Driver'. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.
如果遇到这个异常,可能是你的版本问题,idea和mysql的版本要对应,驱动也是,下载个新的驱动https://dev.mysql.com/downloads/file/?id=500651
Exception in thread "main" com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure The last packet sent successfully to the server was 0 milliseconds ago. The
JDBC各个功能类详解:
DriverManager:
1. DriverManager:驱动管理对象
注册驱动(告诉程序该使用哪一个数据库驱动)
- static void registerDriver(Driver driver):注册与给定的驱动程序 DriverManager
- 写代码使用:Class.forName(“com.mysql.jdbc.Driver”),因为Driver类中已经写了注册驱动
- 通过查看源码发现:在com.mysql.jdbc.Driver类中存在静态代码块
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}
注意:
mysql5之后的驱动jar包可以省略注册驱动的步骤。在jar包中,存在一个java.sql.Driver配置文件,文件中指定了com.mysql.jdbc.Driver
2. 获取数据库连接(获取到数据库的连接并返回连接对象)
- static Connection
getConnection
(String url, String user, String password);
- 返回值:Connection数据库连接对象
- 参数
- url:指定连接的路径。语法:jdbc:mysql://ip地址(域名):端口号/数据库名称
- user:用户名
- password:密码
Connection:
Connection:数据库连接对象
- 获取执行者对象
- 获取普通执行者对象:Statement
createStatement
();也就是执行SQL语句的- 获取预编译执行者对象:PreparedStatement
prepareStatement
(String sql);- 管理事务
- 开启事务:
setAutoCommit
(boolean autoCommit); 参数为false
,则开启事务。- 提交事务:
commit
();- 回滚事务:
rollback
();- 释放资源
- 立即将数据库连接对象释放:void
close
();
Statement:
Statement:执行sql语句的对象
- 执行DML(增删改)语句:int
executeUpdate
(String sql);
- 返回值int:返回影响的行数。
- 参数sql:可以执行insert、update、delete语句。
- 执行DQL(查询)语句:ResultSet
executeQuery
(String sql);
- 返回值ResultSet:封装查询的结果。
- 参数sql:可以执行select语句。
- 释放资源
- 立即将执行者对象释放:void
close
();
ResultSet:
ResultSet:结果集对象
- 判断结果集中是否还有数据:boolean
next
();
- 有数据返回true,并将索引向下移动一行
- 没有数据返回false
- 获取结果集中的数据:XXX
getXxx
(“列名”);
- XXX代表数据类型(要获取某列数据,这一列的数据类型)
- 例如:String getString(“name”); int getInt(“age”);
- 释放资源
- 立即将结果集对象释放:void
close
();
JDBC练习CRUD:
数据准备:
sql语句:
-- 创建student表
CREATE TABLE student(
sid INT PRIMARY KEY AUTO_INCREMENT, -- 学生id
NAME VARCHAR(20), -- 学生姓名
age INT, -- 学生年龄
birthday DATE -- 学生生日
);
-- 添加数据
INSERT INTO student VALUES (NULL,'张三',23,'1999-09-23'),(NULL,'李四',24,'1998-08-10'),(NULL,'王五',25,'1996-06-06'),(NULL,'赵六',26,'1994-10-20');
实体类:
自定义类的功能是为了封装表中每列数据,成员变量和列要保持一致
注意:
所有的基本数据类型需要使用包装类,以防null值无法赋值
public class Student {
private Integer sid;
private String name;
private Integer age;
private Date birthday;
public Student() {
}
public Student(Integer sid, String name, Integer age, Date birthday) {
this.sid = sid;
this.name = name;
this.age = age;
this.birthday = birthday;
}
public Integer getSid() {
return sid;
}
public void setSid(Integer sid) {
this.sid = sid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
@Override
public String toString() {
return "Student{" +
"sid=" + sid +
", name='" + name + '\'' +
", age=" + age +
", birthday=" + birthday +
'}';
}
}
StudentDao
public interface StudentDao {
/**
* 查询所有学生信息
*
* @return 返回一个学生数组
*/
ArrayList<Student> findAll();
/**
* 根据id查询学生信息
*
* @param id 根据id查询
* @return 返回学生类对象,根据id查询
*/
Student findById(Integer id);
/**
* 添加学生
*
* @param stu:学生类
* @return 返回int类型的结果,也就是影响行数
*/
int insert(Student stu);
/**
* 修改学生
*
* @param stu:学生类
* @return 返回int类型的结果,也就是影响行数
*/
int update(Student stu);
/**
* 删除学生
*
* @param id:根据指定id删除
* @return 返回int类型的结果,也就是影响行数
*/
int delete(Integer id);
}
StudentDaoImpl
public class StudentDaoImpl implements StudentDao {
@Override
public ArrayList<Student> findAll() {
ArrayList<Student> list = new ArrayList<>();
Connection conn = null;
PreparedStatement pstm = null;
ResultSet rs = null;
try {
// 获取连接
conn = JDBCUtils.getConnection();
pstm = conn.prepareStatement("SELECT * FROM student");
// 执行sql语句,并接收返回结果
rs = pstm.executeQuery();
// 处理结果
while (rs.next()) {
int sid = rs.getInt("sid");
String name = rs.getString("name");
int age = rs.getInt("age");
Date birthday = rs.getDate("birthday");
// 封装student对象,把student对象保存到结合中
Student stu = new Student(sid, name, age, birthday);
list.add(stu);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.close(conn, pstm, rs);
}
return list;
}
@Override
public Student findById(Integer id) {
Student stu = new Student();
PreparedStatement pstm = null;
Connection conn = null;
ResultSet rs = null;
try {
conn = JDBCUtils.getConnection();
// 获取执行者对象
pstm = conn.prepareStatement("SELECT * FROM student WHERE sid='" + id + "'");
// 执行sql语句,并接收返回结果
rs = pstm.executeQuery();
// 处理结果
while (rs.next()) {
int sid = rs.getInt("sid");
String name = rs.getString("name");
int age = rs.getInt("age");
Date birthday = rs.getDate("birthday");
// 封装student对象,把student对象保存到结合中
stu.setSid(sid);
stu.setName(name);
stu.setAge(age);
stu.setBirthday(birthday);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.close(conn, pstm, rs);
}
return stu;
}
@Override
public int insert(Student stu) {
Connection conn = null;
PreparedStatement pstm = null;
int result = 0;
try {
conn = JDBCUtils.getConnection();
// 获取执行者对象
// 执行sql语句,并接收返回结果
Date d = stu.getBirthday();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String birthday = sdf.format(d);
pstm = conn.prepareStatement("INSERT INTO student VALUES ('" + stu.getSid() + "','" + stu.getName() + "','" + stu.getAge() + "','" + birthday + "')");
// executeUpdate可以返回影响的行数,赋值给result
result = pstm.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.close(conn, pstm);
}
return result;
}
@Override
public int update(Student stu) {
Connection conn = null;
PreparedStatement pstm = null;
int result = 0;
try {
conn = JDBCUtils.getConnection();
// 获取执行者对象
// 执行sql语句,并接收返回结果
Date d = stu.getBirthday();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String birthday = sdf.format(d);
pstm = conn.prepareStatement("UPDATE student SET sid='" + stu.getSid() + "',name='" + stu.getName() + "',age='" + stu.getAge() + "',birthday='" + birthday + "' WHERE sid='" + stu.getSid() + "'");
result = pstm.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.close(conn, pstm);
}
return result;
}
@Override
public int delete(Integer id) {
Connection conn = null;
PreparedStatement pstm = null;
int result = 0;
try {
conn = JDBCUtils.getConnection();
// 获取执行者对象
pstm = conn.prepareStatement("DELETE FROM student WHERE sid='" + id + "'");
// 执行sql语句,并接收返回结果 + id + "
result = pstm.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.close(conn, pstm);
}
return result;
}
}
StudentService
public interface StudentService {
/**
* 查询所有学生信息
*
* @return 返回一个学生数组
*/
ArrayList<Student> findAll();
/**
* 根据id查询学生信息
*
* @param id 根据id查询
* @return 返回学生类对象,根据id查询
*/
Student findById(Integer id);
/**
* 添加学生
*
* @param stu:学生类
* @return 返回int类型的结果,也就是影响行数
*/
int insert(Student stu);
/**
* 修改学生
*
* @param stu:学生类
* @return 返回int类型的结果,也就是影响行数
*/
int update(Student stu);
/**
* 删除学生
*
* @param id:根据指定id删除
* @return 返回int类型的结果,也就是影响行数
*/
int delete(Integer id);
}
StudentServiceImpl
public class StudentServiceImpl implements StudentService {
private StudentDao dao = new StudentDaoImpl();
@Override
public ArrayList<Student> findAll() {
return dao.findAll();
}
@Override
public Student findById(Integer id) {
return dao.findById(id);
}
@Override
public int insert(Student stu) {
return dao.insert(stu);
}
@Override
public int update(Student stu) {
return dao.update(stu);
}
@Override
public int delete(Integer id) {
return dao.delete(id);
}
}
JDBCUtils:工具类
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 {
// 通过类加载器返回配置文件的字节流
// getClassLoader().getResourceAsStream:通过给定名称查找资源,查询资源的规则由给定的类的class load来实现,这个方法由类的loader来执行;如果这个类由bootstrap加载,那么方法由ClassLoader.getSystemResourceAsStream代理执行。
InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("config.properties");
// 创建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) {
close(con, stat, null);
}
}
config.properties:配置文件
driverClass=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/db2
username=root
password=itzhuzhu
Controller
public class StudentControllerTest {
StudentService service = new StudentServiceImpl();
@Test
public void findAll() {
ArrayList<Student> list = service.findAll();
for (Student stu : list) {
System.out.println(stu);
}
}
@Test
public void findById() {
Student student = service.findById(3);
System.out.println(student);
}
@Test
public void insert() {
Student stu = new Student(5,"周七",27,new Date());
int result = service.insert(stu);
if(result != 0) {
System.out.println("新增成功");
}else {
System.out.println("新增失败");
}
}
@Test
public void update() {
Student stu = service.findById(5);
stu.setName("周七七");
int result = service.update(stu);
if(result != 0) {
System.out.println("修改成功");
}else {
System.out.println("修改失败");
}
}
@Test
public void delete() {
int result = service.delete(5);
if(result != 0) {
System.out.println("删除成功");
}else {
System.out.println("删除失败");
}
}
}
SQL注入攻击:
sql注入攻击案例:
在登录界面,输入一个错误的用户名/密码,但是使用
任意字符 'or '1' = '1
就可以登录成功
sql注入攻击的原理:
- 按照正常道理来说,我们在密码处输入的所有内容,都应该认为是密码的组成
- 但是现在Statement对象在执行sql语句时,将一部分内容当做查询条件来执行了,就会出现SQL注入攻击
PreparedStatement:
- 预编译sql语句的执行者对象。在执行sql语句之前,将sql语句进行提前编译。明确sql语句的格式后,就不会改变了。剩余的内容都会认为是参数!参数使用
?
作为占位符 - 为参数赋值的方法:
setXxx(参数1,参数2)
;- 参数1:?的位置编号(编号从1开始)
- 参数2:?的实际参数
- 执行sql语句的方法
- 执行insert、update、delete语句:int executeUpdate();
- 执行select语句:ResultSet executeQuery();
@Override
public User findByLoginNameAndPassword(String loginName, String password) {
//定义必要信息
Connection conn = null;
PreparedStatement pstm = null;
ResultSet rs = null;
User user = null;
try {
//1.获取连接
conn = JDBCUtils.getConnection();
//2.创建操作SQL对象
String sql = "SELECT * FROM user WHERE loginname=? AND password=?";
pstm = conn.prepareStatement(sql);
//3.设置参数
pstm.setString(1,loginName);
pstm.setString(2,password);
System.out.println(sql);
//4.执行sql语句,获取结果集
rs = pstm.executeQuery();
//5.获取结果集
if (rs.next()) {
//6.封装
user = new User();
user.setUid(rs.getString("uid"));
user.setUcode(rs.getString("ucode"));
user.setUsername(rs.getString("username"));
user.setPassword(rs.getString("password"));
user.setGender(rs.getString("gender"));
user.setDutydate(rs.getDate("dutydate"));
user.setBirthday(rs.getDate("birthday"));
user.setLoginname(rs.getString("loginname"));
}
//7.返回
return user;
}catch (Exception e){
throw new RuntimeException(e);
}finally {
JDBCUtils.close(conn,pstm,rs);
}
}
JDBC事务:
管理事务的功能类:Connection
- 开启事务:setAutoCommit(boolean autoCommit);参数为false,则开启事务。
- 提交事务:commit();
- 回滚事务:rollback();