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 /><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 />```javaclass 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>#### 处理结果集**取出数据后的处理**```javaResultset结果集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.preparedStatemengPreparedStatement接口继承自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 在当前事务没有结束之前,被锁定的指定行是数据是无法被修改的
乐观锁
事物不需要排队执行,允许并发,只不过需要一个版本号
