JDBC(du)

JDBC

1、 jdbc是什么
java Database connectivity(java语句连接数据库)
2、JDBC 的本质是什么

JDBC是sun公司制定的一套接口(interface),
接口都有调用者和实现者。
面向接口调用,面向接口实现类。这都是属于面向接口的编程、
接口也是抽象编程
java.sql
为什么要面向接口编程?
解耦合:降低程序的耦合度,提高程序的扩展力。

多态机制是非常典型的的:面向抽象的编程。(不要面向具体编程)
建议
Animal a=new Cat();
Animal a=new Dog();
public void feed(Animal a){//面向父类形编程。
}
不建议
Dog d=new Dog();
cat c=new cat();
public void feed(Dog a){
}
为什么sun制定一套jdbc接口?
因为每一个数据库的底层实现原理都不一样。
ORacle 数据库有自己的原理。
MYSQL数据库也有自己的原理
.............
数据库产品都有自己独特的实现原理。
数据库驱动:所有数据库都是以jar包形式的存在,jar 包中有很多.class文件 就是对jdbc接口的实现
3、jdbc开发

下载对应的驱动jar 包,然后将其配置到classpath环境变量里

4、重要类

重要的类
DriverManager :依据数据库的不同,管理JDBC驱动
Connection :负责连接数据库并担任传送数据的任务——通过DriverManager获取的
Statement :由 Connection 产生、负责执行SQL语句
ResultSet:负责保存Statement执行后所产生的查询结果
ResultSetMetaData:换取关于ResultDate对象中的类型和属性信息的对象
PreparedStatement:继承Statement接口

DriverManager
驱动程序管理器,跟踪可用的驱动程序,并在数据库和相应的驱动程序之间建立连接。
注册驱动程序:
Class.forName(“com.microsoft.sqlserver.jdbc. SQLServerDriver”);
Class.forName(“sun.jdbc.odbc.JdbcOdbcDriver”);
Class.forName( "oracle.jdbc.driver.OracleDriver ");
Class.forName(“com.mysql.jdbc.Driver”);
注册的驱动程序类名称必须在用户的classPath中。

//第一种注册加载驱动
//DriverManger.registerDriver(new Driver()); 放到静态代码块
try {
Class.forName("com.mysql.cj.jdbc.Driver");//第二种
} catch (ClassNotFoundException e) {
e.printStackTrace();
}

Connection

换取数据库连接 对象

Connection conn= DriverManager.getConnection(url,user,pwd);
url:地址: jdbc : <subprotocol> : <subname>
user:数据库名
pwd:密码

Statement
执行sql语句
由Connection接口的createStatement()方法创建。
编译一次执行一次

//获取Statement
//executeupdate 增删改 executequery 查
Statement stm=conn.createStatement();
//4 执行SQL:executeupdate 就是执行增删改查
int i=stm.executeUpdate(sql);

ResultSet
处理查询结果集
在JDBC中数据库的所有查询记录将使用ResultSet接收并显示内容
ResultSet的常用方法:
next():判断有没有下一行,有指向下一行,并返回true,没有返回false
getObject(int index):索引,获取当前行第几列的值。1–Object
getObject(String lieming):列名,根据列名获取列名对应的值
getInt—int
getString-----

注意:随便的用来接注意类型

ResultSetMetaData
可以从这个对象获得有关数据库管理系统的各种信息,包括数据库中的各个表,表中的各个列,数据类型,触发器,存储过程等各方面的信息

ResultSetMetaData是在DatabaseMetaData类的对象上实现的,DataBaseMetaData对象又是在Connection对象上获得的。
 getURL():返回一个String类对象,代表数据库的URL。
 getUserName():返回连接当前数据库管理系统的用户名。
 isReadOnly():返回一个boolean值,指示数据库是否只允许读操作。
 getDatabaseProductName():返回数据库的产品名称。
 getDatabaseProductVersion():返回数据库的版本号。
 getDriverName():返回驱动驱动程序的名称。
 getDriverVersion():返回驱动程序的版本号。

PreparedStatement
 PreparedStatement 接口继承 Statement接口比普通的Statement对象更加灵活,有效解决SQL 注入问题(登录不要用statement)

