1、JDBC简介

JDBC的本质是什么

本质是一套接口
面对接口编程,降低程序的耦合性,增强程序的扩展力
在Java.sql.*  包下
由sun公司提供JDBC接口,各大数据库厂商负责编写JDBC的实现类

JDBC编程六步

  • 注册驱动 说明连接的数据库是什么
  • 获取链接 jvm进程和数据库通信通道打开了(一定要关闭)
  • 获取数据库操作对象 专门执行sql语句的对象
  • 执行sql语句 (DQL DML….)
  • 处理结果集 只有第四步执行了select语句的时候,才会有处理查询结果集
  • 释放资源 Java和数据库之间是进程之间的通信,所以需要关闭资源 ```sql package com.test;

import java.sql.Connection; import java.sql.Driver; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement;

public class JDBCtest1 {

  1. public static void main(String[] args) {
  2. Connection cnn = null;
  3. Statement stmt = null;
  4. try {

// 1、注册驱动 Driver driver = new com.mysql.jdbc.Driver(); DriverManager.registerDriver(driver);

  1. // 2、创建连接
  2. String url = "jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8";
  3. String user = "root";
  4. String password = "123456";
  5. cnn = DriverManager.getConnection(url,user,password);

// System.out.println(“数据库连接对象=”+cnn);

// 3、创立连接操作数据库的对象 stmt = cnn.createStatement();

// 4、执行sql语句 String sql = “insert into stuinfo2(id,name,last_name,salary,age,bteam)value(6,’Cle’,’xy’,20000,20,’GS’)”; int count = stmt.executeUpdate(sql);//处理结果集,在select需要处理 System.out.println(count == 1? “保存成功”:”保存失败”); }catch(SQLException e) { e.printStackTrace();
}finally { //遵循从小到大的关闭原则 关闭资源 if(stmt != null) { try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); }
} if(cnn != null) { try { cnn.close(); } catch (SQLException e) { e.printStackTrace(); } } } } }

  1. <a name="Jlf6k"></a>
  2. ### 2、下载及其导包
  3. 下载MySQL jar包, 可以上maven:[https://mvnrepository.com/artifact/mysql/mysql-connector-java](https://mvnrepository.com/artifact/mysql/mysql-connector-java)<br />下载之后复制到lib目录下:<br />![image.png](https://cdn.nlark.com/yuque/0/2020/png/557364/1607000858508-ef3cece5-633f-434a-92cd-88be5098f476.png#align=left&display=inline&height=403&margin=%5Bobject%20Object%5D&name=image.png&originHeight=403&originWidth=429&size=27243&status=done&style=none&width=429)
  4. <a name="NEicq"></a>
  5. ### 3、加载驱动
  6. **MySQL 8.0 以上版本的数据库连接有所不同:**
  7. - 1、MySQL 8.0 以上版本驱动包版本 [mysql-connector-java-8.0.16.jar](https://static.runoob.com/download/mysql-connector-java-8.0.16.jar)。<br />
  8. - 2、**com.mysql.jdbc.Driver** 更换为 **com.mysql.cj.jdbc.Driver**。<br />
  9. ```java
  10. class forName("com.sql.jdbc.Driver");

驱动:所有的数据库驱动都是以jar包的形式存在的,里面存的都是.class文件的形式存在的
驱动需要去相应的数据库官网下载的

4、连接数据库

  1. String url = "jdbc:mysql://localhost:3306/test?userSSL=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC";
  2. String username = "root";
  3. String password = "Aa123456";
  4. Connection conn = DriverManager.getConnection(url,username,password);
  5. cnn =DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/jsp?useUnicode=true&characterEncoding=UTF-8","root","123456");
  • url表示统一资源定位符(网络中的某个资源的绝对路径)

url组成部分: 通信协议 服务器IP地址 服务器端口号 服务器上的某个资源名
http:// 182.61.200.7 :80 /index.html

  • username表示数据库登录用户
  • password代表用户的登录密码
  • 第四行登录数据库
  • 第五行是创建一个数据库连接,并且创建一个Statemnt

    5、创建数据库操作对象

    1. #以最上为例
    2. stmt = cnn.createStatement();

    6、执行sql语句 处理结果集

    1. String sql = "sql语句";

    对于sql语句执行后的两种处理

    ```java

    处理结果集

    executeUpdate() ===>处理增删改语句 ===>方法返回值为int型 int count = stmt.executeUpdate();

executeQuery() ===>处理查询语句 ===>方法返回值为ResultSet rs = stmt.executeQuery();

  1. <a name="hT2Zb"></a>
  2. #### 处理结果集
  3. **取出数据后的处理**
  4. ```java
  5. Resultset结果集
  6. getString() ===>无论取出的数据类型是什么,都以Sting的形式取出
  7. 需要获得什么类型的数据就可以指定类型===>基本数据类型可以运用

7.学到的语法

拼接字符在MySQL语句中

  1. String sql = "select * from t_user where loginName='"+userLogininfo.get("loginName")+"' and loginPwd='"+userLogininfo.get("loginPwd")+"'";

