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, -- 学生idNAME 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;}@Overridepublic 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 {@Overridepublic 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;}@Overridepublic 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;}@Overridepublic 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可以返回影响的行数,赋值给resultresult = pstm.executeUpdate();} catch (Exception e) {e.printStackTrace();} finally {JDBCUtils.close(conn, pstm);}return result;}@Overridepublic 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;}@Overridepublic 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();@Overridepublic ArrayList<Student> findAll() {return dao.findAll();}@Overridepublic Student findById(Integer id) {return dao.findById(id);}@Overridepublic int insert(Student stu) {return dao.insert(stu);}@Overridepublic int update(Student stu) {return dao.update(stu);}@Overridepublic 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();@Testpublic void findAll() {ArrayList<Student> list = service.findAll();for (Student stu : list) {System.out.println(stu);}}@Testpublic void findById() {Student student = service.findById(3);System.out.println(student);}@Testpublic 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("新增失败");}}@Testpublic void update() {Student stu = service.findById(5);stu.setName("周七七");int result = service.update(stu);if(result != 0) {System.out.println("修改成功");}else {System.out.println("修改失败");}}@Testpublic 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();