区别

  1. Statement 可以先行创建, 然后将sql语句写入.执行时传入sql
  2. PreparedStatement 在创建时一定要传入 sql语句, 因为它要先运送到数据库执行预编译
  3. PreparedStatement 在执行之前 先要设置 语句中的参数. (预处理的sql语句有占位? 执行前需要给?指定参数值,执行时可以直接执行不需要传入sql)
  4. PreparedStatement 解决了sql注入问题
  5. PreparedStatement 效率高 (一个SQL语句一模一样的重复执行不会重新编译 用这个类的 话 执行不同的内容但是sql框架已经好了 编译一次可以执行n次)
  6. PreparedStatement 会在执行编译前阶段进行安全检查

总结::PreparedStatement 使用较多 ,只要少数情况的情况下需要使用Statement
只要在业务需要使用SQL注入的情况下必须使用Statement(需要代码拼接的·)

5、 jdbc编程六步(记)
  1. 注册驱动(作用:告诉java程序,即将连接的是哪一个品牌的数据库)
  2. 获取连接(表示jvm的进程和数据库进程之间的通道打开了,重量级的,使用完必须释放)
  3. 获取数据库操作对象(执行sql语句对象)
  4. 执行sql语句(DQL DML。。。)
  5. 处理查询结果集(只有当第四部执行的是select语句的时候,才有处理查询结果集)
  6. 释放资源(使用完一定要释放资源)
6 、 注入

当前程序存在的问题
用户名:随便
密码: ’ or ‘1’=’
登录成功
这种现象被称为sql注入。(黑客经常使用)
程序中有一个bug
导致的sql注入的根本原因是什么
用户输入的信息中含有SQL语句的关键字,那这些关键字参与啦sql语句的编译过程,
导致sql语句原意被扭曲,进而达到sql注入
使用PreparedStatement的预编译功能来解决sql的住入问题可以

7、事务

mysql的事务
事务:将多条sql当成整体去运行,要成功都成功,要失败都失败,事务的原子性(不可分割)
事务的特性:持久性(一经提交,数据会存储到数据库–存储磁盘中永久存在)
JDBC的事务
默认情况下连接COnnection属于自动模式 在自动提交模式下,每个SQL更新语句(insert,update,delete)成功执行完后就会自动提交到数据库中。

批处理

一次性需要新增上万条 上千数据,此时一条条处理,效率慢,数据库交互时间,可以进行批处理,可以将多条sql打成一个批次,推送给数据库执行一次。
conn.setAutoCommit(false);//关闭自动提交 默认为true
关闭来自动模式 每个sql都是事务的一部分
然后需要用commit()来进行显示的进行提交
在自动提交关闭后,不成功的提交会导致数据库进行隐式的回滚,所有的更新都会丢失。
conn.rollback();//回滚

conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/kong?&serverTimezone=GMT%2B8&yseSSL=false","root","04161220");
conn.setAutoCommit(false);//关闭自动提交
String sql="insert into students_copy1(sno,sname,ssex) values(?,?,?)";//SQL语句
prstm=conn.prepareStatement(sql);
for (int i=1;i<=100008;i++){
prstm.setObject(1,"aa"+1);
prstm.setObject(2,"bb");
prstm.setObject(3,"bb");
//pstm.executeUpdate() 需要数据库交互100万次
prstm.addBatch();//添加
if(i%100==0){//没100条进行来打包
prstm.executeBatch();//执行一批
prstm.clearBatch();
}
}
prstm.executeBatch();//
conn.commit();//
try {
conn.rollback();//回滚
} catch (SQLException ex) {
ex.printStackTrace();
}
JDBC日期

日期赋值
1、给日期赋值 直接赋值日期格式的字符串
2、给日期赋值、java.util.Date dateUtil=new java.util.Date();//当前时间的年月日时分秒
java.sql.Date datesql =new java.sql.Date(dateUtil.getTime());//可以取出sql格式的年月日 当前的日期
3、给日期赋值 Jdk8中的LocakDate LocalDateTIme
LocalDateTime dateTime= LocalDateTime.now();//当前时间的年月日时分秒
LocalDate date=LocalDate.now();//当前时间的年月日时分秒
4、给日期赋值 java.sql.Timestamp dates=new java.sql.Timestamp(dateUtil.getTime());
5、 java.sql.Date datesql =new java.sql.Date(dateUtil.getTime());//可以取出sql格式的年月日 当前的日期

