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 {
public static void main(String[] args) {
Connection cnn = null;
Statement stmt = null;
try {
// 1、注册驱动 Driver driver = new com.mysql.jdbc.Driver(); DriverManager.registerDriver(driver);
// 2、创建连接
String url = "jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8";
String user = "root";
String password = "123456";
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();
}
}
}
}
}
<a name="Jlf6k"></a>
### 2、下载及其导包
下载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)
<a name="NEicq"></a>
### 3、加载驱动
**MySQL 8.0 以上版本的数据库连接有所不同:**
- 1、MySQL 8.0 以上版本驱动包版本 [mysql-connector-java-8.0.16.jar](https://static.runoob.com/download/mysql-connector-java-8.0.16.jar)。<br />
- 2、**com.mysql.jdbc.Driver** 更换为 **com.mysql.cj.jdbc.Driver**。<br />
```java
class forName("com.sql.jdbc.Driver");
驱动:所有的数据库驱动都是以jar包的形式存在的,里面存的都是.class文件的形式存在的
驱动需要去相应的数据库官网下载的
4、连接数据库
String url = "jdbc:mysql://localhost:3306/test?userSSL=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC";
String username = "root";
String password = "Aa123456";
Connection conn = DriverManager.getConnection(url,username,password);
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、创建数据库操作对象
#以最上为例
stmt = cnn.createStatement();
6、执行sql语句 处理结果集
String sql = "sql语句";
对于sql语句执行后的两种处理
```java处理结果集
executeUpdate() ===>处理增删改语句 ===>方法返回值为int型 int count = stmt.executeUpdate();
executeQuery() ===>处理查询语句 ===>方法返回值为ResultSet rs = stmt.executeQuery();
<a name="hT2Zb"></a>
#### 处理结果集
**取出数据后的处理**
```java
Resultset结果集
getString() ===>无论取出的数据类型是什么,都以Sting的形式取出
需要获得什么类型的数据就可以指定类型===>基本数据类型可以运用
7.学到的语法
拼接字符在MySQL语句中
String sql = "select * from t_user where loginName='"+userLogininfo.get("loginName")+"' and loginPwd='"+userLogininfo.get("loginPwd")+"'";
SQL注入
String sql = "select * from t_user where loginName='"+userLogininfo.get("loginName")+"' and loginPwd='"+userLogininfo.get("loginPwd")+"'";
//以上语句完成了sql语句的拼接,语句的作用是将sql语句发送给DBMS,DBMS进行字符的编译
rs = stmt.executeQuery(sql);
//正好将用户的非法信息拼接进去导致了sql的原意被扭曲,进而达到sql注入
用户名:fdsa
密码:'fdsa' or '1'='1'
解决SQL注入问题 PreparedStatement接口
#只要使用户提供的信息不参加编译即可解决
#即使用户提SQL语句,但不参加编译过程,不起作用
#要想用户的信息不参加编译过程,那么必须使用Java.sql.preparedStatemeng
PreparedStatement接口继承自Java.sql.Statement的数据库
preparedStatemeng是属于预编译的数据库操作对象
解决sql注入的关键
preparedStatemeng采用的是:预先对SQL语句进行编译,再SQL语句进行传“值”。
package com.JDBC;
import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
public class JDBCtest7 {
public static void main(String[] args) {
//初始化一个界面
Map<String,String> userLoginInfo = initUI();
boolean loginsucess = login(userLoginInfo);
System.out.println(loginsucess ? "登陆成功" : "登录失败");
}
private static boolean login(Map<String, String> userLogininfo) {
String loginName = userLogininfo.get("loginName");
String loginPwd = userLogininfo.get("loginPwd");
Connection cnn =null;
PreparedStatement ps = null;;
ResultSet rs = null;
try {
boolean flag = false;
Class.forName("com.mysql.jdbc.Driver");
cnn = DriverManager.getConnection( "jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8","root","123456");
String sql = "select * from t_user where loginName=? and loginPwd=?";
ps = cnn.prepareStatement(sql);
//给?占位符传值
ps.setString(1,loginName);
ps.setString(2,loginPwd);
rs = ps.executeQuery();
if(rs.next()){
flag = true;
}
return flag;
} catch (Exception e) {
e.printStackTrace();
}finally{
if(rs != null){
try {
rs.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(ps != null){
try {
ps.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(cnn !=null){
try {
cnn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
return false;
}
private static Map<String, String> initUI() {
Scanner sc = new Scanner(System.in);
System.out.print("用户名:");
String loginName=sc.nextLine();
System.out.print("密码:");
String loginPwd=sc.nextLine();
HashMap<String,String> userLoginInfo = new HashMap<>();
userLoginInfo.put("loginName",loginName);
userLoginInfo.put("loginPwd",loginPwd);
return userLoginInfo;
}
}
Statement和Prepared对比
1、Statement存在sql注入问题 PreparedStatement解决了sql注入问题
2、Statement是编译一次执行一次 PreparedStatement是编译一次可以执行n次 效率更高
3、PreParedStatement会在编译期间做类型的安全检查
JDBC事物自动提交机制
同时提交数据,防止数据的丢失
//将自动提交机制修改为手动提交机制
cnn.setAUtoCOmmit(false) //开启事务
cnn.commit() //提交事物 ===>执行完可能出现异常的语句
if(cnn != null){
try{
cnn.rollback(); //回滚事务
} catch (SQLException throwables) {
throwables.printStackTrace();
}
8、JDBC工具类的封装
JDBC工具类:为了简化JDBC编程
工具类中的构造方法是私有的
用为工具类中的方法都是静态的,不需要new对象,直接使用类名调用
9、悲观锁和乐观锁
行级锁又称悲观锁
事务必须排队执行,数据被锁住了,不支持并发。
select * from stuinfo2 for update;
for update 在当前事务没有结束之前,被锁定的指定行是数据是无法被修改的
乐观锁
事物不需要排队执行,允许并发,只不过需要一个版本号