SQL注入

  1. String sql = "select * from t_user where loginName='"+userLogininfo.get("loginName")+"' and loginPwd='"+userLogininfo.get("loginPwd")+"'";
  2. //以上语句完成了sql语句的拼接,语句的作用是将sql语句发送给DBMS,DBMS进行字符的编译
  3. rs = stmt.executeQuery(sql);
  4. //正好将用户的非法信息拼接进去导致了sql的原意被扭曲,进而达到sql注入
  5. 用户名:fdsa
  6. 密码:'fdsa' or '1'='1'

解决SQL注入问题 PreparedStatement接口

  1. #只要使用户提供的信息不参加编译即可解决
  2. #即使用户提SQL语句,但不参加编译过程,不起作用
  3. #要想用户的信息不参加编译过程,那么必须使用Java.sql.preparedStatemeng
  4. PreparedStatement接口继承自Java.sql.Statement的数据库
  5. preparedStatemeng是属于预编译的数据库操作对象
  6. 解决sql注入的关键
  7. preparedStatemeng采用的是:预先对SQL语句进行编译,再SQL语句进行传“值”。
  1. package com.JDBC;
  2. import java.sql.*;
  3. import java.util.HashMap;
  4. import java.util.Map;
  5. import java.util.Scanner;
  6. public class JDBCtest7 {
  7. public static void main(String[] args) {
  8. //初始化一个界面
  9. Map<String,String> userLoginInfo = initUI();
  10. boolean loginsucess = login(userLoginInfo);
  11. System.out.println(loginsucess ? "登陆成功" : "登录失败");
  12. }
  13. private static boolean login(Map<String, String> userLogininfo) {
  14. String loginName = userLogininfo.get("loginName");
  15. String loginPwd = userLogininfo.get("loginPwd");
  16. Connection cnn =null;
  17. PreparedStatement ps = null;;
  18. ResultSet rs = null;
  19. try {
  20. boolean flag = false;
  21. Class.forName("com.mysql.jdbc.Driver");
  22. cnn = DriverManager.getConnection( "jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8","root","123456");
  23. String sql = "select * from t_user where loginName=? and loginPwd=?";
  24. ps = cnn.prepareStatement(sql);
  25. //给?占位符传值
  26. ps.setString(1,loginName);
  27. ps.setString(2,loginPwd);
  28. rs = ps.executeQuery();
  29. if(rs.next()){
  30. flag = true;
  31. }
  32. return flag;
  33. } catch (Exception e) {
  34. e.printStackTrace();
  35. }finally{
  36. if(rs != null){
  37. try {
  38. rs.close();
  39. } catch (SQLException throwables) {
  40. throwables.printStackTrace();
  41. }
  42. }
  43. if(ps != null){
  44. try {
  45. ps.close();
  46. } catch (SQLException throwables) {
  47. throwables.printStackTrace();
  48. }
  49. }
  50. if(cnn !=null){
  51. try {
  52. cnn.close();
  53. } catch (SQLException throwables) {
  54. throwables.printStackTrace();
  55. }
  56. }
  57. }
  58. return false;
  59. }
  60. private static Map<String, String> initUI() {
  61. Scanner sc = new Scanner(System.in);
  62. System.out.print("用户名:");
  63. String loginName=sc.nextLine();
  64. System.out.print("密码:");
  65. String loginPwd=sc.nextLine();
  66. HashMap<String,String> userLoginInfo = new HashMap<>();
  67. userLoginInfo.put("loginName",loginName);
  68. userLoginInfo.put("loginPwd",loginPwd);
  69. return userLoginInfo;
  70. }
  71. }

Statement和Prepared对比

  1. 1Statement存在sql注入问题 PreparedStatement解决了sql注入问题
  2. 2Statement是编译一次执行一次 PreparedStatement是编译一次可以执行n 效率更高
  3. 3PreParedStatement会在编译期间做类型的安全检查

JDBC事物自动提交机制

同时提交数据,防止数据的丢失

  1. //将自动提交机制修改为手动提交机制
  2. cnn.setAUtoCOmmit(false) //开启事务
  3. cnn.commit() //提交事物 ===>执行完可能出现异常的语句
  4. if(cnn != null){
  5. try{
  6. cnn.rollback(); //回滚事务
  7. } catch (SQLException throwables) {
  8. throwables.printStackTrace();
  9. }

8、JDBC工具类的封装

JDBC工具类:为了简化JDBC编程
工具类中的构造方法是私有的
用为工具类中的方法都是静态的,不需要new对象,直接使用类名调用

9、悲观锁和乐观锁

行级锁又称悲观锁

事务必须排队执行,数据被锁住了,不支持并发。

  1. select * from stuinfo2 for update;
  2. for update 在当前事务没有结束之前,被锁定的指定行是数据是无法被修改的

乐观锁

事物不需要排队执行,允许并发,只不过需要一个版本号