java.util.Date dateUtil=new java.util.Date();//当前时间的年月日时分秒
java.sql.Date datesql =new java.sql.Date(dateUtil.getTime());//可以取出sql格式的年月日 当前的日期
java.sql.Timestamp dates=new java.sql.Timestamp(dateUtil.getTime());
LocalDateTime dateTime= LocalDateTime.now();//当前时间的年月日时分秒
LocalDate date=LocalDate.now();//当前时间的年月日时分秒

JDBC查询日期

ResultSetMetaData resultSetMetaData= rs.getMetaData();//吧ResultSet 查询1的结果 给ResultSetMetaData 这样就有时间类型了
while (rs.next()){
// 注意在 高版本的jdk中 日期只有 LocalDate
for (int i=1;i<resultSetMetaData.getColumnCount();i++){//循环他列数量
if(resultSetMetaData.getColumnClassName(i).equals("java.sql.Timestamp")){//判断这个例的值的属性是不是时间
java.sql.Timestamp timestamp=rs.getTimestamp(i);// 获取这个时间
java.util.Date date =new java.util.Date(timestamp.getTime()); //获取他
SimpleDateFormat format=new SimpleDateFormat("yyyy-MM-dd");
System.out.println(format.format(date));
}
}
}
Dao模式

dao全称是data access object,数据库访问对象,主要的功能就是用于进行数据操作的,在程序的标准开发架构中属于数据层的操作。
什么是Dao模式
分离了业务逻辑代码和数据访问代码,分工明确,降低耦合性,提高可重用性。
采用面向接口编程,提高了项目的可扩展性和可维护性。

1、DAO接口: 把对数据库的所有操作定义成抽象方法,可以提供多种实现
2、DAO 实现类: 针对不同数据库给出DAO接口定义方法的具体实现。
3、实体类:用于存放与传输对象数据。没有不影响
4、数据库连接和关闭工具类: 避免了数据库连接和关闭代码的重复使用,方便修改。

配置文件

A. 后缀为.properties;
B. 格式是“键=值”格式;
C. 使用“#”来注释D. 让用户脱离程序本身修改相关的变量设置——使用配置文件
E. Java中提供了Properties类来读取配置文件F. 注意:第一:前面有 “ / ”:“ / ”代表了工程的根目录,例如工程名叫做myproject,“ / ”代表了myproject 。 eg:me.class.getResourceAsStream("/com/x/file/myfile.xml"); 第二:前面没有 “ / ”::代表当前类的目录。

代码示例

jdbc基础

public class Maintest01 {
//1.加载驱动
//获取连接
public static void main(String[] args) {
//第一种注册加载驱动
//DriverManger.registerDriver(new Driver()); 放到静态代码块
try {
Class.forName("com.mysql.cj.jdbc.Driver");//第二种
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//2 获取连接
String user="root";
String pwd="04161220";
//协议 指明数据类型 连接谁的电脑 连接哪一个库 localhost
String url="jdbc:mysql://localhost:3306/scool?&serverTimezone=GMT%2B8&useSSL=false";
Connection conn=null;
Statement stm=null;
try {
conn= DriverManager.getConnection(url,user,pwd);
//System.out.println(conn);
//3 书写sql
String sql=" insert into t_b values('a','b','c');";
//获取Statement
//executeupdate 增删改 executequery 查
stm=conn.createStatement();
//4 执行SQL:executeupdate 就是执行增删改查
int i=stm.executeUpdate(sql);
//查询的数据应该要excuteQuery
System.out.println(i);
} catch (SQLException e) {
e.printStackTrace();
}finally{
//5 释放内存
//保证资源释放
//必须并列 一个不能关闭不能影响另一个的关闭
try {
if(stm!=null){ stm.close();}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if(conn!=null){ conn.close();}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}

处理查询结果集

public static void main(String[] args) {
Connection conn=null;
Statement stmt=null;
PreparedStatement stm=null;
ResultSet rs=null;
//1
try {
Class.forName("com.mysql.cj.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//是Statement对象的子接口,Statement可以进行它也可以——执行拼接字符串的sql fd
//解决sql注入:?占位,避开字符串拼接的,需要动态写的内容不走拼接走?占位,在执行之前使用固定的方法给?赋值。
//2 &serverTimezone=GMT%2B8&useSSL=false
try {
//"jdbc:mysql://localhost:3306/scool?&serverTimezone=GMT%2B8&useSSL=false";
conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/scool?&serverTimezone=GMT%2B8&useSSL=false","root","04161220");
//3
stmt=conn.createStatement();
//4 insert into 表名(列名)values(列值),(),(),(),(),()。。。。
rs= stmt.executeQuery(
"select * from T_b");
System.out.println(rs);
while(rs.next()){
//数据列的位置 第一个位置的值第二个位置的值(用列的位置来换取这个是不安全的)
String a=rs.getString(1);
String b=rs.getString(2);
String c=rs.getString(3);
//不通过列的下标通过列的名字换取比较安全
//名称
String a=rs.getString("B1");
String b=rs.getString("B2");
String c=rs.getString("A1");
//除了可以以String 类型取出之外还可以,以特定的2类型取出
int a=rs.getInt(1);
St
System.out.println(a+","+b+","+c);
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
if(stmt!=null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}

返回添加内容的主键的方法

/**
* @author zhangyifan
* @version 8.0
* @description: 获取新增的主键
* @date 2021/8/31 15:42
*/
public class JDBC04 {
static int age;
public static void main(String[] args) {
Connection con=null;
PreparedStatement pstm=null;
ResultSet rs=null;
try {//1
Class.forName("com.mysql.cj.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();//&serverTimezone=GMT%2B8&useSSL=false
}
//2
try {//"jdbc:mysql://localhost:3306/kong?&serverTimezone=GMT%2B8&yseSSL=false"
con= DriverManager.getConnection("jdbc:mysql://localhost:3306/scool?&serverTimezone=GMT%2B8&yseSSL=false","root","04161220");
//3
String sql="insert into classinfo(classname,Begintime,endtime) values(?,?,?)";//sql语句
pstm= con.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);//返回新增的一个主键
pstm.setString(1,"aa");
pstm.setString(2,"2011-01-01");
pstm.setString(3,"2022-02-02");
//4
int i = pstm.executeUpdate();//新增的时候需要返回两个值 :1 影响条数 2 主键
rs= pstm.getGeneratedKeys();// pstm中有一个属性来存储主键 getGeneratedKeys(); 可以将主键值取出来
System.out.println(i);
//5
if(rs.next()){
System.out.println(rs.getInt(1));
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
if (rs!=null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (pstm!=null){
try {
pstm.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (con!=null){
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}

封装的JDBC方法
工具类

/**
* @author zhangyifan
* @version 8.0
* @description: 03测试
* @date 2021/8/31 10:14
*/
public class JdbcTest03 {
public static void main(String[] args) {
//1加载驱动
Jdbc03 baseDao=new Jdbc03();
//2/获取连接
Connection conn=null;
PreparedStatement pstm=null;
ResultSet rs=null;
try {
conn=baseDao.getConn();
//3写SQL语句
String sql="select * from students";
pstm=conn.prepareStatement(sql);
//4执行sql语句
rs=pstm.executeQuery();
while (rs.next()){//5处理结果集
System.out.println(rs.getString(1));
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
baseDao.close(rs,pstm,conn);
}
//6释放资源
}
}
public class Jdbc03 {
/*
工具类中的方法都是私有的
因为工具类中的方法都是是类名直接调用的
* */
private static String user;
private static String pwd;
private static String url;
private static String classname;
static{// 静态代码块在类加载时只执行一次
//1加载驱动
try {
Properties m=new Properties();
InputStream is=Jdbc03.class.getResourceAsStream("db.properties");
m.load(is);//引进来
url=(String)m.get("db.url");
pwd=(String)m.get("db.pwd");
user=(String)m.get("db.user");
classname=(String) m.get("db.className");
Class.forName(classname);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public Connection getConn() throws SQLException {
return DriverManager.getConnection(url,user,pwd);
}
public void close(ResultSet rs, Statement stm, Connection conn){
if(rs!=null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(stm!=null){
try {
stm.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
properties文件
db.user=root
db.pwd=04161220
db.url=jdbc:mysql://localhost:3306/kong?&serverTimezone=GMT%2B8&useSSL=false
db.className=com.mysql.cj.jdbc.Driver

封装jdbc增删改查示例

package com.preson.JDBC04;
import com.preson.Jdbc_03lx.JDBC01;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
/**
* @author zhangyifan
* @version 8.0
* @description: 封装
* @date 2021/9/2 8:50
*/
public class BaseDao {
private static String url;
private static String use;
private static String pwd;
private static String classname;
static {
Properties properties=new Properties();//获取对象
InputStream in=BaseDao.class.getResourceAsStream("db.properties");//获取连接
try {
properties.load(in);//用properties对象获取里面的对象
//然后一个一个付值
url= (String) properties.get("db.4url");
use= (String) properties.get("db.4use");
pwd= (String) properties.get("db.4pwd");
classname= (String) properties.get("db.4classname");
Class.forName(classname);//获取连接
} catch (Exception e) {
e.printStackTrace();
}
}
/**
*
* @return 连接数据库
* @throws SQLException
*/
public static Connection getconn() throws SQLException {
return DriverManager.getConnection(url,use,pwd);
}
/**
*
*增删改查封装
* @param sql 语句
* @param objects 添加的对象
* @return 返回确认成功不
* @throws SQLException
*/
public int execupatd(String sql,Object[] objects) throws SQLException {
Connection con = null;
PreparedStatement prsm = null;
try {
con = this.getconn();//把添加中的两个需要改变的元素取出 sql语句 和 修改的内容
// String sql="insert into classinfo(classname,begintime,gradeid) values(?,?,?)";
prsm = con.prepareStatement(sql); //获取预编译sql语句
//修改的内容可以用数组来创建 吸收
// Object[] objects={"aaa","2021-01-02",3};
if (objects!=null&&objects.length>0) {
for (int i = 0; i < objects.length; i++) {//用遍历数组的方式把?的值循环付上去
prsm.setObject(i + 1, objects[i]);
}
}
int i=prsm.executeUpdate();//运行添加 返回的影响条数返回
return i;
} catch (SQLException e) {
e.printStackTrace();
throw e;
} finally {
this.close(con, prsm, null);
}
}
/**
* 查询新增主键
* @param sql
* @param objects
* @return 主键
* @throws SQLException
*/
public Object execupatdkey(String sql,Object[] objects) throws SQLException {
Connection con=null;
PreparedStatement prsm=null;
ResultSet rs=null;
try {
con=this.getconn();
// String sql="insert into classinfo(classname,begintime,gradeid) values(?,?,?)";
prsm=con.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
// Object[] objects={"aaa","2021-01-02",3};
for(int i=0;i<objects.length;i++){
prsm.setObject(i+1,objects[i]);
}
prsm.executeUpdate();
rs= prsm.getGeneratedKeys();
if(rs.next()){
return rs.getInt(1);
}
return -1;
} catch (SQLException e) {
e.printStackTrace();
throw e;
}finally {
this.close(con,prsm,null);
}
}
/**
* 查询封装
* @param sql
* @param objects
*/
public void exeQuery(String sql,Object[] objects){
Connection con=null;
PreparedStatement prtm=null;
ResultSet rs=null;
try {
con=this.getconn();
} catch (SQLException e) {
e.printStackTrace();
}
try {
prtm=con.prepareStatement(sql);
if(objects!=null&&objects.length>0) {//进行判断 判断数组是否为空 如果为空证明没有用?
for (int i = 0; i < objects.length; i++) {
prtm.setObject(i + 1, objects[i]);
}
}
rs = prtm.executeQuery();
ResultSetMetaData rsm = rs.getMetaData();
while (rs.next()) {
for (int i = 1; i < rsm.getColumnCount(); i++) {
System.out.print(rsm.getColumnName(i) + "----" + rs.getObject(i) + "\t");
}
System.out.println();
}
} catch (Exception e) {
e.printStackTrace();
}finally {
this.close(con,prtm,rs);
}
}
//kong?&serverTimezone=GMT%2B8&yseSSL=false
/**
* 释放资源
* @param con
* @param stm
* @param rs
*/
public static void close(Connection con, Statement stm, ResultSet rs){
if(rs!=null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(stm!=null){
try {
stm.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(con!=null){
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
posted @   啧啧啧|(* ̄ ̄*)  阅读(4)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
点击右上角即可分享
微信分享提示